Commit 020839e9 020839e928fe761ea76b0b41389e8de50d57a6e2 by Alain Magloire

Sergey Poznyakoff pointed out that errno change depending

if _REENTRANT is set or not.  So for enable thread we take
the approach of always defining _REENTRANT.
He also noted that when in standalone the child was not exiting.
1 parent 2b99aa95
2001-04-23 Alain Magloire
Sergey Poznyakoff pointed out that errno change depending
if _REENTRANT is set or not. So for enable thread we take
the approach of always defining _REENTRANT.
He also noted that when in standalone the child was not exiting.
* acconfig.h: Define _REENTRANT.
* configure.in: Check for sigaction().
* configuire.in: AC_DEFINE(_REENTRANT).
* doc/Makefile.am: add rfc2060-errata.
* doc/rfc2060-errata: New File.
* imap4d/copy.c: First Implementation.
* imap4d/status.c: First implementation.
* mailbox/file_stream.c (_file_open): For CREAT, close
the fd if we failed.
* mailbox/folder_imap.c: Remove the _REENTRANT.
* mailbox/mbx_mbox.c: Remove the _REENTRANT.
* mailbox/monitor.c: Remove the _REENTRANT.
* pop3d/pop3d.c (main): maxchildren boosted to 20.
(pop3_daemon_init): Use sigaction() for SIGCHLD,
the sematics of signal() is unreliable on some platforms.
* pop3d/signal.c: Save errno.
2001-04-22 Alain Magloire
* imap4d/create.c: First implementation.
......
......@@ -8,3 +8,4 @@ of errors.
Frank Belew <frb@wiw.org>
Vesselin Atanasov <vesselin@bgnet.bg>
Sergey Poznyakoff <gray@Mirddin.farlep.net>
......
......@@ -29,3 +29,6 @@
/* Define if using libreadline */
#undef WITH_READLINE
/* Define _REENTRANT when using threads. */
#undef _REENTRANT
......
......@@ -71,7 +71,7 @@ if test "$ac_cv_func_fnmatch_works" = "no"; then
: LIBOBJS="$LIBOBJS fnmatch.o"
fi
AC_REPLACE_FUNCS(setenv snprintf strtok_r strncasecmp strcasecmp vasprintf)
AC_CHECK_FUNCS(mkstemp)
AC_CHECK_FUNCS(mkstemp sigaction)
dnl Check for libraries
AC_CHECK_FUNCS(argp_parse)
......@@ -104,15 +104,19 @@ if test x"$ac_cv_have_libpam" != x"yes"; then
fi
AC_SUBST(AUTHLIBS)
#When using thread support some platforms need -D_REENTRANT to get the
#right prototypes including errno.
dnl Check threading support
if test x"$usepthread" = x"yes"; then
AC_CHECK_LIB(pthread, pthread_cancel, [AC_CHECK_HEADERS(pthread.h,
AC_DEFINE(WITH_PTHREAD))
LIBS="$LIBS -lpthread"
AC_DEFINE(_REENTRANT)
AC_CHECK_FUNCS(pthread_rwlock_init)],
AC_SEARCH_LIBS(pthread_cancel, pthread,
[AC_CHECK_FUNCS(pthread_rwlock_init)
AC_CHECK_HEADERS(pthread.h, AC_DEFINE(WITH_PTHREAD))]))
AC_CHECK_HEADERS(pthread.h, AC_DEFINE(WITH_PTHREAD))
ACDEFINE(_REENTRANT)]))
fi
dnl Do we need extra libs for networking?
......
......@@ -6,6 +6,7 @@ EXTRA_DIST = \
rfc1939.txt \
rfc1957.txt \
rfc2060.txt \
rfc2060-errata \
rfc2449.txt \
address.texi \
attribute.texi \
......
Known errors in RFC 2060 as of 13 September 1998:
1) The SELECT and EXAMINE response list does not mention UIDVALIDITY.
2) In the definition of store_att_flags, #flag should be 1#flag; in other
words, at least one flag must be given. To do an empty list of flags,
you must use the parenthesized form: "()".
3) The example in 6.4.6 is missing parenthesis around the FETCH attributes.
It should read:
Example: C: A003 STORE 2:4 +FLAGS (\Deleted)
S: * 2 FETCH (FLAGS (\Deleted \Seen))
S: * 3 FETCH (FLAGS (\Deleted))
S: * 4 FETCH (FLAGS (\Deleted \Flagged \Seen))
S: A003 OK STORE completed
4) Section 7.4.2 has an example of "a two part message consisting of a
text and a BASE645-encoded text attachment". "BASE645" should be
BASE64.
5) In the example in 7.4.2 discussed above, there is a spurious close
parenthesis at the end of the example.
6) Spurious obsolete response "MAILBOX" is listed in mailbox_data and
should be removed.
7) There is a spurious "<" in the mailbox_data rule that should be removed.
8) CRLF is missing from the continue_req rule.
9) The atom in resp_text_code should specifically exclude "]".
10) The example in 6.3.11 does not show the command continuation request.
11) NEWNAME is missing from resp_text_code.
12) There is a missing open parenthesis in the media_basic grammar rule.
13) Status attributes are incorrectly defined in mailbox_data rule.
14) The UID FETCH example is missing an "OK" in the response.
15) Multipart extension data incorrectly specifies that language must be
given along with disposition.
......@@ -26,6 +26,7 @@
int
imap4d_check (struct imap4d_command *command, char *arg)
{
(void)arg;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_OK, "Completed");
......
......@@ -23,12 +23,16 @@
int
imap4d_close (struct imap4d_command *command, char *arg)
{
/* FIXME: Check args. */
/* FIXME: Check state and if they selected. */
(void)arg;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
/* FIXME: Check and report errors. */
/* The CLOSE command permanently removes form the currentyl selected
mailbox all messages that have the \\Deleted falg set, and returns
to authenticated state from selected state. */
mailbox_expunge (mbox);
/* No messages are removed, and no error is give, if the mailbox is
selected by an EXAMINE command or is otherwise selected read-only. */
mailbox_close (mbox);
mailbox_destroy (&mbox);
return util_finish (command, RESP_OK, "Completed");
......
......@@ -21,10 +21,77 @@
* copy messages in argv[2] to mailbox in argv[3]
*/
/* FIXME if the mailbox is the one selecte we should send notif. */
int
imap4d_copy (struct imap4d_command *command, char *arg)
{
int status;
char *msgset;
char *name;
char *mailbox_name;
const char *delim = "/";
char *sp = NULL;
int *set = NULL;
size_t n = 0;
mailbox_t cmbox = NULL;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
return util_finish (command, RESP_NO, "Command not supported");
msgset = util_getword (arg, &sp);
name = util_getword (NULL, &sp);
util_unquote (&name);
if (!msgset || !name || *name == '\0')
return util_finish (command, RESP_BAD, "Too few args");
/* Get the message numbers in set[]. */
status = util_msgset (msgset, &set, &n, 0);
if (status != 0)
return util_finish (command, RESP_BAD, "Bogus number set");
if (strcasecmp (name, "INBOX") == 0)
{
struct passwd *pw = getpwuid (getuid());
mailbox_name = strdup ((pw) ? pw->pw_name : "");
}
else
mailbox_name = util_getfullpath (name, delim);
/* If the destination mailbox does not exist, a server should return
an error. */
status = mailbox_create_default (&cmbox, mailbox_name);
if (status == 0)
{
/* It SHOULD NOT automatifcllly create the mailbox. */
status = mailbox_open (cmbox, MU_STREAM_RDWR);
if (status == 0)
{
size_t i;
for (i = 0; i < n; i++)
{
message_t msg = NULL;
mailbox_get_message (mbox, set[i], &msg);
mailbox_append_message (cmbox, msg);
}
mailbox_close (cmbox);
}
mailbox_destroy (&cmbox);
}
free (set);
free (mailbox_name);
if (status == 0)
return util_finish (command, RESP_OK, "Completed");
/* Since we do not call util_finish, reset the state ourself. */
if (command->failure != STATE_NONE)
state = command->failure;
/* Unless it is certain that the destination mailbix can not be created,
the server MUST send the response code "[TRYCREATE]" as the prefix
of the text of the tagged NO response. This gives a hint to the
client that it can attempt a CREATE command and retry the copy if
the CREATE is successful. */
return util_send ("%s NO [TRYCREATE] failed\r\n", command->tag);
}
......
......@@ -19,9 +19,13 @@
#include <unistd.h>
/*
* must create a new mailbox
* Must create a new mailbox
*/
/* FIXME: How do we do this ??????:
IF a new mailbox is created with the same name as a mailbox which was
deleted, its unique identifiers MUST be greater than any unique identifiers
used in the previous incarnation of the mailbox. */
int
imap4d_create (struct imap4d_command *command, char *arg)
{
......@@ -50,11 +54,15 @@ imap4d_create (struct imap4d_command *command, char *arg)
/* Allocates memory. */
name = util_getfullpath (name, delim);
/* It will fail if the mailbx already exists. */
/* It will fail if the mailbox already exists. */
if (access (name, F_OK) != 0)
{
char *dir;
char *d = name + strlen (delim); /* Pass the root delimeter. */
/*If the server's hierarchy separtor character appears elsewhere in
name, the server SHOULD create any superior hierarchcal names
that are needed for the CREATE command to complete successfully. */
if (chdir (delim) == 0) /* start on the root. */
for (; (dir = strchr (d, delim[0])); d = dir)
{
......@@ -76,7 +84,11 @@ imap4d_create (struct imap4d_command *command, char *arg)
}
}
}
/* If it ended with the delim they wanted to create a new folder. */
/* If the mailbox name is suffixed with the server's hierarchy
separator character, this is a declaration that the client intends
to create mailbox names under this name in the hierarchy.
In other words is d == '\0' it is not an error. */
if (rc == RESP_OK && d && *d != '\0')
{
int fd = creat (d, 0600);
......
......@@ -34,17 +34,14 @@ imap4d_delete (struct imap4d_command *command, char *arg)
return util_finish (command, RESP_BAD, "Wrong state");
name = util_getword (arg, &sp);
if (!name)
return util_finish (command, RESP_BAD, "Too few arguments");
util_unquote (&name);
if (*name == '\0')
if (!name || *name == '\0')
return util_finish (command, RESP_BAD, "Too few arguments");
/* Deleting, "Inbox" should always fail. */
/* It is an error to attempt to delele "INBOX or a mailbox
name that dos not exists. */
if (strcasecmp (name, "INBOX") == 0)
return util_finish (command, RESP_BAD, "Already exist");
return util_finish (command, RESP_NO, "Already exist");
/* Allocates memory. */
name = util_getfullpath (name, delim);
......
......@@ -110,10 +110,7 @@ imap4d_fetch (struct imap4d_command *command, char *arg)
return util_finish (command, RESP_BAD, "Wrong state");
msgset = util_getword (arg, &sp);
if (!msgset)
return util_finish (command, RESP_BAD, "Too few args");
if (sp == NULL || *sp == '\0')
if (!msgset || !sp || *sp == '\0')
return util_finish (command, RESP_BAD, "Too few args");
/* Get the message numbers in set[]. */
......
......@@ -31,8 +31,15 @@ imap4d_logout (struct imap4d_command *command, char *arg)
return util_finish (command, RESP_BAD, "Too many args");
util_out (RESP_BYE, "Logging out");
util_finish (command, RESP_OK, "Completed");
mailbox_close (mbox);
mailbox_destroy (&mbox);
/* Even if a mailbox is slected, a SLECT EXAMINE or LOGOUT
command MAY be issued without previously issuing a CLOSE command.
The SELECT, EXAMINE, and LOGUT commands implictly close the
currently selected mailbox withut doing an expunge. */
if (mbox)
{
mailbox_close (mbox);
mailbox_destroy (&mbox);
}
util_quit (0);
return 0;
}
......
......@@ -42,6 +42,10 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
if (util_getword (NULL, &sp))
return util_finish (command, RESP_BAD, "Too many arguments");
/* Even if a mailbox is slected, a SLECT EXAMINE or LOGOUT
command MAY be issued without previously issuing a CLOSE command.
The SELECT, EXAMINE, and LOGUT commands implictly close the
currently selected mailbox withut doing an expunge. */
if (mbox)
{
mailbox_close (mbox);
......
......@@ -21,17 +21,137 @@
*
*/
static int status_messages __P ((mailbox_t));
static int status_recent __P ((mailbox_t));
static int status_uidnext __P ((mailbox_t));
static int status_uidvalidity __P ((mailbox_t));
static int status_unseen __P ((mailbox_t));
int
imap4d_status (struct imap4d_command *command, char *arg)
{
char *sp = NULL;
char *name;
char *mailbox_name;
char *data;
const char *delim = "/";
mailbox_t smbox = NULL;
int status;
if (! (command->states & state))
return util_finish (command, RESP_BAD, "Wrong state");
mailbox_name = util_getword (arg, &sp);
data = util_getword (NULL, &sp);
if (!mailbox_name || !data)
name = util_getword (arg, &sp);
if (!name || !sp)
return util_finish (command, RESP_BAD, "Too few args");
return util_finish (command, RESP_BAD, "Not supported");
util_unquote (&name);
if (*name == '\0' || *sp == '\0')
return util_finish (command, RESP_BAD, "Too few args");
if (strcasecmp (name, "INBOX") == 0)
{
struct passwd *pw = getpwuid (getuid());
mailbox_name = strdup ((pw) ? pw->pw_name : "");
}
else
mailbox_name = util_getfullpath (name, delim);
status = mailbox_create_default (&smbox, mailbox_name);
if (status == 0)
{
status = mailbox_open (smbox, MU_STREAM_READ);
if (status == 0)
{
char item[32];
util_send ("* STATUS %s (", name);
item[0] = '\0';
/* Get the status item names. */
while (*sp && *sp != ')')
{
int err = 1;
util_token (item, sizeof (item), &sp);
if (strcasecmp (item, "MESSAGES") == 0)
err = status_messages (smbox);
else if (strcasecmp (item, "RECENT") == 0)
err = status_recent (smbox);
else if (strcasecmp (item, "UIDNEXT") == 0)
err = status_uidnext (smbox);
else if (strcasecmp (item, "UIDVALIDITY") == 0)
err = status_uidvalidity (smbox);
else if (strcasecmp (item, "UNSEEN") == 0)
err = status_unseen (smbox);
if (!err)
util_send (" ");
}
util_send (")\r\n");
mailbox_close (smbox);
}
mailbox_destroy (&smbox);
}
free (mailbox_name);
if (status == 0)
return util_finish (command, RESP_OK, "Completed");
return util_finish (command, RESP_NO, "Error opening mailbox");
}
static int
status_messages (mailbox_t smbox)
{
size_t total = 0;
mailbox_messages_count (smbox, &total);
util_send ("MESSAGES %u", total);
return 0;
}
static int
status_recent (mailbox_t smbox)
{
size_t recent = 0;
mailbox_messages_recent (smbox, &recent);
util_send ("RECENT %u", recent);
return 0;
}
static int
status_uidnext (mailbox_t smbox)
{
size_t uidnext = 1;
mailbox_uidnext (smbox, &uidnext);
util_send ("UIDNEXT %u", uidnext);
return 0;
}
static int
status_uidvalidity (mailbox_t smbox)
{
unsigned long uidvalidity = 0;
mailbox_uidvalidity (smbox, &uidvalidity);
util_send ("UIDVALIDITY %u", uidvalidity);
return 0;
}
/* Note that unlike the unseen response code, which indicates the message
number of the first unseen message, the unseeen item in the response the
status command indicates the quantity of unseen messages. */
static int
status_unseen (mailbox_t smbox)
{
size_t total = 0;
size_t unseen = 0;
size_t i;
mailbox_messages_count (smbox, &total);
for (i = 1; i <= total; i++)
{
message_t msg = NULL;
attribute_t attr = NULL;
mailbox_get_message (smbox, i, &msg);
message_get_attribute (msg, &attr);
if (!attribute_is_seen (attr))
unseen++;
}
util_send ("UNSEEN %d", unseen);
return 0;
}
......
......@@ -87,7 +87,7 @@ void
util_unquote (char **ptr)
{
char *s = *ptr;
if (*s == '"')
if (s && *s == '"')
{
char *p = ++s;
while (*p && *p != '"')
......@@ -426,6 +426,8 @@ util_start (char *tag)
void
util_quit (int err)
{
if (err)
util_out (RESP_BYE, "Server terminating");
exit (err);
}
......
......@@ -260,14 +260,16 @@ _file_open (stream_t stream, const char *filename, int port, int flags)
/* Now check that: file and fd reference the same file,
file only has one link, file is plain file. */
if (fdbuf.st_dev != filebuf.st_dev ||
fdbuf.st_ino != filebuf.st_ino ||
fdbuf.st_nlink != 1 ||
filebuf.st_nlink != 1 ||
(fdbuf.st_mode & S_IFMT) != S_IFREG) {
fprintf(stderr,"%s must be a plain file with one link\n", filename);
return EINVAL;
}
if (fdbuf.st_dev != filebuf.st_dev
|| fdbuf.st_ino != filebuf.st_ino
|| fdbuf.st_nlink != 1
|| filebuf.st_nlink != 1
|| (fdbuf.st_mode & S_IFMT) != S_IFREG)
{
fprintf(stderr,"%s must be a plain file with one link\n", filename);
close (fd);
return EINVAL;
}
}
/* We use FILE * object. */
if (flags & MU_STREAM_APPEND)
......
......@@ -19,10 +19,6 @@
# include <config.h>
#endif
#ifdef WITH_PTHREAD
# define _REENTRANT
#endif
#include <stdlib.h>
#include <ctype.h>
#include <stdarg.h>
......
......@@ -22,7 +22,6 @@
#endif
#ifdef WITH_PTHREAD
# define _REENTRANT
# ifdef HAVE_PTHREAD_H
# define _XOPEN_SOURCE 500
# include <pthread.h>
......
......@@ -25,7 +25,6 @@
#endif
#ifdef WITH_PTHREAD
# define _REENTRANT
# ifdef HAVE_PTHREAD_H
# include <pthread.h>
# endif
......
......@@ -31,7 +31,7 @@ int ifile;
FILE *ofile;
time_t curr_time;
char *md5shared;
unsigned int children;
volatile unsigned int children;
/* Number of child processes. */
unsigned int children = 0;
......@@ -54,8 +54,9 @@ main (int argc, char **argv)
{
struct group *gr;
static int mode = INTERACTIVE;
size_t maxchildren = 10;
size_t maxchildren = 20;
int c = 0;
int status = OK;
port = 110; /* Default POP3 port. */
timeout = 0; /* Default timeout of 0. */
......@@ -148,14 +149,14 @@ main (int argc, char **argv)
/* Actually run the daemon. */
if (mode == DAEMON)
pop3_daemon (maxchildren);
pop3_daemon (maxchildren);
/* exit() -- no way out of daemon except a signal. */
else
pop3_mainloop (fileno (stdin), fileno (stdout));
status = pop3_mainloop (fileno (stdin), fileno (stdout));
/* Close the syslog connection and exit. */
closelog ();
return OK;
return (OK != status);
}
/* Sets things up for daemon mode. */
......@@ -183,7 +184,7 @@ pop3_daemon_init (void)
if (pid == -1)
{
perror("fork failed:");
exit (-1);
exit (1);
}
else if (pid > 0)
exit (0); /* Parent exits. */
......@@ -192,7 +193,17 @@ pop3_daemon_init (void)
for (i = 0; i < MAXFD; ++i)
close(i);
#ifdef HAVE_SIGACTION
{
struct sigaction act;
act.sa_handler = pop3_sigchld;
sigemptyset (&act.sa_mask);
act.sa_flags = 0;
sigaction (SIGCHLD, &act, NULL);
}
#else
signal (SIGCHLD, pop3_sigchld);
#endif
}
/* The main part of the daemon. This function reads input from the client and
......@@ -237,7 +248,6 @@ pop3_mainloop (int infile, int outfile)
(int)time (NULL), local_hostname);
free (local_hostname);
fflush (ofile);
fprintf (ofile, "+OK POP3 " WELCOME " %s\r\n", md5shared);
while (state != UPDATE)
......@@ -312,7 +322,7 @@ pop3_mainloop (int infile, int outfile)
}
fflush (ofile);
return OK;
return (status != OK);
}
/* Runs GNU POP3 in standalone daemon mode. This opens and binds to a port
......@@ -372,12 +382,15 @@ pop3_daemon (unsigned int maxchildren)
pid = fork ();
if (pid == -1)
syslog(LOG_ERR, "fork: %s", strerror(errno));
syslog(LOG_ERR, "fork: %s", strerror (errno));
else if (pid == 0) /* Child. */
{
int status;
close (listenfd);
/* syslog(); FIXME log the info on the connectiing client. */
pop3_mainloop (connfd, connfd);
/* syslog(); FIXME log the info on the connecting client. */
status = pop3_mainloop (connfd, connfd);
closelog ();
exit (status);
}
else
{
......
/* GNU copyright notice */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "pop3d.h"
......@@ -7,8 +23,11 @@ pop3_sigchld (int signo)
{
pid_t pid;
int status;
int old_errno = errno ;
(void)signo;
errno = 0;
while ( (pid = waitpid(-1, &status, WNOHANG)) > 0)
--children;
errno = old_errno;
}
......