/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2001, 2005 Free Software Foundation, Inc.
GNU Mailutils 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.
GNU Mailutils 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 GNU Mailutils; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301 USA */
#include "imap4d.h"
#include <ctype.h>
#include <mailutils/argcv.h>
/* This will suck, too.
Alain: Yes it does. */
/* Taken from RFC2060
fetch ::= "FETCH" SPACE set SPACE ("ALL" / "FULL" /
"FAST" / fetch_att / "(" 1#fetch_att ")")
fetch_att ::= "ENVELOPE" / "FLAGS" / "INTERNALDATE" /
"RFC822" [".HEADER" / ".SIZE" / ".TEXT"] /
"BODY" ["STRUCTURE"] / "UID" /
"BODY" [".PEEK"] section
["<" number "." nz_number ">"]
*/
struct fetch_command;
static int fetch_all (struct fetch_command *, char**);
static int fetch_full (struct fetch_command *, char**);
static int fetch_fast (struct fetch_command *, char**);
static int fetch_envelope (struct fetch_command *, char**);
static int fetch_flags (struct fetch_command *, char**);
static int fetch_internaldate (struct fetch_command *, char**);
static int fetch_rfc822_header (struct fetch_command *, char**);
static int fetch_rfc822_size (struct fetch_command *, char**);
static int fetch_rfc822_text (struct fetch_command *, char**);
static int fetch_rfc822 (struct fetch_command *, char**);
static int fetch_bodystructure (struct fetch_command *, char**);
static int fetch_body (struct fetch_command *, char**);
static int fetch_uid (struct fetch_command *, char**);
/* Helper functions. */
static int fetch_envelope0 (message_t);
static int fetch_bodystructure0 (message_t, int);
static int bodystructure (message_t, int);
static void send_parameter_list (const char *);
static int fetch_operation (message_t, char **, int);
static int fetch_message (message_t, unsigned long, unsigned long);
static int fetch_header (message_t, unsigned long, unsigned long);
static int fetch_body_content (message_t, unsigned long, unsigned long);
static int fetch_io (stream_t, unsigned long, unsigned long, unsigned long);
static int fetch_header_fields (message_t, char **, unsigned long, unsigned long);
static int fetch_header_fields_not (message_t, char **, unsigned long, unsigned long);
static int fetch_send_address (const char *);
static struct fetch_command* fetch_getcommand (char *, struct fetch_command*);
struct fetch_command
{
const char *name;
int (*func) (struct fetch_command *, char **);
message_t msg;
} fetch_command_table [] =
{
#define F_ALL 0
{"ALL", fetch_all, 0},
#define F_FULL 1
{"FULL", fetch_full, 0},
#define F_FAST 2
{"FAST", fetch_fast, 0},
#define F_ENVELOPE 3
{"ENVELOPE", fetch_envelope, 0},
#define F_FLAGS 4
{"FLAGS", fetch_flags, 0},
#define F_INTERNALDATE 5
{"INTERNALDATE", fetch_internaldate, 0},
#define F_RFC822_HEADER 6
{"RFC822.HEADER", fetch_rfc822_header, 0},
#define F_RFC822_SIZE 7
{"RFC822.SIZE", fetch_rfc822_size, 0},
#define F_RFC822_TEXT 8
{"RFC822.TEXT", fetch_rfc822_text, 0},
#define F_RFC822 9
{"RFC822", fetch_rfc822, 0},
#define F_BODYSTRUCTURE 10
{"BODYSTRUCTURE", fetch_bodystructure, 0},
#define F_BODY 11
{"BODY", fetch_body, 0},
#define F_UID 12
{"UID", fetch_uid, 0},
{ NULL, 0, 0}
};
/* Go through the fetch array sub command and returns the the structure. */
static struct fetch_command *
fetch_getcommand (char *cmd, struct fetch_command *command_table)
{
size_t i, len = strlen (cmd);
for (i = 0; command_table[i].name != 0; i++)
{
if (strlen (command_table[i].name) == len &&
!strcasecmp (command_table[i].name, cmd))
return &command_table[i];
}
return NULL;
}
/* The FETCH command retrieves data associated with a message in the
mailbox. The data items to be fetched can be either a single atom
or a parenthesized list. */
int
imap4d_fetch (struct imap4d_command *command, char *arg)
{
int rc;
char buffer[64];
rc = imap4d_fetch0 (arg, 0, buffer, sizeof buffer);
return util_finish (command, rc, buffer);
}
/* Where the real implementation is. It is here since UID command also
calls FETCH. */
int
imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
{
struct fetch_command *fcmd = NULL;
int rc = RESP_OK;
char *sp = NULL;
char *msgset;
size_t *set = NULL;
int n = 0;
int i;
int status;
msgset = util_getword (arg, &sp);
if (!msgset || !sp || *sp == '\0')
{
snprintf (resp, resplen, "Too few args");
return RESP_BAD;
}
/* Get the message numbers in set[]. */
status = util_msgset (msgset, &set, &n, isuid);
if (status != 0)
{
snprintf (resp, resplen, "Bogus number set");
return RESP_BAD;
}
/* Prepare status code. It will be replaced if an error occurs in the
loop below */
snprintf (resp, resplen, "Completed");
for (i = 0; i < n && rc == RESP_OK; i++)
{
size_t msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
message_t msg = NULL;
if (msgno && mailbox_get_message (mbox, msgno, &msg) == 0)
{
char item[32];
char *items = strdup (sp);
char *p = items;
int space = 0;
fcmd = NULL;
util_send ("* %d FETCH (", msgno);
item[0] = '\0';
/* Server implementations MUST implicitly
include the UID message data item as part of any FETCH
response caused by a UID command, regardless of whether
a UID was specified as a message data item to the FETCH. */
if (isuid)
{
fcmd = &fetch_command_table[F_UID];
fcmd->msg = msg;
rc = fetch_uid (fcmd, &items);
}
/* Get the fetch command names. */
while (*items && *items != ')')
{
util_token (item, sizeof (item), &items);
/* Do not send the UID again. */
if (isuid && strcasecmp (item, "UI
|