11 Commits

Author SHA1 Message Date
4cb77488bc Bump the version to 0.7.13. 2024-09-23 21:34:04 +02:00
6f8e688a46 Merge branch 'master' of github.com:dspiljar/mboxgrep 2024-09-23 16:04:20 +02:00
d8f44235f5 Fix Automake to include AUTHORS.md. 2024-09-23 14:37:53 +02:00
6e9600426a Minor update to the man and info pages
Sync the examples section, refer to RFC 4155 for the mbox mailbox
format, and add URLs to Gitea and Github.
2024-09-23 13:15:05 +02:00
b4d3034c8c Minor update to the man and info pages
Sync the examples section, refer to RFC 4155 for the mbox mailbox
format, and add URLs to Gitea and Github.
2024-09-23 12:59:51 +02:00
9515236244 Merge branch 'mbox_cleanup' 2024-09-20 23:43:29 +02:00
a790494133 Code refactoring
Refactor of mbox_open(). Checking for a "postmark" line, i.e. whether
the file is an mbox mailbox, has been moved to mbox_check_postmark().
2024-09-20 22:18:30 +02:00
631998a849 Code refactoring
Partial refactor of mbox_open(). Opening of file descripts has been
moved to mbox_fdopen().
2024-09-20 13:11:06 +02:00
bd64536e89 Function prototype
Use an enum type instead of a string to define the file opening mode.
2024-09-19 22:40:20 +02:00
b30f2f2362 Suppress "Not an mbox folder" error messages on empty files. 2024-09-19 00:24:21 +02:00
1a63374e73 Move file locking code to a separate function.
Failure to lock a file is now fatal.
2024-09-18 23:48:21 +02:00
11 changed files with 208 additions and 168 deletions

View File

@@ -1,2 +1,2 @@
SUBDIRS = doc src SUBDIRS = doc src
EXTRA_DIST = contrib COPYING.md INSTALL.md NEWS.md README.md TODO.md EXTRA_DIST = contrib COPYING.md INSTALL.md NEWS.md README.md TODO.md AUTHORS.md

View File

@@ -1,5 +1,12 @@
# Changes of mboxgrep # Changes of mboxgrep
## Changes in 0.7.13
- Improve the readability of this file.
- Failure to lock a file (mbox) is now a fatal error.
- Fix Autoconf on Windows.
- Code refactoring, mostly of mbox-related functions.
## Changes in 0.7.12a ## Changes in 0.7.12a
- Fix Automake macros to include the license file and others. - Fix Automake macros to include the license file and others.

View File

@@ -1,5 +1,5 @@
# mboxgrep - scan mailbox for messages matching a regular expression # mboxgrep - scan mailbox for messages matching a regular expression
# Copyright (C) 2000 - 2003, 2023 Daniel Spiljar # Copyright (C) 2000 - 2003, 2023 - 2024 Daniel Spiljar
# #
# Mboxgrep is free software; you can redistribute it and/or modify it # Mboxgrep is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by # under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@
# Process this file with autoconf to produce a configure script. # Process this file with autoconf to produce a configure script.
# Yawn. # Yawn.
AC_INIT([mboxgrep], [0.7.12a], [dspiljar@datatipp.se], [mboxgrep], [https://www.mboxgrep.org/]) AC_INIT([mboxgrep], [0.7.13], [dspiljar@datatipp.se], [mboxgrep], [https://www.mboxgrep.org/])
#AM_INIT_AUTOMAKE #AM_INIT_AUTOMAKE
AM_INIT_AUTOMAKE([foreign]) AM_INIT_AUTOMAKE([foreign])
AC_LANG([C]) AC_LANG([C])

View File

@@ -1,4 +1,4 @@
.TH MBOXGREP 1 "21 May 2023" .TH MBOXGREP 1 "23 September 2024"
.SH NAME .SH NAME
mboxgrep \- displays email messages matching a pattern mboxgrep \- displays email messages matching a pattern
.SH SYNOPSIS .SH SYNOPSIS
@@ -10,7 +10,7 @@ mboxgrep \- displays email messages matching a pattern
This manual page refers to This manual page refers to
.B mboxgrep .B mboxgrep
version version
.BR 0.7.12a . .BR 0.7.13 .
.PP .PP
.B mboxgrep .B mboxgrep
scans a scans a
@@ -97,10 +97,26 @@ Search $MAIL for messages from Dirty Harry:
mboxgrep '^From:.*callahan@sanfranciscopolice\\.org' $MAIL mboxgrep '^From:.*callahan@sanfranciscopolice\\.org' $MAIL
.TP .TP
\(bu \(bu
Re-mail to George messages that mention his name:
.PP
mboxgrep --pipe="/usr/lib/sendmail george" --ignore-case george ~/Mail/*
.TP
\(bu
Display all messages contained in folder ~/Mail/incoming, except those Display all messages contained in folder ~/Mail/incoming, except those
that appear to originate from AOL: that appear to originate from AOL:
.PP .PP
mboxgrep -v 'Received:.*aol\\.com' ~/Mail/incoming mboxgrep -v 'Received:.*aol\\.com' ~/Mail/incoming
.TP
\(bu
Do a case-insensitive scan of ~/Mail/incoming for messages with subject
``Weekly News'' and write them to folder ~/Mail/archive:
.PP
mboxgrep -o ~/Mail/archive -H -i '^Subject: Weekly News' ~/Mail/incoming
.TP
\(bu
Count all messages stored in folder spam, ignoring duplicates:
.PP
mboxgrep -nd -c . spam
.SH BUGS .SH BUGS
Report them to address below. Report them to address below.
.SH SEE ALSO .SH SEE ALSO
@@ -108,7 +124,8 @@ grep(1),
regex(7), regex(7),
perlre(1), perlre(1),
mbox(5), mbox(5),
RFC 2822 RFC 2822,
RFC 4155
.SH DEDICATION .SH DEDICATION
Mboxgrep is dedicated in loving memory of Vicky, my cat who died of Mboxgrep is dedicated in loving memory of Vicky, my cat who died of
tumor on Sep 12, 2002. tumor on Sep 12, 2002.
@@ -116,7 +133,11 @@ tumor on Sep 12, 2002.
You haven't been long with us, but you gave us a lot of joy and all your You haven't been long with us, but you gave us a lot of joy and all your
big heart that stopped ticking too early. I will never forget you. Sleep big heart that stopped ticking too early. I will never forget you. Sleep
well, little friend. well, little friend.
.SH URL .SH HOMEPAGE
http://www.mboxgrep.org/ https://www.mboxgrep.org/
.SH GIT
https://git.datatipp.se/dspiljar/mboxgrep
.PP
https://github.com/dspiljar/mboxgrep
.SH AUTHOR .SH AUTHOR
Daniel Spiljar <dspiljar AT datatipp.se> Daniel Spiljar <dspiljar@datatipp.se>

View File

@@ -9,10 +9,10 @@ END-INFO-DIR-ENTRY
 
File: mboxgrep.info, Node: Top, Up: (dir) File: mboxgrep.info, Node: Top, Up: (dir)
This file documents 'mboxgrep' (version 0.7.12a), a mailbox scanning This file documents 'mboxgrep' (version 0.7.13), a mailbox scanning
utility. utility.
Copyright (C) 2000, 2001, 2002, 2003 Daniel Spiljar Copyright (C) 2000 - 2003, 2024 Daniel Spiljar
* Menu: * Menu:
@@ -250,17 +250,17 @@ Sleep well, little friend.
 
Tag Table: Tag Table:
Node: Top197 Node: Top197
Node: Introduction597 Node: Introduction591
Node: Invoking1466 Node: Invoking1460
Node: Miscellaneous1828 Node: Miscellaneous1822
Node: File locking2113 Node: File locking2107
Node: Regexp selection2750 Node: Regexp selection2744
Node: Output control3302 Node: Output control3296
Node: Search scope selection4342 Node: Search scope selection4336
Node: Mailbox type selection4583 Node: Mailbox type selection4577
Node: Examples4904 Node: Examples4898
Node: Bugs5728 Node: Bugs5722
Node: To Vicky6146 Node: To Vicky6140
 
End Tag Table End Tag Table

View File

@@ -5,8 +5,8 @@
@setchapternewpage odd @setchapternewpage odd
@set EDITION 0.7 @set EDITION 0.7
@set VERSION 0.7.12a @set VERSION 0.7.13
@set UPDATED 21 May 2023 @set UPDATED 23 September 2024
@dircategory Mail @dircategory Mail
@direntry @direntry
@@ -19,7 +19,7 @@
This file documents @code{mboxgrep} (version @value{VERSION}), a This file documents @code{mboxgrep} (version @value{VERSION}), a
mailbox scanning utility. mailbox scanning utility.
Copyright (C) 2000, 2001, 2002, 2003 Daniel Spiljar Copyright (C) 2000 - 2003, 2024 Daniel Spiljar
@end ifinfo @end ifinfo
@menu @menu

View File

@@ -1,6 +1,6 @@
/* /*
mboxgrep - scan mailbox for messages matching a regular expression mboxgrep - scan mailbox for messages matching a regular expression
Copyright (C) 2000 - 2004, 2006, 2023 Daniel Spiljar Copyright (C) 2000 - 2004, 2006, 2023 - 2024 Daniel Spiljar
Mboxgrep is free software; you can redistribute it and/or modify it Mboxgrep is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@@ -117,7 +117,7 @@ main (int argc, char **argv)
if (config.action == ACTION_DELETE) if (config.action == ACTION_DELETE)
{ {
tmpmbox_create (argv[optind]); tmpmbox_create (argv[optind]);
runtime.tmp_mbox = (mbox_t *) mbox_open (config.tmpfilename, "w"); runtime.tmp_mbox = (mbox_t *) mbox_open (config.tmpfilename, w);
} }
config.boxname = xstrdup (argv[optind]); config.boxname = xstrdup (argv[optind]);

View File

@@ -1,6 +1,6 @@
/* /*
mboxgrep - scan mailbox for messages matching a regular expression mboxgrep - scan mailbox for messages matching a regular expression
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006, 2023 Daniel Spiljar Copyright (C) 2000 - 2004, 2006, 2023 - 2024 Daniel Spiljar
Mboxgrep is free software; you can redistribute it and/or modify it Mboxgrep is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@@ -50,166 +50,47 @@
#endif /* HAVE_LIBDMALLOC */ #endif /* HAVE_LIBDMALLOC */
mbox_t * mbox_t *
mbox_open (const char *path, const char *mode) mbox_open (const char *path, const mbox_mode_t mbox_mode)
{ {
mbox_t *mp; mbox_t *mp;
static int fd; static int fd;
#ifndef HAVE_FLOCK #ifndef HAVE_FLOCK
struct flock lck; struct flock lck;
#endif /* HAVE_FLOCK */ #endif /* HAVE_FLOCK */
char buffer[BUFSIZ];
mp = (mbox_t *) xmalloc (sizeof (mbox_t)); mp = (mbox_t *) xmalloc (sizeof (mbox_t));
mp->postmark_cache = (char *) xmalloc (BUFSIZ * sizeof (char)); mp->postmark_cache = NULL;
if (0 == strcmp ("-", path)) if (0 == strcmp ("-", path))
mp->fp = stdin; mp->fp = stdin;
else else
{ {
if (mode[0] == 'r') if (mbox_mode == w)
fd = m_open (path, O_RDONLY, 0);
else if (mode[0] == 'w')
fd = m_open (path, (O_WRONLY | O_CREAT | O_APPEND), fd = m_open (path, (O_WRONLY | O_CREAT | O_APPEND),
(S_IWUSR | S_IRUSR)); (S_IWUSR | S_IRUSR));
else else
{ fd = m_open (path, O_RDONLY, 0);
fprintf (stderr, "%s: mbox.c: Unknown mode %c. You shouldn't "
"get this error...", APPNAME, mode[0]);
exit (2);
}
if (fd == -1) if (fd == -1)
{ {
if (config.merr)
{
fprintf (stderr, "%s: %s: ", APPNAME, path);
perror (NULL);
}
errno = 0; errno = 0;
return NULL; return NULL;
} }
if (config.lock > LOCK_NONE) if (config.lock > LOCK_NONE)
{ mbox_lock (fd, path, mbox_mode);
#ifdef HAVE_FLOCK
int op;
if (mode[0] == 'r') mp->fp = mbox_fdopen (fd, path, mbox_mode);
op = LOCK_SH;
else
op = LOCK_EX;
if (-1 == flock (fd, op))
#else
memset (&lck, 0, sizeof (struct flock));
lck.l_whence = SEEK_SET;
if (mode[0] == 'r')
lck.l_type = F_RDLCK;
else
lck.l_type = F_WRLCK;
if (-1 == fcntl (fd, F_SETLK, &lck))
#endif /* HAVE_FLOCK */
{
if (config.merr)
{
fprintf (stderr, "%s: %s: ", APPNAME, path);
perror (NULL);
}
errno = 0;
close (fd);
return NULL;
}
}
if (mode[0] == 'r')
{
if (config.format == FORMAT_MBOX)
mp->fp = (FILE *) m_fdopen (fd, "r");
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
mp->fp = (gzFile *) m_gzdopen (fd, "rb");
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
mp->fp = (BZFILE *) BZ2_bzdopen (fd, "rb");
#endif /* HAVE_LIBBZ2 */
}
else if (mode[0] == 'w')
{
if (config.format == FORMAT_MBOX)
mp->fp = (FILE *) m_fdopen (fd, "w");
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
mp->fp = (gzFile *) m_gzdopen (fd, "wb");
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
mp->fp = (BZFILE *) BZ2_bzdopen (fd, "wb");
#endif /* HAVE_LIBBZ2 */
}
if (mp->fp == NULL)
{
if (config.merr)
{
fprintf (stderr, "%s: %s: ", APPNAME, path);
perror (NULL);
}
errno = 0;
close (fd);
return NULL;
}
} }
if (mode[0] == 'r') if (mbox_mode == r)
{ {
if (config.format == FORMAT_MBOX) mp->postmark_cache = mbox_check_postmark (mp, path);
fgets (buffer, BUFSIZ, mp->fp);
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
gzgets (mp->fp, buffer, BUFSIZ);
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
{
char c[1] = "\0";
int n = 0;
while (c[0] != '\n' && n < BUFSIZ) if (! mp->postmark_cache)
{ return NULL;
BZ2_bzread (mp->fp, c, 1);
buffer[n] = c[0];
n++;
}
buffer[n] = '\0';
}
#endif /* HAVE_LIBBZ2 */
if (0 != strncmp ("From ", buffer, 5))
{
if (config.merr)
{
if (0 == strcmp ("-", path))
fprintf (stderr, "%s: (standard input): Not a mbox folder\n",
APPNAME);
else
fprintf (stderr, "%s: %s: Not a mbox folder\n", APPNAME,
path);
}
if (config.format == FORMAT_MBOX)
fclose (mp->fp);
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
gzclose (mp->fp);
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
BZ2_bzclose (mp->fp);
#endif /* HAVE_LIBBZ2 */
return NULL;
}
strcpy (mp->postmark_cache, buffer);
} }
return mp; return mp;
} }
@@ -431,3 +312,127 @@ tmpfile_create (void)
} }
return fd; return fd;
} }
void
mbox_lock (int fd, const char *path, const mbox_mode_t mbox_mode)
{
#ifdef HAVE_FLOCK
int op;
if (mbox_mode == r)
op = LOCK_SH;
else
op = LOCK_EX;
if (-1 == flock (fd, op))
#else
memset (&lck, 0, sizeof (struct flock));
lck.l_whence = SEEK_SET;
if (mode[0] == 'r')
lck.l_type = F_RDLCK;
else
lck.l_type = F_WRLCK;
if (-1 == fcntl (fd, F_SETLK, &lck))
#endif /* HAVE_FLOCK */
{
if (config.merr)
{
fprintf (stderr, "%s: %s: ", APPNAME, path);
perror (NULL);
exit (2);
}
}
}
void *
mbox_fdopen (int fd, const char *path, const mbox_mode_t mbox_mode)
{
void *f;
char *file_mode;
if (mbox_mode == w)
file_mode = xstrdup("wb");
else
file_mode = xstrdup("rb");
if (config.format == FORMAT_MBOX)
f = (FILE *) m_fdopen (fd, file_mode);
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
f = (gzFile *) m_gzdopen (fd, file_mode);
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
f = (BZFILE *) BZ2_bzdopen (fd, file_mode);
#endif /* HAVE_LIBBZ2 */
if (f == NULL)
{
if (config.merr)
{
fprintf (stderr, "%s: %s: ", APPNAME, path);
perror (NULL);
}
errno = 0;
close (fd);
return NULL;
}
return f;
}
char *
mbox_check_postmark(mbox_t *mp, const char *path)
{
char *buffer;
buffer = (char *) xmalloc (BUFSIZ * sizeof (char));
memset (buffer, 0, BUFSIZ);
if (config.format == FORMAT_MBOX)
fgets (buffer, BUFSIZ, mp->fp);
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
gzgets (mp->fp, buffer, BUFSIZ);
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
{
char c[1] = "\0";
int n = 0;
while (c[0] != '\n' && n < BUFSIZ)
{
BZ2_bzread (mp->fp, c, 1);
buffer[n] = c[0];
n++;
}
buffer[n] = '\0';
}
#endif /* HAVE_LIBBZ2 */
if (0 != strncmp ("From ", buffer, 5))
{
if ((config.merr) && (buffer[0] != '\0'))
{
if (0 == strcmp ("-", path))
fprintf (stderr, "%s: (standard input): Not an mbox folder\n",
APPNAME);
else
fprintf (stderr, "%s: %s: Not an mbox folder\n", APPNAME,
path);
}
if (config.format == FORMAT_MBOX)
fclose (mp->fp);
#ifdef HAVE_LIBZ
else if (config.format == FORMAT_ZMBOX)
gzclose (mp->fp);
#endif /* HAVE_LIBZ */
#ifdef HAVE_LIBBZ2
else if (config.format == FORMAT_BZ2MBOX)
BZ2_bzclose (mp->fp);
#endif /* HAVE_LIBBZ2 */
return NULL;
}
return buffer;
}

View File

@@ -1,6 +1,6 @@
/* /*
mboxgrep - scan mailbox for messages matching a regular expression mboxgrep - scan mailbox for messages matching a regular expression
Copyright (C) 2000 - 2004, 2023 Daniel Spiljar Copyright (C) 2000 - 2004, 2023 - 2024 Daniel Spiljar
Mboxgrep is free software; you can redistribute it and/or modify it Mboxgrep is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@@ -19,9 +19,7 @@
#ifndef MBOX_H #ifndef MBOX_H
# define MBOX_H 1 # define MBOX_H 1
# include <config.h> # include <config.h>
# include "message.h" # include "message.h"
typedef struct typedef struct
@@ -31,8 +29,14 @@ typedef struct
char *postmark_cache; char *postmark_cache;
} mbox_t; } mbox_t;
typedef enum
{
r,
w,
} mbox_mode_t;
mbox_t *mbox_open (const char *path, const char *mode);
mbox_t *mbox_open (const char *path, const mbox_mode_t mbox_mode);
void tmpmbox_create (const char *path); void tmpmbox_create (const char *path);
void tmpfile_name (const char *path); void tmpfile_name (const char *path);
void tmpfile_mod_own (const int fd, const char *path); void tmpfile_mod_own (const int fd, const char *path);
@@ -40,5 +44,8 @@ int tmpfile_create (void);
void mbox_close (mbox_t * mbp); void mbox_close (mbox_t * mbp);
message_t *mbox_read_message (mbox_t * mp); message_t *mbox_read_message (mbox_t * mp);
void mbox_write_message (message_t * m, mbox_t * mbox); void mbox_write_message (message_t * m, mbox_t * mbox);
void mbox_lock (int fd, const char *path, const mbox_mode_t mbox_mode);
void *mbox_fdopen (int fd, const char *path, const mbox_mode_t mbox_mode);
char *mbox_check_postmark(mbox_t *mp, const char *path);
#endif /* MBOX_H */ #endif /* MBOX_H */

View File

@@ -1,6 +1,6 @@
/* /*
mboxgrep - scan mailbox for messages matching a regular expression mboxgrep - scan mailbox for messages matching a regular expression
Copyright (C) 2000 - 2003, 2006, 2023 Daniel Spiljar Copyright (C) 2000 - 2003, 2006, 2023 - 2024 Daniel Spiljar
Mboxgrep is free software; you can redistribute it and/or modify it Mboxgrep is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@@ -21,8 +21,8 @@
#define MBOXGREP_H #define MBOXGREP_H
#define APPNAME "mboxgrep" #define APPNAME "mboxgrep"
#define VERSION "0.7.12a" #define VERSION "0.7.13"
#define BUGREPORT_ADDR "dspiljar AT datatipp.se" #define BUGREPORT_ADDR "dspiljar@datatipp.se"
#define HOST_NAME_SIZE 256 #define HOST_NAME_SIZE 256

View File

@@ -1,6 +1,6 @@
/* /*
mboxgrep - scan mailbox for messages matching a regular expression mboxgrep - scan mailbox for messages matching a regular expression
Copyright (C) 2000 - 2004, 2006, 2023 Daniel Spiljar Copyright (C) 2000 - 2004, 2006, 2023 - 2024 Daniel Spiljar
Mboxgrep is free software; you can redistribute it and/or modify it Mboxgrep is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by under the terms of the GNU General Public License as published by
@@ -107,7 +107,7 @@ scan_mailbox (char path[])
if ((config.format == FORMAT_MBOX) || (config.format == FORMAT_ZMBOX) if ((config.format == FORMAT_MBOX) || (config.format == FORMAT_ZMBOX)
|| (config.format == FORMAT_BZ2MBOX)) || (config.format == FORMAT_BZ2MBOX))
{ {
mbox = (mbox_t *) mbox_open (path, "r"); mbox = (mbox_t *) mbox_open (path, r);
if (mbox == NULL) if (mbox == NULL)
return; return;
} }
@@ -179,7 +179,7 @@ scan_mailbox (char path[])
else if ((config.format == FORMAT_MBOX) || (config.format == FORMAT_ZMBOX) else if ((config.format == FORMAT_MBOX) || (config.format == FORMAT_ZMBOX)
|| (config.format == FORMAT_BZ2MBOX)) || (config.format == FORMAT_BZ2MBOX))
{ {
out = mbox_open (config.outboxname, "w"); out = mbox_open (config.outboxname, w);
/* fprintf (out->fp, "%s\n%s", msg->headers, msg->body); */ /* fprintf (out->fp, "%s\n%s", msg->headers, msg->body); */
mbox_write_message (msg, out); mbox_write_message (msg, out);
mbox_close (out); mbox_close (out);