mutt stable branch with some hacks
1/*
2 * Copyright (C) 1996-2002,2012 Michael R. Elkins <me@mutt.org>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19#if HAVE_CONFIG_H
20# include "config.h"
21#endif
22
23#include "mutt.h"
24#include "mutt_curses.h"
25#include "mutt_menu.h"
26#include "mapping.h"
27
28#include <string.h>
29#include <stdlib.h>
30#include <ctype.h>
31
32/* globals */
33int *ColorQuote;
34int ColorQuoteUsed;
35int ColorDefs[MT_COLOR_MAX];
36COLOR_LINE *ColorHdrList = NULL;
37COLOR_LINE *ColorBodyList = NULL;
38COLOR_LINE *ColorIndexList = NULL;
39
40/* local to this file */
41static int ColorQuoteSize;
42
43#ifdef HAVE_COLOR
44
45#define COLOR_DEFAULT (-2)
46
47typedef struct color_list
48{
49 short fg;
50 short bg;
51 short index;
52 short count;
53 struct color_list *next;
54} COLOR_LIST;
55
56static COLOR_LIST *ColorList = NULL;
57static int UserColors = 0;
58
59static const struct mapping_t Colors[] =
60{
61 { "black", COLOR_BLACK },
62 { "blue", COLOR_BLUE },
63 { "cyan", COLOR_CYAN },
64 { "green", COLOR_GREEN },
65 { "magenta", COLOR_MAGENTA },
66 { "red", COLOR_RED },
67 { "white", COLOR_WHITE },
68 { "yellow", COLOR_YELLOW },
69#if defined (USE_SLANG_CURSES) || defined (HAVE_USE_DEFAULT_COLORS)
70 { "default", COLOR_DEFAULT },
71#endif
72 { 0, 0 }
73};
74
75#endif /* HAVE_COLOR */
76
77static const struct mapping_t Fields[] =
78{
79 { "hdrdefault", MT_COLOR_HDEFAULT },
80 { "quoted", MT_COLOR_QUOTED },
81 { "signature", MT_COLOR_SIGNATURE },
82 { "indicator", MT_COLOR_INDICATOR },
83 { "status", MT_COLOR_STATUS },
84 { "tree", MT_COLOR_TREE },
85 { "error", MT_COLOR_ERROR },
86 { "normal", MT_COLOR_NORMAL },
87 { "tilde", MT_COLOR_TILDE },
88 { "markers", MT_COLOR_MARKERS },
89 { "header", MT_COLOR_HEADER },
90 { "body", MT_COLOR_BODY },
91 { "message", MT_COLOR_MESSAGE },
92 { "attachment", MT_COLOR_ATTACHMENT },
93 { "search", MT_COLOR_SEARCH },
94 { "bold", MT_COLOR_BOLD },
95 { "underline", MT_COLOR_UNDERLINE },
96 { "index", MT_COLOR_INDEX },
97 { "prompt", MT_COLOR_PROMPT },
98#ifdef USE_SIDEBAR
99 { "sidebar_divider", MT_COLOR_DIVIDER },
100 { "sidebar_flagged", MT_COLOR_FLAGGED },
101 { "sidebar_highlight",MT_COLOR_HIGHLIGHT },
102 { "sidebar_indicator",MT_COLOR_SB_INDICATOR },
103 { "sidebar_new", MT_COLOR_NEW },
104 { "sidebar_spoolfile",MT_COLOR_SB_SPOOLFILE },
105#endif
106 { NULL, 0 }
107};
108
109static const struct mapping_t ComposeFields[] =
110{
111 { "header", MT_COLOR_COMPOSE_HEADER },
112 { "security_encrypt", MT_COLOR_COMPOSE_SECURITY_ENCRYPT },
113 { "security_sign", MT_COLOR_COMPOSE_SECURITY_SIGN },
114 { "security_both", MT_COLOR_COMPOSE_SECURITY_BOTH },
115 { "security_none", MT_COLOR_COMPOSE_SECURITY_NONE },
116 { NULL, 0 }
117};
118
119#define COLOR_QUOTE_INIT 8
120
121static COLOR_LINE *mutt_new_color_line (void)
122{
123 COLOR_LINE *p = safe_calloc (1, sizeof (COLOR_LINE));
124
125 p->fg = p->bg = -1;
126
127 return (p);
128}
129
130static void mutt_free_color_line(COLOR_LINE **l,
131 int free_colors)
132{
133 COLOR_LINE *tmp;
134
135 if (!l || !*l)
136 return;
137
138 tmp = *l;
139
140#ifdef HAVE_COLOR
141 if (free_colors && tmp->fg != -1 && tmp->bg != -1)
142 mutt_free_color(tmp->fg, tmp->bg);
143#endif
144
145 /* we should really introduce a container
146 * type for regular expressions.
147 */
148
149 regfree(&tmp->rx);
150 mutt_pattern_free(&tmp->color_pattern);
151 FREE (&tmp->pattern);
152 FREE (l); /* __FREE_CHECKED__ */
153}
154
155void ci_start_color (void)
156{
157 memset (ColorDefs, A_NORMAL, sizeof (int) * MT_COLOR_MAX);
158 ColorQuote = (int *) safe_malloc (COLOR_QUOTE_INIT * sizeof (int));
159 memset (ColorQuote, A_NORMAL, sizeof (int) * COLOR_QUOTE_INIT);
160 ColorQuoteSize = COLOR_QUOTE_INIT;
161 ColorQuoteUsed = 0;
162
163 /* set some defaults */
164 ColorDefs[MT_COLOR_STATUS] = A_REVERSE;
165 ColorDefs[MT_COLOR_INDICATOR] = A_REVERSE;
166 ColorDefs[MT_COLOR_SEARCH] = A_REVERSE;
167 ColorDefs[MT_COLOR_MARKERS] = A_REVERSE;
168#ifdef USE_SIDEBAR
169 ColorDefs[MT_COLOR_HIGHLIGHT] = A_UNDERLINE;
170#endif
171 /* special meaning: toggle the relevant attribute */
172 ColorDefs[MT_COLOR_BOLD] = 0;
173 ColorDefs[MT_COLOR_UNDERLINE] = 0;
174
175#ifdef HAVE_COLOR
176 start_color ();
177#endif
178}
179
180#ifdef HAVE_COLOR
181
182#ifdef USE_SLANG_CURSES
183static char *get_color_name (char *dest, size_t destlen, int val)
184{
185 static const char * const missing[3] = {"brown", "lightgray", "default"};
186 int i;
187
188 switch (val)
189 {
190 case COLOR_YELLOW:
191 strfcpy (dest, missing[0], destlen);
192 return dest;
193
194 case COLOR_WHITE:
195 strfcpy (dest, missing[1], destlen);
196 return dest;
197
198 case COLOR_DEFAULT:
199 strfcpy (dest, missing[2], destlen);
200 return dest;
201 }
202
203 for (i = 0; Colors[i].name; i++)
204 {
205 if (Colors[i].value == val)
206 {
207 strfcpy (dest, Colors[i].name, destlen);
208 return dest;
209 }
210 }
211
212 /* Sigh. If we got this far, the color is of the form 'colorN'
213 * Slang can handle this itself, so just return 'colorN'
214 */
215
216 snprintf (dest, destlen, "color%d", val);
217 return dest;
218}
219#endif
220
221int mutt_alloc_color (int fg, int bg)
222{
223 COLOR_LIST *p = ColorList;
224 int i;
225
226#if defined (USE_SLANG_CURSES)
227 char fgc[SHORT_STRING], bgc[SHORT_STRING];
228#endif
229
230 /* check to see if this color is already allocated to save space */
231 while (p)
232 {
233 if (p->fg == fg && p->bg == bg)
234 {
235 (p->count)++;
236 return (COLOR_PAIR (p->index));
237 }
238 p = p->next;
239 }
240
241 /* check to see if there are colors left */
242 if (++UserColors > COLOR_PAIRS) return (A_NORMAL);
243
244 /* find the smallest available index (object) */
245 i = 1;
246 FOREVER
247 {
248 p = ColorList;
249 while (p)
250 {
251 if (p->index == i) break;
252 p = p->next;
253 }
254 if (p == NULL) break;
255 i++;
256 }
257
258 p = (COLOR_LIST *) safe_malloc (sizeof (COLOR_LIST));
259 p->next = ColorList;
260 ColorList = p;
261
262 p->index = i;
263 p->count = 1;
264 p->bg = bg;
265 p->fg = fg;
266
267#if defined (USE_SLANG_CURSES)
268 if (fg == COLOR_DEFAULT || bg == COLOR_DEFAULT)
269 SLtt_set_color (i, NULL, get_color_name (fgc, sizeof (fgc), fg), get_color_name (bgc, sizeof (bgc), bg));
270 else
271#elif defined (HAVE_USE_DEFAULT_COLORS)
272 if (fg == COLOR_DEFAULT)
273 fg = -1;
274 if (bg == COLOR_DEFAULT)
275 bg = -1;
276#endif
277
278 init_pair(i, fg, bg);
279
280 dprint (3, (debugfile,"mutt_alloc_color(): Color pairs used so far: %d\n",
281 UserColors));
282
283 return (COLOR_PAIR (p->index));
284}
285
286void mutt_free_color (int fg, int bg)
287{
288 COLOR_LIST *p, *q;
289
290 p = ColorList;
291 while (p)
292 {
293 if (p->fg == fg && p->bg == bg)
294 {
295 (p->count)--;
296 if (p->count > 0) return;
297
298 UserColors--;
299 dprint(1,(debugfile,"mutt_free_color(): Color pairs used so far: %d\n",
300 UserColors));
301
302 if (p == ColorList)
303 {
304 ColorList = ColorList->next;
305 FREE (&p);
306 return;
307 }
308 q = ColorList;
309 while (q)
310 {
311 if (q->next == p)
312 {
313 q->next = p->next;
314 FREE (&p);
315 return;
316 }
317 q = q->next;
318 }
319 /* can't get here */
320 }
321 p = p->next;
322 }
323}
324
325#endif /* HAVE_COLOR */
326
327
328#ifdef HAVE_COLOR
329
330static int
331parse_color_name (const char *s, int *col, int *attr, int is_fg, BUFFER *err)
332{
333 char *eptr;
334 int is_bright = 0, is_light = 0;
335
336 if (ascii_strncasecmp (s, "bright", 6) == 0)
337 {
338 is_bright = 1;
339 s += 6;
340 }
341 else if (ascii_strncasecmp (s, "light", 5) == 0)
342 {
343 is_light = 1;
344 s += 5;
345 }
346
347 /* allow aliases for xterm color resources */
348 if (ascii_strncasecmp (s, "color", 5) == 0)
349 {
350 s += 5;
351 *col = strtol (s, &eptr, 10);
352 if (!*s || *eptr || *col < 0 ||
353 (*col >= COLORS && !option(OPTNOCURSES) && has_colors()))
354 {
355 snprintf (err->data, err->dsize, _("%s: color not supported by term"), s);
356 return (-1);
357 }
358 }
359 else if ((*col = mutt_getvaluebyname (s, Colors)) == -1)
360 {
361 snprintf (err->data, err->dsize, _("%s: no such color"), s);
362 return (-1);
363 }
364
365 if (is_bright || is_light)
366 {
367 if (is_fg)
368 {
369 if ((COLORS >= 16) && is_light)
370 {
371 if (*col >= 0 && *col <= 7)
372 {
373 /* Advance the color 0-7 by 8 to get the light version */
374 *col += 8;
375 }
376 }
377 else
378 {
379 *attr |= A_BOLD;
380 }
381 }
382 else
383 {
384 if (COLORS >= 16)
385 {
386 if (*col >= 0 && *col <= 7)
387 {
388 /* Advance the color 0-7 by 8 to get the light version */
389 *col += 8;
390 }
391 }
392 }
393 }
394
395 return 0;
396}
397
398#endif
399
400
401/* usage: uncolor index pattern [pattern...]
402 * unmono index pattern [pattern...]
403 */
404
405static int
406_mutt_parse_uncolor (BUFFER *buf, BUFFER *s, BUFFER *err, short parse_uncolor);
407
408
409#ifdef HAVE_COLOR
410
411int mutt_parse_uncolor (BUFFER *buf, BUFFER *s, union pointer_long_t udata,
412 BUFFER *err)
413{
414 return _mutt_parse_uncolor(buf, s, err, 1);
415}
416
417#endif
418
419int mutt_parse_unmono (BUFFER *buf, BUFFER *s, union pointer_long_t udata,
420 BUFFER *err)
421{
422 return _mutt_parse_uncolor(buf, s, err, 0);
423}
424
425static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, BUFFER *err, short parse_uncolor)
426{
427 int object = 0, is_index = 0, do_cache = 0;
428 COLOR_LINE *tmp, *last = NULL;
429 COLOR_LINE **list;
430
431 mutt_extract_token (buf, s, 0);
432
433 if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1)
434 {
435 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
436 return (-1);
437 }
438
439 if (mutt_strncmp (buf->data, "index", 5) == 0)
440 {
441 is_index = 1;
442 list = &ColorIndexList;
443 }
444 else if (mutt_strncmp (buf->data, "body", 4) == 0)
445 list = &ColorBodyList;
446 else if (mutt_strncmp (buf->data, "header", 6) == 0)
447 list = &ColorHdrList;
448 else
449 {
450 snprintf (err->data, err->dsize,
451 _("%s: command valid only for index, body, header objects"),
452 parse_uncolor ? "uncolor" : "unmono");
453 return (-1);
454 }
455
456 if (!MoreArgs (s))
457 {
458 snprintf (err->data, err->dsize,
459 _("%s: too few arguments"), parse_uncolor ? "uncolor" : "unmono");
460 return (-1);
461 }
462
463 if (
464#ifdef HAVE_COLOR
465 /* we're running without curses */
466 option (OPTNOCURSES)
467 || /* we're parsing an uncolor command, and have no colors */
468 (parse_uncolor && !has_colors())
469 /* we're parsing an unmono command, and have colors */
470 || (!parse_uncolor && has_colors())
471#else
472 /* We don't even have colors compiled in */
473 parse_uncolor
474#endif
475 )
476 {
477 /* just eat the command, but don't do anything real about it */
478 do
479 mutt_extract_token (buf, s, 0);
480 while (MoreArgs (s));
481
482 return 0;
483 }
484
485 do
486 {
487 mutt_extract_token (buf, s, 0);
488 if (!mutt_strcmp ("*", buf->data))
489 {
490 for (tmp = *list; tmp; )
491 {
492 if (!do_cache)
493 do_cache = 1;
494 last = tmp;
495 tmp = tmp->next;
496 mutt_free_color_line(&last, parse_uncolor);
497 }
498 *list = NULL;
499 }
500 else
501 {
502 for (last = NULL, tmp = *list; tmp; last = tmp, tmp = tmp->next)
503 {
504 if (!mutt_strcmp (buf->data, tmp->pattern))
505 {
506 if (!do_cache)
507 do_cache = 1;
508 dprint(1,(debugfile,"Freeing pattern \"%s\" from color list\n",
509 tmp->pattern));
510 if (last)
511 last->next = tmp->next;
512 else
513 *list = tmp->next;
514 mutt_free_color_line(&tmp, parse_uncolor);
515 break;
516 }
517 }
518 }
519 }
520 while (MoreArgs (s));
521
522
523 if (is_index && do_cache && !option (OPTNOCURSES))
524 {
525 int i;
526 mutt_set_menu_redraw_full (MENU_MAIN);
527 /* force re-caching of index colors */
528 for (i = 0; Context && i < Context->msgcount; i++)
529 Context->hdrs[i]->pair = 0;
530 }
531 return (0);
532}
533
534
535static int
536add_pattern (COLOR_LINE **top, const char *s, int sensitive,
537 int fg, int bg, int attr, BUFFER *err,
538 int is_index)
539{
540
541 /* is_index used to store compiled pattern
542 * only for `index' color object
543 * when called from mutt_parse_color() */
544
545 COLOR_LINE *tmp = *top;
546
547 while (tmp)
548 {
549 if (sensitive)
550 {
551 if (mutt_strcmp (s, tmp->pattern) == 0)
552 break;
553 }
554 else
555 {
556 if (mutt_strcasecmp (s, tmp->pattern) == 0)
557 break;
558 }
559 tmp = tmp->next;
560 }
561
562 if (tmp)
563 {
564#ifdef HAVE_COLOR
565 if (fg != -1 && bg != -1)
566 {
567 if (tmp->fg != fg || tmp->bg != bg)
568 {
569 mutt_free_color (tmp->fg, tmp->bg);
570 tmp->fg = fg;
571 tmp->bg = bg;
572 attr |= mutt_alloc_color (fg, bg);
573 }
574 else
575 attr |= (tmp->pair & ~A_BOLD);
576 }
577#endif /* HAVE_COLOR */
578 tmp->pair = attr;
579 }
580 else
581 {
582 int r;
583 BUFFER *buf = NULL;
584
585 tmp = mutt_new_color_line ();
586 if (is_index)
587 {
588 buf = mutt_buffer_pool_get ();
589 mutt_buffer_strcpy(buf, NONULL(s));
590 mutt_check_simple (buf, NONULL(SimpleSearch));
591 tmp->color_pattern = mutt_pattern_comp (buf->data, MUTT_FULL_MSG, err);
592 mutt_buffer_pool_release (&buf);
593 if (tmp->color_pattern == NULL)
594 {
595 mutt_free_color_line(&tmp, 1);
596 return -1;
597 }
598 }
599 else if ((r = REGCOMP (&tmp->rx, s, (sensitive ? mutt_which_case (s) : REG_ICASE))) != 0)
600 {
601 regerror (r, &tmp->rx, err->data, err->dsize);
602 mutt_free_color_line(&tmp, 1);
603 return (-1);
604 }
605 tmp->next = *top;
606 tmp->pattern = safe_strdup (s);
607#ifdef HAVE_COLOR
608 if (fg != -1 && bg != -1)
609 {
610 tmp->fg = fg;
611 tmp->bg = bg;
612 attr |= mutt_alloc_color (fg, bg);
613 }
614#endif
615 tmp->pair = attr;
616 *top = tmp;
617 }
618
619 /* force re-caching of index colors */
620 if (is_index)
621 {
622 int i;
623
624 for (i = 0; Context && i < Context->msgcount; i++)
625 Context->hdrs[i]->pair = 0;
626 }
627
628 return 0;
629}
630
631static int
632parse_object(BUFFER *buf, BUFFER *s, int *o, int *ql, BUFFER *err)
633{
634 int q_level = 0;
635 char *eptr;
636
637 if (!MoreArgs(s))
638 {
639 strfcpy(err->data, _("Missing arguments."), err->dsize);
640 return -1;
641 }
642
643 mutt_extract_token(buf, s, 0);
644 if (!mutt_strncmp(buf->data, "quoted", 6))
645 {
646 if (buf->data[6])
647 {
648 *ql = strtol(buf->data + 6, &eptr, 10);
649 if (*eptr || q_level < 0)
650 {
651 snprintf(err->data, err->dsize, _("%s: no such object"), buf->data);
652 return -1;
653 }
654 }
655 else
656 *ql = 0;
657
658 *o = MT_COLOR_QUOTED;
659 }
660 else if (!ascii_strcasecmp(buf->data, "compose"))
661 {
662 if (!MoreArgs(s))
663 {
664 strfcpy(err->data, _("Missing arguments."), err->dsize);
665 return -1;
666 }
667
668 mutt_extract_token(buf, s, 0);
669
670 if ((*o = mutt_getvaluebyname (buf->data, ComposeFields)) == -1)
671 {
672 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
673 return (-1);
674 }
675 }
676 else if ((*o = mutt_getvaluebyname (buf->data, Fields)) == -1)
677 {
678 snprintf (err->data, err->dsize, _("%s: no such object"), buf->data);
679 return (-1);
680 }
681
682 return 0;
683}
684
685typedef int (*parser_callback_t)(BUFFER *, BUFFER *, int *, int *, int *, BUFFER *);
686
687#ifdef HAVE_COLOR
688
689static int
690parse_color_pair(BUFFER *buf, BUFFER *s, int *fg, int *bg, int *attr, BUFFER *err)
691{
692 FOREVER
693 {
694 if (! MoreArgs (s))
695 {
696 strfcpy (err->data, _("color: too few arguments"), err->dsize);
697 return (-1);
698 }
699
700 mutt_extract_token (buf, s, 0);
701
702 if (ascii_strcasecmp ("bold", buf->data) == 0)
703 *attr |= A_BOLD;
704 else if (ascii_strcasecmp ("underline", buf->data) == 0)
705 *attr |= A_UNDERLINE;
706 else if (ascii_strcasecmp ("none", buf->data) == 0)
707 *attr = A_NORMAL;
708 else if (ascii_strcasecmp ("reverse", buf->data) == 0)
709 *attr |= A_REVERSE;
710 else if (ascii_strcasecmp ("standout", buf->data) == 0)
711 *attr |= A_STANDOUT;
712 else if (ascii_strcasecmp ("normal", buf->data) == 0)
713 *attr = A_NORMAL; /* needs use = instead of |= to clear other bits */
714 else
715 {
716 if (parse_color_name (buf->data, fg, attr, 1, err) != 0)
717 return (-1);
718 break;
719 }
720 }
721
722 if (! MoreArgs (s))
723 {
724 strfcpy (err->data, _("color: too few arguments"), err->dsize);
725 return (-1);
726 }
727
728 mutt_extract_token (buf, s, 0);
729
730 if (parse_color_name (buf->data, bg, attr, 0, err) != 0)
731 return (-1);
732
733 return 0;
734}
735
736#endif
737
738static int
739parse_attr_spec(BUFFER *buf, BUFFER *s, int *fg, int *bg, int *attr, BUFFER *err)
740{
741
742 if (fg) *fg = -1;
743 if (bg) *bg = -1;
744
745 if (! MoreArgs (s))
746 {
747 strfcpy (err->data, _("mono: too few arguments"), err->dsize);
748 return (-1);
749 }
750
751 mutt_extract_token (buf, s, 0);
752
753 if (ascii_strcasecmp ("bold", buf->data) == 0)
754 *attr |= A_BOLD;
755 else if (ascii_strcasecmp ("underline", buf->data) == 0)
756 *attr |= A_UNDERLINE;
757 else if (ascii_strcasecmp ("none", buf->data) == 0)
758 *attr = A_NORMAL;
759 else if (ascii_strcasecmp ("reverse", buf->data) == 0)
760 *attr |= A_REVERSE;
761 else if (ascii_strcasecmp ("standout", buf->data) == 0)
762 *attr |= A_STANDOUT;
763 else if (ascii_strcasecmp ("normal", buf->data) == 0)
764 *attr = A_NORMAL; /* needs use = instead of |= to clear other bits */
765 else
766 {
767 snprintf (err->data, err->dsize, _("%s: no such attribute"), buf->data);
768 return (-1);
769 }
770
771 return 0;
772}
773
774static int fgbgattr_to_color(int fg, int bg, int attr)
775{
776#ifdef HAVE_COLOR
777 if (fg != -1 && bg != -1)
778 return attr | mutt_alloc_color(fg, bg);
779 else
780#endif
781 return attr;
782}
783
784/* usage: color <object> <fg> <bg> [ <regexp> ]
785 * mono <object> <attr> [ <regexp> ]
786 */
787
788static int
789_mutt_parse_color (BUFFER *buf, BUFFER *s, BUFFER *err,
790 parser_callback_t callback, short dry_run)
791{
792 int object = 0, attr = 0, fg = 0, bg = 0, q_level = 0;
793 int r = 0;
794
795 if (parse_object(buf, s, &object, &q_level, err) == -1)
796 return -1;
797
798 if (callback(buf, s, &fg, &bg, &attr, err) == -1)
799 return -1;
800
801 /* extract a regular expression if needed */
802
803 if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX)
804 {
805 if (!MoreArgs (s))
806 {
807 strfcpy (err->data, _("too few arguments"), err->dsize);
808 return (-1);
809 }
810
811 mutt_extract_token (buf, s, 0);
812 }
813
814 if (MoreArgs (s))
815 {
816 strfcpy (err->data, _("too many arguments"), err->dsize);
817 return (-1);
818 }
819
820 /* dry run? */
821
822 if (dry_run) return 0;
823
824
825#ifdef HAVE_COLOR
826# ifdef HAVE_USE_DEFAULT_COLORS
827 if (!option (OPTNOCURSES) && has_colors()
828 /* delay use_default_colors() until needed, since it initializes things */
829 && (fg == COLOR_DEFAULT || bg == COLOR_DEFAULT)
830 && use_default_colors () != OK)
831 {
832 strfcpy (err->data, _("default colors not supported"), err->dsize);
833 return (-1);
834 }
835# endif /* HAVE_USE_DEFAULT_COLORS */
836#endif
837
838 if (object == MT_COLOR_HEADER)
839 r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err,0);
840 else if (object == MT_COLOR_BODY)
841 r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0);
842 else if (object == MT_COLOR_INDEX)
843 {
844 r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1);
845 mutt_set_menu_redraw_full (MENU_MAIN);
846 }
847 else if (object == MT_COLOR_QUOTED)
848 {
849 if (q_level >= ColorQuoteSize)
850 {
851 safe_realloc (&ColorQuote, (ColorQuoteSize += 2) * sizeof (int));
852 ColorQuote[ColorQuoteSize-2] = ColorDefs[MT_COLOR_QUOTED];
853 ColorQuote[ColorQuoteSize-1] = ColorDefs[MT_COLOR_QUOTED];
854 }
855 if (q_level >= ColorQuoteUsed)
856 ColorQuoteUsed = q_level + 1;
857 if (q_level == 0)
858 {
859 ColorDefs[MT_COLOR_QUOTED] = fgbgattr_to_color(fg, bg, attr);
860
861 ColorQuote[0] = ColorDefs[MT_COLOR_QUOTED];
862 for (q_level = 1; q_level < ColorQuoteUsed; q_level++)
863 {
864 if (ColorQuote[q_level] == A_NORMAL)
865 ColorQuote[q_level] = ColorDefs[MT_COLOR_QUOTED];
866 }
867 }
868 else
869 ColorQuote[q_level] = fgbgattr_to_color(fg, bg, attr);
870 }
871 else
872 ColorDefs[object] = fgbgattr_to_color(fg, bg, attr);
873
874 return (r);
875}
876
877#ifdef HAVE_COLOR
878
879int mutt_parse_color(BUFFER *buff, BUFFER *s, union pointer_long_t udata, BUFFER *err)
880{
881 int dry_run = 0;
882
883 if (option(OPTNOCURSES) || !has_colors())
884 dry_run = 1;
885
886 return _mutt_parse_color(buff, s, err, parse_color_pair, dry_run);
887}
888
889#endif
890
891int mutt_parse_mono(BUFFER *buff, BUFFER *s, union pointer_long_t udata, BUFFER *err)
892{
893 int dry_run = 0;
894
895#ifdef HAVE_COLOR
896 if (option(OPTNOCURSES) || has_colors())
897 dry_run = 1;
898#else
899 if (option(OPTNOCURSES))
900 dry_run = 1;
901#endif
902
903 return _mutt_parse_color(buff, s, err, parse_attr_spec, dry_run);
904}