1use strict;
2use Irssi 20020101.0250 ();
3use vars qw($VERSION %IRSSI);
4$VERSION = "2.1";
5%IRSSI = (
6    authors     => "Timo Sirainen, Ian Peters, David Leadbeater, Bruno Cattáneo",
7    contact	=> "tss\@iki.fi",
8    name        => "Nick Color",
9    description => "assign a different color for each nick",
10    license	=> "Public Domain",
11    url		=> "http://irssi.org/",
12    changed	=> "Mon 08 Jan 21:28:53 BST 2018",
13);
14
15# Settings:
16#   nickcolor_colors: List of color codes to use.
17#   e.g. /set nickcolor_colors 2 3 4 5 6 7 9 10 11 12 13
18#   (avoid 8, as used for hilights in the default theme).
19#
20#   nickcolor_enable_prefix: Enables prefix for same nick.
21#
22#   nickcolor_enable_truncate: Enables nick truncation.
23#
24#   nickcolor_prefix_text: Prefix text for succesive messages.
25#   e.g. /set nickcolor_prefix_text -
26#
27#   nickcolor_truncate_value: Truncate nick value.
28#   e.g. /set nickcolor_truncate_value -7
29#   This will truncate nicknames at 7 characters and make them right aligned
30
31my %saved_colors;
32my %session_colors = {};
33my %saved_nicks; # To store each channel's last nickname
34
35sub load_colors {
36  open my $color_fh, "<", "$ENV{HOME}/.irssi/saved_colors";
37  while (<$color_fh>) {
38    chomp;
39    my($nick, $color) = split ":";
40    $saved_colors{$nick} = $color;
41  }
42}
43
44sub save_colors {
45  open COLORS, ">", "$ENV{HOME}/.irssi/saved_colors";
46
47  foreach my $nick (keys %saved_colors) {
48    print COLORS "$nick:$saved_colors{$nick}\n";
49  }
50
51  close COLORS;
52}
53
54# If someone we've colored (either through the saved colors, or the hash
55# function) changes their nick, we'd like to keep the same color associated
56# with them (but only in the session_colors, ie a temporary mapping).
57
58sub sig_nick {
59  my ($server, $newnick, $nick, $address) = @_;
60  my $color;
61
62  $newnick = substr ($newnick, 1) if ($newnick =~ /^:/);
63
64  if ($color = $saved_colors{$nick}) {
65    $session_colors{$newnick} = $color;
66  } elsif ($color = $session_colors{$nick}) {
67    $session_colors{$newnick} = $color;
68  }
69}
70
71# This gave reasonable distribution values when run across
72# /usr/share/dict/words
73
74sub simple_hash {
75  my ($string) = @_;
76  chomp $string;
77  my @chars = split //, $string;
78  my $counter;
79
80  foreach my $char (@chars) {
81    $counter += ord $char;
82  }
83
84  my @colors = split / /, Irssi::settings_get_str('nickcolor_colors');
85  $counter = $colors[$counter % @colors];
86
87  return $counter;
88}
89
90# process public (others) messages
91sub sig_public {
92  my ($server, $msg, $nick, $address, $target) = @_;
93
94  my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
95  my $enable_truncate = Irssi::settings_get_bool('nickcolor_enable_truncate');
96  my $prefix_text = Irssi::settings_get_str('nickcolor_prefix_text');
97  my $truncate_value = Irssi::settings_get_int('nickcolor_truncate_value');
98
99  # Reference for server/channel
100  my $tagtarget = "$server->{tag}/$target";
101
102  # Set default nick truncate value to 0 if option is disabled
103  $truncate_value = 0 if (!$enable_truncate);
104
105  # Has the user assigned this nick a color?
106  my $color = $saved_colors{$nick};
107
108  # Have -we- already assigned this nick a color?
109  if (!$color) {
110    $color = $session_colors{$nick};
111  }
112
113  # Let's assign this nick a color
114  if (!$color) {
115    $color = simple_hash $nick;
116    $session_colors{$nick} = $color;
117  }
118
119  $color = sprintf "\003%02d", $color;
120
121  # Optional: We check if it's the same nickname for current target
122  if ($saved_nicks{$tagtarget} eq $nick && $enable_prefix)
123  {
124    # Grouped message
125    Irssi::command('/^format pubmsg ' . $prefix_text . '$1');
126  }
127  else
128  {
129    # Normal message
130    Irssi::command('/^format pubmsg {pubmsgnick $2 {pubnick ' . $color . '$[' . $truncate_value . ']0}}$1');
131
132    # Save nickname for next message
133    $saved_nicks{$tagtarget} = $nick;
134  }
135
136}
137
138# process public (me) messages
139sub sig_me {
140  my ($server, $msg, $target) = @_;
141  my $nick = $server->{nick};
142
143  my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
144  my $enable_truncate = Irssi::settings_get_bool('nickcolor_enable_truncate');
145  my $prefix_text = Irssi::settings_get_str('nickcolor_prefix_text');
146  my $truncate_value = Irssi::settings_get_int('nickcolor_truncate_value');
147
148  # Reference for server/channel
149  my $tagtarget = "$server->{tag}/$target";
150
151  # Set default nick truncate value to 0 if option is disabled
152  $truncate_value = 0 if (!$enable_truncate);
153
154  # Optional: We check if it's the same nickname for current target
155  if ($saved_nicks{$tagtarget} eq $nick && $enable_prefix)
156  {
157    # Grouped message
158    Irssi::command('/^format own_msg ' . $prefix_text . '$1');
159  }
160  else
161  {
162    # Normal message
163    Irssi::command('/^format own_msg {ownmsgnick $2 {ownnick $[' . $truncate_value . ']0}}$1');
164
165    # Save nickname for next message
166    $saved_nicks{$tagtarget} = $nick;
167  }
168
169}
170
171# process public (others) actions
172sub sig_action_public {
173  my ($server, $msg, $nick, $address, $target) = @_;
174
175  my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
176
177  # Reference for server/channel
178  my $tagtarget = "$server->{tag}/$target";
179
180  # Empty current target nick if prefix option is enabled
181  $saved_nicks{$tagtarget} = '' if ($enable_prefix);
182
183}
184
185# process public (me) actions
186sub sig_action_me {
187  my ($server, $msg, $target) = @_;
188  my $nick = $server->{nick};
189
190  my $enable_prefix = Irssi::settings_get_bool('nickcolor_enable_prefix');
191
192  # Reference for server/channel
193  my $tagtarget = "$server->{tag}/$target";
194
195  # Empty current target nick if prefix option is enabled
196  $saved_nicks{$tagtarget} = '' if ($enable_prefix);
197
198}
199
200sub cmd_color {
201  my ($data, $server, $witem) = @_;
202  my ($op, $nick, $color) = split " ", $data;
203
204  $op = lc $op;
205
206  if (!$op) {
207    Irssi::print ("No operation given (save/set/clear/list/preview)");
208  } elsif ($op eq "save") {
209    save_colors;
210  } elsif ($op eq "set") {
211    if (!$nick) {
212      Irssi::print ("Nick not given");
213    } elsif (!$color) {
214      Irssi::print ("Color not given");
215    } elsif ($color < 2 || $color > 14) {
216      Irssi::print ("Color must be between 2 and 14 inclusive");
217    } else {
218      $saved_colors{$nick} = $color;
219    }
220  } elsif ($op eq "clear") {
221    if (!$nick) {
222      Irssi::print ("Nick not given");
223    } else {
224      delete ($saved_colors{$nick});
225    }
226  } elsif ($op eq "list") {
227    Irssi::print ("\nSaved Colors:");
228    foreach my $nick (keys %saved_colors) {
229      Irssi::print (chr (3) . sprintf("%02d", $saved_colors{$nick}) . "$nick" .
230		    chr (3) . "1 ($saved_colors{$nick})");
231    }
232  } elsif ($op eq "preview") {
233    Irssi::print ("\nAvailable colors:");
234    foreach my $i (2..14) {
235      Irssi::print (chr (3) . "$i" . "Color #$i");
236    }
237  }
238}
239
240load_colors;
241
242Irssi::settings_add_str('misc', 'nickcolor_colors', '2 3 4 5 6 7 9 10 11 12 13');
243Irssi::settings_add_bool('misc', 'nickcolor_enable_prefix', 0);
244Irssi::settings_add_bool('misc', 'nickcolor_enable_truncate', 0);
245Irssi::settings_add_str('misc', 'nickcolor_prefix_text' => '- ');
246Irssi::settings_add_int('misc', 'nickcolor_truncate_value' => 0);
247Irssi::command_bind('color', 'cmd_color');
248
249Irssi::signal_add('message public', 'sig_public');
250Irssi::signal_add('message own_public', 'sig_me');
251Irssi::signal_add('message irc action', 'sig_action_public');
252Irssi::signal_add('message irc own_action', 'sig_action_me');
253Irssi::signal_add('event nick', 'sig_nick');
254