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