Skip to content

Instantly share code, notes, and snippets.

@perigrin
Created November 2, 2017 14:13
Show Gist options
  • Save perigrin/d11a183c5e2da74e2dd3abcd7b78fd81 to your computer and use it in GitHub Desktop.
Save perigrin/d11a183c5e2da74e2dd3abcd7b78fd81 to your computer and use it in GitHub Desktop.
# Copyright (c) 2012 Henrik Brix Andersen <henrik@brixandersen.dk>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
use strict;
use warnings;
use List::Util qw/min max/;
use Irssi;
use WebService::Prowl;
our $VERSION = '1.10';
our %IRSSI = (
authors => 'Henrik Brix Andersen',
contact => 'henrik@brixandersen.dk',
name => 'prowl',
description => 'Send Prowl notifications from Irssi',
license => 'BSD',
url => 'https://github.com/henrikbrixandersen/irssi-prowl',
modules => 'List::Util WebService::Prowl',
commands => 'prowl',
);
my $prowl;
my %config = ( apikey => '' );
# Settings
Irssi::settings_add_str('prowl', 'prowl_mode', 'AUTO');
Irssi::settings_add_str('prowl', 'prowl_apikey', '');
Irssi::settings_add_bool('prowl', 'prowl_debug', 0);
Irssi::settings_add_int('prowl', 'prowl_priority_msgs', 0);
Irssi::settings_add_int('prowl', 'prowl_priority_hilight', 0);
Irssi::settings_add_int('prowl', 'prowl_priority_cmd', 0);
Irssi::settings_add_str('prowl', 'prowl_regex_include', '');
Irssi::settings_add_str('prowl', 'prowl_regex_exclude', '');
# Signals
Irssi::signal_add('setup changed' => 'setup_changed_handler');
setup_changed_handler();
Irssi::signal_add('print text' => 'print_text_handler');
Irssi::signal_add_first('complete word', 'complete_word_handler');
# Commands
Irssi::command_bind('help', 'help_command_handler');
Irssi::command_bind('prowl', 'prowl_command_handler');
Irssi::command_set_options('prowl', '-url @priority');
# Theme
Irssi::theme_register([
'prowl_event_cmd', 'Manual Message',
# $0 = channel, $1 = nick
'prowl_event_msgs', 'Private Message from $1',
'prowl_event_hilight', 'Hilighted in $0 by $1',
# $0 = irc/ircs, $1 = server address, $2 = chatnet, $3 = server port, $4 = channel/nick
'prowl_url_msgs', '$0://$1:$3/',
'prowl_url_hilight', '$0://$1:$3/$4',
]);
sub setup_changed_handler {
$config{debug} = Irssi::settings_get_bool('prowl_debug');
my $mode = Irssi::settings_get_str('prowl_mode');
$mode =~ s/\s+$//g;
if ($mode ne uc($mode)) {
# Mimic uppercase Irssi bool settings for our tri-state setting
$mode = uc($mode);
Irssi::settings_set_str('prowl_mode', $mode);
Irssi::signal_emit('setup changed');
}
if ($mode !~ /^(AUTO|ON|OFF)$/) {
$mode = 'AUTO';
Irssi::settings_set_str('prowl_mode', $mode);
Irssi::signal_emit('setup changed');
}
$config{mode} = $mode;
for (qw/msgs hilight cmd/) {
my $priority = Irssi::settings_get_int("prowl_priority_$_");
if ($priority < -2 || $priority > 2) {
$priority = max($priority, -2);
$priority = min($priority, 2);
Irssi::settings_set_int("prowl_priority_$_", $priority);
Irssi::signal_emit('setup changed');
}
$config{"priority_$_"} = $priority;
}
for (qw/include exclude/) {
my $regex = Irssi::settings_get_str("prowl_regex_$_");
if ($regex) {
$config{$_} = eval { qr/$regex/ };
Irssi::print("Invalid regular expression for 'prowl_regex_$_' setting: $@") if $@;
} else {
$config{$_} = undef;
}
}
my $apikey = Irssi::settings_get_str('prowl_apikey');
$apikey =~ s/\s+$//g;
if ($apikey) {
if ($apikey ne $config{apikey}) {
$prowl = WebService::Prowl->new(apikey => $apikey);
if (!$prowl->verify) {
Irssi::print('Could not verify Prowl API key: ' . $prowl->error,
MSGLEVEL_CLIENTERROR);
}
}
} else {
$prowl = undef;
}
$config{apikey} = $apikey;
}
sub _create_url {
my ($server, $target, $format_name) = @_;
my $url;
if ($server->{chat_type} eq 'IRC') {
my $format = Irssi::current_theme()->get_format('Irssi::Script::prowl', $format_name);
my @data;
push @data, $server->{use_ssl} ? 'ircs' : 'irc';
push @data, ($server->{address}, $server->{chatnet}, $server->{port}, $target);
$url = Irssi::parse_special($format, join(' ', @data));
}
return $url;
}
sub print_text_handler {
my ($dest, $text, $stripped) = @_;
my $server = $dest->{server};
if (($server->{usermode_away} && $config{mode} eq 'AUTO') || $config{mode} eq 'ON') {
my $target = $dest->{target};
if ((!defined($config{include}) || $target =~ $config{include}) &&
!(defined($config{exclude}) && $target =~ $config{exclude})) {
my $level = $dest->{level};
if (($level & MSGLEVEL_MSGS) || ($level & MSGLEVEL_HILIGHT && !($level & MSGLEVEL_NOHILIGHT))) {
my $nick = $stripped;
if ($level & MSGLEVEL_ACTIONS) {
$nick =~ s/^\s+.\s+(\S+)\s.*/$1/;
} else {
$nick =~ s/^\<[@\+% ]?([^\>]+)\>.*/$1/;
}
unless ($server->{nick} eq $nick) {
my $type = ($level & MSGLEVEL_MSGS) ? 'msgs' : 'hilight';
my $url = _create_url($server, $target, "prowl_url_$type");
my $format = Irssi::current_theme()->get_format('Irssi::Script::prowl', "prowl_event_$type");
my $event = Irssi::parse_special($format, "$target $nick");
_prowl($event, $stripped, $config{"priority_$type"}, $url);
}
}
}
}
}
sub help_command_handler {
my ($data, $server, $witem) = @_;
$data =~ s/\s+$//g;
if (lc($data) eq 'prowl') {
Irssi::print("\nPROWL [-url <url>] [-priority <priority>] [text]\n\n" .
"Send a manual Prowl notification.\n\n" .
"See also: /SET PROWL, /FORMAT PROWL\n",
MSGLEVEL_CLIENTCRAP);
Irssi::signal_stop;
}
}
sub prowl_command_handler {
my ($data, $server, $witem) = @_;
$data =~ s/\s+$//g;
my @options = Irssi::command_parse_options('prowl', $data);
if (@options) {
my $args = $options[0];
my $text = $options[1] ? $options[1] : ' ';;
my $format = Irssi::current_theme()->get_format('Irssi::Script::prowl', 'prowl_event_cmd');
my $event = Irssi::parse_special($format);
$args->{priority} //= $config{priority_cmd};
$args->{priority} = max($args->{priority}, -2);
$args->{priority} = min($args->{priority}, 2);
_prowl($event, $text, $args->{priority}, $args->{url});
}
}
sub complete_word_handler {
my ($strings, $window, $word, $linestart, $want_space) = @_;
if ($linestart =~ /^\/set prowl_mode/i) {
push @$strings, grep(/^\Q$word\E/i, qw/AUTO ON OFF/);
$$want_space = 0;
Irssi::signal_stop;
}
}
sub _prowl {
my ($event, $description, $priority, $url) = @_;
my %options = (application => 'Irssi', event => $event, description => $description);
$options{priority} = $priority if defined $priority;
$options{url} = $url if defined $url;
if ($config{debug}) {
my $debuginfo = join(', ', map { "$_ => '$options{$_}'" } sort keys %options);
Irssi::print("Sending Prowl notification: $debuginfo", MSGLEVEL_CLIENTCRAP);
}
if ($config{apikey}) {
Irssi::print('Error sending Prowl notificaton: ' . $prowl->error) unless $prowl->add(%options);
} else {
Irssi::print('Prowl API key not set, use \'/SET prowl_apikey\' to set a valid key',
MSGLEVEL_CLIENTERROR);
}
}
use Irssi;
use strict;
use FileHandle;
use vars qw($VERSION %IRSSI);
$VERSION = "0.9.7.1+tmux";
%IRSSI = (
authors => 'Nick Moffitt <nick@zork.net>',
name => 'tmux_away',
description => 'set (un)away, if tmux is attached/detached (based on screen_away by Andreas \'ads\' Scherbaum <ads@ufp.de>)',
license => 'GPL v2',
url => 'none',
);
# usage:
#
# put this script into your autorun directory and/or load it with
# /SCRIPT LOAD <name>
#
# there are 5 settings available:
#
# /set tmux_away_active ON/OFF/TOGGLE
# /set tmux_away_repeat <integer>
# /set tmux_away_message <string>
# /set tmux_away_window <string>
# /set tmux_away_nick <string>
#
# active means, that you will be only set away/unaway, if this
# flag is set, default is ON
# repeat is the number of seconds, after the script will check the
# tmux status again, default is 5 seconds
# message is the away message sent to the server, default: not here ...
# window is a window number or name, if set, the script will switch
# to this window, if it sets you away, default is '1'
# nick is the new nick, if the script goes away
# will only be used it not empty
#
# normal you should be able to rename the script to something other
# than 'tmux_away' (as example, if you dont like the name) by simple
# changing the 'name' parameter in the %IRSSI hash at the top of this script
# variables
my $timer_name = undef;
my $away_status = 0;
my %old_nicks = ();
my %away = ();
# Register formats
Irssi::theme_register(
[
'tmux_away_crap',
'{line_start}{hilight ' . $IRSSI{'name'} . ':} $0'
]);
# if we are running
my $tmux_away_used = 0;
# try to find out, if we are running in a tmux
# (see, if $ENV{STY} is set
if (!defined($ENV{TMUX})) {
# just return, we will never be called again
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"could not open status file for parent process (pid: " . getppid() . "): $!");
return;
}
my $socket = $ENV{TMUX};
$socket =~ s/,.*$//;
# register config variables
Irssi::settings_add_bool('misc', $IRSSI{'name'} . '_active', 1);
Irssi::settings_add_int('misc', $IRSSI{'name'} . '_repeat', 5);
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_message', "not here ...");
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_window', "1");
Irssi::settings_add_str('misc', $IRSSI{'name'} . '_nick', "");
# init process
tmux_away();
# tmux_away()
#
# check, set or reset the away status
#
# parameter:
# none
# return:
# 0 (OK)
sub tmux_away {
my ($away, @tmux, $tmux);
# only run, if activated
if (Irssi::settings_get_bool($IRSSI{'name'} . '_active') == 1) {
if ($away_status == 0) {
# display init message at first time
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"activating $IRSSI{'name'} (interval: " . Irssi::settings_get_int($IRSSI{'name'} . '_repeat') . " seconds)");
}
# get actual tmux status
my @tmux = stat($socket);
# 00100 is the mode for "user has execute permissions", see stat.h
if (($tmux[2] & 00100) == 0) {
# no execute permissions, Detached
$away = 1;
} else {
# execute permissions, Attached
$away = 2;
}
# check if status has changed
if ($away == 1 and $away_status != 1) {
# set away
if (length(Irssi::settings_get_str($IRSSI{'name'} . '_window')) > 0) {
# if length of window is greater then 0, make this window active
Irssi::command('window goto ' . Irssi::settings_get_str($IRSSI{'name'} . '_window'));
}
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"Set away");
my $message = Irssi::settings_get_str($IRSSI{'name'} . '_message');
if (length($message) == 0) {
# we have to set a message or we wouldnt go away
$message = "not here ...";
}
my ($server);
foreach $server (Irssi::servers()) {
if (!$server->{usermode_away}) {
# user isnt yet away
$away{$server->{'tag'}} = 0;
$server->command("AWAY " . (($server->{chat_type} ne 'SILC') ? "-one " : "") . "$message") if (!$server->{usermode_away});
if (length(Irssi::settings_get_str($IRSSI{'name'} . '_nick')) > 0) {
# only change, if actual nick isnt already the away nick
if (Irssi::settings_get_str($IRSSI{'name'} . '_nick') ne $server->{nick}) {
# keep old nick
$old_nicks{$server->{'tag'}} = $server->{nick};
# set new nick
$server->command("NICK " . Irssi::settings_get_str($IRSSI{'name'} . '_nick'));
}
}
} else {
# user is already away, remember this
$away{$server->{'tag'}} = 1;
}
}
$away_status = $away;
} elsif ($away == 2 and $away_status != 2) {
# unset away
Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'tmux_away_crap',
"Reset away");
my ($server);
foreach $server (Irssi::servers()) {
if ($away{$server->{'tag'}} == 1) {
# user was already away, dont reset away
$away{$server->{'tag'}} = 0;
next;
}
$server->command("AWAY" . (($server->{chat_type} ne 'SILC') ? " -one" : "")) if ($server->{usermode_away});
if (defined($old_nicks{$server->{'tag'}}) and length($old_nicks{$server->{'tag'}}) > 0) {
# set old nick
$server->command("NICK " . $old_nicks{$server->{'tag'}});
$old_nicks{$server->{'tag'}} = "";
}
}
$away_status = $away;
}
}
# but everytimes install a new timer
register_tmux_away_timer();
return 0;
}
# register_tmux_away_timer()
#
# remove old timer and install a new one
#
# parameter:
# none
# return:
# none
sub register_tmux_away_timer {
if (defined($timer_name)) {
# remove old timer, if defined
Irssi::timeout_remove($timer_name);
}
# add new timer with new timeout (maybe the timeout has been changed)
$timer_name = Irssi::timeout_add(Irssi::settings_get_int($IRSSI{'name'} . '_repeat') * 1000, 'tmux_away', '');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment