summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlain Magloire <alainm@gnu.org>2001-05-13 04:10:54 +0000
committerAlain Magloire <alainm@gnu.org>2001-05-13 04:10:54 +0000
commit1eb0d00a965a06f9a9607a9f43546d6ddcbd0ff3 (patch)
tree8dd646e3287906e890a691c6385ea95fb1389bad
parentdbfad7e18ddeadced961dcd12137ad2b12d4c42e (diff)
downloadmailutils-1eb0d00a965a06f9a9607a9f43546d6ddcbd0ff3.tar.gz
mailutils-1eb0d00a965a06f9a9607a9f43546d6ddcbd0ff3.tar.bz2
Lots of bug fix to get the imap4d server running.
-rw-r--r--ChangeLog17
-rw-r--r--imap4d/fetch.c1206
-rw-r--r--imap4d/imap4d.h12
-rw-r--r--imap4d/login.c1
-rw-r--r--imap4d/select.c19
-rw-r--r--imap4d/util.c61
-rw-r--r--mailbox/address.c15
-rw-r--r--mailbox/include/mime0.h10
-rw-r--r--mailbox/mailbox.c4
-rw-r--r--mailbox/mailer.c4
-rw-r--r--mailbox/mime.c23
-rw-r--r--mailbox/smtp.c3
12 files changed, 885 insertions, 490 deletions
diff --git a/ChangeLog b/ChangeLog
index 8d050274c..612e83825 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2001-05-13 Alain Magloire
+
+ * imap4d/fetch.c: Lots of bug fixing. To many to enumerate.
+ * imap4d/imap4d.h: New prototypes.
+ * imap4d/login.c: syslog() the user.
+ * imap4d/select.c: Remove the call to mailbox_create_default.
+ * imap4d/util.c (util_getitem): New function.
+ (util_send_qstring): New function.
+ (util_send_literal): New function.
+
+ * mailbox/address.c: Parse822 can not handle '\n' inside
+ the buffer, prune them out before.
+ * mailbox/mime.c (_mime_parse_mpart_message): The mime->stream
+ was destroy when doing mime_get_part () better get it every time.
+ (_mime_body_fd): Likewised.
+ * mailbox/smtp.c: Do not close the stream on destroy.
+
2001-05-11 Alain Magloire
* imap4d/fetch.c: More cleanup in the bodystructure code,
diff --git a/imap4d/fetch.c b/imap4d/fetch.c
index 966516b41..fb828efdb 100644
--- a/imap4d/fetch.c
+++ b/imap4d/fetch.c
@@ -34,38 +34,47 @@
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_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_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_bodystructure0 __P ((message_t, int));
static int bodystructure __P ((message_t, int));
-static int fetch_body __P ((struct fetch_command *, char*));
-static int fetch_uid __P ((struct fetch_command *, char*));
-
-static int fetch_operation __P ((message_t, char *, int));
+static int 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_content __P ((message_t, unsigned long, unsigned long));
-static int fetch_io __P ((stream_t, 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_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 ((char *));
+/* The internal date of the message. */
+static const char *MONTHS[] =
+{
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+static const char * get_timezone __P ((const struct tm *));
static struct fetch_command* fetch_getcommand __P ((char *, struct fetch_command[]));
struct fetch_command
{
const char *name;
- int (*func) __P ((struct fetch_command *, char *));
+ int (*func) __P ((struct fetch_command *, char **));
message_t msg;
} fetch_command_table [] =
{
@@ -182,7 +191,7 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
{
fcmd = &fetch_command_table[F_UID];
fcmd->msg = msg;
- rc = fetch_uid (fcmd, p);
+ rc = fetch_uid (fcmd, &items);
}
/* Get the fetch command names. */
while (*items && *items != ')')
@@ -203,7 +212,7 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
space = 0;
}
fcmd->msg = msg;
- rc = fcmd->func (fcmd, items);
+ rc = fcmd->func (fcmd, &items);
}
}
util_send (")\r\n");
@@ -215,14 +224,11 @@ imap4d_fetch0 (char *arg, int isuid, char *resp, size_t resplen)
return rc;
}
-/* The Fetch comand 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. */
-
-/* Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
- or (FAST ENVELOPE) */
+/* ALL:
+ Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
+ Combination of FAST and ENVELOPE. */
static int
-fetch_all (struct fetch_command *command, char *arg)
+fetch_all (struct fetch_command *command, char **arg)
{
struct fetch_command c_env = fetch_command_table[F_ENVELOPE];
fetch_fast (command, arg);
@@ -232,9 +238,12 @@ fetch_all (struct fetch_command *command, char *arg)
return RESP_OK;
}
-/* Combination of (ALL BODY). */
+/* FULL:
+ Macro equivalent to: (FLAGS INTERNALDATE
+ RFC822.SIZE ENVELOPE BODY).
+ Combination of (ALL BODY). */
static int
-fetch_full (struct fetch_command *command, char *arg)
+fetch_full (struct fetch_command *command, char **arg)
{
struct fetch_command c_body = fetch_command_table[F_BODY];
fetch_all (command, arg);
@@ -244,9 +253,11 @@ fetch_full (struct fetch_command *command, char *arg)
return RESP_OK;
}
-/* Combination of (FLAGS INTERNALDATE RFC822.SIZE). */
+/* FAST:
+ Macro equivalent to: (FLAGS INTERNALDATE RFC822.SIZE)
+ Combination of (FLAGS INTERNALDATE RFC822.SIZE). */
static int
-fetch_fast (struct fetch_command *command, char *arg)
+fetch_fast (struct fetch_command *command, char **arg)
{
struct fetch_command c_idate = fetch_command_table[F_INTERNALDATE];
struct fetch_command c_rfc = fetch_command_table[F_RFC822_SIZE];
@@ -262,93 +273,28 @@ fetch_fast (struct fetch_command *command, char *arg)
return RESP_OK;
}
-/* Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To,
+/* ENVELOPE:
+ Header: Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To,
and Message-Id. */
static int
-fetch_envelope (struct fetch_command *command, char *arg)
+fetch_envelope (struct fetch_command *command, char **arg)
{
int status;
- (void)arg;
+ (void)arg; /* No arguments. */
util_send ("%s (", command->name);
status = fetch_envelope0 (command->msg);
util_send (")");
return status;
}
+/* FLAGS: The flags that are set for this message. */
+/* FIXME: User flags not done. If enable change the PERMANENTFLAGS in SELECT */
static int
-fetch_envelope0 (message_t msg)
-{
- char *buffer = NULL;
- char *from = NULL;
- header_t header = NULL;
-
- message_get_header (msg, &header);
-
- /* Date. */
- header_aget_value (header, "Date", &buffer);
- util_send_string (buffer);
- free (buffer);
- util_send (" ");
-
- /* Subject. */
- header_aget_value (header, "Subject", &buffer);
- util_send_string (buffer);
- free (buffer);
- util_send (" ");
-
- /* From. */
- header_aget_value (header, "From", &from);
- fetch_send_address (from);
- util_send (" ");
-
- /* Note that the server MUST default the reply-to and sender fields from
- the From field; a client is not expected to know to do this. */
- header_aget_value (header, "Sender", &buffer);
- fetch_send_address ((*buffer == '\0') ? from : buffer);
- free (buffer);
- util_send (" ");
-
- header_aget_value (header, "Reply-to", &buffer);
- fetch_send_address ((*buffer == '\0') ? from : buffer);
- free (buffer);
- util_send (" ");
-
- header_aget_value (header, "To", &buffer);
- fetch_send_address (buffer);
- free (buffer);
- util_send (" ");
-
- header_aget_value (header, "Cc", &buffer);
- fetch_send_address (buffer);
- free (buffer);
- util_send (" ");
-
- header_aget_value (header, "Bcc", &buffer);
- fetch_send_address (buffer);
- free (buffer);
- util_send (" ");
-
- header_aget_value (header, "In-Reply-To", &buffer);
- fetch_send_address (buffer);
- free (buffer);
- util_send (" ");
-
- header_aget_value (header, "Message-ID", &buffer);
- util_send_string (buffer);
-
- free (buffer);
- free (from);
- return RESP_OK;
-}
-
-/* The flags that are set for this message. */
-/* FIXME: User flags not done. */
-static int
-fetch_flags (struct fetch_command *command, char *arg)
+fetch_flags (struct fetch_command *command, char **arg)
{
attribute_t attr = NULL;
int space = 0;
- (void)arg;
+ (void)arg; /* No argments. */
message_get_attribute (command->msg, &attr);
util_send ("%s (", command->name);
if (attribute_is_deleted (attr))
@@ -387,51 +333,43 @@ fetch_flags (struct fetch_command *command, char *arg)
return RESP_OK;
}
-/* The internal date of the message. */
-static const char *MONTHS[] =
-{
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
-};
+/* INTERNALDATE The internal date of the message.
+ Format:
-static const char *
-get_timezone (const struct tm *tptr)
-{
- char tz[5];
- tz[0] = '\0';
- strftime (tz, sizeof (tz), "%Z", tptr);
- if (strcasecmp (tz, "UT") == 0)
- return "+0000";
- else if (strcasecmp (tz, "GMT") == 0)
- return "+0000";
- else if (strcasecmp (tz, "EDT") == 0)
- return "-0400";
- else if (strcasecmp (tz, "EST") == 0)
- return "-0500";
- else if (strcasecmp (tz, "CDT") == 0)
- return "-0500";
- else if (strcasecmp (tz, "CST") == 0)
- return "-0600";
- else if (strcasecmp (tz, "MDT") == 0)
- return "-0600";
- else if (strcasecmp (tz, "MST") == 0)
- return "-0700";
- else if (strcasecmp (tz, "PDT") == 0)
- return "-0700";
- else if (strcasecmp (tz, "PST") == 0)
- return "-0800";
- return "-0000"; /* Oops. */
-}
+ date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ SPACE time SPACE zone <">
+
+ date_day ::= 1*2digit
+ ;; Day of month
+
+ date_day_fixed ::= (SPACE digit) / 2digit
+ ;; Fixed-format version of date_day
+
+ date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+
+ date_text ::= date_day "-" date_month "-" date_year
-/* FIXME: Wrong format? */
+ date_year ::= 4digit
+
+ time ::= 2digit ":" 2digit ":" 2digit
+ ;; Hours minutes seconds
+
+ zone ::= ("+" / "-") 4digit
+ ;; Signed four-digit value of hhmm representing
+ ;; hours and minutes west of Greenwich (that is,
+ ;; (the amount that the given time differs from
+ ;; Universal Time). Subtracting the timezone
+ ;; from the given time will give the UT form.
+ ;; The Universal Time zone is "+0000". */
static int
-fetch_internaldate (struct fetch_command *command, char *arg)
+fetch_internaldate (struct fetch_command *command, char **arg)
{
- char date[512];
+ char date[128];
envelope_t env = NULL;
struct tm tm;
struct tm *tptr;
- (void)arg;
+ (void)arg; /* No arguments. */
message_get_envelope (command->msg, &env);
date[0] = '\0';
envelope_date (env, date, sizeof (date), NULL);
@@ -447,6 +385,7 @@ fetch_internaldate (struct fetch_command *command, char *arg)
wday[0] = '\0';
day = mon = year = hour = min = sec = offt = 0;
+ /* RFC822 Date: format. */
sscanf (date, "%3s %3s %2d %2d:%2d:%2d %d\n", wday, month, &day,
&hour, &min, &sec, &year);
tm.tm_sec = sec;
@@ -483,115 +422,266 @@ fetch_internaldate (struct fetch_command *command, char *arg)
return RESP_OK;
}
-/* Equivalent to BODY.PEEK[HEADER]. */
+/*
+ RFC822.HEADER:
+ Functionally equivalent to BODY.PEEK[HEADER], differing in the syntax of
+ the resulting untagged FETCH data (RFC822.HEADER is returned). */
static int
-fetch_rfc822_header (struct fetch_command *command, char *arg)
+fetch_rfc822_header (struct fetch_command *command, char **arg)
{
- char buffer[16];
- (void)arg;
- util_send ("%s ", command->name);
- strcpy (buffer, "[HEADER]");
- fetch_operation (command->msg, buffer, 1);
+ char buffer[32];
+ char *p = buffer;
+ (void)arg; /* No arguments. */
+ strcpy (buffer, ".PEEK[HEADER]");
+ fetch_body (command, &p);
return RESP_OK;
}
-/* Equivalent to BODY[TEXT]. */
+/* RFC822.TEXT:
+ Functionally equivalent to BODY[TEXT], differing in the syntax of the
+ resulting untagged FETCH data (RFC822.TEXT is returned). */
static int
-fetch_rfc822_text (struct fetch_command *command, char *arg)
+fetch_rfc822_text (struct fetch_command *command, char **arg)
{
char buffer[16];
- attribute_t attr = NULL;
- (void)arg;
- message_get_attribute (command->msg, &attr);
- if (!attribute_is_seen (attr) && !attribute_is_read (attr))
- {
- util_send ("FLAGS (\\Seen) ");
- attribute_set_seen (attr);
- attribute_set_read (attr);
- }
- util_send ("%s ", command->name);
+ char *p = buffer;
+ (void)arg; /* No arguments. */
strcpy (buffer, "[TEXT]");
- fetch_operation (command->msg, buffer, 1);
+ fetch_body (command, &p);
return RESP_OK;
}
/* The [RFC-822] size of the message. */
static int
-fetch_rfc822_size (struct fetch_command *command, char *arg)
+fetch_rfc822_size (struct fetch_command *command, char **arg)
{
size_t size = 0;
size_t lines = 0;
- (void)arg;
+ (void)arg; /* No arguments. */
message_size (command->msg, &size);
message_lines (command->msg, &lines);
util_send ("%s %u", command->name, size + lines);
return RESP_OK;
}
-/* Equivalent to BODY[]. */
+/* RFC822:
+ Functionally equivalent to BODY[], differing in the syntax of the
+ resulting untagged FETCH data (RFC822 is returned). */
static int
-fetch_rfc822 (struct fetch_command *command, char *arg)
+fetch_rfc822 (struct fetch_command *command, char **arg)
{
- if (*arg == '.')
+ if (**arg == '.')
{
- if (strncasecmp (arg, ".SIZE", 5) == 0)
+ /* We have to catch the other RFC822.XXX commands here. This is because
+ util_token() in imap4d_fetch0 will return the RFC822 token only. */
+ if (strncasecmp (*arg, ".SIZE", 5) == 0)
{
struct fetch_command c_rfc= fetch_command_table[F_RFC822_SIZE];
c_rfc.msg = command->msg;
+ (*arg) += 5;
fetch_rfc822_size (&c_rfc, arg);
}
- else if (strncasecmp (arg, ".TEXT", 5) == 0)
+ else if (strncasecmp (*arg, ".TEXT", 5) == 0)
{
struct fetch_command c_rfc = fetch_command_table[F_RFC822_TEXT];
c_rfc.msg = command->msg;
+ (*arg) += 5;
fetch_rfc822_text (&c_rfc, arg);
}
- else if (strncasecmp (arg, ".HEADER", 7) == 0)
+ else if (strncasecmp (*arg, ".HEADER", 7) == 0)
{
struct fetch_command c_rfc = fetch_command_table[F_RFC822_HEADER];
c_rfc.msg = command->msg;
+ (*arg) += 7;
fetch_rfc822_header (&c_rfc, arg);
}
}
else
{
char buffer[16];
- attribute_t attr = NULL;
- message_get_attribute (command->msg, &attr);
- if (!attribute_is_seen (attr) && !attribute_is_read (attr))
- {
- util_send ("FLAGS (\\Seen) ");
- attribute_set_seen (attr);
- attribute_set_read (attr);
- }
- util_send ("%s ", command->name);
+ char *p = buffer;
strcpy (buffer, "[]");
- fetch_operation (command->msg, buffer, 1);
+ fetch_body (command, &p);
}
return RESP_OK;
}
-/* The unique identifier for the message. */
+/* UID: The unique identifier for the message. */
static int
-fetch_uid (struct fetch_command *command, char *arg)
+fetch_uid (struct fetch_command *command, char **arg)
{
size_t uid = 0;
- (void)arg;
+ (void)arg; /* No arguments. */
message_get_uid (command->msg, &uid);
util_send ("%s %d", command->name, uid);
return RESP_OK;
}
+/* BODYSTRUCTURE:
+ The [MIME-IMB] body structure of the message. This is computed by the
+ server by parsing the [MIME-IMB] header fields in the [RFC-822] header and
+ [MIME-IMB] headers. */
static int
-fetch_bodystructure (struct fetch_command *command, char *arg)
+fetch_bodystructure (struct fetch_command *command, char **arg)
{
- (void)arg;
+ (void)arg; /* No arguments. */
util_send ("%s (", command->name);
- fetch_bodystructure0 (command->msg, 1);
+ fetch_bodystructure0 (command->msg, 1); /* 1 means with extension data. */
util_send (")");
return RESP_OK;
}
+/* BODY: Non-extensible form of BODYSTRUCTURE.
+ BODY[<section>]<<partial>> :
+ The text of a particular body section. The section specification is a set
+ of zero or more part specifiers delimited by periods. A part specifier
+ is either a part number or one of the following: HEADER, HEADER.FIELDS,
+ HEADER.FIELDS.NOT, MIME, and TEXT. An empty section specification refers
+ to the entire message, including the header. */
+static int
+fetch_body (struct fetch_command *command, char **arg)
+{
+ /* It's body section, set the message as seen */
+ if (**arg == '[')
+ {
+ attribute_t attr = NULL;
+ message_get_attribute (command->msg, &attr);
+ if (!attribute_is_seen (attr) && !attribute_is_read (attr))
+ {
+ util_send ("FLAGS (\\Seen) ");
+ attribute_set_seen (attr);
+ attribute_set_read (attr);
+ }
+ }
+ else if (strncasecmp (*arg,".PEEK", 5) == 0)
+ {
+ /* Move pass the .peek */
+ (*arg) += 5;
+ while (isspace ((unsigned)**arg))
+ (*arg)++;
+ }
+ else if (**arg != '[' && **arg != '.')
+ {
+ /* Call body structure without the extension. */
+ util_send ("%s (", command->name);
+ fetch_bodystructure0 (command->msg, 0);
+ util_send (")");
+ return RESP_OK;
+ }
+ util_send ("%s", command->name);
+ return fetch_operation (command->msg, arg,
+ strcasecmp (command->name, "BODY"));
+}
+
+/* Helper Functions: Where the Beef is. */
+
+/* ENVELOPE:
+ The envelope structure of the message. This is computed by the server by
+ parsing the [RFC-822] header into the component parts, defaulting various
+ fields as necessary. The fields are presented in the order:
+ Date, Subject, From, Sender, Reply-To, To, Cc, Bcc, In-Reply-To, Message-ID.
+ Any field of an envelope or address structure that is not applicable is
+ presented as NIL. Note that the server MUST default the reply-to and sender
+ fields from the from field. The date, subject, in-reply-to, and message-id
+ fields are strings. The from, sender, reply-to, to, cc, and bcc fields
+ are parenthesized lists of address structures. */
+static int
+fetch_envelope0 (message_t msg)
+{
+ char *buffer = NULL;
+ char *from = NULL;
+ header_t header = NULL;
+
+ message_get_header (msg, &header);
+
+ /* Date: */
+ header_aget_value (header, "Date", &buffer);
+ util_send_qstring (buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* Subject: */
+ header_aget_value (header, "Subject", &buffer);
+ util_send_qstring (buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* From: */
+ header_aget_value (header, "From", &from);
+ fetch_send_address (from);
+ util_send (" ");
+
+ /* Sender: */
+ /* Note that the server MUST default the reply-to and sender fields from
+ the From field; a client is not expected to know to do this. */
+ header_aget_value (header, "Sender", &buffer);
+ fetch_send_address ((*buffer == '\0') ? from : buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* Reply-To: */
+ /* Note that the server MUST default the reply-to and sender fields from
+ the From field; a client is not expected to know to do this. */
+ header_aget_value (header, "Reply-to", &buffer);
+ fetch_send_address ((*buffer == '\0') ? from : buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* To: */
+ header_aget_value (header, "To", &buffer);
+ fetch_send_address (buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* Cc: */
+ header_aget_value (header, "Cc", &buffer);
+ fetch_send_address (buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* Bcc: */
+ header_aget_value (header, "Bcc", &buffer);
+ fetch_send_address (buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* In-Reply-To: */
+ header_aget_value (header, "In-Reply-To", &buffer);
+ util_send_qstring (buffer);
+ free (buffer);
+ util_send (" ");
+
+ /* Message-ID: */
+ header_aget_value (header, "Message-ID", &buffer);
+ util_send_qstring (buffer);
+
+ free (buffer);
+ free (from);
+ return RESP_OK;
+}
+
+/* The beef BODYSTRUCTURE.
+ A parenthesized list that describes the [MIME-IMB] body structure of a
+ message. Multiple parts are indicated by parenthesis nesting. Instead of
+ a body type as the first element of the parenthesized list there is a nested
+ body. The second element of the parenthesized list is the multipart
+ subtype (mixed, digest, parallel, alternative, etc.).
+
+ The extension data of a multipart body part are in the following order:
+ body parameter parenthesized list:
+ A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz"
+ "rag") where "bar" is the value of "foo" and "rag" is the value of
+ "baz"] as defined in [MIME-IMB].
+
+ body disposition:
+ A parenthesized list, consisting of a disposition type string followed by a
+ parenthesized list of disposition attribute/value pairs. The disposition
+ type and attribute names will be defined in a future standards-track
+ revision to [DISPOSITION].
+
+ body language:
+ A string or parenthesized list giving the body language value as defined
+ in [LANGUAGE-TAGS]. */
static int
fetch_bodystructure0 (message_t message, int extension)
{
@@ -601,88 +691,134 @@ fetch_bodystructure0 (message_t message, int extension)
message_is_multipart (message, &is_multipart);
if (is_multipart)
{
+ char *buffer = NULL;
+ char *s;
+ char *sp = NULL;
+ header_t header = NULL;
+
message_get_num_parts (message, &nparts);
+
+ /* Get all the sub messages. */
for (i = 1; i <= nparts; i++)
+ {
+ message_t msg = NULL;
+ message_get_part (message, i, &msg);
+ util_send ("(");
+ fetch_bodystructure0 (msg, extension);
+ util_send (")");
+ } /* for () */
+
+ message_get_header (message, &header);
+
+ /* The subtype. */
+ header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
+ s = strtok_r (buffer, " \t\r\n;", &sp);
+ if (s)
{
- message_t msg = NULL;
- message_get_part (message, i, &msg);
- util_send ("(");
- fetch_bodystructure0 (msg, extension);
- util_send (")");
- } /* for () */
+ s = strchr (s, '/');
+ if (s)
+ *s++ = '\0';
+ }
+ util_send (" ");
+ util_send_qstring (s);
+
/* The extension data for multipart. */
if (extension)
- {
- header_t header = NULL;
- char *buffer = NULL;
- char *sp = NULL;
- char *s;
- /* The subtype. */
- message_get_header (message, &header);
- header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
- s = strtok_r (buffer, " \t\r\n;", &sp);
- s = strchr (buffer, '/');
- if (s)
+ {
+ while (*sp && isspace ((unsigned)*sp)) sp++;
+ /* body parameter parenthesized list: Content-type parameter list. */
+ if (*sp)
{
- s++;
- util_send (" \"%s\"", s);
- }
- else
- util_send (" NIL");
- /* Content-type parameter list. */
- util_send (" (");
- {
- int space = 0;
- while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
+ util_send (" (");
{
- char *p = strchr (s, '=');
- if (p)
- *p++ = '\0';
- if (space)
- util_send (" ");
- util_send ("\"%s\"", s);
- if (p)
- util_send (" \"%s\"", p);
- space = 1;
+ int space = 0;
+ while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
+ {
+ char *p = strchr (s, '=');
+ if (p)
+ *p++ = '\0';
+ if (space)
+ util_send (" ");
+ space = 1;
+ util_send_qstring (s);
+ if (p)
+ {
+ util_send (" ");
+ util_unquote (&p);
+ util_send_qstring (p);
+ }
+ }
}
- }
- util_send (")");
- free (buffer);
- /* Content-Disposition. */
- header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
- if (*buffer)
- {
- char *t = buffer;
- util_send (" (");
- while ((s = strtok_r (t, " \t\r\n;", &sp)))
- {
- char *p = strchr (s, '=');
- if (p)
- *p++ = '\0';
- if (t == NULL)
- util_send (" ");
- util_send ("\"%s\"", s);
- if (p)
- util_send (" \"%s\"", (p) ? p : "NIL");
- t = NULL;
- }
util_send (")");
}
else
util_send (" NIL");
- free (buffer);
- /* Content-Language. */
- header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
+ free (buffer);
+
+ /* body disposition: Content-Disposition. */
+ header_aget_value (header, MU_HEADER_CONTENT_DISPOSITION, &buffer);
util_send (" ");
- util_send_string (buffer);
- free (buffer);
- } /* extension */
+ send_parameter_list (buffer);
+ free (buffer);
+
+ /* body language: Content-Language. */
+ header_aget_value (header, MU_HEADER_CONTENT_LANGUAGE, &buffer);
+ util_send (" ");
+ send_parameter_list (buffer);
+ free (buffer);
+ } /* extension */
+ else
+ free (buffer);
}
else
bodystructure (message, extension);
return RESP_OK;
}
+/* The basic fields of a non-multipart body part are in the following order:
+ body type:
+ A string giving the content media type name as defined in [MIME-IMB].
+
+ body subtype:
+ A string giving the content subtype name as defined in [MIME-IMB].
+
+ body parameter parenthesized list:
+ A parenthesized list of attribute/value pairs [e.g. ("foo" "bar" "baz"
+ "rag") where "bar" is the value of "foo" and "rag" is the value of "baz"]
+ as defined in [MIME-IMB].
+
+ body id:
+ A string giving the content id as defined in [MIME-IMB].
+
+ body description:
+ A string giving the content description as defined in [MIME-IMB].
+
+ body encoding:
+ A string giving the content transfer encoding as defined in [MIME-IMB].
+
+ body size:
+ A number giving the size of the body in octets. Note that this size is the
+ size in its transfer encoding and not the resulting size after any decoding.
+
+ A body type of type TEXT contains, immediately after the basic fields, the
+ size of the body in text lines.
+
+ A body type of type MESSAGE and subtype RFC822 contains, immediately after
+ the basic fields, the envelope structure, body structure, and size in text
+ lines of the encapsulated message.
+
+ The extension data of a non-multipart body part are in the following order:
+ body MD5:
+ A string giving the body MD5 value as defined in [MD5].
+
+ body disposition:
+ A parenthesized list with the same content and function as the body
+ disposition for a multipart body part.
+
+ body language:\
+ A string or parenthesized list giving the body language value as defined
+ in [LANGUAGE-TAGS].
+ */
static int
bodystructure (message_t msg, int extension)
{
@@ -696,74 +832,90 @@ bodystructure (message_t msg, int extension)
message_get_header (msg, &header);
- /* MIME: */
+ /* body type: Content-Type
+ body subtype: */
header_aget_value (header, MU_HEADER_CONTENT_TYPE, &buffer);
s = strtok_r (buffer, " \t\r\n;", &sp);
- /* MIME media type and subtype */
if (s)
{
char *p = strchr (s, '/');
if (strcasecmp (s, "MESSAGE/RFC822") == 0)
- message_rfc822 = 1;
+ message_rfc822 = 1;
if (strcasecmp (s, "TEXT/PLAIN") == 0)
- text_plain = 1;
+ text_plain = 1;
if (p)
- *p++ = '\0';
- util_send ("\"%s\"", s);
- util_send (" \"%s\"", (p) ? p : "NIL");
+ *p++ = '\0';
+ /* MIME media type and subtype */
+ util_send_qstring (s);
+ util_send (" ");
+ util_unquote (&p);
+ util_send_qstring (p);
}
else
{
- /* Default? */
- util_send ("TEXT");
- util_send (" PLAIN");
+ /* Default? If Content-Type is not present consider as text/plain. */
+ util_send_qstring ("TEXT");
+ util_send (" ");
+ util_send_qstring ("PLAIN");
+ text_plain = 1;
}
- /* Content-type parameter list. */
- util_send (" (");
+
+ while (*sp && isspace ((unsigned)*sp)) sp++;
+ /* body parameter parenthesized list: Content-type attributes */
+ if (*sp || text_plain)
{
- int have_charset = 0;
- int space = 0;
- while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
- {
- char *p = strchr (s, '=');
- if (p)
- *p++ = '\0';
- if (space)
+ util_send (" (");
+ {
+ int space = 0;
+ int have_charset = 0;
+ /* Content-type parameter list. */
+ while ((s = strtok_r (NULL, " \t\r\n;", &sp)))
+ {
+ char *p = strchr (s, '=');
+ if (p)
+ *p++ = '\0';
+ if (space)
+ util_send (" ");
+ util_send_qstring (s);
util_send (" ");
- util_send ("\"%s\"", s);
- util_send (" \"%s\"", (p) ? p : "NIL");
- if (strcasecmp (s, "charset") == 0)
- have_charset = 1;
- }
- /* Default. */
- if (!have_charset)
- {
- util_send ("\"CHARSET\"");
- util_send (" \"US-ASCII\"");
- }
+ util_unquote (&p);
+ if (strcasecmp (s, "charset") == 0)
+ have_charset = 1;
+ util_send_qstring (p);
+ space = 1;
+ }
+ if (!have_charset && text_plain)
+ {
+ if (space)
+ util_send (" ");
+ util_send ("\"CHARSET\" \"US-ASCII\"");
+ }
+ }
+ util_send (")");
}
- util_send (")");
+ else
+ util_send (" NIL");
free (buffer);
- /* Content-ID. */
+ /* body id: Content-ID. */
header_aget_value (header, MU_HEADER_CONTENT_ID, &buffer);
util_send (" ");
- util_send_string (buffer);
+ util_send_qstring (buffer);
free (buffer);
- /* Content-Description. */
+ /* body description: Content-Description. */
header_aget_value (header, MU_HEADER_CONTENT_DESCRIPTION, &buffer);
util_send (" ");
- util_send_string (buffer);
+ util_send_qstring (buffer);
free (buffer);
- /* Content-Transfer-Encoding. */
+ /* body encoding: Content-Transfer-Encoding. */
header_aget_valu