mutt stable branch with some hacks
at jcs 904 lines 20 kB view raw
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}