Commit 5ec8063e 5ec8063eccd7552626991c977bcaa8574604009e by Alain Magloire

* mailbox/imap4d/fetch.c : First draft implementation, very yucky.

* mailbox/imap4d/select.c : First draft implementation.
* mailbox/imap4d/util.c : Add util_msgset() and util_send().
Reuse of util_getcommand() for subcommands.
1 parent 0412541c
......@@ -29,6 +29,7 @@
#endif
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
......@@ -121,14 +122,17 @@ int imap4d_uid __P ((struct imap4d_command *, char *));
/* Helper functions. */
int util_out __P ((int rc, const char *f, ...));
int util_send __P ((const char *f, ...));
int util_start __P ((char *tag));
int util_finish __P ((struct imap4d_command *, int rc, const char *f, ...));
int util_finish __P ((struct imap4d_command *, int sc, const char *f, ...));
int util_getstate __P ((void));
int util_do_command __P ((char *prompt));
char *imap4d_readline __P ((int fd));
void util_quit __P ((int));
char *util_getword __P ((char *s, char **save_ptr));
struct imap4d_command *util_getcommand __P ((char *cmd));
int util_msgset __P ((char *s, int **set, int *n, int isuid));
struct imap4d_command *util_getcommand __P ((char *cmd,
struct imap4d_command []));
#ifdef __cplusplus
}
......
......@@ -17,9 +17,7 @@
#include "imap4d.h"
/*
* argv[2] == mailbox
*/
/* select ::= "SELECT" SPACE mailbox */
int
imap4d_select (struct imap4d_command *command, char *arg)
......@@ -58,18 +56,32 @@ imap4d_select0 (struct imap4d_command *command, char *arg, int flags)
if (mailbox_create_default (&mbox, mailbox_name) == 0
&& mailbox_open (mbox, flags) == 0)
{
const char *sflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
int num = 0, recent = 0, uid = 0;
const char *mflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
const char *pflags = "\\Answered \\Flagged \\Deleted \\Seen \\Draft";
unsigned long uidvalidity = 0;
size_t count = 0, recent = 0, unseen = 0, uidnext = 0;
mailbox_messages_count (mbox, &num);
mailbox_recent_count (mbox, &recent);
util_out (RESP_NONE, "%d EXISTS", num);
mailbox_uidvalidity (mbox, &uidvalidity);
mailbox_uidnext (mbox, &uidnext);
mailbox_messages_count (mbox, &count);
mailbox_messages_recent (mbox, &recent);
mailbox_message_unseen (mbox, &unseen);
util_out (RESP_NONE, "%d EXISTS", count);
util_out (RESP_NONE, "%d RECENT", recent);
util_out (RESP_NONE, "FLAGS (%s)", sflags);
util_out (RESP_OK, "[UIDNEXT %d]", num + 1);
/*util_out (RESP_OK, "[UIDVALIDITY (%d)]", uid);*/
/*util_out (RESP_OK, "[PERMANENTFLAGS (%s)]", flags);*/
return util_finish (command, RESP_OK, "Complete");
util_out (RESP_NONE, "FLAGS (%s)", mflags);
util_out (RESP_OK, "[UIDNEXT %d] Predicted next uid", uidnext);
util_out (RESP_OK, "[UIDVALIDITY (%d)] UID valididy status",
uidvalidity);
if (unseen)
util_out (RESP_OK, "[UNSEEN (%d)] %d is first unseen messsage ",
unseen, unseen);
/* FIXME:
- '\*' can be supported if we use the attribute_set userflag()
- Answered is still not set in the mailbox code. */
util_out (RESP_OK, "[PERMANENTFLAGS (%s)]", pflags);
return util_send ("%s OK [%s] %s Complete\r\n", command->tag,
(MU_STREAM_READ == flags) ?
"READ-ONLY" : "READ-WRITE", command->name);
}
return util_finish (command, RESP_NO, "Couldn't open %s", mailbox_name);
}
......
......@@ -17,34 +17,144 @@
#include "imap4d.h"
static const char *
rc2string (int rc)
static int add2set (int **set, int *n, unsigned long val, size_t max);
static const char * sc2string (int rc);
/* FIXME: Some words are:
between double quotes, between parenthesis. */
char *
util_getword (char *s, char **save)
{
switch (rc)
return strtok_r (s, " \r\n", save);
}
/* Return in set an allocated array contain (n) numbers, for imap messsage set
set ::= sequence_num / (sequence_num ":" sequence_num) / (set "," set)
sequence_num ::= nz_number / "*"
;; * is the largest number in use. For message
;; sequence numbers, it is the number of messages
;; in the mailbox. For unique identifiers, it is
;; the unique identifier of the last message in
;; the mailbox.
nz_number ::= digit_nz *digit
FIXME: The algo below is to relaxe, things like <,,,> or <:12> or <20:10>
will not generate an error. */
int
util_msgset (char *s, int **set, int *n, int isuid)
{
unsigned long val = 0;
unsigned long low = 0;
int done = 0;
int status = 0;
size_t max = 0;
status = mailbox_messages_count (mbox, &max);
if (status != 0)
return status;
if (isuid)
{
case RESP_OK:
return "OK ";
message_t msg = NULL;
mailbox_get_message (mbox, max, &msg);
message_get_uid (msg, &max);
}
case RESP_BAD:
return "BAD ";
*n = 0;
*set = NULL;
while (*s)
{
switch (*s)
{
/* isdigit */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
{
errno = 0;
val = strtoul (s, &s, 10);
if (val == ULONG_MAX && errno == ERANGE)
{
if (*set)
free (*set);
*n = 0;
return EINVAL;
}
if (low)
{
for (;low && low <= val; low++)
{
status = add2set (set, n, low, max);
if (status != 0)
return status;
}
low = 0;
}
else
{
status = add2set(set, n, val, max);
if (status != 0)
return status;
}
break;
}
case RESP_NO:
return "NO ";
case ':':
low = val + 1;
s++;
break;
case RESP_BYE:
return "BYE ";
case '*':
{
if (status != 0)
{
if (*set)
free (*set);
*n = 0;
return status;
}
val = max;
s++;
break;
}
case ',':
s++;
break;
default:
done = 1;
if (*set)
free (*set);
*n = 0;
return EINVAL;
} /* switch */
if (done)
break;
} /* while */
if (low)
{
for (;low && low <= val; low++)
{
status = add2set (set, n, low, max);
if (status != 0)
return status;
}
}
return "";
return 0;
}
/* FIXME: Some words are:
between double quotes, consider like one word.
between parenthesis, consider line one word. */
char *
util_getword (char *s, char **save)
int
util_send (const char *format, ...)
{
static char *sp;
return strtok_r (s, " \r\n", ((save) ? save : &sp));
int status;
va_list ap;
va_start (ap, format);
status = vfprintf (ofile, format, ap);
va_end (ap);
return status;
}
int
......@@ -57,7 +167,7 @@ util_out (int rc, const char *format, ...)
vasprintf (&buf, format, ap);
va_end (ap);
fprintf (ofile, "* %s%s\r\n", rc2string (rc), buf);
fprintf (ofile, "* %s%s\r\n", sc2string (rc), buf);
free (buf);
return 0;
}
......@@ -73,7 +183,7 @@ util_finish (struct imap4d_command *command, int rc, const char *format, ...)
vasprintf (&buf, format, ap);
va_end(ap);
resp = rc2string (rc);
resp = sc2string (rc);
fprintf (ofile, "%s %s%s %s\r\n", command->tag, resp, command->name, buf);
free (buf);
return 0;
......@@ -86,6 +196,7 @@ imap4d_readline (int fd)
struct timeval tv;
char buf[512], *ret = NULL;
int nread;
int total = 0;
int available;
FD_ZERO (&rfds);
......@@ -99,35 +210,35 @@ imap4d_readline (int fd)
{
available = select (fd + 1, &rfds, NULL, NULL, &tv);
if (!available)
util_quit (1); /* FIXME: Timeout. */
util_quit (1); /* FIXME: Timeout, send a "* BYE". */
}
nread = read (fd, buf, sizeof (buf) - 1);
if (nread < 1)
util_quit (1); /* FIXME: dead socket */
util_quit (1); /* FIXME: dead socket, need to do something? */
buf[nread] = '\0';
ret = realloc (ret, (total + nread + 1) * sizeof (char));
if (ret == NULL)
{
ret = malloc ((nread + 1) * sizeof (char));
strcpy (ret, buf);
}
else
{
ret = realloc (ret, (strlen (ret) + nread + 1) * sizeof (char));
strcat (ret, buf);
}
util_quit (1); /* FIXME: ENOMEM, send a "* BYE" to the client. */
memcpy (ret + total, buf, nread + 1);
total += nread;
/* FIXME: handle literal strings here. */
}
while (strchr (buf, '\n') == NULL);
while (memchr (buf, '\n', nread) == NULL);
for (nread = total; nread > 0; nread--)
if (ret[nread] == '\r' || ret[nread] == '\n')
ret[nread] = '\0';
return ret;
}
int
util_do_command (char *prompt)
{
char *sp = NULL, *tag, *cmd, *arg;
char *sp = NULL, *tag, *cmd;
struct imap4d_command *command;
static struct imap4d_command nullcommand;
......@@ -148,7 +259,7 @@ util_do_command (char *prompt)
util_start (tag);
command = util_getcommand (cmd);
command = util_getcommand (cmd, imap4d_command_table);
if (command == NULL)
{
nullcommand.name = "";
......@@ -183,15 +294,54 @@ util_getstate (void)
}
struct imap4d_command *
util_getcommand (char *cmd)
util_getcommand (char *cmd, struct imap4d_command command_table[])
{
size_t i, len = strlen (cmd);
for (i = 0; imap4d_command_table[i].name != 0; i++)
for (i = 0; command_table[i].name != 0; i++)
{
if (strlen (imap4d_command_table[i].name) == len &&
!strcasecmp (imap4d_command_table[i].name, cmd))
return &imap4d_command_table[i];
if (strlen (command_table[i].name) == len &&
!strcasecmp (command_table[i].name, cmd))
return &command_table[i];
}
return NULL;
}
/* Status Code to String. */
static const char *
sc2string (int rc)
{
switch (rc)
{
case RESP_OK:
return "OK ";
case RESP_BAD:
return "BAD ";
case RESP_NO:
return "NO ";
case RESP_BYE:
return "BYE ";
}
return "";
}
static int
add2set (int **set, int *n, unsigned long val, size_t max)
{
int *tmp;
if (val == 0 || val > max
|| (tmp = realloc (*set, (*n + 1) * sizeof (**set))) == NULL)
{
if (*set)
free (*set);
*n = 0;
return ENOMEM;
}
*set = tmp;
(*set)[*n] = val;
(*n)++;
return 0;
}
......