]> asedeno.scripts.mit.edu Git - ColorUtils.git/blob - lib/BarnOwl/Module/ColorUtils.pm
Ignore CC'd personals in when coloring personals.
[ColorUtils.git] / lib / BarnOwl / Module / ColorUtils.pm
1 # -*- mode: cperl; cperl-indent-level: 4; indent-tabs-mode: nil -*-
2 # Colors module.
3 use strict;
4 use warnings;
5
6 package BarnOwl::Module::ColorUtils;
7
8 =head1 NAME
9
10 BarnOwl::Module::ColorUtils
11
12 =head1 DESCRIPTION
13
14 This module implements easy to use color suppot for barnowl.
15
16 =cut
17
18 use Getopt::Long;
19 ################################################################################
20 ## Color state.
21 ################################################################################
22 our @colorList;
23 our %currentColorMap;
24 our %savedColorMap;
25 our %mode2Protocol = ('zephyr' => 'zephyr',
26                       'zephyr-personal' => 'zephyr',
27                       'aim' => 'aim',
28                       'jabber' => 'jabber',
29                       'irc' => 'IRC',
30                       'loopback' => 'loopback');
31
32
33 ################################################################################
34 #Run this on start and reload. Adds styles, sets style to start.
35 ################################################################################
36 my $config_dir = BarnOwl::get_config_dir();
37
38 sub onStart {
39     %currentColorMap = ();
40     %savedColorMap = ();
41     genColorList();
42     bindings_Color();
43     cmd_load();
44 }
45 $BarnOwl::Hooks::startup->add(\&onStart);
46
47 sub genColorList() {
48    @colorList = ('black','red','green','yellow',
49                   'blue','magenta','cyan','white');
50     if ( *BarnOwl::getnumcolors{CODE} ) {
51         for (my $i = 8; $i < BarnOwl::getnumcolors(); $i++) {
52             push(@colorList,$i);
53         }
54     }
55 }
56
57 ################################################################################
58 #Register BarnOwl commands and default keybindings.
59 ################################################################################
60 sub bindings_Color
61 {
62     # Commands
63     BarnOwl::new_command(
64         setcolor => \&cmd_setcolor,
65         {
66             summary => "Change the color for this sender (personals) or class/muc (or instance if zephyr -c message)",
67             usage   => "setcolor [-i] [-b] [color]",
68             description => "Sets the foreground (or background) color for this kind of message.\n\n"
69               . "The following options are available:\n\n"
70               . " -i    Set the color for this instance of this zephyr class.\n\n"
71               . " -b    Sets the background color instead of the foreground color.\n\n"
72               . "color may be any of the colors listed in `:show color'; if using a 256-color\n"
73               . "terminal, you may also use an HTML-style color code, #rrggbb, which will\n"
74               . "be matched to the closest color approximation in a 6x6x6 colorcube.\n"
75               . "The following special values are also allowed:\n"
76               . "  default    uncolors the message\n"
77               . "  restore    restores the last saved color for this message\n"
78               . "If no color is specified, the current color is displayed.\n"
79         }
80     );
81     BarnOwl::new_command(
82         loadcolors => \&cmd_load,
83         {
84             summary => "Load color filter definitions from disk.",
85             usage   => "loadcolors"
86         }
87     );
88     BarnOwl::new_command(
89         savecolors => \&cmd_save,
90         {
91             summary => "Save active color filter definitions to disk.",
92             usage   => "savecolors"
93         }
94     );
95
96     # Key Bindings
97     owl::command('bindkey recv "c" command start-command setcolor ');
98 }
99
100
101 ################################################################################
102 ## Loading function
103 ################################################################################
104 sub createFilters($) {
105     # Prepare the color filters.
106     my $fgbg = shift;
107     return unless (grep(/^[fb]g$/, $fgbg));
108     my $currentView = owl::getview();
109
110     my %workingColorMap = %{ $currentColorMap{$fgbg} };
111
112     foreach my $color (@colorList) {
113         my @strs;
114
115         #######################################################################
116         my $mode = 'zephyr';
117         {
118             my @class = ();
119             my @classInst = ();
120
121             foreach my $c (sort keys %{ $workingColorMap{$mode} }) {
122                 my $c_esc = $c;
123                 $c_esc =~ s/([+*])/\\$1/g;
124                 my @instances = (sort keys %{ $workingColorMap{$mode}{$c} });
125                 my $cHasStar = grep(/\*/, @instances);
126
127                 if ($cHasStar && @instances == 1) {
128                     # Collect classes that are only globally colored.
129                     push(@class, $c_esc) if ($workingColorMap{$mode}{$c}{'*'} eq $color);
130                 } else {
131                     # Collect classes that have varying color for instances.
132                     if ($cHasStar && $workingColorMap{$mode}{$c}{'*'} eq $color) {
133                         my @cInstances;
134                         foreach my $i (@instances) {
135                             next if (($i eq '*') || ($workingColorMap{$mode}{$c}{$i} eq $color));
136                             $i =~ s/([+*])/\\$1/g;
137                             push(@cInstances, $i);
138                         }
139                         push(@classInst, 'class ^'.$c_esc.'(.d)*$ and not instance ^('.join('|',@cInstances).')(.d)*$') if (@cInstances);
140                     } else {
141                         my @cInstances;
142                         foreach my $i (@instances) {
143                             next if (($i eq '*') || ($workingColorMap{$mode}{$c}{$i} ne $color));
144                             $i =~ s/([+*])/\\$1/g;
145                             push(@cInstances, $i);
146                         }
147                         push(@classInst, 'class ^'.$c_esc.'(.d)*$ and instance ^('.join('|',@cInstances).')(.d)*$') if (@cInstances);
148                     }
149                 }
150             }
151
152             # Join the collected classes into one big filter.
153             if (scalar(@class) || scalar(@classInst)) {
154                 push(@strs,
155                      '( type ^'.$mode2Protocol{$mode}.'$ and ( '
156                      . ((scalar(@class)) ? 'class ^('.join('|',@class).')(.d)*$ ' : '')
157                      . ((scalar(@class) && scalar(@classInst)) ? 'or ' : '')
158                      . ((scalar(@classInst)) ? '( '.join(' ) or ( ', @classInst).' ) ' : '')
159                      . ' ) )');
160             }
161         }
162         #######################################################################
163         $mode = 'zephyr-personal';
164         {
165             my $senders = '';
166             my $count = 0;
167             foreach my $sender (sort keys %{ $workingColorMap{$mode} }) {
168                 next if ($workingColorMap{$mode}{$sender} ne $color);
169                 $sender =~ s/([+*])/\\$1/g;
170                 $count++;
171                 $senders .= ($senders eq "") ? $sender : "|$sender";
172             }
173             if ($count) {
174                 push(@strs,
175                      '( type ^'.$mode2Protocol{$mode}.'$ and ( ( class ^message$ and instance ^personal$ ) or class ^login$ )'
176                      . ' and ( not body ^CC )'
177                      . ' and ( sender ^('.$senders.')$ or recipient ^('.$senders.')$ ) )');
178             }
179         }
180         #######################################################################
181         $mode = 'aim';
182         {
183             my $senders = "";
184             my $count = 0;
185             foreach my $sender (sort keys %{ $workingColorMap{$mode} }) {
186                 next if ($workingColorMap{$mode}{$sender} ne $color);
187                 $sender =~ s/([+*])/\\$1/g;
188                 $count++;
189                 $senders .= ($senders eq "") ? $sender : "|$sender";
190             }
191             if ($count) {
192                 push(@strs,
193                      '( type ^'.$mode2Protocol{$mode}.'$'
194                      . ' and ( sender ^('.$senders.')$ or recipient ^('.$senders.')$ ) )');
195             }
196         }
197         #######################################################################
198         $mode = 'jabber';
199         {
200             my $senders = "";
201             my $count = 0;
202             foreach my $sender (sort keys %{ $workingColorMap{$mode} }) {
203                 next if ($workingColorMap{$mode}{$sender} ne $color);
204                 $sender =~ s/([+*])/\\$1/g;
205                 $count++;
206                 $senders .= ($senders eq "") ? $sender : "|$sender";
207             }
208             if ($count) {
209                 push(@strs,
210                      '( type ^'.$mode2Protocol{$mode}.'$'
211                      . ' and ( sender ^('.$senders.')$ or recipient ^('.$senders.')$ ) )');
212             }
213         }
214         #######################################################################
215         $mode = 'irc';
216         {
217             my @servers = ();
218             my $sCount = 0;
219             foreach my $srv (sort keys %{ $workingColorMap{$mode} }) {
220                 my @channels = ();
221                 my $count = 0;
222                 foreach my $chan (sort keys %{ $workingColorMap{$mode}{$srv} }) {
223                     next if ($workingColorMap{$mode}{$srv}{$chan} ne $color);
224                     $chan =~ s/([+*])/\\$1/g;
225                     push(@channels, $chan);
226                     $count++;
227                 }
228                 $srv =~ s/([+*])/\\$1/g;
229                 if ($count) {
230                     push(@servers,
231                          ' ( server ^'.$srv.'$ and channel ^('.join('|',@channels).')$ )'
232                      );
233                     $sCount++;
234                 }
235             }
236             if ($sCount) {
237                 push(@strs,
238                      '( type ^'.$mode2Protocol{$mode}.'$'
239                        . ' and ( '. join(' or ', @servers)
240                          .' ) )');
241             }
242         }
243         #######################################################################
244         $mode = 'loopback';
245         {
246             push(@strs, '( type ^'.$mode2Protocol{$mode}.'$ )') if (($workingColorMap{$mode} || '') eq $color);
247         }
248         #######################################################################
249
250         my $filter = 'ColorUtils::'.$color.(($fgbg eq 'bg') ? '-bg' : '');
251         my $filterspec = "$filter ".(($fgbg eq 'bg') ? '-b' : '-c')." $color ";
252         if (scalar(@strs)) {
253             BarnOwl::filter("$filterspec ( "
254                            . join(' or ', @strs)
255                            . ' )');
256         } else {
257             next if ($currentView eq $filter);
258             BarnOwl::_remove_filter($filter);
259         }
260     }
261 }
262
263 sub normalize_rgb {
264     my $c = shift;
265     return 0 if ($c < 26);
266     return 1 if ($c < 77);
267     return 2 if ($c < 128);
268     return 3 if ($c < 179);
269     return 4 if ($c < 230);
270     return 5;
271 }
272
273 sub find_color($$$) {
274     my $r = normalize_rgb(shift);
275     my $g = normalize_rgb(shift);
276     my $b = normalize_rgb(shift);
277     return 16 + (36 * $r) + (6 * $g) + $b;
278 }
279
280 sub cmd_setcolor {
281     my $fgbg;
282     my $inst;
283
284     shift; #strip setcolor from argument list.
285     local @ARGV = @_;
286     GetOptions(
287         'backgroud'  => \$fgbg,
288         'instance' => \$inst,
289     );
290
291     if ((scalar @ARGV) <= 0) {
292         BarnOwl::message(sprintf("The current message is colored \"%s\".\n", getColor($inst, $fgbg)));
293         return;
294     }
295     my $color = shift @ARGV;
296
297     if ($color =~ /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i) {
298         $color = find_color(hex($1),hex($2),hex($3));
299     }
300     if ($color eq 'default') {
301         unset($inst, $fgbg);
302     } elsif ($color eq 'restore') {
303         restore($inst, $fgbg);
304     } else {
305         die("setcolor: invalid color ($color)\n") unless grep(/$color/,@colorList);
306         setColor($color, $inst, $fgbg);
307     }
308 }
309
310 sub cmd_save {
311     save('fg');
312     save('bg');
313     cmd_load();
314 }
315
316 sub cmd_load {
317     load('fg');
318     load('bg');
319     refreshView('fg');
320     refreshView('bg');
321 }
322
323 ################################################################################
324 ## Color toggling functions
325 ################################################################################
326 sub isZPersonal {
327     # Return 1 for things that would qualify a zephyr as personal.
328     my $m = shift;
329     return 1 if ($m->recipient ne "" and $m->recipient !~ /^@/);
330     return 1 if lc($m->class) eq "login";
331     return 0;
332 }
333
334 sub unset($$) {
335     my $bInst = shift;
336     my $fgbg = (shift || 0) ? 'bg' : 'fg';
337     my $m = owl::getcurmsg();
338     return unless $m;
339     my $type = lc($m->type);
340     if ($type eq 'zephyr') {
341         if (isZPersonal($m)) {
342             my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
343             $sender =~ s/ /./g;
344             delete $currentColorMap{$fgbg}{'zephyr-personal'}{$sender};
345         } else {
346             my $class = lc($m->class);
347             my $instance = ($bInst || ($class eq 'message')) ? lc($m->instance) : '*';
348             $class =~ s/ /./g;
349             $instance =~ s/ /./g;
350             if ($instance eq '*') {
351                 $currentColorMap{$fgbg}{$type}{$class}{$instance} = 'default';
352             } else {
353                 delete $currentColorMap{$fgbg}{$type}{$class}{$instance};
354             }
355         }
356     } elsif ($type eq 'aim' || $type eq 'jabber') {
357         my $sender = (lc($m->direction) eq 'in') ? $m->sender : $m->recipient;
358         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
359         $sender =~ s/ /./g;
360         delete $currentColorMap{$fgbg}{$type}{$sender};
361     } elsif ($type eq 'loopback') {
362         delete $currentColorMap{$fgbg}{$type};
363     }
364     refreshView($fgbg);
365 }
366
367 sub setColor($$$)
368 {
369     my $color = shift;
370     my $bInst = shift;
371     my $fgbg = (shift || 0) ? 'bg' : 'fg';
372     my $m = owl::getcurmsg();
373     return unless $m;
374
375     my $type = lc($m->type);
376     if ($type eq 'zephyr') {
377         if (isZPersonal($m)) {
378             my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
379             $sender =~ s/ /./g;
380             $currentColorMap{$fgbg}{'zephyr-personal'}{$sender} = $color;
381         } else {
382             my $class = lc($m->class);
383             my $instance = ($bInst || ($class eq 'message')) ? lc($m->instance) : '*';
384             $class =~ s/ /./g;
385             $instance =~ s/ /./g;
386             $currentColorMap{$fgbg}{$type}{$class}{$instance} = $color;
387         }
388     } elsif ($type eq 'aim' || $type eq 'jabber') {
389         my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
390         $sender =~ s/ /./g;
391         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
392         $currentColorMap{$fgbg}{$type}{$sender} = $color;
393     } elsif ($type eq 'irc') {
394         $currentColorMap{$fgbg}{$type}{$m->server}{$m->channel} = $color;
395     } elsif ($type eq 'loopback') {
396         $currentColorMap{$fgbg}{$type} = $color;
397     }
398
399     refreshView($fgbg);
400 }
401
402 sub getColor($$)
403 {
404     my $bInst = shift;
405     my $fgbg = (shift || 0) ? 'bg' : 'fg';
406     my $m = owl::getcurmsg();
407     return "" unless $m;
408
409     my $type = lc($m->type);
410     if ($type eq 'zephyr') {
411         if (isZPersonal($m)) {
412             my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
413             $sender =~ s/ /./g;
414             if (exists($currentColorMap{$fgbg}{'zephyr-personal'}{$sender})) {
415                 return $currentColorMap{$fgbg}{'zephyr-personal'}{$sender};
416             }
417         } else {
418             my $class = lc($m->class);
419             my $instance = ($bInst || ($class eq 'message')) ? lc($m->instance) : '*';
420             $class =~ s/ /./g;
421             $instance =~ s/ /./g;
422             if (exists($currentColorMap{$fgbg}{$type}{$class}{$instance})) {
423                 return $currentColorMap{$fgbg}{$type}{$class}{$instance};
424             }
425         }
426     } elsif ($type eq 'aim' || $type eq 'jabber') {
427         my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
428         $sender =~ s/ /./g;
429         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
430         if (exists($currentColorMap{$fgbg}{$type}{$sender})) {
431             return $currentColorMap{$fgbg}{$type}{$sender};
432         }
433     } elsif ($type eq 'irc') {
434         if (exists($currentColorMap{$fgbg}{$type}{$m->server}{$m->channel})) {
435             return $currentColorMap{$fgbg}{$type}{$m->server}{$m->channel};
436         }
437     } elsif ($type eq 'loopback') {
438         if (exists($currentColorMap{$fgbg}{$type})) {
439             return $currentColorMap{$fgbg}{$type};
440         }
441     }
442 }
443
444 sub restore($$) {
445     my $bInst = shift;
446     my $fgbg = (shift || 0) ? 'bg' : 'fg';
447     my $m = owl::getcurmsg();
448     return unless $m;
449     my $type = lc($m->type);
450     my $oldColor;
451     my $sender;
452     if ($type eq 'zephyr') {
453         if (isZPersonal($m)) {
454             $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
455             $sender =~ s/ /./g;
456             if ($oldColor = ($savedColorMap{$fgbg}{'zephyr-personal'}{$sender}) || '') {
457                 $currentColorMap{$fgbg}{'zephyr-personal'}{$sender} = $oldColor;
458             } else {
459                 delete $currentColorMap{$fgbg}{'zephyr-personal'}{$sender};
460             }
461         } else {
462             my $class = lc($m->class);
463             my $instance = lc($m->instance);
464             $instance =
465               ($bInst
466                  || ($class eq 'message')
467                  || ((($savedColorMap{$fgbg}{$type}{$class}{'*'} || '') eq ($currentColorMap{$fgbg}{$type}{$class}{'*'} || ''))
468                      && (($savedColorMap{$fgbg}{$type}{$class}{$instance} || '') ne ($currentColorMap{$fgbg}{$type}{$class}{$instance} || ''))))
469                 ? $instance
470                   : '*';
471             $class =~ s/ /./g;
472             $instance =~ s/ /./g;
473             if ($oldColor = ($savedColorMap{$fgbg}{$type}{$class}{$instance} || '')) {
474                 $currentColorMap{$fgbg}{$type}{$class}{$instance} = $oldColor;
475             } else {
476                 delete $currentColorMap{$fgbg}{$type}{$class}{$instance};
477             }
478         }
479     } elsif ($type eq 'aim' || $type eq 'jabber') {
480         $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
481         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
482         $sender =~ s/ /./g;
483         if ($oldColor = ($savedColorMap{$fgbg}{$type}{$sender} || '')) {
484             $currentColorMap{$fgbg}{$type}{$sender} = $oldColor;
485         } else {
486             delete $currentColorMap{$fgbg}{$type}{$sender};
487         }
488     } elsif ($type eq 'loopback') {
489
490         if ($oldColor = ($savedColorMap{$fgbg}{$type} || '')) {
491             $currentColorMap{$fgbg}{$type} = $oldColor;
492         } else {
493             delete $currentColorMap{$fgbg}{$type};
494         }
495     }
496
497     refreshView($fgbg);
498 }
499
500 sub refreshView($) {
501     my $fgbg = shift;
502     return unless (grep(/^[fb]g$/, $fgbg));
503
504     createFilters($fgbg);
505     if ( *BarnOwl::refresh_view{CODE} ) {
506         BarnOwl::refresh_view();
507     } else {
508         my $filter = owl::command("getview");
509         my $style = owl::command("getstyle");
510         owl::command("view -f $filter ".($style?"-s $style":""));
511     }
512 }
513
514 ################################################################################
515 ## Saving/Loading functions
516 ################################################################################
517 sub save($) {
518     my $fgbg = shift;
519     return unless (grep(/^[fb]g$/, $fgbg));
520
521     if ($fgbg eq 'bg') {
522         open(COLORS, ">$config_dir/colormap_bg");
523     } else {
524         open(COLORS, ">$config_dir/colormap");
525     }
526
527     my $type = 'zephyr';
528     print COLORS "MODE: $type\n";
529     foreach my $c (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
530         foreach my $i (sort keys %{ $currentColorMap{$fgbg}{$type}{$c} }) {
531             if ($i eq '*'
532                 || !($currentColorMap{$fgbg}{$type}{$c}{$i} eq ($currentColorMap{$fgbg}{$type}{$c}{'*'} || '')
533                      || !$currentColorMap{$fgbg}{$type}{$c}{$i})) {
534                 print COLORS "$c,$i,"
535                   . ($currentColorMap{$fgbg}{$type}{$c}{$i}
536                        ? $currentColorMap{$fgbg}{$type}{$c}{$i}
537                        : 'default')
538                   . "\n";
539             }
540         }
541     }
542
543     $type = 'zephyr-personal';
544     print COLORS "MODE: $type\n";
545     foreach my $s (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
546         print COLORS "$s,"
547            . ($currentColorMap{$fgbg}{$type}{$s}
548                 ? $currentColorMap{$fgbg}{$type}{$s}
549                 : 'default')
550            . "\n";
551     }
552
553     $type = 'aim';
554     print COLORS "MODE: $type\n";
555     foreach my $s (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
556         print COLORS "$s,"
557           . ($currentColorMap{$fgbg}{$type}{$s}
558                ? $currentColorMap{$fgbg}{$type}{$s}
559                : 'default')
560           . "\n";
561     }
562
563     $type = 'jabber';
564     print COLORS "MODE: $type\n";
565     foreach my $s (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
566         print COLORS "$s,"
567           . ($currentColorMap{$fgbg}{$type}{$s}
568                ? $currentColorMap{$fgbg}{$type}{$s}
569                : 'default')
570           . "\n";
571     }
572
573     $type = 'irc';
574     print COLORS "MODE: $type\n";
575     foreach my $srv (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
576         foreach my $chan (sort keys %{ $currentColorMap{$fgbg}{$type}{$srv} }) {
577             print COLORS "$srv,$chan,"
578               . ($currentColorMap{$fgbg}{$type}{$srv}{$chan}
579                    ? $currentColorMap{$fgbg}{$type}{$srv}{$chan}
580                    : 'default')
581               . "\n";
582         }
583     }
584
585
586     $type = 'loopback';
587     print COLORS "MODE: $type\n";
588     print COLORS ($currentColorMap{$fgbg}{$type}
589                     ? $currentColorMap{$fgbg}{$type}
590                     : 'default')
591       . "\n";
592
593     close(COLORS);
594 }
595
596 sub load($)
597 {
598     my $fgbg = shift;
599     return unless (grep(/^[fb]g$/, $fgbg));
600
601     $currentColorMap{$fgbg} = {};
602     $savedColorMap{$fgbg} = {};
603
604     # Parse the color file.
605     if ($fgbg eq 'bg') {
606         open(COLORS, "<$config_dir/colormap_bg") || return;
607     }
608     else {
609         open(COLORS, "<$config_dir/colormap") || return;
610     }
611
612
613     my $mode = "zephyr";
614
615     foreach my $line (<COLORS>) {
616         chomp($line);
617         if ($line =~ /^MODE: (.*)$/) {
618             if (lc($1) eq "zephyr") {
619                 $mode = 'zephyr';
620             } elsif (lc($1) eq "zephyr-personal") {
621                 $mode = 'zephyr-personal';
622             } elsif (lc($1) eq "aim") {
623                 $mode = 'aim';
624             } elsif (lc($1) eq "jabber") {
625                 $mode = 'jabber';
626             } elsif (lc($1) eq "irc") {
627                 $mode = 'irc';
628             } elsif (lc($1) eq "loopback") {
629                 $mode = 'loopback';
630             } else {
631                 $mode = 'zephyr';
632             }
633         } elsif ($mode eq 'zephyr' && $line =~ /^(.+),(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
634             $currentColorMap{$fgbg}{$mode}{lc($1)}{lc($2)} = lc($4);
635             $savedColorMap{$fgbg}{$mode}{lc($1)}{lc($2)}   = lc($4);
636         } elsif ($mode eq 'zephyr-personal' && $line =~ /^(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
637             $currentColorMap{$fgbg}{$mode}{lc($1)} = lc($3);
638             $savedColorMap{$fgbg}{$mode}{lc($1)}   = lc($3);
639         } elsif (($mode eq 'aim' || $mode eq 'jabber') && $line =~ /^(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
640             $currentColorMap{$fgbg}{$mode}{lc($1)} = lc($3);
641             $savedColorMap{$fgbg}{$mode}{lc($1)}   = lc($3);
642         } elsif (($mode eq 'irc') && $line =~ /^(.+),(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
643             $currentColorMap{$fgbg}{$mode}{lc($1)}{lc($2)} = lc($4);
644             $savedColorMap{$fgbg}{$mode}{lc($1)}{lc($2)}   = lc($4);
645         } elsif ($mode eq 'loopback' && $line =~ /^(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
646             $currentColorMap{$fgbg}{$mode} = lc($2);
647             $savedColorMap{$fgbg}{$mode}   = lc($2);
648         }
649     }
650     close(COLORS);
651 }