📄 mx.c
字号:
/* * Copyright (C) 1996-2002 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 "mx.h"#include "rfc2047.h"#include "sort.h"#include "mailbox.h"#include "copy.h"#include "keymap.h"#include "url.h"#ifdef USE_IMAP#include "imap.h"#endif#ifdef USE_POP#include "pop.h"#endif#ifdef BUFFY_SIZE#include "buffy.h"#endif#ifdef USE_DOTLOCK#include "dotlock.h"#endif#include "mutt_crypt.h"#include <dirent.h>#include <fcntl.h>#include <sys/file.h>#include <sys/stat.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#ifndef BUFFY_SIZE#include <utime.h>#endif#define mutt_is_spool(s) (mutt_strcmp (Spoolfile, s) == 0)#ifdef USE_DOTLOCK/* parameters: * path - file to lock * retry - should retry if unable to lock? */#ifdef DL_STANDALONEstatic int invoke_dotlock (const char *path, int dummy, int flags, int retry){ char cmd[LONG_STRING + _POSIX_PATH_MAX]; char f[SHORT_STRING + _POSIX_PATH_MAX]; char r[SHORT_STRING]; if (flags & DL_FL_RETRY) snprintf (r, sizeof (r), "-r %d ", retry ? MAXLOCKATTEMPT : 0); mutt_quote_filename (f, sizeof (f), path); snprintf (cmd, sizeof (cmd), "%s %s%s%s%s%s%s%s", NONULL (MuttDotlock), flags & DL_FL_TRY ? "-t " : "", flags & DL_FL_UNLOCK ? "-u " : "", flags & DL_FL_USEPRIV ? "-p " : "", flags & DL_FL_FORCE ? "-f " : "", flags & DL_FL_UNLINK ? "-d " : "", flags & DL_FL_RETRY ? r : "", f); return mutt_system (cmd);}#else #define invoke_dotlock dotlock_invoke#endifstatic int dotlock_file (const char *path, int fd, int retry){ int r; int flags = DL_FL_USEPRIV | DL_FL_RETRY; if (retry) retry = 1;retry_lock: if ((r = invoke_dotlock(path, fd, flags, retry)) == DL_EX_EXIST) { if (!option (OPTNOCURSES)) { char msg[LONG_STRING]; snprintf(msg, sizeof(msg), _("Lock count exceeded, remove lock for %s?"), path); if(retry && mutt_yesorno(msg, M_YES) == M_YES) { flags |= DL_FL_FORCE; retry--; mutt_clear_error (); goto retry_lock; } } else { mutt_error ( _("Can't dotlock %s.\n"), path); } } return (r == DL_EX_OK ? 0 : -1);}static int undotlock_file (const char *path, int fd){ return (invoke_dotlock(path, fd, DL_FL_USEPRIV | DL_FL_UNLOCK, 0) == DL_EX_OK ? 0 : -1);}#endif /* USE_DOTLOCK *//* Args: * excl if excl != 0, request an exclusive lock * dot if dot != 0, try to dotlock the file * timeout should retry locking? */int mx_lock_file (const char *path, int fd, int excl, int dot, int timeout){#if defined (USE_FCNTL) || defined (USE_FLOCK) int count; int attempt; struct stat prev_sb;#endif int r = 0;#ifdef USE_FCNTL struct flock lck; memset (&lck, 0, sizeof (struct flock)); lck.l_type = excl ? F_WRLCK : F_RDLCK; lck.l_whence = SEEK_SET; count = 0; attempt = 0; prev_sb.st_size = 0; /* silence a GCC warning */ while (fcntl (fd, F_SETLK, &lck) == -1) { struct stat sb; dprint(1,(debugfile, "mx_lock_file(): fcntl errno %d.\n", errno)); if (errno != EAGAIN && errno != EACCES) { mutt_perror ("fcntl"); return (-1); } if (fstat (fd, &sb) != 0) sb.st_size = 0; if (count == 0) prev_sb = sb; /* only unlock file if it is unchanged */ if (prev_sb.st_size == sb.st_size && ++count >= (timeout?MAXLOCKATTEMPT:0)) { if (timeout) mutt_error _("Timeout exceeded while attempting fcntl lock!"); return (-1); } prev_sb = sb; mutt_message (_("Waiting for fcntl lock... %d"), ++attempt); sleep (1); }#endif /* USE_FCNTL */#ifdef USE_FLOCK count = 0; attempt = 0; while (flock (fd, (excl ? LOCK_EX : LOCK_SH) | LOCK_NB) == -1) { struct stat sb; if (errno != EWOULDBLOCK) { mutt_perror ("flock"); r = -1; break; } if (fstat(fd,&sb) != 0 ) sb.st_size=0; if (count == 0) prev_sb=sb; /* only unlock file if it is unchanged */ if (prev_sb.st_size == sb.st_size && ++count >= (timeout?MAXLOCKATTEMPT:0)) { if (timeout) mutt_error _("Timeout exceeded while attempting flock lock!"); r = -1; break; } prev_sb = sb; mutt_message (_("Waiting for flock attempt... %d"), ++attempt); sleep (1); }#endif /* USE_FLOCK */#ifdef USE_DOTLOCK if (r == 0 && dot) r = dotlock_file (path, fd, timeout);#endif /* USE_DOTLOCK */ if (r == -1) { /* release any other locks obtained in this routine */#ifdef USE_FCNTL lck.l_type = F_UNLCK; fcntl (fd, F_SETLK, &lck);#endif /* USE_FCNTL */#ifdef USE_FLOCK flock (fd, LOCK_UN);#endif /* USE_FLOCK */ return (-1); } return 0;}int mx_unlock_file (const char *path, int fd, int dot){#ifdef USE_FCNTL struct flock unlockit = { F_UNLCK, 0, 0, 0 }; memset (&unlockit, 0, sizeof (struct flock)); unlockit.l_type = F_UNLCK; unlockit.l_whence = SEEK_SET; fcntl (fd, F_SETLK, &unlockit);#endif#ifdef USE_FLOCK flock (fd, LOCK_UN);#endif#ifdef USE_DOTLOCK if (dot) undotlock_file (path, fd);#endif return 0;}void mx_unlink_empty (const char *path){ int fd;#ifndef USE_DOTLOCK struct stat sb;#endif if ((fd = open (path, O_RDWR)) == -1) return; if (mx_lock_file (path, fd, 1, 0, 1) == -1) { close (fd); return; }#ifdef USE_DOTLOCK invoke_dotlock (path, fd, DL_FL_UNLINK, 1);#else if (fstat (fd, &sb) == 0 && sb.st_size == 0) unlink (path);#endif mx_unlock_file (path, fd, 0); close (fd);}/* try to figure out what type of mailbox ``path'' is * * return values: * M_* mailbox type * 0 not a mailbox * -1 error */#ifdef USE_IMAPint mx_is_imap(const char *p){ url_scheme_t scheme; if (!p) return 0; if (*p == '{') return 1; scheme = url_check_scheme (p); if (scheme == U_IMAP || scheme == U_IMAPS) return 1; return 0;}#endif#ifdef USE_POPint mx_is_pop (const char *p){ url_scheme_t scheme; if (!p) return 0; scheme = url_check_scheme (p); if (scheme == U_POP || scheme == U_POPS) return 1; return 0;}#endifint mx_get_magic (const char *path){ struct stat st; int magic = 0; char tmp[_POSIX_PATH_MAX]; FILE *f;#ifdef USE_IMAP if(mx_is_imap(path)) return M_IMAP;#endif /* USE_IMAP */#ifdef USE_POP if (mx_is_pop (path)) return M_POP;#endif /* USE_POP */ if (stat (path, &st) == -1) { dprint (1, (debugfile, "mx_get_magic(): unable to stat %s: %s (errno %d).\n", path, strerror (errno), errno)); return (-1); } if (S_ISDIR (st.st_mode)) { /* check for maildir-style mailbox */ snprintf (tmp, sizeof (tmp), "%s/cur", path); if (stat (tmp, &st) == 0 && S_ISDIR (st.st_mode)) return (M_MAILDIR); /* check for mh-style mailbox */ snprintf (tmp, sizeof (tmp), "%s/.mh_sequences", path); if (access (tmp, F_OK) == 0) return (M_MH); snprintf (tmp, sizeof (tmp), "%s/.xmhcache", path); if (access (tmp, F_OK) == 0) return (M_MH); snprintf (tmp, sizeof (tmp), "%s/.mew_cache", path); if (access (tmp, F_OK) == 0) return (M_MH); snprintf (tmp, sizeof (tmp), "%s/.mew-cache", path); if (access (tmp, F_OK) == 0) return (M_MH); snprintf (tmp, sizeof (tmp), "%s/.sylpheed_cache", path); if (access (tmp, F_OK) == 0) return (M_MH); /* * ok, this isn't an mh folder, but mh mode can be used to read * Usenet news from the spool. ;-) */ snprintf (tmp, sizeof (tmp), "%s/.overview", path); if (access (tmp, F_OK) == 0) return (M_MH); } else if (st.st_size == 0) { /* hard to tell what zero-length files are, so assume the default magic */ if (DefaultMagic == M_MBOX || DefaultMagic == M_MMDF) return (DefaultMagic); else return (M_MBOX); } else if ((f = fopen (path, "r")) != NULL) {#ifndef BUFFY_SIZE struct utimbuf times;#endif fgets (tmp, sizeof (tmp), f); if (mutt_strncmp ("From ", tmp, 5) == 0) magic = M_MBOX; else if (mutt_strcmp (MMDF_SEP, tmp) == 0) magic = M_MMDF; safe_fclose (&f);#ifndef BUFFY_SIZE /* need to restore the times here, the file was not really accessed, * only the type was accessed. This is important, because detection * of "new mail" depends on those times set correctly. */ times.actime = st.st_atime; times.modtime = st.st_mtime; utime (path, ×);#endif } else { dprint (1, (debugfile, "mx_get_magic(): unable to open file %s for reading.\n", path)); mutt_perror (path); return (-1); } return (magic);}/* * set DefaultMagic to the given value */int mx_set_magic (const char *s){ if (ascii_strcasecmp (s, "mbox") == 0) DefaultMagic = M_MBOX; else if (ascii_strcasecmp (s, "mmdf") == 0) DefaultMagic = M_MMDF; else if (ascii_strcasecmp (s, "mh") == 0) DefaultMagic = M_MH; else if (ascii_strcasecmp (s, "maildir") == 0) DefaultMagic = M_MAILDIR; else return (-1); return 0;}/* mx_access: Wrapper for access, checks permissions on a given mailbox. * We may be interested in using ACL-style flags at some point, currently * we use the normal access() flags. */int mx_access (const char* path, int flags){#ifdef USE_IMAP if (mx_is_imap (path)) return imap_access (path, flags);#endif return access (path, flags);}static int mx_open_mailbox_append (CONTEXT *ctx, int flags){ struct stat sb; ctx->append = 1;#ifdef USE_IMAP if(mx_is_imap(ctx->path)) return imap_open_mailbox_append (ctx);#endif if(stat(ctx->path, &sb) == 0) { ctx->magic = mx_get_magic (ctx->path); switch (ctx->magic) { case 0: mutt_error (_("%s is not a mailbox."), ctx->path); /* fall through */ case -1: return (-1); } } else if (errno == ENOENT) { ctx->magic = DefaultMagic; if (ctx->magic == M_MH || ctx->magic == M_MAILDIR) { char tmp[_POSIX_PATH_MAX]; if (mkdir (ctx->path, S_IRWXU)) { mutt_perror (ctx->path); return (-1); } if (ctx->magic == M_MAILDIR) { snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path); if (mkdir (tmp, S_IRWXU)) { mutt_perror (tmp); rmdir (ctx->path); return (-1); } snprintf (tmp, sizeof (tmp), "%s/new", ctx->path); if (mkdir (tmp, S_IRWXU)) { mutt_perror (tmp); snprintf (tmp, sizeof (tmp), "%s/cur", ctx->path); rmdir (tmp); rmdir (ctx->path); return (-1); } snprintf (tmp, sizeof (tmp), "%s/tmp", ctx->path); if (mkdir (tmp, S_IRWXU))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -