diff options
Diffstat (limited to 'scripts/friends_peder.pl')
| -rw-r--r-- | scripts/friends_peder.pl | 729 | 
1 files changed, 729 insertions, 0 deletions
| diff --git a/scripts/friends_peder.pl b/scripts/friends_peder.pl new file mode 100644 index 0000000..bc4355b --- /dev/null +++ b/scripts/friends_peder.pl @@ -0,0 +1,729 @@ +# friends - irssi 0.8.4.CVS +# +#    $Id: friends.pl,v 1.34 2004/03/08 21:47:12 peder Exp $ +# +# Copyright (C) 2001, 2002, 2003 by Peder Stray <peder@ninja.no> +# + +use strict; +use Irssi 20020427.2353; +use Irssi::Irc; +use Irssi::TextUI; + +use Data::Dumper; +$Data::Dumper::Indent = 1; + +# ======[ Script Header ]=============================================== + +use vars qw{$VERSION %IRSSI}; +($VERSION) = '$Revision: 1.34 $' =~ / (\d+\.\d+) /; +%IRSSI = ( +          name        => 'friends', +          authors     => 'Peder Stray', +          contact     => 'peder@ninja.no', +          url         => 'http://ninja.no/irssi/friends.pl', +          license     => 'GPL', +          description => 'Basicly an autoop script with a nice interface and nick coloring ;)', +         ); + +# ======[ Variables ]=================================================== + +my(%friends, @friends); + +my(%flagshort) = ( +		  op => 'o', +		  voice => 'v', +		  color => 'c', +		 ); +my(%flaglong) = map { $flagshort{$_} => $_ } keys %flagshort; + +# ======[ Helper functions ]============================================ + +# --------[ crap ]------------------------------------------------------ + +sub crap { +    my $template = shift; +    my $msg = sprintf $template, @_; +    Irssi::printformat(MSGLEVEL_CLIENTCRAP, 'friends_crap', $msg); +} + +# --------[ load_friends ]---------------------------------------------- + +sub load_friends { +    my($file) = Irssi::get_irssi_dir."/friends"; +    my($count) = 0; +    my($mask,$net,$channel,$flags,$flag); +    local(*FILE); + +    %friends = (); +    open FILE, "< $file"; +    while (<FILE>) { +	($mask,$net,$channel,$flags) = split; +	for (split //, $flags) { +	    if ($flag = $flaglong{$_}) { +		$friends{$mask}{lc $net}{lc $channel}{$flag} = 1; +	    } +	} +    } +    close FILE; +    $count = keys %friends; +     +    crap("Loaded $count friends from $file"); +} + +# --------[ save_friends ]---------------------------------------------- + +sub save_friends { +    my($auto) = @_; +    my($file) = Irssi::get_irssi_dir."/friends"; +    my($count) = 0; +    local(*FILE); + +    return if $auto && !Irssi::settings_get_bool('friends_autosave'); + +    open FILE, "> $file"; +    for my $mask (keys %friends) { +	$count++; +	for my $net (keys %{$friends{$mask}}) { +	    for my $channel (keys %{$friends{$mask}{$net}}) { +		print FILE "$mask\t$net\t$channel\t". +		  join("", sort map {$flagshort{$_}} keys %{$friends{$mask}{$net}{$channel}}). +		    "\n"; +	    } +	} +    } +    close FILE; + +    crap("Saved $count friends to $file") +      unless $auto; +} + +# --------[ is_friends_window ]----------------------------------------- + +sub is_friends_window { +    my($win) = @_; +    return $win->{name} eq '<Friends>'; +} + +# --------[ get_friends_window ]---------------------------------------- + +sub get_friends_window { +    my($win) = Irssi::window_find_name('<Friends>'); +    if ($win) { +	$win->set_active; +    } else { +	Irssi::command("window new hide"); +	$win = Irssi::active_win; +	$win->set_name('<Friends>'); +	$win->set_history('<Friends>'); +    } +    return $win; +} + +# --------[ get_friend ]------------------------------------------------ + +sub get_friend { +    my($channel,$nick) = @_; +    my($server) = $channel->{server}; +    my($chan) = lc $channel->{name}; +    my($net) = lc $server->{chatnet}; +    my($flags,@friend); +     +    for my $mask (keys %friends) { +	next unless $server->mask_match_address($mask,  +						$nick->{nick}, +						$nick->{host}); +	for my $n ('*', $net) { +	    for my $c ('*', $chan) { +		if (exists $friends{$mask}{$n}{$c}) { +		    for my $flag (keys %{$friends{$mask}{$n}{$c}}) { +			$flags->{$flag} = 1; +		    } +		} +	    } +	} +	return $flags if $flags; +    } +    return undef; +} + +# --------[ check_friends ]--------------------------------------------- + +sub check_friends { +    my($channel, @nicks) = @_; +    my(%op,%voice); +    my($nick,$friend,$list);  +    my(@friends); + +    return unless $channel->{chanop} || $channel->{ownnick}{op}; + +    for $nick (@nicks) { +	$friend = get_friend($channel, $nick); +	next unless $friend; +	next if $nick->{nick} eq $channel->{server}{nick}; +	if ($friend->{op} && !$nick->{op}) { +	    $op{$nick->{nick}} = 1; +	} +	if ($friend->{voice} && !$nick->{voice}) { +	    $voice{$nick->{nick}} = 1; +	} +	push @friends, ($nick->{op}?'@':''). +	  ($nick->{voice}?'+':'').$nick->{nick}; +    } + +    if (@friends && Irssi::settings_get_bool("friends_show_check")) { +	my($max) = Irssi::settings_get_int("friends_max_nicks"); +	@friends = sort @friends; +	$channel->printformat(MSGLEVEL_CLIENTCRAP, +			      @friends>$max  +			      ? 'friends_check_more' : 'friends_check', +			      join(" ", splice @friends, 0, $max), +			      scalar @friends); +    } + +    if ($list = join " ", sort keys %op) { +        $channel->command("op $list"); +    } +    if ($list = join " ", sort keys %voice) { +        $channel->command("voice $list"); +    } +} + +# --------[ update_friends_hash ]--------------------------------------- + +sub update_friends_hash { +    %friends = (); +    for (@friends) { +	my($num,$mask,$chan,$net,$flags) = @$_; +	for (split //, $flags) { +	    $friends{$mask}{$net}{$chan}{$flaglong{$_}} = 1; +	} +    } +} + +# --------[ update_friends_window ]------------------------------------- + +sub update_friends_window { +    my($win) = Irssi::window_find_name('<Friends>'); +    my($view); +    my($num) = 0; +    my($mask,$net,$channel,$flags); + +    my(%net); + +    if ($win) { +	@friends = (); +	for $mask (sort keys %friends) { +	    for $net (sort keys %{$friends{$mask}}) { +		for $channel (sort keys %{$friends{$mask}{$net}}) { +		    $flags = join "", sort map {$flagshort{$_}}  +		      keys %{$friends{$mask}{$net}{$channel}}; +		    push @friends, [ ++$num, $mask, $channel, $net, $flags ]; +		} +	    } +	} + +	$view = $win->view; +	$view->remove_all_lines(); +	$view->clear(); +	$win->printformat(MSGLEVEL_NEVER, 'friends_header', +			  '##', 'Mask', 'Channel', 'ChatNet', 'Flags'); +	for (@friends) { +	    ($num,$mask,$channel,$net,$flags) = @$_; +	    if (!$net{$net}) { +		my($n) = Irssi::chatnet_find($net); +		$net{$net} = $n?$n->{name}:$net; +	    } +	    $win->printformat(MSGLEVEL_NEVER, 'friends_line', +			      $num, $mask, $channel, $net{$net}, $flags); +	} +	$win->printformat(MSGLEVEL_NEVER, 'friends_footer', scalar @friends); +    } +} + +# ======[ Signal Hooks ]================================================ + +# --------[ sig_send_command ]------------------------------------------ + +sub sig_send_command { +    my($win) = Irssi::active_win; +    if (is_friends_window($win)) { +	my($cmd,@param) = split " ", $_[0]; +	my($changed) = 0; + +	Irssi::signal_stop; + +	for (lc $cmd) { +	    s,^/,,; +	    if (/^m(ask)?$/) { +		$changed = subcmd_friends_mask($win,@param); + +	    } elsif (/^c(han(nel)?)?$/) { +		$changed = subcmd_friends_channel($win,@param); + +	    } elsif (/^(?:n(et)?|chat(net)?)$/) { +		$changed = subcmd_friends_net($win,@param); +		 +	    } elsif (/^del(ete)?$/) { +		$changed = subcmd_friends_delete($win,@param); +		 +	    } elsif (/^f(lags?)?$/) { +		$changed = subcmd_friends_flags($win,@param); + +	    } elsif (/^s(ave)?/) { +		save_friends(); + +	    } elsif (/^(?:e(xit)?|q(uit)?)$/) { +		$win->destroy; + +	    } elsif (/^(?:h(elp)?|\?)$/) { +		subcmd_friends_help($win); + +	    } else { +		$win->print("CMD: $cmd @{[map{\"[$_]\"}@param]}"); + +	    } +	} + +	if ($changed) { +	    update_friends_hash(); +	    update_friends_window(); +	    save_friends(1); +	} +    } +} + +# --------[ sig_massjoin ]---------------------------------------------- + +sub sig_massjoin { +    my($channel, $nicks) = @_; +    check_friends($channel, @$nicks); +} + +# --------[ sig_nick_mode_changed ]------------------------------------- + +sub sig_nick_mode_changed { +    my($channel, $nick) = @_; +    if ($channel->{synced} && $channel->{server}{nick} eq $nick->{nick}) { +	check_friends($channel, $channel->nicks); +    } +} + +# --------[ sig_channel_sync ]------------------------------------------ + +sub sig_channel_sync { +    my($channel) = @_; +    check_friends($channel, $channel->nicks); +} + +# --------[ sig_setup_reread ]------------------------------------------ + +sub sig_setup_reread { +    load_friends; +} + +# --------[ sig_setup_save ]-------------------------------------------- + +sub sig_setup_save { +    my($mainconf,$auto) = @_; +    save_friends($auto); +} + +# --------[ sig_window_changed ]---------------------------------------- + +sub sig_window_changed { +    my($new,$old) = @_; +    if (is_friends_window($new)) { +	update_friends_window(); +    } +} + +# --------[ sig_message_public ]---------------------------------------- + +sub sig_message_public { +    my($server, $msg, $nick, $addr, $target) = @_; +    my($window,$theme,$friend,$oform,$nform); +    my($channel) = $server->channel_find($target); + +    return unless $channel; + +    my($color) = Irssi::settings_get_str("friends_nick_color"); + +    $friend = get_friend($channel, $channel->nick_find($nick)); + +    if ($friend && $color =~ /^[rgbcmykpwRGBCMYKPWFU0-9_]$/) { +	$window = $server->window_find_item($target); +	$theme = $window->{theme} || Irssi::current_theme; +	 +	$oform = $nform = $theme->get_format('fe-common/core', 'pubmsg'); +	$nform =~ s/(\$(\[-?\d+\])?0)/%$color$1%n/g; + +	$window->command("^format pubmsg $nform"); +	Irssi::signal_continue(@_); +	$window->command("^format pubmsg $oform"); +    } +} + +# --------[ sig_message_irc_action ]------------------------------------ + +sub sig_message_irc_action { +    my($server, $msg, $nick, $addr, $target) = @_; +    my($window,$theme,$friend,$oform,$nform); +    my($channel) = $server->channel_find($target); + +    return unless $channel; + +    my($color) = Irssi::settings_get_str("friends_nick_color"); + +    $friend = get_friend($channel, $channel->nick_find($nick)); + +    if ($friend && $color =~ /^[rgbcmykpwRGBCMYKPWFU0-9_]$/) { +	$window = $server->window_find_item($target); +	$theme = $window->{theme} || Irssi::current_theme; +	 +	$oform = $nform = $theme->get_format('fe-common/irc',  +					     'action_public'); +	$nform =~ s/(\$(\[-?\d+\])?0)/%$color$1%n/g; + +	$window->command("^format action_public $nform"); +	Irssi::signal_continue(@_); +	$window->command("^format action_public $oform"); +    } +} + +# ======[ Commands ]==================================================== + +# --------[ FRIENDS ]--------------------------------------------------- + +# Usage: /FRIENDS +sub cmd_friends { +    my($win) = get_friends_window; +    update_friends_window(); +} + +# --------[ subcmd_friends_channel ]------------------------------------ + +sub subcmd_friends_channel { +    my($win,$num,$chan) = @_; + +    unless ($chan && defined $num) { +	$win->print("Syntax: CHANNEL <num> <channel>", MSGLEVEL_NEVER); +	return; +    } + +    unless (0 < $num && $num <= @friends) { +	$win->print("Error: Element $num not in list", MSGLEVEL_NEVER); +	return; +    } + +    $friends[$num-1][2] = $chan; + +    return 1; +} + +# --------[ subcmd_friends_delete ]------------------------------------- + +sub subcmd_friends_delete { +    my($win,$num) = @_; + +    unless (defined $num) { +	$win->print("Syntax: DELETE <num>", MSGLEVEL_NEVER); +	return; +    } +     +    unless (0 < $num && $num <= @friends) { +	$win->print("Error: Element $num not in list", MSGLEVEL_NEVER); +	return; +    } +     +    splice @friends, $num-1, 1; + +    return 1; +} + +# --------[ subcmd_friends_flags ]-------------------------------------- + +sub subcmd_friends_flags { +    my($win,$num,$flags) = @_; +    my(%f); +     +    unless ($flags && defined $num) { +	$win->print("Syntax: FLAGS <num> <flags>", MSGLEVEL_NEVER); +	return; +    } + +    unless (0 < $num && $num <= @friends) { +	$win->print("Error: Element $num not in list", MSGLEVEL_NEVER); +	return; +    } +     +    $friends[$num-1][4] = join "", sort grep {!$f{$_}++} +      split //, $flags; + +    return 1; +} + +# --------[ subcmd_friends_help ]--------------------------------------- + +sub subcmd_friends_help { +    my($win) = @_; + +    $win->print(q{CHANNEL <num> <channel>    - set channel + +    <channel> is either a channel name or * for all +}, MSGLEVEL_NEVER); + +    $win->print(q{DELETE  <num>              - delete entry +}, MSGLEVEL_NEVER); + +    $win->print(q{FLAGS   <num> <flags>      - set flags + +    <flags> is a list of c (color), o (give op), v (give voice) +}, MSGLEVEL_NEVER); + +    $win->print(q{MASK    <num> <mask>       - set mask + +    <mask> is in the usual nick!user@host format +}, MSGLEVEL_NEVER); + +    $win->print(q{NET     <num> <net>        - set net + +   <net> is one of your defined ircnets or * for all +}, MSGLEVEL_NEVER); + +} + +# --------[ subcmd_friends_mask ]--------------------------------------- + +sub subcmd_friends_mask { +    my($win, $num, $mask) = @_; + +    unless ($mask && defined $num) { +	$win->print("Syntax: MASK <num> <mask>", MSGLEVEL_NEVER); +	return; +    } +     +    unless (0 < $num && $num <= @friends) { +	$win->print("Error: Element $num not in list", MSGLEVEL_NEVER); +	return; +    } +     +    unless ($mask =~ /^.+!.+@.+$/) { +	$win->print("Error: Mask $mask is not valid", MSGLEVEL_NEVER); +    } +     +    $friends[$num-1][1] = $mask; + +    return 1; +} + +# --------[ subcmd_friends_net ]---------------------------------------- + +sub subcmd_friends_net { +    my($win,$num,$net) = @_; +    my($n); + +    unless ($net && defined $num) { +	$win->print("Syntax: NET <num> <net>", MSGLEVEL_NEVER); +	return; +    } + +    unless (0 < $num && $num <= @friends) { +	$win->print("Error: Element $num not in list", MSGLEVEL_NEVER); +	return; +    } +     +    if ($net eq '*') { +	# all is well +    } elsif ($n = Irssi::chatnet_find($net)) { +	$net = $n->{name}; +    } else { +	$win->print("Error: No defined chatnet named $net", +		    MSGLEVEL_NEVER); +	return; +    } +     +    $friends[$num-1][3] = $net; + +    return 1; +} + +# --------[ ADDFRIEND ]------------------------------------------------- + +# Usage: /ADDFRIEND <nick>|<mask> [<channel>|* [<net>|*]] +#                                 [-mask host|normal|domain|full] +#			          [-flags <flags>] +sub cmd_addfriend { +    my($param,$serv,$chan) = @_; +    my(@param,@flags); +    my($type) = Irssi::Irc::MASK_USER | Irssi::Irc::MASK_DOMAIN; +    my($mask,$flags,$channel,$net); +    my(@split) = split " ", $param; + +    while (@split) { +	$_ = shift @split; +	if (/^-m(ask)?$/) { +	    $_ = shift @split; +	    if (/^h(ost)?$/) { +		$type = Irssi::Irc::MASK_HOST; +	    } elsif (/^n(ormal)?$/) { +		$type = Irssi::Irc::MASK_USER +	              | Irssi::Irc::MASK_DOMAIN; +	    } elsif (/^d(omain)?$/) { +		$type = Irssi::Irc::MASK_DOMAIN; +	    } elsif (/^f(ull)?$/) { +		$type = Irssi::Irc::MASK_NICK +	              | Irssi::Irc::MASK_USER +		      | Irssi::Irc::MASK_HOST; +	    } else { +		# fjekk +	    } +	} elsif (/^-flags?$/) { +	    $flags = shift @split; +	} else { +	    push @param, $_; +	} +    } +    ($mask,$channel,$net) = @param; + +    unless ($mask) { +	crap("/ADDFRIEND [-mask full|normal|host|domain] [-flags <[o][v][c]>] <nick|mask> [<channel> [<chatnet>]]]"); +	return; +    } + +    $flags ||= "o"; + +    unless ($channel) { +	if ($chan) { +	    $channel = $chan->{name}; +	} else { +	    crap("/ADDFRIEND needs a channel."); +	    return; +	} +    } + +    unless ($net) { +	if ($serv) { +	    $net = $serv->{chatnet}; +	} else { +	    crap("/ADDFRIEND needs a chatnet."); +	    return; +	} +    } + +    # is this a nick we need to expand? +    unless ($mask =~ /.+!.+@.+/) { +	my($nick); +	if ($net ne '*') { +	    unless ($serv = Irssi::server_find_chatnet($net)) { +		crap("Error locating server for $net."); +		return; +	    } +	} else { +	    unless ($serv) { +		crap("Need a server for nick expansion"); +		return +	    } +	} +	if ($channel ne '*') { +	    unless ($chan = $serv->channel_find($channel)) { +		crap("Error locating channel $channel."); +		return; +	    } +	} else { +	    unless ($chan) { +		crap("Need a channel for nick expansion"); +		return; +	    } +	} +	unless ($nick = $chan->nick_find($mask)) { +	    crap("Error locating nick $mask."); +	    return; +	} +	$mask = Irssi::Irc::get_mask($nick->{nick}, $nick->{host}, $type); +    } + +    for my $flag (split //, $flags) { +	unless ($flag = $flaglong{$flag}) { +	    crap("Unknown flag [$flag]"); +	    next; +	} +	push @flags, $flag; +	$friends{$mask}{lc $net}{lc $channel}{$flag} = 1; +    } + +    if (@flags) { +	crap("Added %s for %s in %s on %s.", +	     join(",", @flags), $mask, $channel, $net); +    } + +    save_friends(1); +} + +# ======[ Setup ]======================================================= + +# --------[ Register settings ]----------------------------------------- + +Irssi::settings_add_bool('friends', 'friends_autosave', 1); +Irssi::settings_add_int('friends', 'friends_max_nicks', 10); +Irssi::settings_add_bool('friends', 'friends_show_check', 1); + +Irssi::settings_add_str('friends', 'friends_nick_color', ''); + +# --------[ Register formats ]------------------------------------------ + +Irssi::theme_register( +[ + 'friends_crap', + '{line_start}{hilight Friends:} $0', + + 'friends_check', + '{line_start}{hilight Friends} checked: $0', + + 'friends_check_more', + '{line_start}{hilight Friends} checked: $0 (+$1 more)', + + 'friends_header', + '<%W$[2]0%n> <%W$[33]1%n> <%W$[13]2%n> <%W$[13]3%n> <%W$[5]4%n>', + + 'friends_line', + '[%R$[-2]0%n] $[35]1 $[15]2 $[15]3 $[7]4', + + 'friends_footer', + "\n".'%4 List contains $0 friends %>%n', + +]); + +# --------[ Register signals ]------------------------------------------ + +Irssi::signal_add_first("send command", "sig_send_command"); + +Irssi::signal_add_last("massjoin", "sig_massjoin"); +Irssi::signal_add_last("nick mode changed", "sig_nick_mode_changed"); +Irssi::signal_add_last("channel sync", "sig_channel_sync"); + +Irssi::signal_add('setup saved', 'sig_setup_save'); +Irssi::signal_add('setup reread', 'sig_setup_reread'); + +Irssi::signal_add('window changed', 'sig_window_changed'); + +Irssi::signal_add_first('message public', 'sig_message_public'); +Irssi::signal_add_first('message irc action', 'sig_message_irc_action'); + +# --------[ Register commands ]----------------------------------------- + +Irssi::command_bind('friends', 'cmd_friends'); +Irssi::command_bind('addfriend', 'cmd_addfriend'); + +# --------[ Register timers ]------------------------------------------- + +# --------[ Load config ]----------------------------------------------- + +load_friends; + +# ======[ END ]========================================================= + +# Local Variables: +# header-initial-hide: t +# mode: header-minor +# end: | 
