📄 init.c
字号:
for (i = 0; Commands[i].name; i++) { if (!mutt_strcmp (token->data, Commands[i].name)) { if (Commands[i].func (token, &expn, Commands[i].data, err) != 0) goto finish; break; } } if (!Commands[i].name) { snprintf (err->data, err->dsize, _("%s: unknown command"), NONULL (token->data)); goto finish; } } r = 0;finish: if (expn.destroy) FREE (&expn.data); return (r);}#define NUMVARS (sizeof (MuttVars)/sizeof (MuttVars[0]))#define NUMCOMMANDS (sizeof (Commands)/sizeof (Commands[0]))/* initial string that starts completion. No telling how much crap * the user has typed so far. Allocate LONG_STRING just to be sure! */char User_typed [LONG_STRING] = {0}; int Num_matched = 0; /* Number of matches for completion */char Completed [STRING] = {0}; /* completed string (command or variable) */const char **Matches;/* this is a lie until mutt_init runs: */int Matches_listsize = MAX(NUMVARS,NUMCOMMANDS) + 10;static void matches_ensure_morespace(int current){ int base_space, extra_space, space; if (current > Matches_listsize - 2) { base_space = MAX(NUMVARS,NUMCOMMANDS) + 1; extra_space = Matches_listsize - base_space; extra_space *= 2; space = base_space + extra_space; safe_realloc (&Matches, space * sizeof (char *)); memset (&Matches[current + 1], 0, space - current); Matches_listsize = space; }}/* helper function for completion. Changes the dest buffer if necessary/possible to aid completion. dest == completion result gets here. src == candidate for completion. try == user entered data for completion. len == length of dest buffer.*/static void candidate (char *dest, char *try, const char *src, int len){ int l; if (strstr (src, try) == src) { matches_ensure_morespace (Num_matched); Matches[Num_matched++] = src; if (dest[0] == 0) strfcpy (dest, src, len); else { for (l = 0; src[l] && src[l] == dest[l]; l++); dest[l] = 0; } }}int mutt_command_complete (char *buffer, size_t len, int pos, int numtabs){ char *pt = buffer; int num; int spaces; /* keep track of the number of leading spaces on the line */ myvar_t *myv; SKIPWS (buffer); spaces = buffer - pt; pt = buffer + pos - spaces; while ((pt > buffer) && !isspace ((unsigned char) *pt)) pt--; if (pt == buffer) /* complete cmd */ { /* first TAB. Collect all the matches */ if (numtabs == 1) { Num_matched = 0; strfcpy (User_typed, pt, sizeof (User_typed)); memset (Matches, 0, Matches_listsize); memset (Completed, 0, sizeof (Completed)); for (num = 0; Commands[num].name; num++) candidate (Completed, User_typed, Commands[num].name, sizeof (Completed)); matches_ensure_morespace (Num_matched); Matches[Num_matched++] = User_typed; /* All matches are stored. Longest non-ambiguous string is "" * i.e. dont change 'buffer'. Fake successful return this time */ if (User_typed[0] == 0) return 1; } if (Completed[0] == 0 && User_typed[0]) return 0; /* Num_matched will _always_ be atleast 1 since the initial * user-typed string is always stored */ if (numtabs == 1 && Num_matched == 2) snprintf(Completed, sizeof(Completed),"%s", Matches[0]); else if (numtabs > 1 && Num_matched > 2) /* cycle thru all the matches */ snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % Num_matched]); /* return the completed command */ strncpy (buffer, Completed, len - spaces); } else if (!mutt_strncmp (buffer, "set", 3) || !mutt_strncmp (buffer, "unset", 5) || !mutt_strncmp (buffer, "reset", 5) || !mutt_strncmp (buffer, "toggle", 6)) { /* complete variables */ char *prefixes[] = { "no", "inv", "?", "&", 0 }; pt++; /* loop through all the possible prefixes (no, inv, ...) */ if (!mutt_strncmp (buffer, "set", 3)) { for (num = 0; prefixes[num]; num++) { if (!mutt_strncmp (pt, prefixes[num], mutt_strlen (prefixes[num]))) { pt += mutt_strlen (prefixes[num]); break; } } } /* first TAB. Collect all the matches */ if (numtabs == 1) { Num_matched = 0; strfcpy (User_typed, pt, sizeof (User_typed)); memset (Matches, 0, Matches_listsize); memset (Completed, 0, sizeof (Completed)); for (num = 0; MuttVars[num].option; num++) candidate (Completed, User_typed, MuttVars[num].option, sizeof (Completed)); for (myv = MyVars; myv; myv = myv->next) candidate (Completed, User_typed, myv->name, sizeof (Completed)); matches_ensure_morespace (Num_matched); Matches[Num_matched++] = User_typed; /* All matches are stored. Longest non-ambiguous string is "" * i.e. dont change 'buffer'. Fake successful return this time */ if (User_typed[0] == 0) return 1; } if (Completed[0] == 0 && User_typed[0]) return 0; /* Num_matched will _always_ be atleast 1 since the initial * user-typed string is always stored */ if (numtabs == 1 && Num_matched == 2) snprintf(Completed, sizeof(Completed),"%s", Matches[0]); else if (numtabs > 1 && Num_matched > 2) /* cycle thru all the matches */ snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % Num_matched]); strncpy (pt, Completed, buffer + len - pt - spaces); } else if (!mutt_strncmp (buffer, "exec", 4)) { struct binding_t *menu = km_get_table (CurrentMenu); if (!menu && CurrentMenu != MENU_PAGER) menu = OpGeneric; pt++; /* first TAB. Collect all the matches */ if (numtabs == 1) { Num_matched = 0; strfcpy (User_typed, pt, sizeof (User_typed)); memset (Matches, 0, Matches_listsize); memset (Completed, 0, sizeof (Completed)); for (num = 0; menu[num].name; num++) candidate (Completed, User_typed, menu[num].name, sizeof (Completed)); /* try the generic menu */ if (Completed[0] == 0 && CurrentMenu != MENU_PAGER) { menu = OpGeneric; for (num = 0; menu[num].name; num++) candidate (Completed, User_typed, menu[num].name, sizeof (Completed)); } matches_ensure_morespace (Num_matched); Matches[Num_matched++] = User_typed; /* All matches are stored. Longest non-ambiguous string is "" * i.e. dont change 'buffer'. Fake successful return this time */ if (User_typed[0] == 0) return 1; } if (Completed[0] == 0 && User_typed[0]) return 0; /* Num_matched will _always_ be atleast 1 since the initial * user-typed string is always stored */ if (numtabs == 1 && Num_matched == 2) snprintf(Completed, sizeof(Completed),"%s", Matches[0]); else if (numtabs > 1 && Num_matched > 2) /* cycle thru all the matches */ snprintf(Completed, sizeof(Completed), "%s", Matches[(numtabs - 2) % Num_matched]); strncpy (pt, Completed, buffer + len - pt - spaces); } else return 0; return 1;}int mutt_var_value_complete (char *buffer, size_t len, int pos){ char var[STRING], *pt = buffer; int spaces; if (buffer[0] == 0) return 0; SKIPWS (buffer); spaces = buffer - pt; pt = buffer + pos - spaces; while ((pt > buffer) && !isspace ((unsigned char) *pt)) pt--; pt++; /* move past the space */ if (*pt == '=') /* abort if no var before the '=' */ return 0; if (mutt_strncmp (buffer, "set", 3) == 0) { int idx; char val[LONG_STRING]; const char *myvarval; strfcpy (var, pt, sizeof (var)); /* ignore the trailing '=' when comparing */ var[mutt_strlen (var) - 1] = 0; if ((idx = mutt_option_index (var)) == -1) { if ((myvarval = myvar_get(var)) != NULL) { snprintf (pt, len - (pt - buffer), "%s=\"%s\"", var, myvarval); return 1; } return 0; /* no such variable. */ } else if (var_to_string (idx, val, sizeof (val))) { snprintf (pt, len - (pt - buffer), "%s=\"%s\"", var, val); return 1; } } return 0;}static int var_to_string (int idx, char* val, size_t len){ char tmp[LONG_STRING]; char *s, *d; char *vals[] = { "no", "yes", "ask-no", "ask-yes" }; tmp[0] = '\0'; if ((DTYPE(MuttVars[idx].type) == DT_STR) || (DTYPE(MuttVars[idx].type) == DT_PATH) || (DTYPE(MuttVars[idx].type) == DT_RX)) { strfcpy (tmp, NONULL (*((char **) MuttVars[idx].data)), sizeof (tmp)); if (DTYPE (MuttVars[idx].type) == DT_PATH) mutt_pretty_mailbox (tmp); } else if (DTYPE (MuttVars[idx].type) == DT_ADDR) { rfc822_write_address (tmp, sizeof (tmp), *((ADDRESS **) MuttVars[idx].data), 0); } else if (DTYPE (MuttVars[idx].type) == DT_QUAD) strfcpy (tmp, vals[quadoption (MuttVars[idx].data)], sizeof (tmp)); else if (DTYPE (MuttVars[idx].type) == DT_NUM) snprintf (tmp, sizeof (tmp), "%d", (*((short *) MuttVars[idx].data))); else if (DTYPE (MuttVars[idx].type) == DT_SORT) { const struct mapping_t *map; char *p; switch (MuttVars[idx].type & DT_SUBTYPE_MASK) { case DT_SORT_ALIAS: map = SortAliasMethods; break; case DT_SORT_BROWSER: map = SortBrowserMethods; break; case DT_SORT_KEYS: if ((WithCrypto & APPLICATION_PGP)) map = SortKeyMethods; else map = SortMethods; break; default: map = SortMethods; break; } p = mutt_getnamebyvalue (*((short *) MuttVars[idx].data) & SORT_MASK, map); snprintf (tmp, sizeof (tmp), "%s%s%s", (*((short *) MuttVars[idx].data) & SORT_REVERSE) ? "reverse-" : "", (*((short *) MuttVars[idx].data) & SORT_LAST) ? "last-" : "", p); } else if (DTYPE (MuttVars[idx].type) == DT_MAGIC) { char *p; switch (DefaultMagic) { case M_MBOX: p = "mbox"; break; case M_MMDF: p = "MMDF"; break; case M_MH: p = "MH"; break; case M_MAILDIR: p = "Maildir"; break; default: p = "unknown"; } strfcpy (tmp, p, sizeof (tmp)); } else if (DTYPE (MuttVars[idx].type) == DT_BOOL) strfcpy (tmp, option (MuttVars[idx].data) ? "yes" : "no", sizeof (tmp)); else return 0; for (s = tmp, d = val; *s && len - (d - val) > 2; len--) { if (*s == '\\' || *s == '"') *d++ = '\\'; *d++ = *s++; } *d = '\0'; return 1;}/* Implement the -Q command line flag */int mutt_query_variables (LIST *queries){ LIST *p; char errbuff[STRING]; char command[STRING]; BUFFER err, token; memset (&err, 0, sizeof (err)); memset (&token, 0, sizeof (token)); err.data = errbuff; err.dsize = sizeof (errbuff); for (p = queries; p; p = p->next) { snprintf (command, sizeof (command), "set ?%s\n", p->data); if (mutt_parse_rc_line (command, &token, &err) == -1) { fprintf (stderr, "%s\n", err.data); FREE (&token.data); return 1; } printf ("%s\n", err.data); } FREE (&token.data); return 0;}/* dump out the value of all the variables we have */int mutt_dump_variables (void){ int i; char errbuff[STRING]; char command[STRING]; BUFFER err, token; memset (&err, 0, sizeof (err)); memset (&token, 0, sizeof (token)); err.data = errbuff; err.dsize = sizeof (errbuff); for (i = 0; MuttVars[i].option; i++) { if (MuttVars[i].type == DT_SYN) continue; snprintf (command, sizeof (command), "set ?%s\n", MuttVars[i].option); if (mutt_parse_rc_line (command, &token, &err) == -1) { fprintf (stderr, "%s\n", err.data); FREE (&token.data); return 1; } printf("%s\n", err.data); } FREE (&token.data); return 0;}char *mutt_getnamebyvalue (int val, const struct mapping_t *map){ int i; for (i=0; map[i].name; i++) if (map[i].value == val) return (map[i].name); return NULL;}int mutt_getvaluebyname (const char *name, const struct mapping_t *map){ int i; for (i = 0; map[i].name; i++) if (ascii_strcasecmp (map[i].name, name) == 0) return (map[i].value); return (-1);}#ifdef DEBUGstatic void start_debug (void){ time_t t; int i; char buf[_POSIX_PATH_MAX]; char buf2[_POSIX_PATH_MAX]; /* rotate the old debug logs */ for (i=3; i>=0; i--) { snprintf (buf, sizeof(buf), "%s/.muttdebug%d", NONULL(Homedir), i); snprintf (buf2, sizeof(buf2), "%s/.muttdebug%d", NONULL(Homedir), i+1); rename (buf, buf2); } if ((debugfile = safe_fopen(buf, "w")) != NULL) { t = time (0); setbuf (debugfile, NULL); /* don't buffer the debugging output! */ fprintf (debugfile, "Mutt %s started at %s.\nDebugging at level %d.\n\n", MUTT_VERSION, asctime (localtime (&t)), debuglevel); }}#endifstatic int mutt_execute_commands (LIST *p){ BUFFER err, token; char errstr[SHORT_STRING]; memset (&err, 0, sizeof (err)); err.data = errstr; err.dsize = sizeof (errstr); memset (&token, 0, sizeof (token)); for (; p; p = p->next) { if (mutt_parse_rc_line (p->data, &token, &err) != 0) { fprintf (stderr, _("Error in command line: %s\n"), err.data); FREE (&token.data); return (-1); } } FREE (&token.data); return 0;}void mutt_init (int skip_sys_rc, LIST *commands){ struct passwd *pw; struct utsname utsname; char *p, buffer[STRING], error[STRING]; int i, default_rc = 0, need_pause = 0; BUFFER err; memset (&err, 0, sizeof (err)); err.data = error; err.dsize = sizeof (error); Groups = hash_create (1031); /* * XXX - use something even more difficult to predict? */ snprintf (AttachmentMarker, sizeof (AttachmentMarker), "\033]9;%ld\a", (long) time (NULL)); /* on one of the systems I use, getcwd() does not return the same prefix as is listed in the passwd file */ if ((p = getenv ("HOME"))) Homedir = safe_strdup (p); /* Get some information about the user */ if ((pw = getpwuid (getuid ()))) { char rnbuf[STRING]; Username = safe_strdup (pw->pw_name); if (!Homedir) Homedir = safe_strdup (pw->pw_dir); Realname = safe_strdup (mutt_gecos_name (rnbuf, sizeof (rnbuf), pw)); Shell = safe_strdup (pw->pw_shell); endpwent (); } else { if (!Homedir) { mutt_endwin (NULL); fputs (_("unable to determine home directory"), stderr); exit (1); } if ((p = getenv ("USER"))) Username = safe_strdup (p); else { mutt_endwin (NULL); fputs (_("unable to determine username"), stderr); exit (1); } Shell = safe_strdup ((p =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -