/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 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 "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 __P ((struct fetch_command *, char**));
static int fetch_full __P ((struct fetch_command *, char**));
static int fetch_fast __P ((struct fetch_command *, char**));
static int fetch_envelope __P ((struct fetch_command *, char**));
static int fetch_flags __P ((struct fetch_command *, char**));
static int fetch_internaldate __P ((struct fetch_command *, char**));
static int fetch_rfc822_header __P ((struct fetch_command *, char**));
static int fetch_rfc822_size __P ((struct fetch_command *, char**));
static int fetch_rfc822_text __P ((struct fetch_command *, char**));
static int fetch_rfc822 __P ((struct fetch_command *, char**));
static int fetch_bodystructure __P ((struct fetch_command *, char**));
static int fetch_body __P ((struct fetch_command *, char**));
static int fetch_uid __P ((struct fetch_command *, char**));
/* Helper functions. */
static int fetch_envelope0 __P ((message_t));
static int fetch_bodystructure0 __P ((message_t, int));
static int bodystructure __P ((message_t, int));
static void send_parameter_list __P ((char *));
static int fetch_operation __P ((message_t, char **, int));
static int fetch_message __P ((message_t, unsigned long, unsigned long));
static int fetch_header __P ((message_t, unsigned long, unsigned long));
static int fetch_body_content __P ((message_t, unsigned long, unsigned long));
static int fetch_io __P ((stream_t, unsigned long, unsigned long, unsigned long));
static int fetch_header_fields __P ((message_t, char **, unsigned long, unsigned long));
static int fetch_header_fields_not __P ((message_t, char **, unsigned long, unsigned long));
static int fetch_send_address __P ((const char *));
static struct fetch_command* fetch_getcommand __P ((char *, struct fetch_command[]));
struct fetch_command
{
const char *name;
int (*func) __P ((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_NO;
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;
}
for (i = 0; i < n; i++)
{
char item[32];
char *items = strdup (sp);
char *p = items;
size_t msgno;
int space = 0;
message_t msg = NULL;
msgno = (isuid) ? uid_to_msgno (set[i]) : set[i];
if (msgno && mailbox_get_message (mbox, msgno, &msg) == 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, "UID") == 0)
continue;
if (fcmd)
space = 1;
/* Search in the table. */
fcmd = fetch_getcommand (item, fetch_command_table);
if (fcmd)
{
if (space)
{
util_send (" ");
space = 0;
}
fcmd->msg = msg;
rc = fcmd->func (fcmd, &items);
}
}
util_send (")\r\n");
}
free (p);
}
free (set);
snprintf (resp, resplen, "Completed");
return RESP_OK;
}
/* ALL:
Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
Combination of FAST and ENVELOPE. */
static int
fetch_all (struct fetch_command *command, char **arg)
{
struct fetch_command c_env = fetch_command_table[F_ENVELOPE];
fetch_fast (command, arg);
util_send (" ");
c_env.msg = command->msg;
fetch_envelope (&c_env, arg);
return RESP_OK;
}
/* FULL:
Macro equivalent to: (FLAGS INTERNALDATE
RFC822.SIZE ENVELOPE BODY).
Combination of (ALL BODY). */
static int
fetch_full (s
|