📄 init.c
字号:
/* * Copyright (C) 1996-2002 Michael R. Elkins <me@mutt.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #if HAVE_CONFIG_H# include "config.h"#endif#include "mutt.h"#include "mapping.h"#include "mutt_curses.h"#include "mutt_regex.h"#include "history.h"#include "keymap.h"#include "mbyte.h"#include "charset.h"#include "mutt_crypt.h"#include "mutt_idna.h"#if defined(USE_SSL)#include "mutt_ssl.h"#endif#include "mx.h"#include "init.h"#include "mailbox.h"#include <ctype.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/utsname.h>#include <errno.h>#include <sys/wait.h>#define CHECK_PAGER \ if ((CurrentMenu == MENU_PAGER) && (idx >= 0) && \ (MuttVars[idx].flags & R_RESORT)) \ { \ snprintf (err->data, err->dsize, \ _("Not available in this menu.")); \ return (-1); \ } elsetypedef struct myvar{ char *name; char *value; struct myvar* next;} myvar_t;static myvar_t* MyVars;static int var_to_string (int idx, char* val, size_t len);static void myvar_set (const char* var, const char* val);static const char* myvar_get (const char* var);static void myvar_del (const char* var);void toggle_quadoption (int opt){ int n = opt/4; int b = (opt % 4) * 2; QuadOptions[n] ^= (1 << b);}void set_quadoption (int opt, int flag){ int n = opt/4; int b = (opt % 4) * 2; QuadOptions[n] &= ~(0x3 << b); QuadOptions[n] |= (flag & 0x3) << b;}int quadoption (int opt){ int n = opt/4; int b = (opt % 4) * 2; return (QuadOptions[n] >> b) & 0x3;}int query_quadoption (int opt, const char *prompt){ int v = quadoption (opt); switch (v) { case M_YES: case M_NO: return (v); default: v = mutt_yesorno (prompt, (v == M_ASKYES)); CLEARLINE (LINES - 1); return (v); } /* not reached */}/* given the variable ``s'', return the index into the rc_vars array which matches, or -1 if the variable is not found. */int mutt_option_index (char *s){ int i; for (i = 0; MuttVars[i].option; i++) if (mutt_strcmp (s, MuttVars[i].option) == 0) return (MuttVars[i].type == DT_SYN ? mutt_option_index ((char *) MuttVars[i].data) : i); return (-1);}int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags){ char ch; char qc = 0; /* quote char */ char *pc; /* reset the destination pointer to the beginning of the buffer */ dest->dptr = dest->data; SKIPWS (tok->dptr); while ((ch = *tok->dptr)) { if (!qc) { if ((ISSPACE (ch) && !(flags & M_TOKEN_SPACE)) || (ch == '#' && !(flags & M_TOKEN_COMMENT)) || (ch == '=' && (flags & M_TOKEN_EQUAL)) || (ch == ';' && !(flags & M_TOKEN_SEMICOLON)) || ((flags & M_TOKEN_PATTERN) && strchr ("~%=!|", ch))) break; } tok->dptr++; if (ch == qc) qc = 0; /* end of quote */ else if (!qc && (ch == '\'' || ch == '"') && !(flags & M_TOKEN_QUOTE)) qc = ch; else if (ch == '\\' && qc != '\'') { if (!*tok->dptr) return -1; /* premature end of token */ switch (ch = *tok->dptr++) { case 'c': case 'C': if (!*tok->dptr) return -1; /* premature end of token */ mutt_buffer_addch (dest, (toupper ((unsigned char) *tok->dptr) - '@') & 0x7f); tok->dptr++; break; case 'r': mutt_buffer_addch (dest, '\r'); break; case 'n': mutt_buffer_addch (dest, '\n'); break; case 't': mutt_buffer_addch (dest, '\t'); break; case 'f': mutt_buffer_addch (dest, '\f'); break; case 'e': mutt_buffer_addch (dest, '\033'); break; default: if (isdigit ((unsigned char) ch) && isdigit ((unsigned char) *tok->dptr) && isdigit ((unsigned char) *(tok->dptr + 1))) { mutt_buffer_addch (dest, (ch << 6) + (*tok->dptr << 3) + *(tok->dptr + 1) - 3504); tok->dptr += 2; } else mutt_buffer_addch (dest, ch); } } else if (ch == '^' && (flags & M_TOKEN_CONDENSE)) { if (!*tok->dptr) return -1; /* premature end of token */ ch = *tok->dptr++; if (ch == '^') mutt_buffer_addch (dest, ch); else if (ch == '[') mutt_buffer_addch (dest, '\033'); else if (isalpha ((unsigned char) ch)) mutt_buffer_addch (dest, toupper ((unsigned char) ch) - '@'); else { mutt_buffer_addch (dest, '^'); mutt_buffer_addch (dest, ch); } } else if (ch == '`' && (!qc || qc == '"')) { FILE *fp; pid_t pid; char *cmd, *ptr; size_t expnlen; BUFFER expn; int line = 0; pc = tok->dptr; do { if ((pc = strpbrk (pc, "\\`"))) { /* skip any quoted chars */ if (*pc == '\\') pc += 2; } } while (pc && *pc != '`'); if (!pc) { dprint (1, (debugfile, "mutt_get_token: mismatched backtics\n")); return (-1); } cmd = mutt_substrdup (tok->dptr, pc); if ((pid = mutt_create_filter (cmd, NULL, &fp, NULL)) < 0) { dprint (1, (debugfile, "mutt_get_token: unable to fork command: %s", cmd)); FREE (&cmd); return (-1); } FREE (&cmd); tok->dptr = pc + 1; /* read line */ memset (&expn, 0, sizeof (expn)); expn.data = mutt_read_line (NULL, &expn.dsize, fp, &line); fclose (fp); mutt_wait_filter (pid); /* if we got output, make a new string consiting of the shell ouptput plus whatever else was left on the original line */ /* BUT: If this is inside a quoted string, directly add output to * the token */ if (expn.data && qc) { mutt_buffer_addstr (dest, expn.data); FREE (&expn.data); } else if (expn.data) { expnlen = mutt_strlen (expn.data); tok->dsize = expnlen + mutt_strlen (tok->dptr) + 1; ptr = safe_malloc (tok->dsize); memcpy (ptr, expn.data, expnlen); strcpy (ptr + expnlen, tok->dptr); /* __STRCPY_CHECKED__ */ if (tok->destroy) FREE (&tok->data); tok->data = ptr; tok->dptr = ptr; tok->destroy = 1; /* mark that the caller should destroy this data */ ptr = NULL; FREE (&expn.data); } } else if (ch == '$' && (!qc || qc == '"') && (*tok->dptr == '{' || isalpha ((unsigned char) *tok->dptr))) { const char *env = NULL; char *var = NULL; int idx; if (*tok->dptr == '{') { tok->dptr++; if ((pc = strchr (tok->dptr, '}'))) { var = mutt_substrdup (tok->dptr, pc); tok->dptr = pc + 1; } } else { for (pc = tok->dptr; isalnum ((unsigned char) *pc) || *pc == '_'; pc++) ; var = mutt_substrdup (tok->dptr, pc); tok->dptr = pc; } if (var) { if ((env = getenv (var)) || (env = myvar_get (var))) mutt_buffer_addstr (dest, env); else if ((idx = mutt_option_index (var)) != -1) { /* expand settable mutt variables */ char val[LONG_STRING]; if (var_to_string (idx, val, sizeof (val))) mutt_buffer_addstr (dest, val); } FREE (&var); } } else mutt_buffer_addch (dest, ch); } mutt_buffer_addch (dest, 0); /* terminate the string */ SKIPWS (tok->dptr); return 0;}static void mutt_free_opt (struct option_t* p){ REGEXP* pp; switch (p->type & DT_MASK) { case DT_ADDR: rfc822_free_address ((ADDRESS**)p->data); break; case DT_RX: pp = (REGEXP*)p->data; FREE (&pp->pattern); if (pp->rx) { regfree (pp->rx); FREE (&pp->rx); } break; case DT_PATH: case DT_STR: FREE ((char**)p->data); /* __FREE_CHECKED__ */ break; }}/* clean up before quitting */void mutt_free_opts (void){ int i; for (i = 0; MuttVars[i].option; i++) mutt_free_opt (MuttVars + i); mutt_free_rx_list (&Alternates); mutt_free_rx_list (&UnAlternates); mutt_free_rx_list (&MailLists); mutt_free_rx_list (&UnMailLists); mutt_free_rx_list (&SubscribedLists); mutt_free_rx_list (&UnSubscribedLists); mutt_free_rx_list (&NoSpamList);}static void add_to_list (LIST **list, const char *str){ LIST *t, *last = NULL; /* don't add a NULL or empty string to the list */ if (!str || *str == '\0') return; /* check to make sure the item is not already on this list */ for (last = *list; last; last = last->next) { if (ascii_strcasecmp (str, last->data) == 0) { /* already on the list, so just ignore it */ last = NULL; break; } if (!last->next) break; } if (!*list || last) { t = (LIST *) safe_calloc (1, sizeof (LIST)); t->data = safe_strdup (str); if (last) { last->next = t; last = last->next; } else *list = last = t; }}int mutt_add_to_rx_list (RX_LIST **list, const char *s, int flags, BUFFER *err){ RX_LIST *t, *last = NULL; REGEXP *rx; if (!s || !*s) return 0; if (!(rx = mutt_compile_regexp (s, flags))) { snprintf (err->data, err->dsize, "Bad regexp: %s\n", s); return -1; } /* check to make sure the item is not already on this list */ for (last = *list; last; last = last->next) { if (ascii_strcasecmp (rx->pattern, last->rx->pattern) == 0) { /* already on the list, so just ignore it */ last = NULL; break; } if (!last->next) break; } if (!*list || last) { t = mutt_new_rx_list(); t->rx = rx; if (last) { last->next = t; last = last->next; } else *list = last = t; } else /* duplicate */ mutt_free_regexp (&rx); return 0;}static int add_to_spam_list (SPAM_LIST **list, const char *pat, const char *templ, BUFFER *err){ SPAM_LIST *t = NULL, *last = NULL; REGEXP *rx; int n; const char *p; if (!pat || !*pat || !templ) return 0; if (!(rx = mutt_compile_regexp (pat, REG_ICASE))) { snprintf (err->data, err->dsize, _("Bad regexp: %s"), pat); return -1; } /* check to make sure the item is not already on this list */ for (last = *list; last; last = last->next) { if (ascii_strcasecmp (rx->pattern, last->rx->pattern) == 0) { /* Already on the list. Formerly we just skipped this case, but * now we're supporting removals, which means we're supporting * re-adds conceptually. So we probably want this to imply a * removal, then do an add. We can achieve the removal by freeing * the template, and leaving t pointed at the current item. */ t = last; FREE(&t->template); break; } if (!last->next) break; } /* If t is set, it's pointing into an extant SPAM_LIST* that we want to * update. Otherwise we want to make a new one to link at the list's end. */ if (!t) { t = mutt_new_spam_list(); t->rx = rx; if (last) last->next = t; else *list = t; } /* Now t is the SPAM_LIST* that we want to modify. It is prepared. */ t->template = safe_strdup(templ); /* Find highest match number in template string */ t->nmatch = 0; for (p = templ; *p;) { if (*p == '%') { n = atoi(++p); if (n > t->nmatch) t->nmatch = n; while (*p && isdigit((int)*p)) ++p; } else ++p; } t->nmatch++; /* match 0 is always the whole expr */ return 0;}static int remove_from_spam_list (SPAM_LIST **list, const char *pat){ SPAM_LIST *spam, *prev; int nremoved = 0; /* Being first is a special case. */ spam = *list; if (!spam) return 0; if (spam->rx && !mutt_strcmp(spam->rx->pattern, pat)) { *list = spam->next; mutt_free_regexp(&spam->rx); FREE(&spam->template); FREE(&spam); return 1; } prev = spam; for (spam = prev->next; spam;) { if (!mutt_strcmp(spam->rx->pattern, pat)) { prev->next = spam->next; mutt_free_regexp(&spam->rx); FREE(&spam->template); FREE(&spam); spam = prev->next; ++nremoved; } else spam = spam->next; } return nremoved;}static void remove_from_list (LIST **l, const char *str){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -