]> asedeno.scripts.mit.edu Git - ColorUtils.git/blob - lib/BarnOwl/Module/ColorUtils.pm
Let setcolor also return the existing color if none is given.
[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 ( sender ^('.$senders.')$ or recipient ^('.$senders.')$ ) )');
177             }
178         }
179         #######################################################################
180         $mode = 'aim';
181         {
182             my $senders = "";
183             my $count = 0;
184             foreach my $sender (sort keys %{ $workingColorMap{$mode} }) {
185                 next if ($workingColorMap{$mode}{$sender} ne $color);
186                 $sender =~ s/([+*])/\\$1/g;
187                 $count++;
188                 $senders .= ($senders eq "") ? $sender : "|$sender";
189             }
190             if ($count) {
191                 push(@strs,
192                      '( type ^'.$mode2Protocol{$mode}.'$'
193                      . ' and ( sender ^('.$senders.')$ or recipient ^('.$senders.')$ ) )');
194             }
195         }
196         #######################################################################
197         $mode = 'jabber';
198         {
199             my $senders = "";
200             my $count = 0;
201             foreach my $sender (sort keys %{ $workingColorMap{$mode} }) {
202                 next if ($workingColorMap{$mode}{$sender} ne $color);
203                 $sender =~ s/([+*])/\\$1/g;
204                 $count++;
205                 $senders .= ($senders eq "") ? $sender : "|$sender";
206             }
207             if ($count) {
208                 push(@strs,
209                      '( type ^'.$mode2Protocol{$mode}.'$'
210                      . ' and ( sender ^('.$senders.')$ or recipient ^('.$senders.')$ ) )');
211             }
212         }
213         #######################################################################
214         $mode = 'irc';
215         {
216             my @servers = ();
217             my $sCount = 0;
218             foreach my $srv (sort keys %{ $workingColorMap{$mode} }) {
219                 my @channels = ();
220                 my $count = 0;
221                 foreach my $chan (sort keys %{ $workingColorMap{$mode}{$srv} }) {
222                     next if ($workingColorMap{$mode}{$srv}{$chan} ne $color);
223                     $chan =~ s/([+*])/\\$1/g;
224                     push(@channels, $chan);
225                     $count++;
226                 }
227                 $srv =~ s/([+*])/\\$1/g;
228                 if ($count) {
229                     push(@servers,
230                          ' ( server ^'.$srv.'$ and channel ^('.join('|',@channels).')$ )'
231                      );
232                     $sCount++;
233                 }
234             }
235             if ($sCount) {
236                 push(@strs,
237                      '( type ^'.$mode2Protocol{$mode}.'$'
238                        . ' and ( '. join(' or ', @servers)
239                          .' ) )');
240             }
241         }
242         #######################################################################
243         $mode = 'loopback';
244         {
245             push(@strs, '( type ^'.$mode2Protocol{$mode}.'$ )') if (($workingColorMap{$mode} || '') eq $color);
246         }
247         #######################################################################
248
249         my $filter = 'ColorUtils::'.$color.(($fgbg eq 'bg') ? '-bg' : '');
250         my $filterspec = "$filter ".(($fgbg eq 'bg') ? '-b' : '-c')." $color ";
251         if (scalar(@strs)) {
252             BarnOwl::filter("$filterspec ( "
253                            . join(' or ', @strs)
254                            . ' )');
255         } else {
256             next if ($currentView eq $filter);
257             BarnOwl::_remove_filter($filter);
258         }
259     }
260 }
261
262 sub normalize_rgb {
263     my $c = shift;
264     return 0 if ($c < 26);
265     return 1 if ($c < 77);
266     return 2 if ($c < 128);
267     return 3 if ($c < 179);
268     return 4 if ($c < 230);
269     return 5;
270 }
271
272 sub find_color($$$) {
273     my $r = normalize_rgb(shift);
274     my $g = normalize_rgb(shift);
275     my $b = normalize_rgb(shift);
276     return 16 + (36 * $r) + (6 * $g) + $b;
277 }
278
279 sub cmd_setcolor {
280     my $fgbg;
281     my $inst;
282
283     shift; #strip setcolor from argument list.
284     local @ARGV = @_;
285     GetOptions(
286         'backgroud'  => \$fgbg,
287         'instance' => \$inst,
288     );
289
290     if ((scalar @ARGV) <= 0) {
291         BarnOwl::message(sprintf("The current message is colored \"%s\".\n", getColor($inst, $fgbg)));
292         return;
293     }
294     my $color = shift @ARGV;
295
296     if ($color =~ /^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i) {
297         $color = find_color(hex($1),hex($2),hex($3));
298     }
299     if ($color eq 'default') {
300         unset($inst, $fgbg);
301     } elsif ($color eq 'restore') {
302         restore($inst, $fgbg);
303     } else {
304         die("setcolor: invalid color ($color)\n") unless grep(/$color/,@colorList);
305         setColor($color, $inst, $fgbg);
306     }
307 }
308
309 sub cmd_save {
310     save('fg');
311     save('bg');
312     cmd_load();
313 }
314
315 sub cmd_load {
316     load('fg');
317     load('bg');
318     refreshView('fg');
319     refreshView('bg');
320 }
321
322 ################################################################################
323 ## Color toggling functions
324 ################################################################################
325 sub isZPersonal {
326     # Return 1 for things that would qualify a zephyr as personal.
327     my $m = shift;
328     return 1 if ($m->recipient ne "" and $m->recipient !~ /^@/);
329     return 1 if lc($m->class) eq "login";
330     return 0;
331 }
332
333 sub unset($$) {
334     my $bInst = shift;
335     my $fgbg = (shift || 0) ? 'bg' : 'fg';
336     my $m = owl::getcurmsg();
337     return unless $m;
338     my $type = lc($m->type);
339     if ($type eq 'zephyr') {
340         if (isZPersonal($m)) {
341             my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
342             $sender =~ s/ /./g;
343             delete $currentColorMap{$fgbg}{'zephyr-personal'}{$sender};
344         } else {
345             my $class = lc($m->class);
346             my $instance = ($bInst || ($class eq 'message')) ? lc($m->instance) : '*';
347             $class =~ s/ /./g;
348             $instance =~ s/ /./g;
349             if ($instance eq '*') {
350                 $currentColorMap{$fgbg}{$type}{$class}{$instance} = 'default';
351             } else {
352                 delete $currentColorMap{$fgbg}{$type}{$class}{$instance};
353             }
354         }
355     } elsif ($type eq 'aim' || $type eq 'jabber') {
356         my $sender = (lc($m->direction) eq 'in') ? $m->sender : $m->recipient;
357         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
358         $sender =~ s/ /./g;
359         delete $currentColorMap{$fgbg}{$type}{$sender};
360     } elsif ($type eq 'loopback') {
361         delete $currentColorMap{$fgbg}{$type};
362     }
363     refreshView($fgbg);
364 }
365
366 sub setColor($$$)
367 {
368     my $color = shift;
369     my $bInst = shift;
370     my $fgbg = (shift || 0) ? 'bg' : 'fg';
371     my $m = owl::getcurmsg();
372     return unless $m;
373
374     my $type = lc($m->type);
375     if ($type eq 'zephyr') {
376         if (isZPersonal($m)) {
377             my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
378             $sender =~ s/ /./g;
379             $currentColorMap{$fgbg}{'zephyr-personal'}{$sender} = $color;
380         } else {
381             my $class = lc($m->class);
382             my $instance = ($bInst || ($class eq 'message')) ? lc($m->instance) : '*';
383             $class =~ s/ /./g;
384             $instance =~ s/ /./g;
385             $currentColorMap{$fgbg}{$type}{$class}{$instance} = $color;
386         }
387     } elsif ($type eq 'aim' || $type eq 'jabber') {
388         my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
389         $sender =~ s/ /./g;
390         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
391         $currentColorMap{$fgbg}{$type}{$sender} = $color;
392     } elsif ($type eq 'irc') {
393         $currentColorMap{$fgbg}{$type}{$m->server}{$m->channel} = $color;
394     } elsif ($type eq 'loopback') {
395         $currentColorMap{$fgbg}{$type} = $color;
396     }
397
398     refreshView($fgbg);
399 }
400
401 sub getColor($$)
402 {
403     my $bInst = shift;
404     my $fgbg = (shift || 0) ? 'bg' : 'fg';
405     my $m = owl::getcurmsg();
406     return "" unless $m;
407
408     my $type = lc($m->type);
409     if ($type eq 'zephyr') {
410         if (isZPersonal($m)) {
411             my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
412             $sender =~ s/ /./g;
413             if (exists($currentColorMap{$fgbg}{'zephyr-personal'}{$sender})) {
414                 return $currentColorMap{$fgbg}{'zephyr-personal'}{$sender};
415             }
416         } else {
417             my $class = lc($m->class);
418             my $instance = ($bInst || ($class eq 'message')) ? lc($m->instance) : '*';
419             $class =~ s/ /./g;
420             $instance =~ s/ /./g;
421             if (exists($currentColorMap{$fgbg}{$type}{$class}{$instance})) {
422                 return $currentColorMap{$fgbg}{$type}{$class}{$instance};
423             }
424         }
425     } elsif ($type eq 'aim' || $type eq 'jabber') {
426         my $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
427         $sender =~ s/ /./g;
428         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
429         if (exists($currentColorMap{$fgbg}{$type}{$sender})) {
430             return $currentColorMap{$fgbg}{$type}{$sender};
431         }
432     } elsif ($type eq 'irc') {
433         if (exists($currentColorMap{$fgbg}{$type}{$m->server}{$m->channel})) {
434             return $currentColorMap{$fgbg}{$type}{$m->server}{$m->channel};
435         }
436     } elsif ($type eq 'loopback') {
437         if (exists($currentColorMap{$fgbg}{$type})) {
438             return $currentColorMap{$fgbg}{$type};
439         }
440     }
441 }
442
443 sub restore($$) {
444     my $bInst = shift;
445     my $fgbg = (shift || 0) ? 'bg' : 'fg';
446     my $m = owl::getcurmsg();
447     return unless $m;
448     my $type = lc($m->type);
449     my $oldColor;
450     my $sender;
451     if ($type eq 'zephyr') {
452         if (isZPersonal($m)) {
453             $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
454             $sender =~ s/ /./g;
455             if ($oldColor = ($savedColorMap{$fgbg}{'zephyr-personal'}{$sender}) || '') {
456                 $currentColorMap{$fgbg}{'zephyr-personal'}{$sender} = $oldColor;
457             } else {
458                 delete $currentColorMap{$fgbg}{'zephyr-personal'}{$sender};
459             }
460         } else {
461             my $class = lc($m->class);
462             my $instance = lc($m->instance);
463             $instance =
464               ($bInst
465                  || ($class eq 'message')
466                  || ((($savedColorMap{$fgbg}{$type}{$class}{'*'} || '') eq ($currentColorMap{$fgbg}{$type}{$class}{'*'} || ''))
467                      && (($savedColorMap{$fgbg}{$type}{$class}{$instance} || '') ne ($currentColorMap{$fgbg}{$type}{$class}{$instance} || ''))))
468                 ? $instance
469                   : '*';
470             $class =~ s/ /./g;
471             $instance =~ s/ /./g;
472             if ($oldColor = ($savedColorMap{$fgbg}{$type}{$class}{$instance} || '')) {
473                 $currentColorMap{$fgbg}{$type}{$class}{$instance} = $oldColor;
474             } else {
475                 delete $currentColorMap{$fgbg}{$type}{$class}{$instance};
476             }
477         }
478     } elsif ($type eq 'aim' || $type eq 'jabber') {
479         $sender = lc((lc($m->direction) eq 'in') ? $m->sender : $m->recipient);
480         $sender = $m->recipient if ($type eq 'jabber' && lc($m->jtype) eq 'groupchat');
481         $sender =~ s/ /./g;
482         if ($oldColor = ($savedColorMap{$fgbg}{$type}{$sender} || '')) {
483             $currentColorMap{$fgbg}{$type}{$sender} = $oldColor;
484         } else {
485             delete $currentColorMap{$fgbg}{$type}{$sender};
486         }
487     } elsif ($type eq 'loopback') {
488
489         if ($oldColor = ($savedColorMap{$fgbg}{$type} || '')) {
490             $currentColorMap{$fgbg}{$type} = $oldColor;
491         } else {
492             delete $currentColorMap{$fgbg}{$type};
493         }
494     }
495
496     refreshView($fgbg);
497 }
498
499 sub refreshView($) {
500     my $fgbg = shift;
501     return unless (grep(/^[fb]g$/, $fgbg));
502
503     createFilters($fgbg);
504     if ( *BarnOwl::refresh_view{CODE} ) {
505         BarnOwl::refresh_view();
506     } else {
507         my $filter = owl::command("getview");
508         my $style = owl::command("getstyle");
509         owl::command("view -f $filter ".($style?"-s $style":""));
510     }
511 }
512
513 ################################################################################
514 ## Saving/Loading functions
515 ################################################################################
516 sub save($) {
517     my $fgbg = shift;
518     return unless (grep(/^[fb]g$/, $fgbg));
519
520     if ($fgbg eq 'bg') {
521         open(COLORS, ">$config_dir/colormap_bg");
522     } else {
523         open(COLORS, ">$config_dir/colormap");
524     }
525
526     my $type = 'zephyr';
527     print COLORS "MODE: $type\n";
528     foreach my $c (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
529         foreach my $i (sort keys %{ $currentColorMap{$fgbg}{$type}{$c} }) {
530             if ($i eq '*'
531                 || !($currentColorMap{$fgbg}{$type}{$c}{$i} eq ($currentColorMap{$fgbg}{$type}{$c}{'*'} || '')
532                      || !$currentColorMap{$fgbg}{$type}{$c}{$i})) {
533                 print COLORS "$c,$i,"
534                   . ($currentColorMap{$fgbg}{$type}{$c}{$i}
535                        ? $currentColorMap{$fgbg}{$type}{$c}{$i}
536                        : 'default')
537                   . "\n";
538             }
539         }
540     }
541
542     $type = 'zephyr-personal';
543     print COLORS "MODE: $type\n";
544     foreach my $s (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
545         print COLORS "$s,"
546            . ($currentColorMap{$fgbg}{$type}{$s}
547                 ? $currentColorMap{$fgbg}{$type}{$s}
548                 : 'default')
549            . "\n";
550     }
551
552     $type = 'aim';
553     print COLORS "MODE: $type\n";
554     foreach my $s (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
555         print COLORS "$s,"
556           . ($currentColorMap{$fgbg}{$type}{$s}
557                ? $currentColorMap{$fgbg}{$type}{$s}
558                : 'default')
559           . "\n";
560     }
561
562     $type = 'jabber';
563     print COLORS "MODE: $type\n";
564     foreach my $s (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
565         print COLORS "$s,"
566           . ($currentColorMap{$fgbg}{$type}{$s}
567                ? $currentColorMap{$fgbg}{$type}{$s}
568                : 'default')
569           . "\n";
570     }
571
572     $type = 'irc';
573     print COLORS "MODE: $type\n";
574     foreach my $srv (sort keys %{ $currentColorMap{$fgbg}{$type} }) {
575         foreach my $chan (sort keys %{ $currentColorMap{$fgbg}{$type}{$srv} }) {
576             print COLORS "$srv,$chan,"
577               . ($currentColorMap{$fgbg}{$type}{$srv}{$chan}
578                    ? $currentColorMap{$fgbg}{$type}{$srv}{$chan}
579                    : 'default')
580               . "\n";
581         }
582     }
583
584
585     $type = 'loopback';
586     print COLORS "MODE: $type\n";
587     print COLORS ($currentColorMap{$fgbg}{$type}
588                     ? $currentColorMap{$fgbg}{$type}
589                     : 'default')
590       . "\n";
591
592     close(COLORS);
593 }
594
595 sub load($)
596 {
597     my $fgbg = shift;
598     return unless (grep(/^[fb]g$/, $fgbg));
599
600     $currentColorMap{$fgbg} = {};
601     $savedColorMap{$fgbg} = {};
602
603     # Parse the color file.
604     if ($fgbg eq 'bg') {
605         open(COLORS, "<$config_dir/colormap_bg") || return;
606     }
607     else {
608         open(COLORS, "<$config_dir/colormap") || return;
609     }
610
611
612     my $mode = "zephyr";
613
614     foreach my $line (<COLORS>) {
615         chomp($line);
616         if ($line =~ /^MODE: (.*)$/) {
617             if (lc($1) eq "zephyr") {
618                 $mode = 'zephyr';
619             } elsif (lc($1) eq "zephyr-personal") {
620                 $mode = 'zephyr-personal';
621             } elsif (lc($1) eq "aim") {
622                 $mode = 'aim';
623             } elsif (lc($1) eq "jabber") {
624                 $mode = 'jabber';
625             } elsif (lc($1) eq "irc") {
626                 $mode = 'irc';
627             } elsif (lc($1) eq "loopback") {
628                 $mode = 'loopback';
629             } else {
630                 $mode = 'zephyr';
631             }
632         } elsif ($mode eq 'zephyr' && $line =~ /^(.+),(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
633             $currentColorMap{$fgbg}{$mode}{lc($1)}{lc($2)} = lc($4);
634             $savedColorMap{$fgbg}{$mode}{lc($1)}{lc($2)}   = lc($4);
635         } elsif ($mode eq 'zephyr-personal' && $line =~ /^(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
636             $currentColorMap{$fgbg}{$mode}{lc($1)} = lc($3);
637             $savedColorMap{$fgbg}{$mode}{lc($1)}   = lc($3);
638         } elsif (($mode eq 'aim' || $mode eq 'jabber') && $line =~ /^(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
639             $currentColorMap{$fgbg}{$mode}{lc($1)} = lc($3);
640             $savedColorMap{$fgbg}{$mode}{lc($1)}   = lc($3);
641         } elsif (($mode eq 'irc') && $line =~ /^(.+),(.+),(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
642             $currentColorMap{$fgbg}{$mode}{lc($1)}{lc($2)} = lc($4);
643             $savedColorMap{$fgbg}{$mode}{lc($1)}{lc($2)}   = lc($4);
644         } elsif ($mode eq 'loopback' && $line =~ /^(b?)(black|red|green|yellow|blue|magenta|cyan|white|default|[0-9]{1,3})$/i) {
645             $currentColorMap{$fgbg}{$mode} = lc($2);
646             $savedColorMap{$fgbg}{$mode}   = lc($2);
647         }
648     }
649     close(COLORS);
650 }