static int parse_color_pair(BUFFER *buf, BUFFER *s, int *fg, int *bg, int *attr, BUFFER *err) { if (! MoreArgs (s)) { strfcpy (err->data, _("color: too few arguments"), err->dsize); return (-1); } mutt_extract_token (buf, s, 0); if (parse_color_name (buf->data, fg, attr, A_BOLD, err) != 0) return (-1); if (! MoreArgs (s)) { strfcpy (err->data, _("color: too few arguments"), err->dsize); return (-1); } mutt_extract_token (buf, s, 0); if (parse_color_name (buf->data, bg, attr, A_BLINK, err) != 0) return (-1); return 0; }
int mutt_parse_score (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { SCORE *ptr, *last; char *pattern, *pc; struct pattern_t *pat; mutt_extract_token (buf, s, 0); if (!MoreArgs (s)) { strfcpy (err->data, _("score: too few arguments"), err->dsize); return (-1); } pattern = buf->data; memset (buf, 0, sizeof (BUFFER)); mutt_extract_token (buf, s, 0); if (MoreArgs (s)) { FREE (&pattern); strfcpy (err->data, _("score: too many arguments"), err->dsize); return (-1); } /* look for an existing entry and update the value, else add it to the end of the list */ for (ptr = Score, last = NULL; ptr; last = ptr, ptr = ptr->next) if (mutt_strcmp (pattern, ptr->str) == 0) break; if (!ptr) { if ((pat = mutt_pattern_comp (pattern, 0, err)) == NULL) { FREE (&pattern); return (-1); } ptr = safe_calloc (1, sizeof (SCORE)); if (last) last->next = ptr; else Score = ptr; ptr->pat = pat; ptr->str = pattern; } else /* 'buf' arg was cleared and 'pattern' holds the only reference; * as here 'ptr' != NULL -> update the value only in which case * ptr->str already has the string, so pattern should be freed. */ FREE (&pattern); pc = buf->data; if (*pc == '=') { ptr->exact = 1; pc++; } ptr->val = atoi (pc); set_option (OPTNEEDRESCORE); return 0; }
static int parse_attr_spec(BUFFER *buf, BUFFER *s, int *fg, int *bg, int *attr, BUFFER *err) { if(fg) *fg = -1; if(bg) *bg = -1; if (! MoreArgs (s)) { strfcpy (err->data, _("mono: too few arguments"), err->dsize); return (-1); } mutt_extract_token (buf, s, 0); if (ascii_strcasecmp ("bold", buf->data) == 0) *attr |= A_BOLD; else if (ascii_strcasecmp ("underline", buf->data) == 0) *attr |= A_UNDERLINE; else if (ascii_strcasecmp ("none", buf->data) == 0) *attr = A_NORMAL; else if (ascii_strcasecmp ("reverse", buf->data) == 0) *attr |= A_REVERSE; else if (ascii_strcasecmp ("standout", buf->data) == 0) *attr |= A_STANDOUT; else if (ascii_strcasecmp ("normal", buf->data) == 0) *attr = A_NORMAL; /* needs use = instead of |= to clear other bits */ else { snprintf (err->data, err->dsize, _("%s: no such attribute"), buf->data); return (-1); } return 0; }
static int parse_unlist (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { do { mutt_extract_token (buf, s, 0); remove_from_list ((LIST **) data, buf->data); } while (MoreArgs (s)); return 0; }
static int parse_ignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { do { mutt_extract_token (buf, s, 0); remove_from_list (&UnIgnore, buf->data); add_to_list (&Ignore, buf->data); } while (MoreArgs (s)); return 0; }
static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { do { mutt_extract_token (buf, s, 0); /* don't add "*" to the unignore list */ if (strcmp (buf->data, "*")) add_to_list (&UnIgnore, buf->data); remove_from_list (&Ignore, buf->data); } while (MoreArgs (s)); return 0; }
static int parse_unalias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { ALIAS *tmp, *last = NULL; do { mutt_extract_token (buf, s, 0); tmp = Aliases; for (tmp = Aliases; tmp; tmp = tmp->next) { if (CurrentMenu == MENU_ALIAS) { for (tmp = Aliases; tmp ; tmp = tmp->next) tmp->del = 1; set_option (OPTFORCEREDRAWINDEX); } else mutt_free_alias (&Aliases); break; } else for (tmp = Aliases; tmp; tmp = tmp->next) { if (mutt_strcasecmp (buf->data, tmp->name) == 0) { if (CurrentMenu == MENU_ALIAS) { tmp->del = 1; set_option (OPTFORCEREDRAWINDEX); break; } if (last) last->next = tmp->next; else Aliases = tmp->next; tmp->next = NULL; mutt_free_alias (&tmp); break; } last = tmp; } }
int mutt_parse_unscore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { SCORE *tmp, *last = NULL; while (MoreArgs (s)) { mutt_extract_token (buf, s, 0); if (!mutt_strcmp ("*", buf->data)) { for (tmp = Score; tmp; ) { last = tmp; tmp = tmp->next; mutt_pattern_free (&last->pat); safe_free ((void **) &last); } Score = NULL; } else { for (tmp = Score; tmp; last = tmp, tmp = tmp->next) { if (!mutt_strcmp (buf->data, tmp->str)) { if (last) last->next = tmp->next; else Score = tmp->next; mutt_pattern_free (&tmp->pat); safe_free ((void **) &tmp); /* there should only be one score per pattern, so we can stop here */ break; } } } } set_option (OPTNEEDRESCORE); return 0; }
/** * mutt_parse_icommand - Parse an informational command * @param line Command to execute * @param err Buffer for error messages * @retval #MUTT_CMD_SUCCESS Success * @retval #MUTT_CMD_ERROR Error (no message): command not found * @retval #MUTT_CMD_ERROR Error with message: command failed * @retval #MUTT_CMD_WARNING Warning with message: command failed */ enum CommandResult mutt_parse_icommand(/* const */ char *line, struct Buffer *err) { if (!line || !*line || !err) return MUTT_CMD_ERROR; enum CommandResult rc = MUTT_CMD_ERROR; struct Buffer expn, token; mutt_buffer_init(&expn); mutt_buffer_init(&token); expn.data = expn.dptr = line; expn.dsize = mutt_str_strlen(line); mutt_buffer_reset(err); SKIPWS(expn.dptr); while (*expn.dptr) { mutt_extract_token(&token, &expn, 0); for (size_t i = 0; ICommandList[i].name; i++) { if (mutt_str_strcmp(token.data, ICommandList[i].name) != 0) continue; rc = ICommandList[i].func(&token, &expn, ICommandList[i].data, err); if (rc != 0) goto finish; break; /* Continue with next command */ } } finish: if (expn.destroy) FREE(&expn.data); return rc; }
int mutt_parse_unhook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { while (MoreArgs (s)) { mutt_extract_token (buf, s, 0); if (mutt_strcmp ("*", buf->data) == 0) { if (current_hook_type) { snprintf (err->data, err->dsize, _("unhook: Can't do unhook * from within a hook.")); return -1; } delete_hooks (0); } else { int type = mutt_get_hook_type (buf->data); if (!type) { snprintf (err->data, err->dsize, _("unhook: unknown hook type: %s"), buf->data); return (-1); } if (current_hook_type == type) { snprintf (err->data, err->dsize, _("unhook: Can't delete a %s from within a %s."), buf->data, buf->data); return -1; } delete_hooks (type); } } return 0; }
static int parse_object(BUFFER *buf, BUFFER *s, int *o, int *ql, BUFFER *err) { int q_level = 0; char *eptr; if(!MoreArgs(s)) { strfcpy(err->data, _("Missing arguments."), err->dsize); return -1; } mutt_extract_token(buf, s, 0); if(!mutt_strncmp(buf->data, "quoted", 6)) { if(buf->data[6]) { *ql = strtol(buf->data + 6, &eptr, 10); if(*eptr || q_level < 0) { snprintf(err->data, err->dsize, _("%s: no such object"), buf->data); return -1; } } else *ql = 0; *o = MT_COLOR_QUOTED; } else if ((*o = mutt_getvaluebyname (buf->data, Fields)) == -1) { snprintf (err->data, err->dsize, _("%s: no such object"), buf->data); return (-1); } return 0; }
int mutt_parse_hook (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err) { HOOK *ptr; BUFFER command, pattern; int rc, not = 0; regex_t *rx = NULL; pattern_t *pat = NULL; char path[_POSIX_PATH_MAX]; mutt_buffer_init (&pattern); mutt_buffer_init (&command); if (*s->dptr == '!') { s->dptr++; SKIPWS (s->dptr); not = 1; } mutt_extract_token (&pattern, s, 0); if (!MoreArgs (s)) { strfcpy (err->data, _("too few arguments"), err->dsize); goto error; } mutt_extract_token (&command, s, (data & (M_FOLDERHOOK | M_SENDHOOK | M_SEND2HOOK | M_ACCOUNTHOOK | M_REPLYHOOK)) ? M_TOKEN_SPACE : 0); if (!command.data) { strfcpy (err->data, _("too few arguments"), err->dsize); goto error; } if (MoreArgs (s)) { strfcpy (err->data, _("too many arguments"), err->dsize); goto error; } if (data & (M_FOLDERHOOK | M_MBOXHOOK)) { strfcpy (path, pattern.data, sizeof (path)); _mutt_expand_path (path, sizeof (path), 1); FREE (&pattern.data); memset (&pattern, 0, sizeof (pattern)); pattern.data = safe_strdup (path); } else if (DefaultHook && !(data & (M_CHARSETHOOK | M_ICONVHOOK | M_ACCOUNTHOOK)) && (!WithCrypto || !(data & M_CRYPTHOOK)) ) { char tmp[HUGE_STRING]; /* At this stage remain only message-hooks, reply-hooks, send-hooks, * send2-hooks, save-hooks, and fcc-hooks: All those allowing full * patterns. If given a simple regexp, we expand $default_hook. */ strfcpy (tmp, pattern.data, sizeof (tmp)); mutt_check_simple (tmp, sizeof (tmp), DefaultHook); FREE (&pattern.data); memset (&pattern, 0, sizeof (pattern)); pattern.data = safe_strdup (tmp); } if (data & (M_MBOXHOOK | M_SAVEHOOK | M_FCCHOOK)) { strfcpy (path, command.data, sizeof (path)); mutt_expand_path (path, sizeof (path)); FREE (&command.data); memset (&command, 0, sizeof (command)); command.data = safe_strdup (path); } /* check to make sure that a matching hook doesn't already exist */ for (ptr = Hooks; ptr; ptr = ptr->next) { if (ptr->type == data && ptr->rx.not == not && !mutt_strcmp (pattern.data, ptr->rx.pattern)) { if (data & (M_FOLDERHOOK | M_SENDHOOK | M_SEND2HOOK | M_MESSAGEHOOK | M_ACCOUNTHOOK | M_REPLYHOOK)) { /* these hooks allow multiple commands with the same * pattern, so if we've already seen this pattern/command pair, just * ignore it instead of creating a duplicate */ if (!mutt_strcmp (ptr->command, command.data)) { FREE (&command.data); FREE (&pattern.data); return 0; } } else { /* other hooks only allow one command per pattern, so update the * entry with the new command. this currently does not change the * order of execution of the hooks, which i think is desirable since * a common action to perform is to change the default (.) entry * based upon some other information. */ FREE (&ptr->command); ptr->command = command.data; FREE (&pattern.data); return 0; } } if (!ptr->next) break; } if (data & (M_SENDHOOK | M_SEND2HOOK | M_SAVEHOOK | M_FCCHOOK | M_MESSAGEHOOK | M_REPLYHOOK)) { if ((pat = mutt_pattern_comp (pattern.data, (data & (M_SENDHOOK | M_SEND2HOOK | M_FCCHOOK)) ? 0 : M_FULL_MSG, err)) == NULL) goto error; } else { /* Hooks not allowing full patterns: Check syntax of regexp */ rx = safe_malloc (sizeof (regex_t)); #ifdef M_CRYPTHOOK if ((rc = REGCOMP (rx, NONULL(pattern.data), ((data & (M_CRYPTHOOK|M_CHARSETHOOK|M_ICONVHOOK)) ? REG_ICASE : 0))) != 0) #else if ((rc = REGCOMP (rx, NONULL(pattern.data), (data & (M_CHARSETHOOK|M_ICONVHOOK)) ? REG_ICASE : 0)) != 0) #endif /* M_CRYPTHOOK */ { regerror (rc, rx, err->data, err->dsize); FREE (&rx); goto error; } } if (ptr) { ptr->next = safe_calloc (1, sizeof (HOOK)); ptr = ptr->next; } else Hooks = ptr = safe_calloc (1, sizeof (HOOK)); ptr->type = data; ptr->command = command.data; ptr->pattern = pat; ptr->rx.pattern = pattern.data; ptr->rx.rx = rx; ptr->rx.not = not; return 0; error: FREE (&pattern.data); FREE (&command.data); return (-1); }
static int _mutt_parse_color (BUFFER *buf, BUFFER *s, BUFFER *err, parser_callback_t callback, short dry_run) { int object = 0, attr = 0, fg = 0, bg = 0, q_level = 0; int r = 0; if(parse_object(buf, s, &object, &q_level, err) == -1) return -1; if(callback(buf, s, &fg, &bg, &attr, err) == -1) return -1; /* extract a regular expression if needed */ if (object == MT_COLOR_HEADER || object == MT_COLOR_BODY || object == MT_COLOR_INDEX) { if (!MoreArgs (s)) { strfcpy (err->data, _("too few arguments"), err->dsize); return (-1); } mutt_extract_token (buf, s, 0); } if (MoreArgs (s)) { strfcpy (err->data, _("too many arguments"), err->dsize); return (-1); } /* dry run? */ if(dry_run) return 0; #ifdef HAVE_COLOR # ifdef HAVE_USE_DEFAULT_COLORS if (!option (OPTNOCURSES) && has_colors() /* delay use_default_colors() until needed, since it initializes things */ && (fg == COLOR_DEFAULT || bg == COLOR_DEFAULT) && use_default_colors () != OK) { strfcpy (err->data, _("default colors not supported"), err->dsize); return (-1); } # endif /* HAVE_USE_DEFAULT_COLORS */ #endif if (object == MT_COLOR_HEADER) r = add_pattern (&ColorHdrList, buf->data, 0, fg, bg, attr, err,0); else if (object == MT_COLOR_BODY) r = add_pattern (&ColorBodyList, buf->data, 1, fg, bg, attr, err, 0); else if (object == MT_COLOR_INDEX) { r = add_pattern (&ColorIndexList, buf->data, 1, fg, bg, attr, err, 1); set_option (OPTFORCEREDRAWINDEX); } else if (object == MT_COLOR_QUOTED) { if (q_level >= ColorQuoteSize) { safe_realloc (&ColorQuote, (ColorQuoteSize += 2) * sizeof (int)); ColorQuote[ColorQuoteSize-2] = ColorDefs[MT_COLOR_QUOTED]; ColorQuote[ColorQuoteSize-1] = ColorDefs[MT_COLOR_QUOTED]; } if (q_level >= ColorQuoteUsed) ColorQuoteUsed = q_level + 1; if (q_level == 0) { ColorDefs[MT_COLOR_QUOTED] = fgbgattr_to_color(fg, bg, attr); ColorQuote[0] = ColorDefs[MT_COLOR_QUOTED]; for (q_level = 1; q_level < ColorQuoteUsed; q_level++) { if (ColorQuote[q_level] == A_NORMAL) ColorQuote[q_level] = ColorDefs[MT_COLOR_QUOTED]; } } else ColorQuote[q_level] = fgbgattr_to_color(fg, bg, attr); } else ColorDefs[object] = fgbgattr_to_color(fg, bg, attr); #ifdef HAVE_COLOR # ifdef HAVE_BKGDSET if (object == MT_COLOR_NORMAL && !option (OPTNOCURSES) && has_colors()) BKGDSET (MT_COLOR_NORMAL); # endif #endif return (r); }
static int _mutt_parse_uncolor (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err, short parse_uncolor) { int object = 0, do_cache = 0; COLOR_LINE *tmp, *last = NULL; COLOR_LINE **list; mutt_extract_token (buf, s, 0); if ((object = mutt_getvaluebyname (buf->data, Fields)) == -1) { snprintf (err->data, err->dsize, _("%s: no such object"), buf->data); return (-1); } if (mutt_strncmp (buf->data, "index", 5) == 0) list = &ColorIndexList; else if (mutt_strncmp (buf->data, "body", 4) == 0) list = &ColorBodyList; else if (mutt_strncmp (buf->data, "header", 7) == 0) list = &ColorHdrList; else { snprintf (err->data, err->dsize, _("%s: command valid only for index, body, header objects"), parse_uncolor ? "uncolor" : "unmono"); return (-1); } if (!MoreArgs (s)) { snprintf (err->data, err->dsize, _("%s: too few arguments"), parse_uncolor ? "uncolor" : "unmono"); return (-1); } if( #ifdef HAVE_COLOR /* we're running without curses */ option (OPTNOCURSES) || /* we're parsing an uncolor command, and have no colors */ (parse_uncolor && !has_colors()) /* we're parsing an unmono command, and have colors */ || (!parse_uncolor && has_colors()) #else /* We don't even have colors compiled in */ parse_uncolor #endif ) { /* just eat the command, but don't do anything real about it */ do mutt_extract_token (buf, s, 0); while (MoreArgs (s)); return 0; } do { mutt_extract_token (buf, s, 0); if (!mutt_strcmp ("*", buf->data)) { for (tmp = *list; tmp; ) { if (!do_cache) do_cache = 1; last = tmp; tmp = tmp->next; mutt_free_color_line(&last, parse_uncolor); } *list = NULL; } else { for (last = NULL, tmp = *list; tmp; last = tmp, tmp = tmp->next) { if (!mutt_strcmp (buf->data, tmp->pattern)) { if (!do_cache) do_cache = 1; dprint(1,(debugfile,"Freeing pattern \"%s\" from color list\n", tmp->pattern)); if (last) last->next = tmp->next; else *list = tmp->next; mutt_free_color_line(&tmp, parse_uncolor); break; } } } } while (MoreArgs (s)); if (do_cache && !option (OPTNOCURSES)) { int i; set_option (OPTFORCEREDRAWINDEX); /* force re-caching of index colors */ for (i = 0; Context && i < Context->msgcount; i++) Context->hdrs[i]->pair = 0; } return (0); }
/** * icmd_bind - Parse 'bind' and 'macro' commands - Implements ::icommand_t */ static enum CommandResult icmd_bind(struct Buffer *buf, struct Buffer *s, unsigned long data, struct Buffer *err) { FILE *fp_out = NULL; char tempfile[PATH_MAX]; bool dump_all = false, bind = (data == 0); if (!MoreArgs(s)) dump_all = true; else mutt_extract_token(buf, s, 0); if (MoreArgs(s)) { /* More arguments potentially means the user is using the * ::command_t :bind command thus we delegate the task. */ return MUTT_CMD_ERROR; } struct Buffer *filebuf = mutt_buffer_alloc(4096); if (dump_all || (mutt_str_strcasecmp(buf->data, "all") == 0)) { dump_all_menus(filebuf, bind); } else { const int menu_index = mutt_map_get_value(buf->data, Menus); if (menu_index == -1) { mutt_buffer_printf(err, _("%s: no such menu"), buf->data); mutt_buffer_free(&filebuf); return MUTT_CMD_ERROR; } struct Mapping menu = { buf->data, menu_index }; dump_menu(filebuf, &menu, bind); } if (mutt_buffer_is_empty(filebuf)) { mutt_buffer_printf(err, _("%s: no %s for this menu"), dump_all ? "all" : buf->data, bind ? "binds" : "macros"); mutt_buffer_free(&filebuf); return MUTT_CMD_ERROR; } mutt_mktemp(tempfile, sizeof(tempfile)); fp_out = mutt_file_fopen(tempfile, "w"); if (!fp_out) { mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile); mutt_buffer_free(&filebuf); return MUTT_CMD_ERROR; } fputs(filebuf->data, fp_out); mutt_file_fclose(&fp_out); mutt_buffer_free(&filebuf); struct Pager info = { 0 }; if (mutt_pager((bind) ? "bind" : "macro", tempfile, 0, &info) == -1) { mutt_buffer_printf(err, _("Could not create temporary file %s"), tempfile); return MUTT_CMD_ERROR; } return MUTT_CMD_SUCCESS; }