📄 muttlib.c
字号:
/* * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org> * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.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 "mutt_curses.h"#include "mime.h"#include "mailbox.h"#include "mx.h"#include "url.h"#ifdef USE_IMAP#include "imap.h"#endif#include "mutt_crypt.h"#include <string.h>#include <ctype.h>#include <unistd.h>#include <stdlib.h>#include <sys/wait.h>#include <errno.h>#include <sys/stat.h>#include <fcntl.h>#include <time.h>#include <sys/types.h>#include <utime.h>BODY *mutt_new_body (void){ BODY *p = (BODY *) safe_calloc (1, sizeof (BODY)); p->disposition = DISPATTACH; p->use_disp = 1; return (p);}/* Modified by blong to accept a "suggestion" for file name. If * that file exists, then construct one with unique name but * keep any extension. This might fail, I guess. * Renamed to mutt_adv_mktemp so I only have to change where it's * called, and not all possible cases. */void mutt_adv_mktemp (char *s, size_t l){ char buf[_POSIX_PATH_MAX]; char tmp[_POSIX_PATH_MAX]; char *period; size_t sl; struct stat sb; strfcpy (buf, NONULL (Tempdir), sizeof (buf)); mutt_expand_path (buf, sizeof (buf)); if (s[0] == '\0') { snprintf (s, l, "%s/muttXXXXXX", buf); mktemp (s); } else { strfcpy (tmp, s, sizeof (tmp)); mutt_sanitize_filename (tmp, 1); snprintf (s, l, "%s/%s", buf, tmp); if (lstat (s, &sb) == -1 && errno == ENOENT) return; if ((period = strrchr (tmp, '.')) != NULL) *period = 0; snprintf (s, l, "%s/%s.XXXXXX", buf, tmp); mktemp (s); if (period != NULL) { *period = '.'; sl = mutt_strlen(s); strfcpy(s + sl, period, l - sl); } }}/* create a send-mode duplicate from a receive-mode body */int mutt_copy_body (FILE *fp, BODY **tgt, BODY *src){ char tmp[_POSIX_PATH_MAX]; BODY *b; PARAMETER *par, **ppar; short use_disp; if (src->filename) { use_disp = 1; strfcpy (tmp, src->filename, sizeof (tmp)); } else { use_disp = 0; tmp[0] = '\0'; } mutt_adv_mktemp (tmp, sizeof (tmp)); if (mutt_save_attachment (fp, src, tmp, 0, NULL) == -1) return -1; *tgt = mutt_new_body (); b = *tgt; memcpy (b, src, sizeof (BODY)); b->parts = NULL; b->next = NULL; b->filename = safe_strdup (tmp); b->use_disp = use_disp; b->unlink = 1; if (mutt_is_text_part (b)) b->noconv = 1; b->xtype = safe_strdup (b->xtype); b->subtype = safe_strdup (b->subtype); b->form_name = safe_strdup (b->form_name); b->filename = safe_strdup (b->filename); b->d_filename = safe_strdup (b->d_filename); b->description = safe_strdup (b->description); /* * we don't seem to need the HEADER structure currently. * XXX - this may change in the future */ if (b->hdr) b->hdr = NULL; /* copy parameters */ for (par = b->parameter, ppar = &b->parameter; par; ppar = &(*ppar)->next, par = par->next) { *ppar = mutt_new_parameter (); (*ppar)->attribute = safe_strdup (par->attribute); (*ppar)->value = safe_strdup (par->value); } mutt_stamp_attachment (b); return 0;}void mutt_free_body (BODY **p){ BODY *a = *p, *b; while (a) { b = a; a = a->next; if (b->parameter) mutt_free_parameter (&b->parameter); if (b->unlink && b->filename) { dprint (1, (debugfile, "mutt_free_body: Unlinking %s.\n", b->filename)); unlink (b->filename); } else if (b->filename) dprint (1, (debugfile, "mutt_free_body: Not unlinking %s.\n", b->filename)); FREE (&b->filename); FREE (&b->content); FREE (&b->xtype); FREE (&b->subtype); FREE (&b->description); FREE (&b->form_name); if (b->hdr) { /* Don't free twice (b->hdr->content = b->parts) */ b->hdr->content = NULL; mutt_free_header(&b->hdr); } if (b->parts) mutt_free_body (&b->parts); FREE (&b); } *p = 0;}void mutt_free_parameter (PARAMETER **p){ PARAMETER *t = *p; PARAMETER *o; while (t) { FREE (&t->attribute); FREE (&t->value); o = t; t = t->next; FREE (&o); } *p = 0;}LIST *mutt_add_list (LIST *head, const char *data){ size_t len = mutt_strlen (data); return mutt_add_list_n (head, data, len ? len + 1 : 0);}LIST *mutt_add_list_n (LIST *head, const void *data, size_t len){ LIST *tmp; for (tmp = head; tmp && tmp->next; tmp = tmp->next) ; if (tmp) { tmp->next = safe_malloc (sizeof (LIST)); tmp = tmp->next; } else head = tmp = safe_malloc (sizeof (LIST)); tmp->data = safe_malloc (len); if (len) memcpy (tmp->data, data, len); tmp->next = NULL; return head;}void mutt_free_list (LIST **list){ LIST *p; if (!list) return; while (*list) { p = *list; *list = (*list)->next; FREE (&p->data); FREE (&p); }}HEADER *mutt_dup_header(HEADER *h){ HEADER *hnew; hnew = mutt_new_header(); memcpy(hnew, h, sizeof (HEADER)); return hnew;}void mutt_free_header (HEADER **h){ if(!h || !*h) return; mutt_free_envelope (&(*h)->env); mutt_free_body (&(*h)->content); FREE (&(*h)->maildir_flags); FREE (&(*h)->tree); FREE (&(*h)->path);#ifdef MIXMASTER mutt_free_list (&(*h)->chain);#endif#if defined USE_POP || defined USE_IMAP FREE (&(*h)->data);#endif FREE (h); /* __FREE_CHECKED__ */}/* returns true if the header contained in "s" is in list "t" */int mutt_matches_ignore (const char *s, LIST *t){ for (; t; t = t->next) { if (!ascii_strncasecmp (s, t->data, mutt_strlen (t->data)) || *t->data == '*') return 1; } return 0;}/* prepend the path part of *path to *link */void mutt_expand_link (char *newpath, const char *path, const char *link){ const char *lb = NULL; size_t len; /* link is full path */ if (*link == '/') { strfcpy (newpath, link, _POSIX_PATH_MAX); return; } if ((lb = strrchr (path, '/')) == NULL) { /* no path in link */ strfcpy (newpath, link, _POSIX_PATH_MAX); return; } len = lb - path + 1; memcpy (newpath, path, len); strfcpy (newpath + len, link, _POSIX_PATH_MAX - len);}char *mutt_expand_path (char *s, size_t slen){ return _mutt_expand_path (s, slen, 0);}char *_mutt_expand_path (char *s, size_t slen, int rx){ char p[_POSIX_PATH_MAX] = ""; char q[_POSIX_PATH_MAX] = ""; char tmp[_POSIX_PATH_MAX]; char *t; char *tail = ""; int recurse = 0; do { recurse = 0; switch (*s) { case '~': { if (*(s + 1) == '/' || *(s + 1) == 0) { strfcpy (p, NONULL(Homedir), sizeof (p)); tail = s + 1; } else { struct passwd *pw; if ((t = strchr (s + 1, '/'))) *t = 0; if ((pw = getpwnam (s + 1))) { strfcpy (p, pw->pw_dir, sizeof (p)); if (t) { *t = '/'; tail = t; } else tail = ""; } else { /* user not found! */ if (t) *t = '/'; *p = '\0'; tail = s; } } } break; case '=': case '+': {#ifdef USE_IMAP /* if folder = {host} or imap[s]://host/: don't append slash */ if (mx_is_imap (NONULL (Maildir)) && (Maildir[strlen (Maildir) - 1] == '}' || Maildir[strlen (Maildir) - 1] == '/')) strfcpy (p, NONULL (Maildir), sizeof (p)); else#endif snprintf (p, sizeof (p), "%s/", NONULL (Maildir)); tail = s + 1; } break; /* elm compatibility, @ expands alias to user name */ case '@': { HEADER *h; ADDRESS *alias; if ((alias = mutt_lookup_alias (s + 1))) { h = mutt_new_header(); h->env = mutt_new_envelope(); h->env->from = h->env->to = alias; mutt_default_save (p, sizeof (p), h); h->env->from = h->env->to = NULL; mutt_free_header (&h); /* Avoid infinite recursion if the resulting folder starts with '@' */ if (*p != '@') recurse = 1; tail = ""; } } break; case '>': { strfcpy (p, NONULL(Inbox), sizeof (p)); tail = s + 1; } break; case '<': { strfcpy (p, NONULL(Outbox), sizeof (p)); tail = s + 1; } break; case '!': { if (*(s+1) == '!') { strfcpy (p, NONULL(LastFolder), sizeof (p)); tail = s + 2; } else { strfcpy (p, NONULL(Spoolfile), sizeof (p)); tail = s + 1; } } break; case '-': { strfcpy (p, NONULL(LastFolder), sizeof (p)); tail = s + 1; } break; case '^': { strfcpy (p, NONULL(CurrentFolder), sizeof (p)); tail = s + 1; } break; default: { *p = '\0'; tail = s; } } if (rx && *p && !recurse) { mutt_rx_sanitize_string (q, sizeof (q), p); snprintf (tmp, sizeof (tmp), "%s%s", q, tail); } else snprintf (tmp, sizeof (tmp), "%s%s", p, tail); strfcpy (s, tmp, slen); } while (recurse);#ifdef USE_IMAP /* Rewrite IMAP path in canonical form - aids in string comparisons of * folders. May possibly fail, in which case s should be the same. */ if (mx_is_imap (s)) imap_expand_path (s, slen);#endif return (s);}/* Extract the real name from /etc/passwd's GECOS field. * When set, honor the regular expression in GecosMask, * otherwise assume that the GECOS field is a * comma-separated list. * Replace "&" by a capitalized version of the user's login * name. */char *mutt_gecos_name (char *dest, size_t destlen, struct passwd *pw){ regmatch_t pat_match[1]; size_t pwnl; int idx; char *p; if (!pw || !pw->pw_gecos) return NULL; memset (dest, 0, destlen); if (GecosMask.rx) { if (regexec (GecosMask.rx, pw->pw_gecos, 1, pat_match, 0) == 0) strfcpy (dest, pw->pw_gecos + pat_match[0].rm_so, MIN (pat_match[0].rm_eo - pat_match[0].rm_so + 1, destlen)); } else if ((p = strchr (pw->pw_gecos, ','))) strfcpy (dest, pw->pw_gecos, MIN (destlen, p - pw->pw_gecos + 1)); else strfcpy (dest, pw->pw_gecos, destlen); pwnl = strlen (pw->pw_name); for (idx = 0; dest[idx]; idx++) { if (dest[idx] == '&') { memmove (&dest[idx + pwnl], &dest[idx + 1], MAX(destlen - idx - pwnl - 1, 0)); memcpy (&dest[idx], pw->pw_name, MIN(destlen - idx - 1, pwnl)); dest[idx] = toupper ((unsigned char) dest[idx]); } } return dest;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -