Commit 32016c8f authored by Thomas Roessler's avatar Thomas Roessler

Various patches from last week, including:

- new mh/maildir access code.
- subscribe/unsubscribe
- various fixes.
parent edfda8e8
/*
* Copyright (C) 1996-8 Michael R. Elkins <[email protected]>
* Copyright (C) 1999 Thomas Roessler <[email protected]>
*
* 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
......@@ -699,9 +700,10 @@ int mutt_save_attachment (FILE *fp, BODY *m, char *path, int flags, HEADER *hdr)
chflags |= (ctx.magic == M_MAILDIR ? CH_NOSTATUS : CH_UPDATE);
if ((r = _mutt_copy_message (msg->fp, fp, hn, hn->content, 0, chflags)) == 0)
mutt_message _("Attachment saved.");
mx_commit_message (msg, &ctx);
mx_close_message (&msg);
mx_close_mailbox(&ctx);
mx_close_mailbox (&ctx);
return r;
}
else
......
......@@ -18,8 +18,9 @@
#include "mutt.h"
#include "buffy.h"
#include "mx.h"
#include "mailbox.h"
#include "mx.h"
#ifdef USE_IMAP
#include "imap.h"
#endif
......
......@@ -599,8 +599,10 @@ _mutt_append_message (CONTEXT *dest, FILE *fpin, CONTEXT *src, HEADER *hdr,
chflags |= CH_FROM;
chflags |= (dest->magic == M_MAILDIR ? CH_NOSTATUS : CH_UPDATE);
r = _mutt_copy_message (msg->fp, fpin, hdr, body, flags, chflags);
if (mx_close_message (&msg) != 0)
return (-1);
if (mx_commit_message (msg, dest) != 0)
r = -1;
mx_close_message (&msg);
return r;
}
......
......@@ -300,6 +300,7 @@ int mutt_any_key_to_continue (const char *s)
tcsetattr (f, TCSADRAIN, &old);
close (f);
fputs ("\r\n", stdout);
mutt_clear_error ();
return (ch);
}
......
......@@ -100,6 +100,7 @@ WHERE LIST *HeaderOrderList INITVAL(0);
WHERE LIST *Ignore INITVAL(0);
WHERE LIST *UnIgnore INITVAL(0);
WHERE LIST *MailLists INITVAL(0);
WHERE LIST *SubscribedLists INITVAL(0);
/* bit vector for boolean variables */
#ifdef MAIN_C
......
......@@ -146,6 +146,9 @@ static pgp_key_t *parse_pub_line (char *buf, int *is_subkey, pgp_key_t *k)
case 'r':
k->flags |= KEYFLAG_REVOKED;
break;
case 'd':
k->flags |= KEYFLAG_DISABLED;
break;
case 'n':
trust = 1;
break;
......
......@@ -32,19 +32,27 @@
#include <string.h>
#include <locale.h>
int mutt_is_mail_list (ADDRESS *addr)
static int _mutt_is_mail_list (ADDRESS *addr, LIST *p)
{
LIST *p;
if (addr->mailbox)
{
for (p = MailLists; p; p = p->next)
for (;p; p = p->next)
if (mutt_strncasecmp (addr->mailbox, p->data, mutt_strlen (p->data)) == 0)
return 1;
}
return 0;
}
int mutt_is_mail_list (ADDRESS *addr)
{
return _mutt_is_mail_list (addr, MailLists);
}
int mutt_is_subscribed_list (ADDRESS *addr)
{
return _mutt_is_mail_list (addr, SubscribedLists);
}
/* Search for a mailing list in the list of addresses pointed to by adr.
* If one is found, print pfx and the name of the list into buf, then
* return 1. Otherwise, simply return 0.
......@@ -54,7 +62,7 @@ check_for_mailing_list (ADDRESS *adr, char *pfx, char *buf, int buflen)
{
for (; adr; adr = adr->next)
{
if (mutt_is_mail_list (adr))
if (mutt_is_subscribed_list (adr))
{
if (pfx && buf && buflen)
snprintf (buf, buflen, "%s%s", pfx, mutt_get_name (adr));
......@@ -73,7 +81,7 @@ check_for_mailing_list_addr (ADDRESS *adr, char *buf, int buflen)
{
for (; adr; adr = adr->next)
{
if (mutt_is_mail_list (adr))
if (mutt_is_subscribed_list (adr))
{
if (buf && buflen)
snprintf (buf, buflen, "%s", adr->mailbox);
......@@ -88,7 +96,7 @@ static int first_mailing_list (char *buf, size_t buflen, ADDRESS *a)
{
for (; a; a = a->next)
{
if (mutt_is_mail_list (a))
if (mutt_is_subscribed_list (a))
{
mutt_save_path (buf, buflen, a);
return 1;
......
......@@ -286,112 +286,144 @@ int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags)
return 0;
}
void mutt_add_to_list (LIST **list, BUFFER *inp)
static void add_to_list (LIST **list, const char *str)
{
LIST *t, *last = NULL;
BUFFER buf;
memset (&buf, 0, sizeof (buf));
do
/* check to make sure the item is not already on this list */
for (last = *list; last; last = last->next)
{
mutt_extract_token (&buf, inp, 0);
/* check to make sure the item is not already on this list */
for (last = *list; last; last = last->next)
if (mutt_strcasecmp (str, last->data) == 0)
{
if (mutt_strcasecmp (buf.data, last->data) == 0)
{
/* already on the list, so just ignore it */
last = NULL;
break;
}
if (!last->next)
break;
/* already on the list, so just ignore it */
last = NULL;
break;
}
if (!last->next)
break;
}
if (!*list || last)
if (!*list || last)
{
t = (LIST *) safe_calloc (1, sizeof (LIST));
t->data = safe_strdup (str);
if (last)
{
t = (LIST *) safe_calloc (1, sizeof (LIST));
t->data = buf.data;
memset (&buf, 0, sizeof (buf));
if (last)
{
last->next = t;
last = last->next;
}
else
*list = last = t;
last->next = t;
last = last->next;
}
else
*list = last = t;
}
while (MoreArgs (inp));
FREE (&buf.data);
}
static void remove_from_list (LIST **l, BUFFER *inp)
static void remove_from_list (LIST **l, const char *str)
{
LIST *p, *last = NULL;
BUFFER buf;
memset (&buf, 0, sizeof (buf));
do
if (mutt_strcmp ("*", str) == 0)
mutt_free_list (l); /* ``unCMD *'' means delete all current entries */
else
{
mutt_extract_token (&buf, inp, 0);
if (mutt_strcmp ("*", buf.data) == 0)
mutt_free_list (l); /* ``unCMD *'' means delete all current entries */
else
p = *l;
last = NULL;
while (p)
{
p = *l;
last = NULL;
while (p)
if (mutt_strcasecmp (str, p->data) == 0)
{
if (mutt_strcasecmp (buf.data, p->data) == 0)
{
safe_free ((void **) &p->data);
if (last)
last->next = p->next;
else
(*l) = p->next;
safe_free ((void **) &p);
}
safe_free ((void **) &p->data);
if (last)
last->next = p->next;
else
{
last = p;
p = p->next;
}
(*l) = p->next;
safe_free ((void **) &p);
}
else
{
last = p;
p = p->next;
}
}
}
while (MoreArgs (inp));
FREE (&buf.data);
}
static int parse_unignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
mutt_add_to_list (&UnIgnore, s);
remove_from_list (&Ignore, s);
do
{
mutt_extract_token (buf, s, 0);
add_to_list (&UnIgnore, buf->data);
remove_from_list (&Ignore, buf->data);
}
while (MoreArgs (s));
return 0;
}
static int parse_ignore (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
mutt_add_to_list (&Ignore, s);
remove_from_list (&UnIgnore, s);
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_list (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
mutt_add_to_list ((LIST **) data, s);
do
{
mutt_extract_token (buf, s, 0);
add_to_list ((LIST **) data, buf->data);
}
while (MoreArgs (s));
return 0;
}
static int parse_unlist (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
remove_from_list ((LIST **) data, s);
do
{
mutt_extract_token (buf, s, 0);
remove_from_list ((LIST **) data, buf->data);
}
while (MoreArgs (s));
return 0;
}
static int parse_unlists (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
do
{
mutt_extract_token (buf, s, 0);
remove_from_list (&MailLists, buf->data);
remove_from_list (&SubscribedLists, buf->data);
}
while (MoreArgs (s));
return 0;
}
static int parse_subscribe (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
do
{
mutt_extract_token (buf, s, 0);
add_to_list (&MailLists, buf->data);
add_to_list (&SubscribedLists, buf->data);
}
while (MoreArgs (s));
return 0;
}
static int parse_unalias (BUFFER *buf, BUFFER *s, unsigned long data, BUFFER *err)
{
ALIAS *tmp, *last = NULL;
......
......@@ -340,6 +340,7 @@ const struct mapping_t SortKeyMethods[] = {
static int parse_list (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unlist (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unlists (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_alias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unalias (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_ignore (BUFFER *, BUFFER *, unsigned long, BUFFER *);
......@@ -348,6 +349,7 @@ static int parse_source (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_set (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_my_hdr (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_unmy_hdr (BUFFER *, BUFFER *, unsigned long, BUFFER *);
static int parse_subscribe (BUFFER *, BUFFER *, unsigned long, BUFFER *);
struct command_t
{
......@@ -388,14 +390,16 @@ struct command_t Commands[] = {
{ "send-hook", mutt_parse_hook, M_SENDHOOK },
{ "set", parse_set, 0 },
{ "source", parse_source, 0 },
{ "subscribe", parse_subscribe, 0 },
{ "toggle", parse_set, M_SET_INV },
{ "unalias", parse_unalias, 0 },
{ "unhdr_order", parse_unlist, UL &HeaderOrderList },
{ "unignore", parse_unignore, 0 },
{ "unlists", parse_unlist, UL &MailLists },
{ "unlists", parse_unlists, 0 },
{ "unmono", mutt_parse_unmono, 0 },
{ "unmy_hdr", parse_unmy_hdr, 0 },
{ "unscore", mutt_parse_unscore, 0 },
{ "unset", parse_set, M_SET_UNSET },
{ "unsubscribe", parse_unlist, UL &SubscribedLists },
{ NULL }
};
......@@ -119,6 +119,17 @@ void safe_free (void **p)
}
}
int safe_fclose (FILE **f)
{
int r = 0;
if (*f)
r = fclose (*f);
*f = NULL;
return r;
}
char *safe_strdup (const char *s)
{
char *p;
......@@ -254,6 +265,59 @@ int safe_symlink(const char *oldpath, const char *newpath)
return 0;
}
/*
* This function is supposed to do nfs-safe renaming of files.
*
* Warning: We don't check whether src and target are equal.
*/
int safe_rename (const char *src, const char *target)
{
struct stat ssb, tsb;
if (!src || !target)
return -1;
if (link (src, target) != 0)
{
return -1;
}
/*
* Stat both links and check if they are equal.
*/
if (stat (src, &ssb) == -1)
{
return -1;
}
if (stat (target, &tsb) == -1)
{
return -1;
}
/*
* pretend that the link failed because the target file
* did already exist.
*/
if (compare_stat (&ssb, &tsb) == -1)
{
errno = EEXIST;
return -1;
}
/*
* Unlink the original link. Should we really ignore the return
* value here? XXX
*/
unlink (src);
return 0;
}
int safe_open (const char *path, int flags)
{
struct stat osb, nsb;
......
......@@ -107,6 +107,8 @@ int mutt_strncasecmp (const char *, const char *, size_t);
int mutt_strncmp (const char *, const char *, size_t);
int safe_open (const char *, int);
int safe_symlink (const char *, const char *);
int safe_rename (const char *, const char *);
int safe_fclose (FILE **);
size_t mutt_quote_filename (char *, size_t, const char *);
size_t mutt_strlen (const char *);
......
......@@ -16,6 +16,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _MAILBOX_H
#define _MAILBOX_H
/* flags for mutt_open_mailbox() */
#define M_NOSORT (1<<0) /* do not sort the mailbox after opening it */
#define M_APPEND (1<<1) /* open mailbox for appending messages */
......@@ -36,10 +39,7 @@ enum
typedef struct
{
FILE *fp; /* pointer to the message data */
#ifdef USE_IMAP
CONTEXT *ctx; /* context (mailbox) for this message */
char *path; /* path to temp file */
#endif /* USE_IMAP */
short magic; /* type of mailbox this message belongs to */
short write; /* nonzero if message is open for writing */
} MESSAGE;
......@@ -53,7 +53,8 @@ void mx_fastclose_mailbox (CONTEXT *);
int mx_close_mailbox (CONTEXT *);
int mx_sync_mailbox (CONTEXT *);
int mx_close_message (MESSAGE **msg);
int mx_commit_message (MESSAGE *, CONTEXT *);
int mx_close_message (MESSAGE **);
int mx_get_magic (const char *);
int mx_set_magic (const char *);
int mx_check_mailbox (CONTEXT *, int *);
......@@ -61,3 +62,5 @@ int mx_check_mailbox (CONTEXT *, int *);
int mx_is_imap (const char *);
#endif
#endif
This diff is collapsed.
......@@ -405,7 +405,6 @@ typedef struct list_t
} LIST;
#define mutt_new_list() safe_calloc (1, sizeof (LIST))
void mutt_add_to_list (LIST **, BUFFER *);
void mutt_free_list (LIST **);
int mutt_matches_ignore (const char *, LIST *);
......@@ -498,7 +497,7 @@ typedef struct body
* encoding update.
*/
unsigned int type : 3; /* content-type primary type */
unsigned int type : 4; /* content-type primary type */
unsigned int encoding : 3; /* content-transfer-encoding */
unsigned int disposition : 2; /* content-disposition */
unsigned int use_disp : 1; /* Content-Disposition field printed? */
......
......@@ -706,7 +706,7 @@ static int sync_mailbox (CONTEXT *ctx)
}
#if 0
if (!ctx->quiet && rc == -1)
if (!ctx->quiet && !ctx->shutup && rc == -1)
mutt_error ( _("Could not synchronize mailbox %s!"), ctx->path);
#endif
......@@ -1015,70 +1015,8 @@ int mx_sync_mailbox (CONTEXT *ctx)
return (rc);
}
int mh_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
{
int hi = 0;
int fd, n;
char *cp;
char path[_POSIX_PATH_MAX];
DIR *dirp;
struct dirent *de;
do
{
if ((dirp = opendir (dest->path)) == NULL)
{
mutt_perror (dest->path);
return (-1);
}
/* figure out what the next message number is */
while ((de = readdir (dirp)) != NULL)
{
cp = de->d_name;
while (*cp)
{
if (!isdigit ((unsigned char) *cp))
break;
cp++;
}
if (!*cp)
{
n = atoi (de->d_name);
if (n > hi)
hi = n;
}
}
closedir (dirp);
hi++;
snprintf (path, sizeof (path), "%s/%d", dest->path, hi);
if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0600)) == -1)
{
if (errno != EEXIST)
{
mutt_perror (path);
return (-1);
}
}
}
while (fd < 0);
if ((msg->fp = fdopen (fd, "w")) == NULL)
return (-1);
return 0;
}
int maildir_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
{
char tmp[_POSIX_PATH_MAX];
char path[_POSIX_PATH_MAX];
maildir_create_filename (dest->path, hdr, path, tmp);
if ((msg->fp = safe_fopen (tmp, "w")) == NULL)
return (-1);
return 0;
}
/* {maildir,mh}_open_new_message are in mh.c. */
int mbox_open_new_message (MESSAGE *msg, CONTEXT *dest, HEADER *hdr)
{
......@@ -1213,30 +1151,31 @@ MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
case M_MH:
case M_MAILDIR:
{
HEADER *cur = ctx->hdrs[msgno];
char path[_POSIX_PATH_MAX];
snprintf (path, sizeof (path), "%s/%s", ctx->path, cur->path);
if ((msg->fp = fopen (path, "r")) == NULL)
{
HEADER *cur = ctx->hdrs[msgno];
char path[_POSIX_PATH_MAX];
snprintf (path, sizeof (path), "%s/%s", ctx->path, cur->path);
if ((msg->fp = fopen (path, "r")) == NULL)
{
mutt_perror (path);
dprint (1, (debugfile, "mx_open_message: fopen: %s: %s (errno %d).\n",
path, strerror (errno), errno));
FREE (&msg);
}
mutt_perror (path);
dprint (1, (debugfile, "mx_open_message: fopen: %s: %s (errno %d).\n",
path, strerror (errno), errno));
FREE (&msg);
}
break;
}
break;
#ifdef USE_IMAP
case M_IMAP:
{
if (imap_fetch_message (msg, ctx, msgno) != 0)
FREE (&msg);
break;
}
#endif /* USE_IMAP */
default:
dprint (1, (debugfile, "mx_open_message(): function not implemented for mailbox type %d.\n", ctx->magic));
FREE (&msg);
break;
......@@ -1244,45 +1183,87 @@ MESSAGE *mx_open_message (CONTEXT *ctx, int msgno)
return (msg);
}
/* close a pointer to a message */
int mx_close_message (MESSAGE **msg)
/* commit a message to a folder */
int mx_commit_message (MESSAGE *msg, CONTEXT *ctx)
{
int r = 0;
if ((*msg)->write)
if (!(msg->write && ctx->append))
{
dprint (1, (debugfile, "mx_commit_message(): msg->write = %d, ctx->append = %d\n",
msg->write, ctx->append));
return -1;
}
switch (msg->magic)
{
/* add the message terminator */
switch ((*msg)->magic)
case M_MMDF:
{
case M_MMDF:
fputs (MMDF_SEP, (*msg)->fp);
break;
fputs (MMDF_SEP, msg->fp);
break;
}
case M_MBOX:
{
fputc ('\n', msg->fp);
break;
}
case M_MBOX:
fputc ('\n', (*msg)->fp);
break;
case M_KENDRA:
{
fputs (KENDRA_SEP, msg->fp);
break;
}
}
switch ((*msg)->magic)
{
case M_MH:
#ifdef USE_IMAP
case M_IMAP:
{
if ((r = safe_fclose (&msg->fp)) == 0)
r = imap_append_message (ctx, msg);
break;
}
#endif
case M_MAILDIR:
r = fclose ((*msg)->fp);
{
if ((r = safe_fclose (&msg->fp)) == 0)
r = maildir_commit_message (ctx, msg, NULL);
break;
}
case M_MH:
{
if ((r = safe_fclose (&msg->fp)) == 0)
r = mh_commit_message (ctx, msg, NULL);
break;
}
}
return r;
}
/* close a pointer to a message */
int mx_close_message (MESSAGE **msg)
{
int r = 0;
if ((*msg)->magic == M_MH || (*msg)->magic == M_MAILDIR
#ifdef USE_IMAP
case M_IMAP:
r = fclose ((*msg)->fp);
if ((*msg)->write && (*msg)->ctx->append)
{
r = imap_append_message ((*msg)->ctx, *msg);
unlink ((*msg)->path);
}
|| (*msg)->magic == M_IMAP
#endif
)
{
r = safe_fclose (&(*msg)->fp);
}
else
(*msg)->fp = NULL;
default: