use strict; use vars qw($VERSION %IRSSI %HELP); use Irssi 0 qw ( active_win server_find_tag signal_stop window_find_name parse_special ); use Irssi::UI; use Irssi::TextUI; $VERSION = '1.1'; %IRSSI = ( 'authors' => 'Marcin Rozycki', 'contact' => 'derwan@irssi.pl', 'name' => 'paste', 'description' => 'Pasting lines to specified targets, type "/paste -help" for help', 'license' => 'GNU GPL v2', 'modules' => '', 'url' => 'http://derwan.irssi.pl', 'changed' => '2018-07-14', ); $HELP{'paste'} = <] [] [] -help: print this help -c: enable colors -q: quiet mode (pasted lines are not dispalyed) -msg: sends messages as msg (as default) -notice: sends messages as notice -: sends messages to specified server : targets (separated with commas) : indexes of lines to paste ( separated with spaces) Examples: /PASTE - pasting to active channel or query /PASTE -c - pasting to active channel or query with colors /PASTE -c 1 3-5 - pasting to active channel or query lines 1, 3, 4 and 5 /PASTE -notice - pasting to active item - messages sent as notice, not msg /PASTE derwan - sends messages to derwan /PASTE -ircnet -c derwan,#irssi - sends messages (with colors) to derwan and #irssi in IRCNet Paste window - indexes: [0] [] [-] Examples: 0 - cancel 4 - line 4 4 8 9 10 - lines 4, 8, 9, 10 4 8-10 - lines 4, 8, 9, 10 Themes: paste_normal - \$0 line paste_reverse - \$0 line paste_count - \$0 count, \$1 server tag, \$2 target paste_input paste_no_server - \$0 comment paste_argument_missing - \$0 option, \$1 comment paste_argument_unknown - \$0 option, \$1 comment paste_nothing Your version is $VERSION - for updates visit $IRSSI{url} Mail bug reports and suggestions to <$IRSSI{contact}> EOF my ( $p ); # paste (str data, rec server, rec window) sub paste ($$$) { buf_destroy(); $p = {}; $p->{color} = 0; $p->{cmd} = 'msg'; $p->{quiet} = 0; my $win = active_win(); foreach my $arg ( split /\s+/, $_[0] ) { ( $arg eq '-help' ) and Irssi::print($HELP{'paste'}, MSGLEVEL_CLIENTCRAP), return; ( $arg eq '-c' ) and $p->{color} = 1, next; ( $arg eq '-q' ) and $p->{quiet} = 1, next; ( $arg =~ m/^-(msg|notice)$/ ) and $p->{cmd} = $1, next; ( $arg =~ m/^-(.*)$/ and !$p->{tag} ) and $p->{tag} = $1, next; ( $arg =~ m/^([^-\s]*[^-\d]+[^\s]*)$/ and !$p->{target} ) and $p->{target} = $1, next; ( $arg =~ m/^([1-9]\d*)$/ ) and $p->{l}->{$1} = 1, next; if ( $arg =~ m/^([1-9]\d*)-(\d+)$/ and $1 <= $2 ) { map { $p->{l}->{$_} = $p->{buf}->[$_-1] } ( $1 .. $2 ); next; } $win->printformat ( MSGLEVEL_CRAP, 'paste_argument_unknown', $arg, 'type /paste -help for help' ); buf_destroy(), return; } if ( !exists $p->{tag} or !defined $p->{tag} ) { if ( !ref $_[1] and !ref $win->{server} ) { $win->printformat ( MSGLEVEL_CRAP, 'paste_argument_missing', 'server tag', 'type /paste -help for help' ); buf_destroy(), return; } $p->{tag} = ( ref $_[1] ) ? $_[1]->{tag} : $win->{active}->{server}->{tag}; } elsif ( ! ref server_find_tag($p->{tag}) ) { $win->printformat ( MSGLEVEL_CRAP, 'paste_argument_unknown', $p->{tag}, 'not connected to that server' ); buf_destroy(), return; } unless ( exists $p->{target} and defined $p->{target} ) { if ( !ref $win->{active} or !$win->{active}->{name} ) { $win->printformat ( MSGLEVEL_CRAP, 'paste_argument_missing', 'target', 'type /paste -help for help' ); buf_destroy(), return; } $p->{target} = $win->{active}->{name}; } if ( buf_create() == 0 ) { $win->printformat ( MSGLEVEL_CRAP, 'paste_nothing' ); buf_destroy(), return; } foreach my $idx ( keys %{$p->{l}} ) { $p->{l}->{$idx} = $p->{buf}->[$idx-1]; } buf_destroy(), return if ( buf_flush() != 0 ); $p->{win} = sprintf('paste.%d', (int(rand(9000))+1000)); my $input = Irssi::Windowitem::window_create($p->{win}, 1); $input->set_name($p->{win}); $input->set_history($p->{win}); $input->change_server(server_find_tag($p->{tag})); my $width = $input->{width} - 8; my $theme = 'normal'; for ( my $idx = $#{$p->{buf}}; $idx >= 0; $idx-- ) { my $text = $p->{buf}->[$idx]->get_text(0); $text = sprintf ( '%03d %'.( length($text) > $width ? '.'.($width-1).'s$' : '-'.$width.'s' ). ' %03d', $idx+1, $text, $idx+1 ); $input->printformat(MSGLEVEL_NOHILIGHT, 'paste_'.$theme, $text); $theme = $theme eq 'normal' ? 'reverse' : 'normal'; } $input->printformat(MSGLEVEL_NOHILIGHT, 'paste_input'); $input->set_active(); }; sub buf_create () { return unless ( defined $p and ref $p ); my $win = active_win(); return 0 unless ( ref $win ); my $curline = $win->view()->{buffer}->{cur_line}; return 0 unless ( ref $curline ); for ( my $idx = 0; $idx < 100; $idx++ ) { last unless ( ref $curline ); push @{$p->{buf}}, $curline; $curline = $curline->prev(); } return ( $#{$p->{buf}} >= 0 ? 1 : 0 ); } sub buf_flush () { return unless ( defined $p and ref $p ); my $serv = server_find_tag($p->{tag}); unless ( ref $serv and $serv->{connected} ) { active_win()->printformat ( MSGLEVEL_CRAP, 'paste_no_server', $p->{tag} ); return -1; } my $count = 0; foreach my $idx ( sort { $b <=> $a } ( keys %{$p->{l}} ) ) { if ( defined $p->{l}->{$idx} and ref $p->{l}->{$idx} and ++$count ) { if ( $p->{quiet} == 0 ) { my $cmd = sprintf ( '%s %s %s', $p->{cmd}, $p->{target}, convertstr($p->{l}->{$idx}->get_text($p->{color})) ); $serv->command($cmd); } else { my $raw = sprintf ( '%s %s :%s', ( $p->{cmd} eq 'msg' ? 'privmsg' : 'notice' ), $p->{target}, convertstr($p->{l}->{$idx}->get_text($p->{color})) ); $serv->send_raw($raw); } } } if ( $count > 0 ) { active_win()->printformat(MSGLEVEL_CRAP, 'paste_count', $count, $p->{tag}, $p->{target}); } else { active_win()->printformat(MSGLEVEL_CRAP, 'paste_nothing'); } return $count; } # sig_send_command (str data, rec server, rec window) sub sig_send_command ($$$) { unless ( defined $p and ref $p and defined $p->{win} ) { return; } my $win = active_win(); if ( $_[0] eq 0 ) { buf_destroy(), return; } if ( substr($_[0], 0, 1) eq parse_special('$K') ) { return; } unless ( ref $win and $win->{name} eq $p->{win} ) { return; } signal_stop (); $win->destroy(); delete $p->{win}; foreach my $arg ( split /\s+/, $_[0] ) { if ( $arg =~ m/^(\d+)$/ and $1 > 0 ) { $p->{l}->{$1} = $p->{buf}->[$1-1]; } elsif ( $arg =~ m/^([1-9]\d*)-(\d+)$/ and $1 <= $2 ) { map { $p->{l}->{$_} = $p->{buf}->[$_-1] } ( $1 .. $2 ); } else { active_win()->printformat(MSGLEVEL_CRAP, 'paste_argument_unknown', $arg, 'type /paste -help for help'); } } buf_flush(); buf_destroy(); }; sub buf_destroy () { if ( defined $p and ref $p ) { @{$p->{buf}} = () if ( defined $p->{buf} and ref $p->{buf} ); %{$p->{l}} = () if ( defined $p->{l} and ref $p->{l} ); if ( defined $p->{win} ) { my $win = window_find_name($p->{win}); $win->destroy if ( ref $win ); } undef ( $p ); } } # convertstr (str text), str text # thanks for Stanislaw Halik sub convertstr ($) { if ( $_[0] ) { $_[0] =~ s/[\004]g\//\003\002\002/g; $_[0] =~ s/[\004]\?\/+/\0030\002\002/g; $_[0] =~ s/[\004]0\//\0031\002\002/g; $_[0] =~ s/[\004]0/\0031\002\002/g; $_[0] =~ s/[\004]1\//\0032\002\002/g; $_[0] =~ s/[\004]1/\0032\002\002/g; $_[0] =~ s/[\004]2\//\0033\002\002/g; $_[0] =~ s/[\004]2/\0033\002\002/g; $_[0] =~ s/[\004]<\//\0034\002\002/g; $_[0] =~ s/[\004]\//\0038\002\002/g; $_[0] =~ s/[\004]>/\0038\002\002/g; $_[0] =~ s/[\004]:\//\0039\002\002/g; $_[0] =~ s/[\004]:/\0039\002\002/g; $_[0] =~ s/[\004]3\//\00310\002\002/g; $_[0] =~ s/[\004]3/\00310\002\002/g; $_[0] =~ s/[\004]\;\//\00311\002\002/g; $_[0] =~ s/[\004]\;/\00311\002\002/g; $_[0] =~ s/[\004]9\//\00312\002\002/g; $_[0] =~ s/[\004]9/\00312\002\002/g; $_[0] =~ s/[\004]=\//\00313\002\002/g; $_[0] =~ s/[\004]=/\00313\002\002/g; $_[0] =~ s/[\004]8\//\00314\002\002/g; $_[0] =~ s/[\004]8/\00314\002\002/g; $_[0] =~ s/[\004]7\//\00315\002\002/g; $_[0] =~ s/[\004]7/\00315\002\002/g; $_[0] =~ s/[\004]g\//\003\002\002/g; $_[0] =~ s/[\004]g/\003\002\002/g; $_[0] =~ s/[\004]8\//\003\002\002/g; $_[0] =~ s/[\004]8/\003\002\002/g; } return $_[0]; } Irssi::theme_register ([ 'paste_normal', '$0-', 'paste_reverse', '%c$0-%n', 'paste_input', '%7%r type indexes of lines to paste (type "0" for cancel or "/paste -help" for help): %8%n', 'paste_count', '%_Irssi%_: {hilight $0} line(s) have been pasted to {nick $2} in $1', 'paste_argument_unknown', '%_Irssi%_: Unknown option: {hilight $0} {comment $1}', 'paste_argument_missing', '%_Irssi%_: Not enough parameters given: $0 {comment $1}', 'paste_no_server', '%_Irssi%_: Not connected to specified server {comment $0}', 'paste_nothing', '%_Irssi%_: Nothing to paste', ]); Irssi::signal_add_first('send command', 'sig_send_command'); Irssi::command_bind('paste', 'paste');