From db8dd3e6140e66db46f309bff9054ba137eb797a Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Mon, 29 Oct 2018 03:03:29 -0400 Subject: move around some type-specific scripts --- bashrc | 2 +- bin/gpg | 6 - bin/gpg2 | 1 - bin/i3-switch-workspace | 122 -------------------- bin/kill_focused | 48 -------- bin/laptop/gpg | 6 + bin/laptop/gpg2 | 1 + bin/laptop/i3-switch-workspace | 122 ++++++++++++++++++++ bin/laptop/kill_focused | 48 ++++++++ bin/laptop/numkeys | 52 +++++++++ bin/laptop/pass | 88 +++++++++++++++ bin/laptop/scp | 1 + bin/laptop/setup-inputs | 18 +++ bin/laptop/sftp | 1 + bin/laptop/ssh | 8 ++ bin/laptop/ssh-add-helper | 14 +++ bin/laptop/ssh-key-unlock | 7 ++ bin/laptop/status | 251 +++++++++++++++++++++++++++++++++++++++++ bin/laptop/svdn | 13 +++ bin/laptop/svget | 3 + bin/laptop/svkill | 4 + bin/laptop/svlog | 3 + bin/laptop/svre | 4 + bin/laptop/svst | 3 + bin/laptop/svstop | 4 + bin/laptop/svup | 4 + bin/laptop/update-weather | 9 ++ bin/laptop/update_mail | 9 ++ bin/laptop/volume | 24 ++++ bin/laptop/weather | 60 ++++++++++ bin/laptop/webcam | 2 + bin/laptop/wifi | 38 +++++++ bin/learn_spam | 36 ------ bin/numkeys | 52 --------- bin/pass | 88 --------------- bin/scp | 1 - bin/server/learn_spam | 36 ++++++ bin/setup-inputs | 18 --- bin/sftp | 1 - bin/ssh | 8 -- bin/ssh-add-helper | 14 --- bin/ssh-key-unlock | 7 -- bin/status | 251 ----------------------------------------- bin/svdn | 13 --- bin/svget | 3 - bin/svkill | 4 - bin/svlog | 3 - bin/svre | 4 - bin/svst | 3 - bin/svstop | 4 - bin/svup | 4 - bin/update-weather | 9 -- bin/update_mail | 9 -- bin/volume | 24 ---- bin/weather | 60 ---------- bin/webcam | 2 - bin/wifi | 38 ------- i3/config | 6 +- sh/env | 4 +- zshrc | 2 +- 60 files changed, 840 insertions(+), 840 deletions(-) delete mode 100755 bin/gpg delete mode 120000 bin/gpg2 delete mode 100755 bin/i3-switch-workspace delete mode 100755 bin/kill_focused create mode 100755 bin/laptop/gpg create mode 120000 bin/laptop/gpg2 create mode 100755 bin/laptop/i3-switch-workspace create mode 100755 bin/laptop/kill_focused create mode 100755 bin/laptop/numkeys create mode 100755 bin/laptop/pass create mode 120000 bin/laptop/scp create mode 100755 bin/laptop/setup-inputs create mode 120000 bin/laptop/sftp create mode 100755 bin/laptop/ssh create mode 100755 bin/laptop/ssh-add-helper create mode 100755 bin/laptop/ssh-key-unlock create mode 100755 bin/laptop/status create mode 100755 bin/laptop/svdn create mode 100755 bin/laptop/svget create mode 100755 bin/laptop/svkill create mode 100755 bin/laptop/svlog create mode 100755 bin/laptop/svre create mode 100755 bin/laptop/svst create mode 100755 bin/laptop/svstop create mode 100755 bin/laptop/svup create mode 100755 bin/laptop/update-weather create mode 100755 bin/laptop/update_mail create mode 100755 bin/laptop/volume create mode 100755 bin/laptop/weather create mode 100755 bin/laptop/webcam create mode 100755 bin/laptop/wifi delete mode 100755 bin/learn_spam delete mode 100755 bin/numkeys delete mode 100755 bin/pass delete mode 120000 bin/scp create mode 100755 bin/server/learn_spam delete mode 100755 bin/setup-inputs delete mode 120000 bin/sftp delete mode 100755 bin/ssh delete mode 100755 bin/ssh-add-helper delete mode 100755 bin/ssh-key-unlock delete mode 100755 bin/status delete mode 100755 bin/svdn delete mode 100755 bin/svget delete mode 100755 bin/svkill delete mode 100755 bin/svlog delete mode 100755 bin/svre delete mode 100755 bin/svst delete mode 100755 bin/svstop delete mode 100755 bin/svup delete mode 100755 bin/update-weather delete mode 100755 bin/update_mail delete mode 100755 bin/volume delete mode 100755 bin/weather delete mode 100755 bin/webcam delete mode 100755 bin/wifi diff --git a/bashrc b/bashrc index 83c2145..5242207 100644 --- a/bashrc +++ b/bashrc @@ -5,7 +5,7 @@ type rbenv > /dev/null 2>&1 && eval "$(rbenv init -)" test -d $HOME/.cargo/bin && export PATH="$HOME/.cargo/bin:$PATH" # }}} # environment {{{ -export PATH="/usr/share/git/diff-highlight:${HOME}/.bin/local:${HOME}/.bin:/usr/lib/ccache/bin:$PATH" +export PATH="${HOME}/.bin/local:${HOME}/.bin/$(cat "${HOME}/conf/.conf-type"):${HOME}/.bin:/usr/lib/ccache/bin:/usr/share/git/diff-highlight:$PATH" [ -f "$HOME/.sh/env" ] && source $HOME/.sh/env # }}} # Test for an interactive shell. {{{ diff --git a/bin/gpg b/bin/gpg deleted file mode 100755 index d418711..0000000 --- a/bin/gpg +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -GPG=/usr/bin/$(basename $0) - -keychain -q --timeout 30 -$GPG $* diff --git a/bin/gpg2 b/bin/gpg2 deleted file mode 120000 index a7506d6..0000000 --- a/bin/gpg2 +++ /dev/null @@ -1 +0,0 @@ -gpg \ No newline at end of file diff --git a/bin/i3-switch-workspace b/bin/i3-switch-workspace deleted file mode 100755 index 8e77cf2..0000000 --- a/bin/i3-switch-workspace +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -use IO::Socket::UNIX; -use JSON; - -my $json = JSON->new; - -my %message_types = ( - command => 0, - get_workspaces => 1, - subscribe => 2, - get_outputs => 3, - get_tree => 4, - get_marks => 5, - get_bar_config => 6, - get_version => 7, -); - -my %message_codes = (reverse %message_types); - -my $dir = $ARGV[0]; - -chomp(my $path = qx(i3 --get-socketpath)); -my $sock = IO::Socket::UNIX->new(Peer => $path); - -my $workspace_data = $json->decode(i3_msg('get_workspaces')); - -my $next_workspace = $workspace_data->[-1]{num} + 1; -my $prev_workspace = $workspace_data->[0]{num} - 1; - -if (@$workspace_data == 1) { - my $current_workspace = $workspace_data->[0]{num}; - my $tree_data = $json->decode(i3_msg('get_tree')); - my $workspace_tree = find_workspace($tree_data, $current_workspace); - if ($dir eq 'prev') { - i3_msg('command', "workspace number $prev_workspace"); - } - else { - i3_msg('command', "workspace number $next_workspace"); - } -} -elsif ($workspace_data->[0]{focused} && $dir eq 'prev') { - my $current_workspace = $workspace_data->[0]{num}; - my $tree_data = $json->decode(i3_msg('get_tree')); - my $workspace_tree = find_workspace($tree_data, $current_workspace); - if (@{ $workspace_tree->{nodes} } || @{ $workspace_tree->{floating_nodes} }) { - if ($prev_workspace > 0) { - i3_msg('command', "workspace number $prev_workspace"); - } - } -} -elsif ($workspace_data->[-1]{focused} && $dir eq 'next') { - my $current_workspace = $workspace_data->[-1]{num}; - my $tree_data = $json->decode(i3_msg('get_tree')); - my $workspace_tree = find_workspace($tree_data, $current_workspace); - if (@{ $workspace_tree->{nodes} } || @{ $workspace_tree->{floating_nodes} }) { - i3_msg('command', "workspace number $next_workspace"); - } -} -else { - for my $i (0..$#$workspace_data) { - if ($workspace_data->[$i]{focused}) { - my $to = $workspace_data->[$i]{num} + ($dir eq 'prev' ? -1 : 1); - i3_msg('command', "workspace number $to"); - last; - } - } -} - -sub find_workspace { - my ($tree, $num) = @_; - if (exists $tree->{num} && $tree->{num} == $num) { - return $tree; - } - for my $node (@{ $tree->{nodes} }) { - my $found = find_workspace($node, $num); - return $found if $found; - } - return; -} - -sub build_i3_msg { - my ($type, $payload) = @_; - - $payload = '' - unless $type eq 'command' || $type eq 'subscribe'; - - utf8::encode($payload); - - return 'i3-ipc' - . pack('LL', length($payload), $message_types{$type}) - . $payload; -} - -sub get_i3_msg { - my $bytes = $sock->read(my $header, 14); - die "invalid read" if $bytes != 14; - die "invalid format: $header" if substr($header, 0, 6) ne 'i3-ipc'; - my ($length, $type) = unpack('LL', substr($header, 6, 8)); - - if ($length) { - my $bytes = $sock->read(my $payload, $length); - die "invalid read" if $bytes != $length; - utf8::decode($payload); - return ($message_codes{$type}, $payload); - } - else { - return ($message_codes{$type}); - } -} - -sub i3_msg { - my ($type, $payload) = @_; - my $msg = build_i3_msg($type, $payload); - $sock->write($msg); - my ($got_type, $got_payload) = get_i3_msg(); - die "got $got_type message, expected $type message" - unless $type eq $got_type; - return $got_payload; -} diff --git a/bin/kill_focused b/bin/kill_focused deleted file mode 100755 index 06010d4..0000000 --- a/bin/kill_focused +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -use JSON; - -my ($sig) = @ARGV; -my $pid = get_pid(); -my $pgrp = get_pgrp($pid); -kill $sig, -$pgrp; - -sub get_pid { - my $window_id = get_window_id(); - die "couldn't find window" unless defined $window_id; - my $prop = `xprop -id $window_id _NET_WM_PID`; - die "couldn't get pid from focused window" - if $prop =~ /not found/; - chomp($prop); - $prop =~ s/^_NET_WM_PID\(CARDINAL\) = //; - return $prop; -} - -sub get_pgrp { - my ($pid) = @_; - open my $stat_fh, '<', "/proc/$pid/stat" - or die "couldn't open /proc/$pid/stat"; - my $stat = do { local $/; <$stat_fh> }; - my @f = ($stat =~ /\([^)]*\)|[^ ]+/g); - return $f[4]; -} - -sub get_window_id { - return find(decode_json(`i3-msg -t get_tree`))->{window}; -} - -sub find { - my ($t) = @_; - if ($t->{focused}) { - return $t; - } - - for my $subtree (@{ $t->{nodes} }, @{ $t->{floating_nodes} }) { - my $found = find($subtree); - return $found if $found; - } - - return; -} diff --git a/bin/laptop/gpg b/bin/laptop/gpg new file mode 100755 index 0000000..d418711 --- /dev/null +++ b/bin/laptop/gpg @@ -0,0 +1,6 @@ +#!/bin/bash + +GPG=/usr/bin/$(basename $0) + +keychain -q --timeout 30 +$GPG $* diff --git a/bin/laptop/gpg2 b/bin/laptop/gpg2 new file mode 120000 index 0000000..a7506d6 --- /dev/null +++ b/bin/laptop/gpg2 @@ -0,0 +1 @@ +gpg \ No newline at end of file diff --git a/bin/laptop/i3-switch-workspace b/bin/laptop/i3-switch-workspace new file mode 100755 index 0000000..8e77cf2 --- /dev/null +++ b/bin/laptop/i3-switch-workspace @@ -0,0 +1,122 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use IO::Socket::UNIX; +use JSON; + +my $json = JSON->new; + +my %message_types = ( + command => 0, + get_workspaces => 1, + subscribe => 2, + get_outputs => 3, + get_tree => 4, + get_marks => 5, + get_bar_config => 6, + get_version => 7, +); + +my %message_codes = (reverse %message_types); + +my $dir = $ARGV[0]; + +chomp(my $path = qx(i3 --get-socketpath)); +my $sock = IO::Socket::UNIX->new(Peer => $path); + +my $workspace_data = $json->decode(i3_msg('get_workspaces')); + +my $next_workspace = $workspace_data->[-1]{num} + 1; +my $prev_workspace = $workspace_data->[0]{num} - 1; + +if (@$workspace_data == 1) { + my $current_workspace = $workspace_data->[0]{num}; + my $tree_data = $json->decode(i3_msg('get_tree')); + my $workspace_tree = find_workspace($tree_data, $current_workspace); + if ($dir eq 'prev') { + i3_msg('command', "workspace number $prev_workspace"); + } + else { + i3_msg('command', "workspace number $next_workspace"); + } +} +elsif ($workspace_data->[0]{focused} && $dir eq 'prev') { + my $current_workspace = $workspace_data->[0]{num}; + my $tree_data = $json->decode(i3_msg('get_tree')); + my $workspace_tree = find_workspace($tree_data, $current_workspace); + if (@{ $workspace_tree->{nodes} } || @{ $workspace_tree->{floating_nodes} }) { + if ($prev_workspace > 0) { + i3_msg('command', "workspace number $prev_workspace"); + } + } +} +elsif ($workspace_data->[-1]{focused} && $dir eq 'next') { + my $current_workspace = $workspace_data->[-1]{num}; + my $tree_data = $json->decode(i3_msg('get_tree')); + my $workspace_tree = find_workspace($tree_data, $current_workspace); + if (@{ $workspace_tree->{nodes} } || @{ $workspace_tree->{floating_nodes} }) { + i3_msg('command', "workspace number $next_workspace"); + } +} +else { + for my $i (0..$#$workspace_data) { + if ($workspace_data->[$i]{focused}) { + my $to = $workspace_data->[$i]{num} + ($dir eq 'prev' ? -1 : 1); + i3_msg('command', "workspace number $to"); + last; + } + } +} + +sub find_workspace { + my ($tree, $num) = @_; + if (exists $tree->{num} && $tree->{num} == $num) { + return $tree; + } + for my $node (@{ $tree->{nodes} }) { + my $found = find_workspace($node, $num); + return $found if $found; + } + return; +} + +sub build_i3_msg { + my ($type, $payload) = @_; + + $payload = '' + unless $type eq 'command' || $type eq 'subscribe'; + + utf8::encode($payload); + + return 'i3-ipc' + . pack('LL', length($payload), $message_types{$type}) + . $payload; +} + +sub get_i3_msg { + my $bytes = $sock->read(my $header, 14); + die "invalid read" if $bytes != 14; + die "invalid format: $header" if substr($header, 0, 6) ne 'i3-ipc'; + my ($length, $type) = unpack('LL', substr($header, 6, 8)); + + if ($length) { + my $bytes = $sock->read(my $payload, $length); + die "invalid read" if $bytes != $length; + utf8::decode($payload); + return ($message_codes{$type}, $payload); + } + else { + return ($message_codes{$type}); + } +} + +sub i3_msg { + my ($type, $payload) = @_; + my $msg = build_i3_msg($type, $payload); + $sock->write($msg); + my ($got_type, $got_payload) = get_i3_msg(); + die "got $got_type message, expected $type message" + unless $type eq $got_type; + return $got_payload; +} diff --git a/bin/laptop/kill_focused b/bin/laptop/kill_focused new file mode 100755 index 0000000..06010d4 --- /dev/null +++ b/bin/laptop/kill_focused @@ -0,0 +1,48 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use JSON; + +my ($sig) = @ARGV; +my $pid = get_pid(); +my $pgrp = get_pgrp($pid); +kill $sig, -$pgrp; + +sub get_pid { + my $window_id = get_window_id(); + die "couldn't find window" unless defined $window_id; + my $prop = `xprop -id $window_id _NET_WM_PID`; + die "couldn't get pid from focused window" + if $prop =~ /not found/; + chomp($prop); + $prop =~ s/^_NET_WM_PID\(CARDINAL\) = //; + return $prop; +} + +sub get_pgrp { + my ($pid) = @_; + open my $stat_fh, '<', "/proc/$pid/stat" + or die "couldn't open /proc/$pid/stat"; + my $stat = do { local $/; <$stat_fh> }; + my @f = ($stat =~ /\([^)]*\)|[^ ]+/g); + return $f[4]; +} + +sub get_window_id { + return find(decode_json(`i3-msg -t get_tree`))->{window}; +} + +sub find { + my ($t) = @_; + if ($t->{focused}) { + return $t; + } + + for my $subtree (@{ $t->{nodes} }, @{ $t->{floating_nodes} }) { + my $found = find($subtree); + return $found if $found; + } + + return; +} diff --git a/bin/laptop/numkeys b/bin/laptop/numkeys new file mode 100755 index 0000000..ab9dc14 --- /dev/null +++ b/bin/laptop/numkeys @@ -0,0 +1,52 @@ +#!/bin/sh + +on() { + xmodmap -e 'keycode 10 = exclam 1' + xmodmap -e 'keycode 11 = at 2' + xmodmap -e 'keycode 12 = numbersign 3' + xmodmap -e 'keycode 13 = dollar 4' + xmodmap -e 'keycode 14 = percent 5' + xmodmap -e 'keycode 15 = asciicircum 6' + xmodmap -e 'keycode 16 = ampersand 7' + xmodmap -e 'keycode 17 = asterisk 8' + xmodmap -e 'keycode 18 = parenleft 9' + xmodmap -e 'keycode 19 = parenright 0' + xmodmap -e 'keycode 20 = underscore minus' + xmodmap -e 'keycode 34 = braceleft bracketleft' + xmodmap -e 'keycode 35 = braceright bracketright' + xmodmap -e 'keycode 49 = asciitilde grave' + xmodmap -e 'keycode 51 = bar backslash' +} + +off() { + xmodmap -e 'keycode 10 = 1 exclam' + xmodmap -e 'keycode 11 = 2 at' + xmodmap -e 'keycode 12 = 3 numbersign' + xmodmap -e 'keycode 13 = 4 dollar' + xmodmap -e 'keycode 14 = 5 percent' + xmodmap -e 'keycode 15 = 6 asciicircum' + xmodmap -e 'keycode 16 = 7 ampersand' + xmodmap -e 'keycode 17 = 8 asterisk' + xmodmap -e 'keycode 18 = 9 parenleft' + xmodmap -e 'keycode 19 = 0 parenright' + xmodmap -e 'keycode 20 = minus underscore' + xmodmap -e 'keycode 34 = bracketleft braceleft' + xmodmap -e 'keycode 35 = bracketright braceright' + xmodmap -e 'keycode 49 = grave asciitilde' + xmodmap -e 'keycode 51 = backslash bar' +} + +toggle() { + if xmodmap -pk | grep -q '(1).*(exclam).*(1).*(exclam)'; then + on + else + off + fi +} + +case "$1" in + on) on ;; + off) off ;; + toggle) toggle ;; + *) echo invalid 1>&2; exit 1 ;; +esac diff --git a/bin/laptop/pass b/bin/laptop/pass new file mode 100755 index 0000000..fd4a9aa --- /dev/null +++ b/bin/laptop/pass @@ -0,0 +1,88 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +my $PASS = '/usr/bin/pass'; + +my $cmd = $ARGV[0]; + +if ($cmd && $cmd eq 'search') { + shift @ARGV; + + chdir "$ENV{HOME}/.password-store" + or die "password store not initialized"; + + require Path::Class; + + my $pat_str = pop @ARGV; + my $pattern = qr/$pat_str/; + + my $username = grep { $_ eq '-u' } @ARGV; + @ARGV = grep { $_ ne '-u' } @ARGV; + + my $clipboard = grep { $_ eq '-c' || $_ eq '--clip' } @ARGV; + + my @found = Path::Class::Dir->new('.')->traverse(sub { + my ($file, $c) = @_; + return if $file eq '.git'; + return ( + $c->(), + ((-f $file && $file =~ s/\.gpg$// && $file =~ $pattern) + ? ($file) + : ()), + ); + }); + + if (@found < 1) { + die "No passwords found matching '$pat_str'\n"; + } + elsif (@found > 1) { + die "Ambiguous pattern '$pat_str': could match any of @found\n"; + } + else { + if (my $pass = `$PASS show '$found[0]'`) { + if ($username) { + if ($found[0] =~ m{^[^/]*/[^/]*/([^/]*)$}) { + my $user = $1; + if ($clipboard) { + clip($user); + } + else { + print "$user\n"; + } + } + else { + die "$found[0] has no username"; + } + } + + if ($clipboard) { + $pass =~ s/\n.*//s; + clip($pass); + } + else { + print $pass; + } + } + } +} +else { + exec { $PASS } $PASS, @ARGV +} + +sub clip { + my ($text) = @_; + my @pids; + for my $selection (qw(primary clipboard)) { + my $pid = fork; + if (!$pid) { + open my $fh, '|-', "timeout 1m xclip -loops 1 -quiet -selection $selection 2> /dev/null" + or die "couldn't run xclip"; + $fh->write("$text\n"); + $fh->close; + exit; + } + push @pids, $pid; + } + waitpid($_, 0) for @pids; +} diff --git a/bin/laptop/scp b/bin/laptop/scp new file mode 120000 index 0000000..ffd8d03 --- /dev/null +++ b/bin/laptop/scp @@ -0,0 +1 @@ +ssh \ No newline at end of file diff --git a/bin/laptop/setup-inputs b/bin/laptop/setup-inputs new file mode 100755 index 0000000..6aaa19f --- /dev/null +++ b/bin/laptop/setup-inputs @@ -0,0 +1,18 @@ +#!/bin/sh + +# key bindings +setxkbmap -option ctrl:nocaps +setxkbmap -option compose:caps +xmodmap $HOME/.Xmodmap +"$(dirname "$0")"/numkeys on + +# trackpad settings +xinput set-prop "SynPS/2 Synaptics TouchPad" "libinput Accel Speed" 0.4 +xinput set-prop "SynPS/2 Synaptics TouchPad" "libinput Tapping Enabled" 1 + +# restart services that depend on keyboard reconfigurations +if pgrep readproctitle > /dev/null; then + svre xcape + svre kuake + svre xbindkeys +fi diff --git a/bin/laptop/sftp b/bin/laptop/sftp new file mode 120000 index 0000000..ffd8d03 --- /dev/null +++ b/bin/laptop/sftp @@ -0,0 +1 @@ +ssh \ No newline at end of file diff --git a/bin/laptop/ssh b/bin/laptop/ssh new file mode 100755 index 0000000..453bb11 --- /dev/null +++ b/bin/laptop/ssh @@ -0,0 +1,8 @@ +#!/bin/bash + +SSH=/usr/bin/$(basename $0) + +if [[ $1 != '-V' ]]; then + . ssh-key-unlock +fi +exec $SSH $* diff --git a/bin/laptop/ssh-add-helper b/bin/laptop/ssh-add-helper new file mode 100755 index 0000000..cae6f27 --- /dev/null +++ b/bin/laptop/ssh-add-helper @@ -0,0 +1,14 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use IO::Pty::Easy; + +my $hostname = `hostname`; +my $pass = `pass search ssh.$hostname`; +my $pty = IO::Pty::Easy->new; +$pty->spawn("ssh-add -t 1800 $ARGV[0]"); +$pty->read; +$pty->write($pass . "\n"); +while (1) { + last if $pty->read =~ 'Identity added'; +} diff --git a/bin/laptop/ssh-key-unlock b/bin/laptop/ssh-key-unlock new file mode 100755 index 0000000..e2654f1 --- /dev/null +++ b/bin/laptop/ssh-key-unlock @@ -0,0 +1,7 @@ +#!/bin/bash + +keychain -q --timeout 30 +. ~/.keychain/${HOSTNAME}-sh +if ! ssh-add -l | grep -q '.ssh/id_rsa'; then + ssh-add-helper ~/.ssh/id_rsa +fi diff --git a/bin/laptop/status b/bin/laptop/status new file mode 100755 index 0000000..062455d --- /dev/null +++ b/bin/laptop/status @@ -0,0 +1,251 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use 5.010; + +use IO::Select; +use IO::Socket::UNIX; +use JSON; + +my $i3status = get_i3status_handle(); +my $ipc = get_ipc_handle(); +$|++; +say "[]"; + +my $select = IO::Select->new; +$select->add($i3status); +$select->add($ipc); + +my $current_data; + +while (my @ready = $select->can_read) { + for my $fh (@ready) { + if ($fh == $i3status) { + handle_i3status(scalar <$fh>); + } + elsif ($fh == $ipc) { + handle_ipc(receive_ipc_message($fh)); + } + else { + die "???"; + } + } +} + +sub get_i3status_handle { + open my $i3status, '-|', 'i3status'; + + print scalar(<$i3status>); + print scalar(<$i3status>); + + return $i3status; +} + +sub handle_i3status { + $_ = shift; + s/^,//; + + my $data = decode_json($_); + + my %line = map { $_->{name} => $_ } @$data; + my $line = [ + grep { + $_->{name} eq 'wireless' || $_->{name} eq 'ethernet' + ? $_->{instance} ne $_->{full_text} + : $_->{name} ne 'load' + } @$data + ]; + + my %discharge_rate; + my %battery_index; + + my $index = 0; + for my $item (@$line) { + if ($item->{name} eq 'wireless' || $item->{name} eq 'ethernet') { + my $iface = $item->{instance}; + my ($up, $down) = map { net_rate($iface, $_) } 'rx', 'tx'; + my $rate = sprintf("%6s/%6s", map { human_bytes($_) } $up, $down); + $item->{full_text} =~ s{^($iface:)}{$1 $rate}; + $item->{color} = + $up + $down >= 512000 ? '#FF0000' + : $up + $down >= 51200 ? '#FFFF00' + : $up + $down >= 5120 ? '#00FF00' + : '#FFFFFF'; + } + if ($item->{name} eq 'cpu_usage') { + my ($val) = $line{load}{full_text} * 100 / ncpu(); + $item->{color} = + $val >= 50 ? '#FF0000' + : $val >= 25 ? '#FFFF00' + : $val >= 5 ? '#00FF00' + : '#FFFFFF'; + } + if ($item->{name} eq 'battery') { + my ($state, $val) = $item->{full_text} =~ /(\w+) (\d+(?:\.\d+))%/; + my ($rate) = $item->{full_text} =~ /\(.* (.*)W\)/; + $rate *= -1 if defined($rate) && $state ne 'BAT'; + $rate //= 0; + + $discharge_rate{$item->{instance}} = $rate; + $battery_index{$item->{instance}} = $index; + + $item->{full_text} =~ s/\((.*) (.*)W\)/\($1\)/; + $item->{full_text} =~ s/ \(\)//; + $item->{color} = + !defined($val) ? '#FFFFFF' + : $val >= 80 ? '#00FF00' + : $state ne 'BAT' ? '#FFFFFF' + : $val >= 40 ? '#FFFFFF' + : $val >= 15 ? '#FFFF00' + : $val >= 5 ? '#CD0000' + : '#FF0000'; + } + $index++; + } + + my @batteries = sort { $battery_index{$b} <=> $battery_index{$a} } + keys %battery_index; + for my $battery (@batteries) { + next unless $discharge_rate{$battery}; + splice @$line, $battery_index{$battery} + 1, 0, { + name => 'battery_discharge', + full_text => sprintf("%0.2fW", $discharge_rate{$battery}), + color => ( + $discharge_rate{$battery} < 6 ? '#FFFFFF' + : $discharge_rate{$battery} < 10 ? '#00FF00' + : $discharge_rate{$battery} < 14 ? '#FFFF00' + : '#FF0000' + ), + }; + } + + my $weather_file = "$ENV{HOME}/.cache/weather"; + if (-r $weather_file && -f $weather_file) { + my $weather = slurp($weather_file); + chomp($weather); + my ($temp) = $weather =~ /\d+%.*?(-?\d+)F.*?-?\d+F/; + unshift @$line, { + name => 'weather', + full_text => $weather, + color => ( + $temp >= 90 ? '#FF0000' + : $temp >= 78 ? '#FFFF00' + : $temp >= 73 ? '#00FF00' + : $temp >= 55 ? '#FFFFFF' + : $temp >= 32 ? '#CDCDFF' + : '#0000FF' + ), + }; + } + + $current_data = $line; + + show_status(); +} + +sub get_ipc_handle { + chomp(my $path = qx(i3 --get-socketpath)); + + my $sock = IO::Socket::UNIX->new(Peer => $path); + $sock->write(format_ipc_message(2, q{["window", "workspace"]})); + my ($type, $payload) = receive_ipc_message($sock); + die "Couldn't subscribe: ($type) $payload" + unless $type == 2 && decode_json($payload)->{success}; + + return $sock; +} + +sub handle_ipc { + my ($type, $payload) = @_; + show_status(); +} + +sub format_ipc_message { + my ($type, $payload) = @_; + my $len = do { use bytes; length($payload) }; + return "i3-ipc" . pack("LL", $len, $type) . $payload; +} + +sub receive_ipc_message { + my ($sock) = @_; + + $sock->read(my $magic, 6); + die "unknown response: $magic" unless $magic eq 'i3-ipc'; + $sock->read(my $len, 4); + $len = unpack("L", $len); + $sock->read(my $type, 4); + $type = unpack("L", $type); + $sock->read(my $payload, $len); + + return ($type, $payload); +} + +sub show_status { + my @line = @$current_data; + unshift @line, { name => 'title', full_text => get_title() }; + say "," . encode_json(\@line); +} + +sub get_title { + my $node = find(decode_json(`i3-msg -t get_tree`)); + if ($node->{window}) { + return $node->{name}; + } + else { + return '-none-'; + } +} + +sub find { + my ($t) = @_; + if ($t->{focused}) { + return $t; + } + + for my $subtree (@{ $t->{nodes} }, @{ $t->{floating_nodes} }) { + my $found = find($subtree); + return $found if $found; + } + + return; +} + +{ + my %last_bytes; + sub net_rate { + my ($iface, $which) = @_; + my $stat_file = "/sys/class/net/$iface/statistics/${which}_bytes"; + chomp(my $bytes = slurp($stat_file)); + my $prev = $last_bytes{$iface}{$which}; + $last_bytes{$iface}{$which} = $bytes; + return 0 unless defined $prev; + return $bytes - $prev; + } +} + +sub ncpu { + scalar grep { !/^#/ } `lscpu -p=cpu` +} + +sub human_bytes { + my ($bytes) = @_; + my @prefixes = ('', qw(k M G T)); + my $prefix_index = 0; + while ($bytes > 512) { + $bytes /= 1024; + $prefix_index++; + } + my $prec = ($prefix_index == 0 ? 0 : 1); + return sprintf("%0.${prec}f%sB", $bytes, $prefixes[$prefix_index]); +} + +sub slurp { + open my $fh, '<:encoding(UTF-8)', $_[0] or die "Couldn't open $_[0]: $!"; + if (wantarray) { + <$fh> + } + else { + local $/; + <$fh> + } +} diff --git a/bin/laptop/svdn b/bin/laptop/svdn new file mode 100755 index 0000000..ce6f4c4 --- /dev/null +++ b/bin/laptop/svdn @@ -0,0 +1,13 @@ +#!/bin/bash + +svst "$1" && svstop "$1" +svst "$1" && sleep 1 +svst "$1" && svstop "$1" +for i in 1..5; do + svst "$1" && sleep 1 +done +svst "$1" && svstop "$1" +for i in 1..10; do + svst "$1" && sleep 1 +done +svst "$1" && svkill "$1" diff --git a/bin/laptop/svget b/bin/laptop/svget new file mode 100755 index 0000000..77c18f4 --- /dev/null +++ b/bin/laptop/svget @@ -0,0 +1,3 @@ +#!/bin/bash + +svstat "$HOME/.services/enabled/$1" diff --git a/bin/laptop/svkill b/bin/laptop/svkill new file mode 100755 index 0000000..060d2c7 --- /dev/null +++ b/bin/laptop/svkill @@ -0,0 +1,4 @@ +#!/bin/bash + +svc -k "$HOME/.services/enabled/$1" +svget "$1" diff --git a/bin/laptop/svlog b/bin/laptop/svlog new file mode 100755 index 0000000..436b25a --- /dev/null +++ b/bin/laptop/svlog @@ -0,0 +1,3 @@ +#!/bin/bash + +tail -F "$HOME/.log/$1/current" | tai64nlocal diff --git a/bin/laptop/svre b/bin/laptop/svre new file mode 100755 index 0000000..e57576e --- /dev/null +++ b/bin/laptop/svre @@ -0,0 +1,4 @@ +#!/bin/bash + +svdn "$1" +svup "$1" diff --git a/bin/laptop/svst b/bin/laptop/svst new file mode 100755 index 0000000..92d20c1 --- /dev/null +++ b/bin/laptop/svst @@ -0,0 +1,3 @@ +#!/bin/bash + +svget "$1" | grep -q ": up (" diff --git a/bin/laptop/svstop b/bin/laptop/svstop new file mode 100755 index 0000000..36c0132 --- /dev/null +++ b/bin/laptop/svstop @@ -0,0 +1,4 @@ +#!/bin/bash + +svc -d "$HOME/.services/enabled/$1" +svget "$1" diff --git a/bin/laptop/svup b/bin/laptop/svup new file mode 100755 index 0000000..c49a99e --- /dev/null +++ b/bin/laptop/svup @@ -0,0 +1,4 @@ +#!/bin/bash + +svc -u "$HOME/.services/enabled/$1" +svget "$1" diff --git a/bin/laptop/update-weather b/bin/laptop/update-weather new file mode 100755 index 0000000..e3a6bc3 --- /dev/null +++ b/bin/laptop/update-weather @@ -0,0 +1,9 @@ +#!/usr/bin/env perl +use strict; +use warnings; + +use Path::Class; + +if (my $weather = `weather`) { + file("$ENV{HOME}/.cache/weather")->openw->print($weather); +} diff --git a/bin/laptop/update_mail b/bin/laptop/update_mail new file mode 100755 index 0000000..b909d9f --- /dev/null +++ b/bin/laptop/update_mail @@ -0,0 +1,9 @@ +#!/bin/sh + +stat=$(svstat "$HOME/.services/enabled/offlineimap") +if echo $stat | grep -q "offlineimap: down"; then + echo "no offlineimap process running" >&2 + exit 1 +fi +pid=$(echo $stat | sed 's/.*offlineimap: up (pid \([[:digit:]]\+\)).*/\1/') +kill -USR1 $pid diff --git a/bin/laptop/volume b/bin/laptop/volume new file mode 100755 index 0000000..bc37b45 --- /dev/null +++ b/bin/laptop/volume @@ -0,0 +1,24 @@ +#!/bin/bash + +case $1 in + up) + pactl set-sink-mute 0 0 + pactl set-sink-volume 0 +5% + ;; + down) + pactl set-sink-mute 0 0 + pactl set-sink-volume 0 -5% + ;; + mute) + pactl set-sink-mute 0 toggle + ;; +esac + +INFO=$(pacmd dump | grep analog-stereo) +VOLUME=$(echo "$INFO" | grep 'set-sink-volume' | cut -d' ' -f 3 | perl -e'my $vol = 100*oct(<>)/0x10000; print $vol > 100 ? 100 : $vol') +STATE=$(echo "$INFO" | grep 'set-sink-mute' | cut -d' ' -f 3) +if [[ "x$STATE" == "xyes" ]]; then + volnoti-show -m +else + volnoti-show $VOLUME +fi diff --git a/bin/laptop/weather b/bin/laptop/weather new file mode 100755 index 0000000..a0a9d14 --- /dev/null +++ b/bin/laptop/weather @@ -0,0 +1,60 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use 5.010; + +use open ':encoding(UTF-8)', ':std'; + +use DateTime; +use Path::Class; +use WWW::Wunderground::API; + +chomp(my $api_key = file("$ENV{HOME}/.wunderground")->slurp); + +my %weather_pics = ( + 'Thunderstorm' => "\x{26a1}", + 'Rain' => "\x{2614}", + 'Drizzle' => "\x{2614}", + 'Showers' => "\x{2614}", + 'Cloudy' => "\x{2601}", + 'Clouds' => "\x{2601}", + 'Overcast' => "\x{2601}", + 'Fog' => "\x{2592}", + 'Mist' => "\x{2592}", + 'Haze' => "\x{2592}", + 'Clear' => "\x{2600}", + 'Pellets' => "\x{2744}", + 'Snow' => "\x{2744}", +); + +my $wu = WWW::Wunderground::API->new( + location => '10012', + auto_api => 1, + api_key => $api_key, +); + +my $forecast = $wu->forecast->simpleforecast->forecastday->[0]; +my $conditions = $wu->conditions; + +my $temp = int($conditions->temp_f); +my $high = $forecast->{high}{fahrenheit}; +my $low = $forecast->{low}{fahrenheit}; +my $feelslike = int($conditions->feelslike_f); +my $precip = $forecast->{pop}; + +(my $description = $conditions->weather) =~ s/.* //; +my $weather = $weather_pics{$description} // $description; + +my $time = DateTime->now(time_zone => 'local'); + +say join(' ', + "$precip%", + $weather, + "${temp}F", + (($feelslike != $temp) + ? ("(\x{2245}${feelslike}F)") + : ()), + (($time->hour > 16 || $time->hour <= 4) + ? ("\x{2193}${low}F") + : ("\x{2191}${high}F")), +); diff --git a/bin/laptop/webcam b/bin/laptop/webcam new file mode 100755 index 0000000..48ee3f3 --- /dev/null +++ b/bin/laptop/webcam @@ -0,0 +1,2 @@ +#!/bin/sh +mpv av://v4l2:/dev/video0 diff --git a/bin/laptop/wifi b/bin/laptop/wifi new file mode 100755 index 0000000..38c70ee --- /dev/null +++ b/bin/laptop/wifi @@ -0,0 +1,38 @@ +#!/bin/sh +set -eu +set -o pipefail + +DEV=wlp3s0 +OPEN=open + +if [ -z "${1:-}" ]; then + if sudo netctl status $OPEN > /dev/null 2>&1; then + sudo netctl restart $OPEN + else + sudo systemctl restart netctl-auto@$DEV + fi +else + case "$1" in + open) + if [ -n "${2:-}" ]; then + sudo sed -i "s/^ESSID=.*/ESSID='${2}'/" "/etc/netctl/${OPEN}" + fi + + if sudo netctl status $OPEN > /dev/null 2>&1; then + sudo netctl restart $OPEN + else + sudo systemctl stop netctl-auto@$DEV + sudo netctl start $OPEN + fi + ;; + wpa) + if ! sudo systemctl status netctl-auto@$DEV > /dev/null 2>&1; then + sudo netctl stop $OPEN + sudo systemctl start netctl-auto@$DEV + fi + ;; + scan) + sudo iw dev $DEV scan | grep SSID | perl -nle 's/^.*SSID: //; print unless $seen{$_}++' + ;; + esac +fi diff --git a/bin/learn_spam b/bin/learn_spam deleted file mode 100755 index ab5603a..0000000 --- a/bin/learn_spam +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -MAILDIR=~/Maildir -OPTS="--no-sync" -SALEARN=/usr/bin/vendor_perl/sa-learn - -if [[ "$1" == "-q" ]]; then - OPTS="$OPTS" - OUTFILE="/dev/null" -else - OPTS="$OPTS --showdots" - OUTFILE="/dev/stdout" -fi - -if [[ ! "$1" == "-q" ]]; then - echo "$(date): Learning ham..." -fi -nice find $MAILDIR -type f | \ - perl -nl0e'chomp; ($ts) = /(\d{10})/; $now = time; print if m{/(new|cur)/} && !m{/(\.old|\.spam)/} && $ts > $now - 60*60*24*30' | \ - xargs -n1000 -0 $SALEARN $OPTS --ham > $OUTFILE - -if [[ ! "$1" == "-q" ]]; then - echo "$(date): Learning spam..." -fi -nice find $MAILDIR -type f | \ - perl -nl0e'chomp; ($ts) = /(\d{10})/; $now = time; print if m{/(new|cur)/} && m{/\.spam/} && $ts > $now - 60*60*24*30' | \ - xargs -n1000 -0 $SALEARN $OPTS --spam > $OUTFILE - -if [[ ! "$1" == "-q" ]]; then - echo "$(date): Syncing..." -fi -nice $SALEARN --sync > $OUTFILE - -if [[ ! "$1" == "-q" ]]; then - echo "$(date): Done!" -fi diff --git a/bin/numkeys b/bin/numkeys deleted file mode 100755 index ab9dc14..0000000 --- a/bin/numkeys +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/sh - -on() { - xmodmap -e 'keycode 10 = exclam 1' - xmodmap -e 'keycode 11 = at 2' - xmodmap -e 'keycode 12 = numbersign 3' - xmodmap -e 'keycode 13 = dollar 4' - xmodmap -e 'keycode 14 = percent 5' - xmodmap -e 'keycode 15 = asciicircum 6' - xmodmap -e 'keycode 16 = ampersand 7' - xmodmap -e 'keycode 17 = asterisk 8' - xmodmap -e 'keycode 18 = parenleft 9' - xmodmap -e 'keycode 19 = parenright 0' - xmodmap -e 'keycode 20 = underscore minus' - xmodmap -e 'keycode 34 = braceleft bracketleft' - xmodmap -e 'keycode 35 = braceright bracketright' - xmodmap -e 'keycode 49 = asciitilde grave' - xmodmap -e 'keycode 51 = bar backslash' -} - -off() { - xmodmap -e 'keycode 10 = 1 exclam' - xmodmap -e 'keycode 11 = 2 at' - xmodmap -e 'keycode 12 = 3 numbersign' - xmodmap -e 'keycode 13 = 4 dollar' - xmodmap -e 'keycode 14 = 5 percent' - xmodmap -e 'keycode 15 = 6 asciicircum' - xmodmap -e 'keycode 16 = 7 ampersand' - xmodmap -e 'keycode 17 = 8 asterisk' - xmodmap -e 'keycode 18 = 9 parenleft' - xmodmap -e 'keycode 19 = 0 parenright' - xmodmap -e 'keycode 20 = minus underscore' - xmodmap -e 'keycode 34 = bracketleft braceleft' - xmodmap -e 'keycode 35 = bracketright braceright' - xmodmap -e 'keycode 49 = grave asciitilde' - xmodmap -e 'keycode 51 = backslash bar' -} - -toggle() { - if xmodmap -pk | grep -q '(1).*(exclam).*(1).*(exclam)'; then - on - else - off - fi -} - -case "$1" in - on) on ;; - off) off ;; - toggle) toggle ;; - *) echo invalid 1>&2; exit 1 ;; -esac diff --git a/bin/pass b/bin/pass deleted file mode 100755 index fd4a9aa..0000000 --- a/bin/pass +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -my $PASS = '/usr/bin/pass'; - -my $cmd = $ARGV[0]; - -if ($cmd && $cmd eq 'search') { - shift @ARGV; - - chdir "$ENV{HOME}/.password-store" - or die "password store not initialized"; - - require Path::Class; - - my $pat_str = pop @ARGV; - my $pattern = qr/$pat_str/; - - my $username = grep { $_ eq '-u' } @ARGV; - @ARGV = grep { $_ ne '-u' } @ARGV; - - my $clipboard = grep { $_ eq '-c' || $_ eq '--clip' } @ARGV; - - my @found = Path::Class::Dir->new('.')->traverse(sub { - my ($file, $c) = @_; - return if $file eq '.git'; - return ( - $c->(), - ((-f $file && $file =~ s/\.gpg$// && $file =~ $pattern) - ? ($file) - : ()), - ); - }); - - if (@found < 1) { - die "No passwords found matching '$pat_str'\n"; - } - elsif (@found > 1) { - die "Ambiguous pattern '$pat_str': could match any of @found\n"; - } - else { - if (my $pass = `$PASS show '$found[0]'`) { - if ($username) { - if ($found[0] =~ m{^[^/]*/[^/]*/([^/]*)$}) { - my $user = $1; - if ($clipboard) { - clip($user); - } - else { - print "$user\n"; - } - } - else { - die "$found[0] has no username"; - } - } - - if ($clipboard) { - $pass =~ s/\n.*//s; - clip($pass); - } - else { - print $pass; - } - } - } -} -else { - exec { $PASS } $PASS, @ARGV -} - -sub clip { - my ($text) = @_; - my @pids; - for my $selection (qw(primary clipboard)) { - my $pid = fork; - if (!$pid) { - open my $fh, '|-', "timeout 1m xclip -loops 1 -quiet -selection $selection 2> /dev/null" - or die "couldn't run xclip"; - $fh->write("$text\n"); - $fh->close; - exit; - } - push @pids, $pid; - } - waitpid($_, 0) for @pids; -} diff --git a/bin/scp b/bin/scp deleted file mode 120000 index ffd8d03..0000000 --- a/bin/scp +++ /dev/null @@ -1 +0,0 @@ -ssh \ No newline at end of file diff --git a/bin/server/learn_spam b/bin/server/learn_spam new file mode 100755 index 0000000..ab5603a --- /dev/null +++ b/bin/server/learn_spam @@ -0,0 +1,36 @@ +#!/bin/bash + +MAILDIR=~/Maildir +OPTS="--no-sync" +SALEARN=/usr/bin/vendor_perl/sa-learn + +if [[ "$1" == "-q" ]]; then + OPTS="$OPTS" + OUTFILE="/dev/null" +else + OPTS="$OPTS --showdots" + OUTFILE="/dev/stdout" +fi + +if [[ ! "$1" == "-q" ]]; then + echo "$(date): Learning ham..." +fi +nice find $MAILDIR -type f | \ + perl -nl0e'chomp; ($ts) = /(\d{10})/; $now = time; print if m{/(new|cur)/} && !m{/(\.old|\.spam)/} && $ts > $now - 60*60*24*30' | \ + xargs -n1000 -0 $SALEARN $OPTS --ham > $OUTFILE + +if [[ ! "$1" == "-q" ]]; then + echo "$(date): Learning spam..." +fi +nice find $MAILDIR -type f | \ + perl -nl0e'chomp; ($ts) = /(\d{10})/; $now = time; print if m{/(new|cur)/} && m{/\.spam/} && $ts > $now - 60*60*24*30' | \ + xargs -n1000 -0 $SALEARN $OPTS --spam > $OUTFILE + +if [[ ! "$1" == "-q" ]]; then + echo "$(date): Syncing..." +fi +nice $SALEARN --sync > $OUTFILE + +if [[ ! "$1" == "-q" ]]; then + echo "$(date): Done!" +fi diff --git a/bin/setup-inputs b/bin/setup-inputs deleted file mode 100755 index 4afd5a7..0000000 --- a/bin/setup-inputs +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -# key bindings -setxkbmap -option ctrl:nocaps -setxkbmap -option compose:caps -xmodmap $HOME/.Xmodmap -$HOME/.bin/numkeys on - -# trackpad settings -xinput set-prop "SynPS/2 Synaptics TouchPad" "libinput Accel Speed" 0.4 -xinput set-prop "SynPS/2 Synaptics TouchPad" "libinput Tapping Enabled" 1 - -# restart services that depend on keyboard reconfigurations -if pgrep readproctitle > /dev/null; then - svre xcape - svre kuake - svre xbindkeys -fi diff --git a/bin/sftp b/bin/sftp deleted file mode 120000 index ffd8d03..0000000 --- a/bin/sftp +++ /dev/null @@ -1 +0,0 @@ -ssh \ No newline at end of file diff --git a/bin/ssh b/bin/ssh deleted file mode 100755 index 453bb11..0000000 --- a/bin/ssh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -SSH=/usr/bin/$(basename $0) - -if [[ $1 != '-V' ]]; then - . ssh-key-unlock -fi -exec $SSH $* diff --git a/bin/ssh-add-helper b/bin/ssh-add-helper deleted file mode 100755 index cae6f27..0000000 --- a/bin/ssh-add-helper +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; -use IO::Pty::Easy; - -my $hostname = `hostname`; -my $pass = `pass search ssh.$hostname`; -my $pty = IO::Pty::Easy->new; -$pty->spawn("ssh-add -t 1800 $ARGV[0]"); -$pty->read; -$pty->write($pass . "\n"); -while (1) { - last if $pty->read =~ 'Identity added'; -} diff --git a/bin/ssh-key-unlock b/bin/ssh-key-unlock deleted file mode 100755 index e2654f1..0000000 --- a/bin/ssh-key-unlock +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -keychain -q --timeout 30 -. ~/.keychain/${HOSTNAME}-sh -if ! ssh-add -l | grep -q '.ssh/id_rsa'; then - ssh-add-helper ~/.ssh/id_rsa -fi diff --git a/bin/status b/bin/status deleted file mode 100755 index 062455d..0000000 --- a/bin/status +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; -use 5.010; - -use IO::Select; -use IO::Socket::UNIX; -use JSON; - -my $i3status = get_i3status_handle(); -my $ipc = get_ipc_handle(); -$|++; -say "[]"; - -my $select = IO::Select->new; -$select->add($i3status); -$select->add($ipc); - -my $current_data; - -while (my @ready = $select->can_read) { - for my $fh (@ready) { - if ($fh == $i3status) { - handle_i3status(scalar <$fh>); - } - elsif ($fh == $ipc) { - handle_ipc(receive_ipc_message($fh)); - } - else { - die "???"; - } - } -} - -sub get_i3status_handle { - open my $i3status, '-|', 'i3status'; - - print scalar(<$i3status>); - print scalar(<$i3status>); - - return $i3status; -} - -sub handle_i3status { - $_ = shift; - s/^,//; - - my $data = decode_json($_); - - my %line = map { $_->{name} => $_ } @$data; - my $line = [ - grep { - $_->{name} eq 'wireless' || $_->{name} eq 'ethernet' - ? $_->{instance} ne $_->{full_text} - : $_->{name} ne 'load' - } @$data - ]; - - my %discharge_rate; - my %battery_index; - - my $index = 0; - for my $item (@$line) { - if ($item->{name} eq 'wireless' || $item->{name} eq 'ethernet') { - my $iface = $item->{instance}; - my ($up, $down) = map { net_rate($iface, $_) } 'rx', 'tx'; - my $rate = sprintf("%6s/%6s", map { human_bytes($_) } $up, $down); - $item->{full_text} =~ s{^($iface:)}{$1 $rate}; - $item->{color} = - $up + $down >= 512000 ? '#FF0000' - : $up + $down >= 51200 ? '#FFFF00' - : $up + $down >= 5120 ? '#00FF00' - : '#FFFFFF'; - } - if ($item->{name} eq 'cpu_usage') { - my ($val) = $line{load}{full_text} * 100 / ncpu(); - $item->{color} = - $val >= 50 ? '#FF0000' - : $val >= 25 ? '#FFFF00' - : $val >= 5 ? '#00FF00' - : '#FFFFFF'; - } - if ($item->{name} eq 'battery') { - my ($state, $val) = $item->{full_text} =~ /(\w+) (\d+(?:\.\d+))%/; - my ($rate) = $item->{full_text} =~ /\(.* (.*)W\)/; - $rate *= -1 if defined($rate) && $state ne 'BAT'; - $rate //= 0; - - $discharge_rate{$item->{instance}} = $rate; - $battery_index{$item->{instance}} = $index; - - $item->{full_text} =~ s/\((.*) (.*)W\)/\($1\)/; - $item->{full_text} =~ s/ \(\)//; - $item->{color} = - !defined($val) ? '#FFFFFF' - : $val >= 80 ? '#00FF00' - : $state ne 'BAT' ? '#FFFFFF' - : $val >= 40 ? '#FFFFFF' - : $val >= 15 ? '#FFFF00' - : $val >= 5 ? '#CD0000' - : '#FF0000'; - } - $index++; - } - - my @batteries = sort { $battery_index{$b} <=> $battery_index{$a} } - keys %battery_index; - for my $battery (@batteries) { - next unless $discharge_rate{$battery}; - splice @$line, $battery_index{$battery} + 1, 0, { - name => 'battery_discharge', - full_text => sprintf("%0.2fW", $discharge_rate{$battery}), - color => ( - $discharge_rate{$battery} < 6 ? '#FFFFFF' - : $discharge_rate{$battery} < 10 ? '#00FF00' - : $discharge_rate{$battery} < 14 ? '#FFFF00' - : '#FF0000' - ), - }; - } - - my $weather_file = "$ENV{HOME}/.cache/weather"; - if (-r $weather_file && -f $weather_file) { - my $weather = slurp($weather_file); - chomp($weather); - my ($temp) = $weather =~ /\d+%.*?(-?\d+)F.*?-?\d+F/; - unshift @$line, { - name => 'weather', - full_text => $weather, - color => ( - $temp >= 90 ? '#FF0000' - : $temp >= 78 ? '#FFFF00' - : $temp >= 73 ? '#00FF00' - : $temp >= 55 ? '#FFFFFF' - : $temp >= 32 ? '#CDCDFF' - : '#0000FF' - ), - }; - } - - $current_data = $line; - - show_status(); -} - -sub get_ipc_handle { - chomp(my $path = qx(i3 --get-socketpath)); - - my $sock = IO::Socket::UNIX->new(Peer => $path); - $sock->write(format_ipc_message(2, q{["window", "workspace"]})); - my ($type, $payload) = receive_ipc_message($sock); - die "Couldn't subscribe: ($type) $payload" - unless $type == 2 && decode_json($payload)->{success}; - - return $sock; -} - -sub handle_ipc { - my ($type, $payload) = @_; - show_status(); -} - -sub format_ipc_message { - my ($type, $payload) = @_; - my $len = do { use bytes; length($payload) }; - return "i3-ipc" . pack("LL", $len, $type) . $payload; -} - -sub receive_ipc_message { - my ($sock) = @_; - - $sock->read(my $magic, 6); - die "unknown response: $magic" unless $magic eq 'i3-ipc'; - $sock->read(my $len, 4); - $len = unpack("L", $len); - $sock->read(my $type, 4); - $type = unpack("L", $type); - $sock->read(my $payload, $len); - - return ($type, $payload); -} - -sub show_status { - my @line = @$current_data; - unshift @line, { name => 'title', full_text => get_title() }; - say "," . encode_json(\@line); -} - -sub get_title { - my $node = find(decode_json(`i3-msg -t get_tree`)); - if ($node->{window}) { - return $node->{name}; - } - else { - return '-none-'; - } -} - -sub find { - my ($t) = @_; - if ($t->{focused}) { - return $t; - } - - for my $subtree (@{ $t->{nodes} }, @{ $t->{floating_nodes} }) { - my $found = find($subtree); - return $found if $found; - } - - return; -} - -{ - my %last_bytes; - sub net_rate { - my ($iface, $which) = @_; - my $stat_file = "/sys/class/net/$iface/statistics/${which}_bytes"; - chomp(my $bytes = slurp($stat_file)); - my $prev = $last_bytes{$iface}{$which}; - $last_bytes{$iface}{$which} = $bytes; - return 0 unless defined $prev; - return $bytes - $prev; - } -} - -sub ncpu { - scalar grep { !/^#/ } `lscpu -p=cpu` -} - -sub human_bytes { - my ($bytes) = @_; - my @prefixes = ('', qw(k M G T)); - my $prefix_index = 0; - while ($bytes > 512) { - $bytes /= 1024; - $prefix_index++; - } - my $prec = ($prefix_index == 0 ? 0 : 1); - return sprintf("%0.${prec}f%sB", $bytes, $prefixes[$prefix_index]); -} - -sub slurp { - open my $fh, '<:encoding(UTF-8)', $_[0] or die "Couldn't open $_[0]: $!"; - if (wantarray) { - <$fh> - } - else { - local $/; - <$fh> - } -} diff --git a/bin/svdn b/bin/svdn deleted file mode 100755 index ce6f4c4..0000000 --- a/bin/svdn +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -svst "$1" && svstop "$1" -svst "$1" && sleep 1 -svst "$1" && svstop "$1" -for i in 1..5; do - svst "$1" && sleep 1 -done -svst "$1" && svstop "$1" -for i in 1..10; do - svst "$1" && sleep 1 -done -svst "$1" && svkill "$1" diff --git a/bin/svget b/bin/svget deleted file mode 100755 index 77c18f4..0000000 --- a/bin/svget +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -svstat "$HOME/.services/enabled/$1" diff --git a/bin/svkill b/bin/svkill deleted file mode 100755 index 060d2c7..0000000 --- a/bin/svkill +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -svc -k "$HOME/.services/enabled/$1" -svget "$1" diff --git a/bin/svlog b/bin/svlog deleted file mode 100755 index 436b25a..0000000 --- a/bin/svlog +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -tail -F "$HOME/.log/$1/current" | tai64nlocal diff --git a/bin/svre b/bin/svre deleted file mode 100755 index e57576e..0000000 --- a/bin/svre +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -svdn "$1" -svup "$1" diff --git a/bin/svst b/bin/svst deleted file mode 100755 index 92d20c1..0000000 --- a/bin/svst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -svget "$1" | grep -q ": up (" diff --git a/bin/svstop b/bin/svstop deleted file mode 100755 index 36c0132..0000000 --- a/bin/svstop +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -svc -d "$HOME/.services/enabled/$1" -svget "$1" diff --git a/bin/svup b/bin/svup deleted file mode 100755 index c49a99e..0000000 --- a/bin/svup +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -svc -u "$HOME/.services/enabled/$1" -svget "$1" diff --git a/bin/update-weather b/bin/update-weather deleted file mode 100755 index e3a6bc3..0000000 --- a/bin/update-weather +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; - -use Path::Class; - -if (my $weather = `weather`) { - file("$ENV{HOME}/.cache/weather")->openw->print($weather); -} diff --git a/bin/update_mail b/bin/update_mail deleted file mode 100755 index b909d9f..0000000 --- a/bin/update_mail +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -stat=$(svstat "$HOME/.services/enabled/offlineimap") -if echo $stat | grep -q "offlineimap: down"; then - echo "no offlineimap process running" >&2 - exit 1 -fi -pid=$(echo $stat | sed 's/.*offlineimap: up (pid \([[:digit:]]\+\)).*/\1/') -kill -USR1 $pid diff --git a/bin/volume b/bin/volume deleted file mode 100755 index bc37b45..0000000 --- a/bin/volume +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -case $1 in - up) - pactl set-sink-mute 0 0 - pactl set-sink-volume 0 +5% - ;; - down) - pactl set-sink-mute 0 0 - pactl set-sink-volume 0 -5% - ;; - mute) - pactl set-sink-mute 0 toggle - ;; -esac - -INFO=$(pacmd dump | grep analog-stereo) -VOLUME=$(echo "$INFO" | grep 'set-sink-volume' | cut -d' ' -f 3 | perl -e'my $vol = 100*oct(<>)/0x10000; print $vol > 100 ? 100 : $vol') -STATE=$(echo "$INFO" | grep 'set-sink-mute' | cut -d' ' -f 3) -if [[ "x$STATE" == "xyes" ]]; then - volnoti-show -m -else - volnoti-show $VOLUME -fi diff --git a/bin/weather b/bin/weather deleted file mode 100755 index a0a9d14..0000000 --- a/bin/weather +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env perl -use strict; -use warnings; -use 5.010; - -use open ':encoding(UTF-8)', ':std'; - -use DateTime; -use Path::Class; -use WWW::Wunderground::API; - -chomp(my $api_key = file("$ENV{HOME}/.wunderground")->slurp); - -my %weather_pics = ( - 'Thunderstorm' => "\x{26a1}", - 'Rain' => "\x{2614}", - 'Drizzle' => "\x{2614}", - 'Showers' => "\x{2614}", - 'Cloudy' => "\x{2601}", - 'Clouds' => "\x{2601}", - 'Overcast' => "\x{2601}", - 'Fog' => "\x{2592}", - 'Mist' => "\x{2592}", - 'Haze' => "\x{2592}", - 'Clear' => "\x{2600}", - 'Pellets' => "\x{2744}", - 'Snow' => "\x{2744}", -); - -my $wu = WWW::Wunderground::API->new( - location => '10012', - auto_api => 1, - api_key => $api_key, -); - -my $forecast = $wu->forecast->simpleforecast->forecastday->[0]; -my $conditions = $wu->conditions; - -my $temp = int($conditions->temp_f); -my $high = $forecast->{high}{fahrenheit}; -my $low = $forecast->{low}{fahrenheit}; -my $feelslike = int($conditions->feelslike_f); -my $precip = $forecast->{pop}; - -(my $description = $conditions->weather) =~ s/.* //; -my $weather = $weather_pics{$description} // $description; - -my $time = DateTime->now(time_zone => 'local'); - -say join(' ', - "$precip%", - $weather, - "${temp}F", - (($feelslike != $temp) - ? ("(\x{2245}${feelslike}F)") - : ()), - (($time->hour > 16 || $time->hour <= 4) - ? ("\x{2193}${low}F") - : ("\x{2191}${high}F")), -); diff --git a/bin/webcam b/bin/webcam deleted file mode 100755 index 48ee3f3..0000000 --- a/bin/webcam +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -mpv av://v4l2:/dev/video0 diff --git a/bin/wifi b/bin/wifi deleted file mode 100755 index 38c70ee..0000000 --- a/bin/wifi +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -set -eu -set -o pipefail - -DEV=wlp3s0 -OPEN=open - -if [ -z "${1:-}" ]; then - if sudo netctl status $OPEN > /dev/null 2>&1; then - sudo netctl restart $OPEN - else - sudo systemctl restart netctl-auto@$DEV - fi -else - case "$1" in - open) - if [ -n "${2:-}" ]; then - sudo sed -i "s/^ESSID=.*/ESSID='${2}'/" "/etc/netctl/${OPEN}" - fi - - if sudo netctl status $OPEN > /dev/null 2>&1; then - sudo netctl restart $OPEN - else - sudo systemctl stop netctl-auto@$DEV - sudo netctl start $OPEN - fi - ;; - wpa) - if ! sudo systemctl status netctl-auto@$DEV > /dev/null 2>&1; then - sudo netctl stop $OPEN - sudo systemctl start netctl-auto@$DEV - fi - ;; - scan) - sudo iw dev $DEV scan | grep SSID | perl -nle 's/^.*SSID: //; print unless $seen{$_}++' - ;; - esac -fi diff --git a/i3/config b/i3/config index 7232cb0..d8b0b67 100644 --- a/i3/config +++ b/i3/config @@ -39,8 +39,8 @@ bindsym $mod+f fullscreen bindsym $mod+Shift+space floating toggle bindsym $mod+space focus mode_toggle -bindsym $mod+bracketleft exec ~/.bin/i3-switch-workspace prev -bindsym $mod+bracketright exec ~/.bin/i3-switch-workspace next +bindsym $mod+bracketleft exec ~/.bin/laptop/i3-switch-workspace prev +bindsym $mod+bracketright exec ~/.bin/laptop/i3-switch-workspace next bindsym $mod+1 workspace 1 bindsym $mod+2 workspace 2 @@ -68,7 +68,7 @@ bindsym $mod+Shift+q exec "i3-nagbar -t warning -m 'You pressed the exit shortcu bar { tray_output primary - status_command ~/.bin/status + status_command ~/.bin/laptop/status font xft:DejaVuSansMono 10 } diff --git a/sh/env b/sh/env index f8a0504..0d0424c 100644 --- a/sh/env +++ b/sh/env @@ -3,8 +3,8 @@ export MPD_HOST=bishamon export MANPAGER="$HOME/.bin/vimmanpager" export PERLDOC_PAGER="$HOME/.bin/vimmanpager" export EDITOR=$(/usr/bin/which vim) -export GIT_SSH="$HOME/.bin/ssh" -export RSYNC_RSH="$HOME/.bin/ssh" +[ "$(cat "${HOME}/conf/.conf-type")" = "laptop" ] && export GIT_SSH="$HOME/.bin/laptop/ssh" +[ "$(cat "${HOME}/conf/.conf-type")" = "laptop" ] && export RSYNC_RSH="$HOME/.bin/laptop/ssh" export TEXINPUTS=".:$HOME/conf/tex:" export LESS='-QR' export NOPASTE_SERVICES="ssh" diff --git a/zshrc b/zshrc index fd589cf..1d1525c 100644 --- a/zshrc +++ b/zshrc @@ -7,7 +7,7 @@ test -d $HOME/.cargo/bin && export PATH="$HOME/.cargo/bin:$PATH" # environment {{{ # not using .zshenv, because it runs before /etc/profile, and /etc/profile # tends to hard-set $PATH and such -export PATH="/usr/share/git/diff-highlight:${HOME}/.bin/local:${HOME}/.bin:/usr/lib/ccache/bin:$PATH" +export PATH="${HOME}/.bin/local:${HOME}/.bin/$(cat "${HOME}/conf/.conf-type"):${HOME}/.bin:/usr/lib/ccache/bin:/usr/share/git/diff-highlight:$PATH" [ -f "$HOME/.sh/env" ] && source $HOME/.sh/env # }}} # Change the window title of X terminals {{{ -- cgit v1.2.3-54-g00ecf