summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@ximian.com>2001-04-02 04:43:38 +0000
committerJeffrey Stedfast <fejj@src.gnome.org>2001-04-02 04:43:38 +0000
commitd6e232c69c4fc7867be520311bf060c939f1fb67 (patch)
tree8dfdeb85cea8392ba8abfb333a674b6e39af6dbb
parentdc49c2e85b28b0ee5b43149cefdd92492956bceb (diff)
downloadgmime-d6e232c69c4fc7867be520311bf060c939f1fb67.tar.gz
Made smarter.
2001-04-01 Jeffrey Stedfast <fejj@ximian.com> * gmime-utils.c (g_mime_utils_quote_string): Made smarter. 2001-03-31 Jeffrey Stedfast <fejj@ximian.com> * Makefile.am: Added rules to build gen-table.c and added gmime-table-private.h to the build. * gen-table.c: New file to generate gmime-table-private.h if need be. * gmime-table-private.h: New file that contains gmime_special_table. * gmime-utils.c: Remove the gmime_special_table from here and instead #include gmime-table-private.h. * internet-address.c: #include gmime-table-private.h 2001-03-30 Jeffrey Stedfast <fejj@ximian.com> * gmime-message.c (create_header): Simplified a tad. (g_mime_message_add_recipient): Updated for the new InternetAddress API. (g_mime_message_add_recipients_from_string): Simplified greatly using the new InternetAddress API. * internet-address.[c,h]: Completely rewritten to be a lot more rfc0822 compliant. 2001-03-28 Jeffrey Stedfast <fejj@ximian.com> * README, configure.in: Updated version to 0.5.0
-rw-r--r--ChangeLog35
-rw-r--r--Makefile.am8
-rw-r--r--README2
-rw-r--r--configure.in2
-rw-r--r--gen-table.c183
-rw-r--r--gmime-content-type.c9
-rw-r--r--gmime-message.c55
-rw-r--r--gmime-parser.c567
-rw-r--r--gmime-table-private.h76
-rw-r--r--gmime-utils.c169
-rw-r--r--gmime/gen-table.c183
-rw-r--r--gmime/gmime-content-type.c9
-rw-r--r--gmime/gmime-message.c55
-rw-r--r--gmime/gmime-parser.c567
-rw-r--r--gmime/gmime-table-private.h76
-rw-r--r--gmime/gmime-utils.c169
-rw-r--r--gmime/internet-address.c782
-rw-r--r--gmime/internet-address.h24
-rw-r--r--internet-address.c782
-rw-r--r--internet-address.h24
-rw-r--r--test-mime.c85
-rw-r--r--tests/test-mime.c85
22 files changed, 2690 insertions, 1257 deletions
diff --git a/ChangeLog b/ChangeLog
index 49336b0e..c501c872 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+2001-04-01 Jeffrey Stedfast <fejj@ximian.com>
+
+ * gmime-utils.c (g_mime_utils_quote_string): Made smarter.
+
+2001-03-31 Jeffrey Stedfast <fejj@ximian.com>
+
+ * Makefile.am: Added rules to build gen-table.c and added
+ gmime-table-private.h to the build.
+
+ * gen-table.c: New file to generate gmime-table-private.h if need
+ be.
+
+ * gmime-table-private.h: New file that contains
+ gmime_special_table.
+
+ * gmime-utils.c: Remove the gmime_special_table from here and
+ instead #include gmime-table-private.h.
+
+ * internet-address.c: #include gmime-table-private.h
+
+2001-03-30 Jeffrey Stedfast <fejj@ximian.com>
+
+ * gmime-message.c (create_header): Simplified a tad.
+ (g_mime_message_add_recipient): Updated for the new
+ InternetAddress API.
+ (g_mime_message_add_recipients_from_string): Simplified greatly
+ using the new InternetAddress API.
+
+ * internet-address.[c,h]: Completely rewritten to be a lot more
+ rfc0822 compliant.
+
+2001-03-28 Jeffrey Stedfast <fejj@ximian.com>
+
+ * README, configure.in: Updated version to 0.5.0
+
2001-03-29 Charles Kerr <charles@rebelbase.com>
* gmime-parser.c (g_mime_parser_construct_message_from_file): new
diff --git a/Makefile.am b/Makefile.am
index 7d7820e6..0f3700ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,7 +6,7 @@ INCLUDES = -I@srcdir@ $(VERSION_FLAGS) @GLIB_CFLAGS@ -DG_LOG_DOMAIN=\"gmime\"
VERSION_FLAGS = -DGMIME_VERSION=\"@GMIME_VERSION@\"
-noinst_PROGRAMS = test-mime test-parser
+noinst_PROGRAMS = gen-table test-mime test-parser
bin_SCRIPTS = gmime-config
@@ -27,6 +27,7 @@ libgmime_la_SOURCES = \
gmimeincdir = $(includedir)/gmime
gmimeinc_HEADERS = \
gmime.h \
+ gmime-table-private.h \
gmime-content-type.h \
gmime-message.h \
gmime-param.h \
@@ -49,6 +50,11 @@ test_parser_LDFLAGS =
test_parser_DEPENDENCIES = $(DEPS)
test_parser_LDADD = $(LDADDS)
+gen_table_SOURCES = gen-table.c
+gen_table_LDFLAGS =
+gen_table_DEPENDENCIES =
+gen_table_LDADD =
+
check-local: tests
testall : tests
diff --git a/README b/README
index 3c2e5e36..f6fadf6c 100644
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
- GMime, version 0.4
+ GMime, version 0.5
by Jeffrey Stedfast <fejj@helixcode.com>
diff --git a/configure.in b/configure.in
index 00d9940d..829425d0 100644
--- a/configure.in
+++ b/configure.in
@@ -11,7 +11,7 @@ AM_CONFIG_HEADER(config.h)
# glib_libs: libs to store in gmime-config
GMIME_MAJOR_VERSION=0
-GMIME_MINOR_VERSION=4
+GMIME_MINOR_VERSION=5
GMIME_MICRO_VERSION=0
GMIME_VERSION=$GMIME_MAJOR_VERSION.$GMIME_MINOR_VERSION.$GMIME_MICRO_VERSION
GMIME_VERSION_INFO=`expr $GMIME_MAJOR_VERSION + $GMIME_MINOR_VERSION`:$GMIME_MICRO_VERSION:$GMIME_MINOR_VERSION
diff --git a/gen-table.c b/gen-table.c
new file mode 100644
index 00000000..672ef9a9
--- /dev/null
+++ b/gen-table.c
@@ -0,0 +1,183 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximain, Inc. (www.ximian.com)
+ *
+ * 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 of the License, 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+enum {
+ FALSE,
+ TRUE
+};
+
+#define CHARS_LWSP " \t\n\r" /* linear whitespace chars */
+#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
+#define CHARS_SPECIAL "()<>@,;:\\\".[]"
+#define CHARS_CSPECIAL "()\\\r" /* not in comments */
+#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
+#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials (rfc2047 5.1) */
+#define CHARS_PSPECIAL "!*+-/" /* encoded phrase specials (rfc2047 5.3) */
+
+static unsigned char gmime_special_table[256];
+
+enum {
+ IS_CTRL = 1<<0,
+ IS_LWSP = 1<<1,
+ IS_TSPECIAL = 1<<2,
+ IS_SPECIAL = 1<<3,
+ IS_SPACE = 1<<4,
+ IS_DSPECIAL = 1<<5,
+ IS_QPSAFE = 1<<6,
+ IS_ESAFE = 1<<7, /* encoded word safe */
+ IS_PSAFE = 1<<8, /* encoded word in phrase safe */
+};
+
+#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)
+#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)
+#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)
+#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)
+#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)
+#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)
+#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)
+#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)
+#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
+#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
+#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
+
+/* code to rebuild the gmime_special_table */
+static void
+header_remove_bits (unsigned short bit, unsigned char *vals)
+{
+ int i;
+
+ for (i = 0; vals[i]; i++)
+ gmime_special_table[vals[i]] &= ~bit;
+}
+
+static void
+header_init_bits (unsigned short bit, unsigned short bitcopy, int remove, unsigned char *vals)
+{
+ int i, len = strlen (vals);
+
+ if (!remove) {
+ for (i = 0; i < len; i++) {
+ gmime_special_table[vals[i]] |= bit;
+ }
+ if (bitcopy) {
+ for (i = 0; i < 256; i++) {
+ if (gmime_special_table[i] & bitcopy)
+ gmime_special_table[i] |= bit;
+ }
+ }
+ } else {
+ for (i = 0; i < 256; i++)
+ gmime_special_table[i] |= bit;
+ for (i = 0; i < len; i++) {
+ gmime_special_table[vals[i]] &= ~bit;
+ }
+ if (bitcopy) {
+ for (i = 0; i < 256; i++) {
+ if (gmime_special_table[i] & bitcopy)
+ gmime_special_table[i] &= ~bit;
+ }
+ }
+ }
+}
+
+static void
+header_decode_init (void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ gmime_special_table[i] = 0;
+ if (i < 32)
+ gmime_special_table[i] |= IS_CTRL;
+ if ((i >= 33 && i <= 60) || (i >= 62 && i <= 126) || i == 32 || i == 9)
+ gmime_special_table[i] |= (IS_QPSAFE | IS_ESAFE);
+ if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z'))
+ gmime_special_table[i] |= IS_PSAFE;
+ }
+
+ gmime_special_table[127] |= IS_CTRL;
+ gmime_special_table[' '] |= IS_SPACE;
+ header_init_bits (IS_LWSP, 0, FALSE, CHARS_LWSP);
+ header_init_bits (IS_TSPECIAL, IS_CTRL, FALSE, CHARS_TSPECIAL);
+ header_init_bits (IS_SPECIAL, 0, FALSE, CHARS_SPECIAL);
+ header_init_bits (IS_DSPECIAL, 0, FALSE, CHARS_DSPECIAL);
+ header_remove_bits (IS_ESAFE, CHARS_ESPECIAL);
+ header_init_bits (IS_PSAFE, 0, FALSE, CHARS_PSPECIAL);
+}
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ header_decode_init ();
+
+ printf ("/* THIS FILE IS AUTOGENERATED: DO NOT EDIT! */\n\n");
+ printf ("/**\n * To regenerate:\n * make gen-table\n");
+ printf (" * ./gen-table > gmime-table-private.h\n **/\n\n");
+
+ /* print out the table */
+ printf ("static unsigned short gmime_special_table[256] = {");
+ for (i = 0; i < 256; i++) {
+ printf ("%s%3d%s", (i % 16) ? "" : "\n\t",
+ gmime_special_table[i], i != 255 ? "," : "\n");
+ }
+ printf ("};\n\n");
+
+ /* print out the enum */
+ printf ("enum {\n");
+ printf ("\tIS_CTRL \t= 1 << 0,\n");
+ printf ("\tIS_LWSP \t= 1 << 1,\n");
+ printf ("\tIS_TSPECIAL\t= 1 << 2,\n");
+ printf ("\tIS_SPECIAL \t= 1 << 3,\n");
+ printf ("\tIS_SPACE \t= 1 << 4,\n");
+ printf ("\tIS_DSPECIAL\t= 1 << 5,\n");
+ printf ("\tIS_QPSAFE \t= 1 << 6,\n");
+ printf ("\tIS_ESAFE \t= 1 << 7, /* encoded word safe */\n");
+ printf ("\tIS_PPSAFE \t= 1 << 8 /* encode word in phrase safe */\n");
+ printf ("};\n\n");
+
+ printf ("#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)\n");
+ printf ("#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)\n");
+ printf ("#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)\n");
+ printf ("#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)\n");
+ printf ("#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)\n");
+ printf ("#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)\n");
+ printf ("#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)\n");
+ printf ("#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)\n");
+ printf ("#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)\n");
+ printf ("#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)\n");
+ printf ("#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)\n\n");
+
+ printf ("#define CHARS_LWSP \" \\t\\n\\r\" /* linear whitespace chars */\n");
+ printf ("#define CHARS_TSPECIAL \"%s\"\n", CHARS_TSPECIAL);
+ printf ("#define CHARS_SPECIAL \"%s\"\n", CHARS_SPECIAL);
+ printf ("#define CHARS_CSPECIAL \"()\\\\\\r\" /* not in comments */\n");
+ printf ("#define CHARS_DSPECIAL \"[]\\\\\\r \\t\" /* not in domains */\n");
+ printf ("#define CHARS_ESPECIAL \"()<>@,;:\\\"/[]?.=\" /* encoded word specials (rfc2047 5.1) */\n");
+ printf ("#define CHARS_PSPECIAL \"!*+-/\" /* encoded phrase specials (rfc2047 5.3) */\n");
+
+ return 0;
+}
diff --git a/gmime-content-type.c b/gmime-content-type.c
index de4d76d2..a37b0974 100644
--- a/gmime-content-type.c
+++ b/gmime-content-type.c
@@ -49,10 +49,15 @@ g_mime_content_type_new (const gchar *type, const gchar *subtype)
} else {
if (type && *type) {
mime_type->type = g_strdup (type);
- if (!g_strcasecmp (type, "text"))
+ if (!g_strcasecmp (type, "text")) {
mime_type->subtype = g_strdup ("plain");
- else
+ } else if (!g_strcasecmp (type, "multipart")) {
+ mime_type->subtype = g_strdup ("mixed");
+ } else {
+ g_free (mime_type->type);
+ mime_type->type = g_strdup ("application");
mime_type->subtype = g_strdup ("octet-stream");
+ }
} else {
mime_type->type = g_strdup ("application");
mime_type->subtype = g_strdup ("octet-stream");
diff --git a/gmime-message.c b/gmime-message.c
index 726fdeeb..02f74eef 100644
--- a/gmime-message.c
+++ b/gmime-message.c
@@ -20,10 +20,14 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "gmime-message.h"
#include "gmime-utils.h"
#include "internet-address.h"
-#include <config.h>
+
#include <string.h>
#include <ctype.h>
#include <locale.h>
@@ -202,7 +206,7 @@ g_mime_message_add_recipient (GMimeMessage *message, gchar *type, const gchar *n
InternetAddress *ia;
GList *recipients;
- ia = internet_address_new (name, address);
+ ia = internet_address_new_name (name, address);
recipients = g_hash_table_lookup (message->header->recipients, type);
g_hash_table_remove (message->header->recipients, type);
@@ -227,9 +231,7 @@ g_mime_message_add_recipient (GMimeMessage *message, gchar *type, const gchar *n
void
g_mime_message_add_recipients_from_string (GMimeMessage *message, gchar *type, const gchar *string)
{
- InternetAddress *ia;
- GList *recipients;
- gchar *ptr, *eptr, *recipient;
+ GList *recipients, *addrlist;
g_return_if_fail (message != NULL);
g_return_if_fail (string != NULL);
@@ -237,38 +239,9 @@ g_mime_message_add_recipients_from_string (GMimeMessage *message, gchar *type, c
recipients = g_hash_table_lookup (message->header->recipients, type);
g_hash_table_remove (message->header->recipients, type);
- ptr = (gchar *) string;
-
- while (*ptr) {
- gboolean in_quotes = FALSE;
-
- /* skip through leading whitespace */
- for ( ; *ptr && isspace (*ptr); ptr++);
-
- if (*ptr == '"')
- in_quotes = TRUE;
-
- /* find the end of this address */
- eptr = ptr + 1;
- while (*eptr) {
- if (*eptr == '"' && *(eptr - 1) != '\\')
- in_quotes = !in_quotes;
- else if (*eptr == ',' && !in_quotes)
- break;
-
- eptr++;
- }
-
- recipient = g_strndup (ptr, (gint) (eptr - ptr));
- ia = internet_address_new_from_string (recipient);
- g_free (recipient);
- recipients = g_list_append (recipients, ia);
-
- if (*eptr)
- ptr = eptr + 1;
- else
- break;
- }
+ addrlist = internet_address_parse_string (string);
+ if (addrlist)
+ recipients = g_list_concat (recipients, addrlist);
g_hash_table_insert (message->header->recipients, type, recipients);
}
@@ -523,7 +496,7 @@ create_header (GMimeMessage *message)
GString *recip;
recip = g_string_new ("To: ");
- while (TRUE) {
+ while (recipients) {
InternetAddress *ia;
gchar *address;
@@ -535,8 +508,6 @@ create_header (GMimeMessage *message)
recipients = recipients->next;
if (recipients)
g_string_append (recip, ", ");
- else
- break;
}
g_string_append (recip, "\n");
buf = g_mime_utils_header_fold (recip->str);
@@ -551,7 +522,7 @@ create_header (GMimeMessage *message)
GString *recip;
recip = g_string_new ("Cc: ");
- while (TRUE) {
+ while (recipients) {
InternetAddress *ia;
gchar *address;
@@ -563,8 +534,6 @@ create_header (GMimeMessage *message)
recipients = recipients->next;
if (recipients)
g_string_append (recip, ", ");
- else
- break;
}
g_string_append (recip, "\n");
buf = g_mime_utils_header_fold (recip->str);
diff --git a/gmime-parser.c b/gmime-parser.c
index 98326ac0..f2c69a79 100644
--- a/gmime-parser.c
+++ b/gmime-parser.c
@@ -21,9 +21,13 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "gmime-parser.h"
#include "gmime-utils.h"
-#include <config.h>
+
#include <string.h>
#include <ctype.h>
@@ -114,51 +118,56 @@ g_strstrbound (const gchar *haystack, const gchar *needle, const gchar *end)
* leave fp_in pointing at the message body that comes after the
* headers.
**/
-static GArray*
+static GArray *
get_header_block_from_file (FILE *fp)
{
- GArray * a;
+ GArray *a;
gchar buf [GMIME_PARSER_MAX_LINE_WIDTH];
-
- g_return_val_if_fail (fp!=NULL, NULL);
-
+
+ g_return_val_if_fail (fp != NULL, NULL);
+
a = g_array_new (TRUE, FALSE, 1);
for (;;) {
- gchar * pch = fgets (buf, sizeof(buf), fp);
- if (pch == NULL) { /* eof reached before end-of-headers! */
+ gchar *pch;
+
+ pch = fgets (buf, sizeof (buf), fp);
+ if (pch == NULL) {
+ /* eof reached before end-of-headers! */
g_array_free (a, TRUE);
a = NULL;
break;
}
- if (!strcmp(buf,"\n")) /* empty line -- end of headers */
+
+ /* empty line -- end of headers */
+ if (!strcmp (buf,"\n"))
break;
-
+
g_array_append_vals (a, buf, strlen(buf));
}
-
+
return a;
}
/**
* get_header_block: Get the header block from a message.
- * @message the message text; that is, header + body.
+ * @message: the message text; that is, header + body.
*
* This will read all of the headers into an unparsed GArray.
**/
-static GArray*
+static GArray *
get_header_block (const gchar *pch)
{
- GArray * a = NULL;
- const gchar * header_end;
-
- g_return_val_if_fail (pch!=NULL, NULL);
-
+ GArray *a = NULL;
+ const gchar *header_end;
+
+ g_return_val_if_fail (pch != NULL, NULL);
+
header_end = strstr (pch, "\n\n");
if (header_end != NULL) {
a = g_array_new (TRUE, FALSE, 1);
- g_array_append_vals (a, pch, header_end-pch);
+ g_array_append_vals (a, pch, header_end - pch);
}
-
+
return a;
}
@@ -170,235 +179,234 @@ get_header_block (const gchar *pch)
*
* Returns a pointer to the end of a header.
**/
-static const gchar*
+static const gchar *
find_header_end (const gchar *header, const gchar *boundary)
{
const gchar * eptr;
-
- g_return_val_if_fail (header!=NULL, NULL);
- g_return_val_if_fail (boundary!=NULL, NULL);
-
- for (eptr=header; eptr<boundary; ++eptr)
- if (*eptr=='\n' && !isblank(eptr[1]))
+
+ g_return_val_if_fail (header != NULL, NULL);
+ g_return_val_if_fail (boundary != NULL, NULL);
+
+ for (eptr = header; eptr < boundary; eptr++)
+ if (*eptr == '\n' && !isblank (eptr[1]))
break;
-
- return (gchar*)eptr;
+
+ return eptr;
}
/**
- * parse_content_heaaders: picks the Content-* headers from a header block and extracts info from them.
+ * parse_content_heaaders: picks the Content-* headers from a header block
+ * and extracts info from them.
* @headers: string containing the zero-terminated header block.
* @headers_len: length of the header block.
- * @mime_part: mime_part to populate with the information we get from the Content-* headers.
- * @is_multipart: set to TRUE if the part is a multipart, FALSE otherwise
- * @boundary: if this is a multipart, *boundary is set with the boundary string, which must be g_free()d by the caller.
- * @end_boundary: if this is a multipart, *boundary is set with the end boundary string, which must be g_free()d by the caller.
+ * @mime_part: mime part to populate with the information we get from the Content-* headers.
+ * @is_multipart: set to TRUE if the part is a multipart, FALSE otherwise (to be set by function)
+ * @boundary: multipart boundary string (to be set by function)
+ * @end_boundary: multipart end boundary string (to be set by function)
*
* Parse a header block for content information.
*/
static void
-parse_content_headers (const gchar *headers,
- gint headers_len,
- GMimePart *mime_part,
- gboolean *is_multipart,
- gchar **boundary,
- gchar **end_boundary)
+parse_content_headers (const gchar *headers, gint headers_len,
+ GMimePart *mime_part, gboolean *is_multipart,
+ gchar **boundary, gchar **end_boundary)
{
- const gchar * headers_ptr = headers;
- const gchar * headers_end = headers + headers_len;
-
+ const gchar *headers_ptr = headers;
+ const gchar *headers_end = headers + headers_len;
+
while (headers_ptr < headers_end) {
const gint type = content_header (headers_ptr);
-
+
switch (type) {
- case CONTENT_DESCRIPTION: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *desc_enc = g_strndup (pch, (gint)(end - pch));
- gchar *desc_dec = g_mime_utils_8bit_header_decode (desc_enc);
- g_strstrip (desc_dec);
- g_mime_part_set_content_description (mime_part, desc_dec);
- g_free (desc_enc);
- g_free (desc_dec);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_LOCATION: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar * loc = g_strndup (pch, (gint)(end - pch));
- g_strstrip (loc);
- g_mime_part_set_content_location (mime_part, loc);
- g_free (loc);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_MD5: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *md5 = g_strndup (pch, (gint) (end - pch));
- g_strstrip (md5);
- g_mime_part_set_content_md5 (mime_part, md5);
- g_free (md5);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_ID: {
- const gchar* pch = headers_ptr + strlen(content_headers[type]);
- const gchar* end = find_header_end (pch, headers_end);
- gchar *id = g_strndup (pch, (gint) (end - pch));
- g_strstrip (id);
- g_mime_part_set_content_id (mime_part, id);
- g_free (id);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_TRANSFER_ENCODING: {
- const gchar* pch = headers_ptr + strlen(content_headers[type]);
- const gchar* end = find_header_end (pch, headers_end);
- gchar *encoding = g_strndup (pch, (gint) (end - pch));
- g_strstrip (encoding);
- g_mime_part_set_encoding (mime_part, g_mime_part_encoding_from_string(encoding));
- g_free (encoding);
+ case CONTENT_DESCRIPTION: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *desc_enc = g_strndup (pch, (gint)(end - pch));
+ gchar *desc_dec = g_mime_utils_8bit_header_decode (desc_enc);
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_TYPE: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *type = g_strndup (pch, (gint) (end - pch));
- GMimeContentType *mime_type;
- g_strstrip (type);
- mime_type = g_mime_content_type_new_from_string (type);
- g_free (type);
-
- *is_multipart = g_mime_content_type_is_type (mime_type, "multipart", "*");
- if (*is_multipart) {
- const gchar *b;
- b = g_mime_content_type_get_parameter (mime_type, "boundary");
- if (b != NULL) {
- /* create our temp boundary vars */
- *boundary = g_strdup_printf ("--%s\n", b);
- *end_boundary = g_strdup_printf ("--%s--\n", b);
- } else {
- g_warning ("Invalid MIME structure: boundary not found for multipart"
- " - defaulting to text/plain.");
-
- /* let's continue onward as if this was not a multipart */
- g_mime_content_type_destroy (mime_type);
- mime_type = g_mime_content_type_new ("text", "plain");
- is_multipart = FALSE;
- }
+ g_strstrip (desc_dec);
+ g_mime_part_set_content_description (mime_part, desc_dec);
+ g_free (desc_enc);
+ g_free (desc_dec);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_LOCATION: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar * loc = g_strndup (pch, (gint)(end - pch));
+
+ g_strstrip (loc);
+ g_mime_part_set_content_location (mime_part, loc);
+ g_free (loc);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_MD5: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *md5 = g_strndup (pch, (gint) (end - pch));
+
+ g_strstrip (md5);
+ g_mime_part_set_content_md5 (mime_part, md5);
+ g_free (md5);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_ID: {
+ const gchar* pch = headers_ptr + strlen (content_headers[type]);
+ const gchar* end = find_header_end (pch, headers_end);
+ gchar *id = g_strndup (pch, (gint) (end - pch));
+
+ g_strstrip (id);
+ g_mime_part_set_content_id (mime_part, id);
+ g_free (id);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_TRANSFER_ENCODING: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *encoding = g_strndup (pch, (gint) (end - pch));
+
+ g_strstrip (encoding);
+ g_mime_part_set_encoding (mime_part, g_mime_part_encoding_from_string (encoding));
+ g_free (encoding);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_TYPE: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *type = g_strndup (pch, (gint) (end - pch));
+ GMimeContentType *mime_type;
+
+ g_strstrip (type);
+ mime_type = g_mime_content_type_new_from_string (type);
+ g_free (type);
+
+ *is_multipart = g_mime_content_type_is_type (mime_type, "multipart", "*");
+ if (*is_multipart) {
+ const gchar *b;
+
+ b = g_mime_content_type_get_parameter (mime_type, "boundary");
+ if (b != NULL) {
+ /* create our temp boundary vars */
+ *boundary = g_strdup_printf ("--%s\n", b);
+ *end_boundary = g_strdup_printf ("--%s--\n", b);
+ } else {
+ g_warning ("Invalid MIME structure: boundary not found for multipart"
+ " - defaulting to text/plain.");
+
+ /* let's continue onward as if this was not a multipart */
+ g_mime_content_type_destroy (mime_type);
+ mime_type = g_mime_content_type_new ("text", "plain");
+ is_multipart = FALSE;
}
- g_mime_part_set_content_type (mime_part, mime_type);
-
- headers_ptr = end + 1;
- break;
}
- case CONTENT_DISPOSITION: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *disposition = g_strndup (pch, (gint) (end - pch));
- gchar *ptr;
- gchar *disp;
-
- /* get content disposition part */
- for (ptr=disposition; *ptr && *ptr!=';'; ++ptr); /* find ; or \0 */
- disp = g_strndup (disposition, (gint)(ptr - disposition));
- g_strstrip (disp);
- g_mime_part_set_content_disposition (mime_part, disp);
- g_free (disp);
-
- /* parse the parameters, if any */
- while (*ptr==';') {
- gchar *name;
- gchar *value;
-
- /* get the param name */
- for (name = ptr + 1; *name && !isspace((int)*name); ++name);
- for (ptr = name; *ptr && *ptr != '='; ++ptr);
- name = g_strndup (name, (gint) (ptr - name));
- g_strstrip (name);
-
- /* convert param name to lowercase */
- g_strdown (name);
+ g_mime_part_set_content_type (mime_part, mime_type);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_DISPOSITION: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *disposition = g_strndup (pch, (gint) (end - pch));
+ gchar *ptr;
+ gchar *disp;
+
+ /* get content disposition part */
+ for (ptr = disposition; *ptr && *ptr != ';'; ptr++); /* find ; or \0 */
+ disp = g_strndup (disposition, (gint)(ptr - disposition));
+ g_strstrip (disp);
+ g_mime_part_set_content_disposition (mime_part, disp);
+ g_free (disp);
+
+ /* parse the parameters, if any */
+ while (*ptr == ';') {
+ gchar *name;
+ gchar *value;
+
+ /* get the param name */
+ for (name = ptr + 1; *name && !isspace ((int)*name); name++);
+ for (ptr = name; *ptr && *ptr != '='; ptr++);
+ name = g_strndup (name, (gint) (ptr - name));
+ g_strstrip (name);
+
+ /* convert param name to lowercase */
+ g_strdown (name);
- /* skip any whitespace */
- for (value = ptr + 1; *value && isspace((int)*value); value++);
+ /* skip any whitespace */
+ for (value = ptr + 1; *value && isspace ((int)*value); value++);
- if (*value == '"') /* value is in quotes */
- {
- value++;
- for (ptr = value; *ptr; ptr++)
- if (*ptr == '"' && *(ptr - 1) != '\\')
- break;
- value = g_strndup (value, (gint) (ptr - value));
- g_strstrip (value);
- g_mime_utils_unquote_string (value);
+ if (*value == '"') {
+ /* value is in quotes */
+ value++;
+ for (ptr = value; *ptr; ptr++)
+ if (*ptr == '"' && *(ptr - 1) != '\\')
+ break;
+ value = g_strndup (value, (gint) (ptr - value));
+ g_strstrip (value);
+ g_mime_utils_unquote_string (value);
- for ( ; *ptr && *ptr != ';'; ptr++);
- }
- else /* value is not in quotes */
- {
- for (ptr = value; *ptr && *ptr != ';'; ptr++);
- value = g_strndup (value, (gint) (ptr - value));
- g_strstrip (value);
- }
-
- g_mime_part_add_content_disposition_parameter (mime_part, name, value);
-
- g_free (name);
- g_free (value);
+ for ( ; *ptr && *ptr != ';'; ptr++);
+ } else {
+ /* value is not in quotes */
+ for (ptr = value; *ptr && *ptr != ';'; ptr++);
+ value = g_strndup (value, (gint) (ptr - value));
+ g_strstrip (value);
}
-
- g_free (disposition);
- headers_ptr = end + 1;
- break;
- }
- default: { /* ignore this header */
- const gchar *pch = headers_ptr;
- const gchar *end = find_header_end (pch, headers_end);
- headers_ptr = end + 1;
- break;
+ g_mime_part_add_content_disposition_parameter (mime_part, name, value);
+
+ g_free (name);
+ g_free (value);
}
+
+ g_free (disposition);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ default: { /* ignore this header */
+ const gchar *pch = headers_ptr;
+ const gchar *end = find_header_end (pch, headers_end);
+
+ headers_ptr = end + 1;
+ break;
+ }
}
}
}
-typedef enum
-{
+typedef enum {
PARSER_EOF,
PARSER_BOUNDARY,
PARSER_END_BOUNDARY,
PARSER_LINE
-}
-ParserState;
+} ParserState;
static ParserState
-get_next_line (gchar *buf,
- guint buf_len,
- FILE *fp,
- const gchar *boundary,
- const gchar *end_boundary)
+get_next_line (gchar *buf, guint buf_len, FILE *fp, const gchar *boundary, const gchar *end_boundary)
{
ParserState state;
-
+
*buf = '\0';
- if (fgets(buf, buf_len, fp) == NULL)
+ if (fgets (buf, buf_len, fp) == NULL)
state = PARSER_EOF;
- else if (boundary!=NULL && !strcmp (buf, boundary))
+ else if (boundary != NULL && !strcmp (buf, boundary))
state = PARSER_BOUNDARY;
- else if (end_boundary!=NULL && !strcmp (buf, end_boundary))
+ else if (end_boundary != NULL && !strcmp (buf, end_boundary))
state = PARSER_END_BOUNDARY;
else
state = PARSER_LINE;
-
+
return state;
}
@@ -420,49 +428,47 @@ g_mime_parser_construct_part_from_file (const gchar *headers,
gchar *end_boundary;
gboolean is_multipart;
GMimePart *mime_part;
-
- g_return_val_if_fail (headers!=NULL, NULL);
- g_return_val_if_fail (headers_len>0, NULL);
- g_return_val_if_fail (fp!=NULL, NULL);
- g_return_val_if_fail (setme_state!=NULL, NULL);
-
- /**
- *** Headers
- **/
-
+
+ g_return_val_if_fail (headers != NULL, NULL);
+ g_return_val_if_fail (headers_len > 0, NULL);
+ g_return_val_if_fail (fp != NULL, NULL);
+ g_return_val_if_fail (setme_state != NULL, NULL);
+
+ /* Headers */
boundary = NULL;
end_boundary = NULL;
is_multipart = FALSE;
mime_part = g_mime_part_new ();
parse_content_headers (headers, headers_len, mime_part, &is_multipart, &boundary, &end_boundary);
-
- /**
- *** Body
- **/
-
+
+ /* Body */
if (is_multipart && boundary!=NULL && end_boundary!=NULL) { /* is a multipart */
/* get all the subparts */
gchar buf[GMIME_PARSER_MAX_LINE_WIDTH];
-
+
for (;;) {
/* get the next line, we're looking for the beginning of a subpart */
- ParserState ps = get_next_line (buf, sizeof(buf), fp, parent_boundary, parent_end_boundary);
+ ParserState ps = get_next_line (buf, sizeof (buf), fp, parent_boundary,
+ parent_end_boundary);
if (ps != PARSER_LINE) {
*setme_state = ps;
break;
}
-
+
/* is the beginning of a subpart? */
if (strcmp (buf, boundary))
continue;
-
+
/* add subparts as long as we keep getting boundaries */
for (;;) {
GArray *h = get_header_block_from_file (fp);
if (h != NULL) {
ParserState ps = 0;
- GMimePart * part = g_mime_parser_construct_part_from_file (
- h->data, h->len, fp, boundary, end_boundary, &ps);
+ GMimePart *part;
+
+ part = g_mime_parser_construct_part_from_file (h->data, h->len,
+ fp, boundary,
+ end_boundary, &ps);
g_array_free (h, TRUE);
if (part != NULL)
g_mime_part_add_subpart (mime_part, part);
@@ -471,36 +477,38 @@ g_mime_parser_construct_part_from_file (const gchar *headers,
}
}
}
- }
- else { /* not a multipart */
+ } else {
+ /* not a multipart */
GMimePartEncodingType encoding = g_mime_part_get_encoding (mime_part);
- GArray * a = g_array_new (TRUE, FALSE, 1);
+ GArray *a = g_array_new (TRUE, FALSE, 1);
gchar buf [GMIME_PARSER_MAX_LINE_WIDTH];
-
+
/* keep reading lines until we reach a boundary or EOF, we're populating a part */
for (;;) {
- ParserState ps = get_next_line (buf, sizeof(buf), fp, parent_boundary, parent_end_boundary);
- if (ps == PARSER_LINE)
- g_array_append_vals (a, buf, strlen(buf));
- else {
+ ParserState ps = get_next_line (buf, sizeof (buf), fp,
+ parent_boundary,
+ parent_end_boundary);
+ if (ps == PARSER_LINE) {
+ g_array_append_vals (a, buf, strlen (buf));
+ } else {
*setme_state = ps;
break;
}
-
}
-
+
/* trim off excess trailing \n's */
- while (a->len>2 && a->data[a->len-1]=='\n' && a->data[a->len-2]=='\n')
- g_array_set_size (a, a->len-1);
-
+ while (a->len > 2 && a->data[a->len-1] == '\n' && a->data[a->len - 2] == '\n')
+ g_array_set_size (a, a->len - 1);
+
if (a->len > 0)
g_mime_part_set_pre_encoded_content (mime_part, a->data, a->len, encoding);
-
+
g_array_free (a, TRUE);
}
-
+
g_free (boundary);
g_free (end_boundary);
+
return mime_part;
}
@@ -523,33 +531,27 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
gboolean is_multipart;
const gchar *inptr;
const gchar *inend = in + inlen;
-
- g_return_val_if_fail (in!=NULL, NULL);
- g_return_val_if_fail (inlen!=0, NULL);
- /**
- *** Headers
- **/
-
+ g_return_val_if_fail (in != NULL, NULL);
+ g_return_val_if_fail (inlen != 0, NULL);
+
+ /* Headers */
headers = get_header_block (in);
mime_part = g_mime_part_new ();
is_multipart = FALSE;
boundary = NULL;
end_boundary = NULL;
- parse_content_headers (headers->data, headers->len, mime_part, &is_multipart, &boundary, &end_boundary);
-
- /**
- *** Body
- **/
-
+ parse_content_headers (headers->data, headers->len, mime_part,
+ &is_multipart, &boundary, &end_boundary);
+
+ /* Body */
inptr = in + headers->len;
-
- if (is_multipart && boundary && end_boundary)
- {
+
+ if (is_multipart && boundary && end_boundary) {
/* get all the subparts */
- GMimePart * subpart;
- const gchar * part_begin;
- const gchar * part_end;
+ GMimePart *subpart;
+ const gchar *part_begin;
+ const gchar *part_end;
part_begin = g_strstrbound (inptr, boundary, inend);
while (part_begin && part_begin < inend) {
@@ -560,7 +562,8 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
/* find the end of this part */
part_end = g_strstrbound (part_begin + strlen (boundary), boundary, inend);
if (!part_end || part_end >= inend) {
- part_end = g_strstrbound (part_begin + strlen (boundary), end_boundary, inend);
+ part_end = g_strstrbound (part_begin + strlen (boundary),
+ end_boundary, inend);
if (!part_end || part_end >= inend)
part_end = inend;
}
@@ -578,12 +581,12 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
g_free (end_boundary);
} else {
GMimePartEncodingType encoding;
- const gchar * content = NULL;
+ const gchar *content = NULL;
guint len = 0;
/* from here to the end is the content */
if (inptr < inend) {
- for (inptr++; inptr < inend && isspace((int)*inptr); inptr++);
+ for (inptr++; inptr < inend && isspace ((int)*inptr); inptr++);
len = inend - inptr;
content = inptr;
@@ -600,8 +603,9 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
if (len > 0)
g_mime_part_set_pre_encoded_content (mime_part, content, len, encoding);
}
-
+
g_array_free (headers, TRUE);
+
return mime_part;
}
@@ -734,21 +738,20 @@ construct_headers (GMimeMessage *message, const gchar *headers, gint inlen, gboo
GMimeMessage *
g_mime_parser_construct_message (const gchar *data, gboolean save_extra_headers)
{
- GMimeMessage * message = NULL;
- GArray * headers;
+ GMimeMessage *message = NULL;
+ GArray *headers;
g_return_val_if_fail (data != NULL, NULL);
-
+
headers = get_header_block (data);
- if (headers != NULL)
- {
+ if (headers != NULL) {
GMimePart * part;
-
+
message = g_mime_message_new ();
construct_headers (message, headers->data, headers->len, save_extra_headers);
part = g_mime_parser_construct_part (data, strlen(data));
g_mime_message_set_mime_part (message, part);
-
+
g_array_free (headers, TRUE);
}
@@ -765,24 +768,24 @@ g_mime_parser_construct_message (const gchar *data, gboolean save_extra_headers)
GMimeMessage *
g_mime_parser_construct_message_from_file (FILE *fp, gboolean save_extra_headers)
{
- GMimeMessage * message = NULL;
- GArray * headers;
-
- g_return_val_if_fail (fp!=NULL, NULL);
-
+ GMimeMessage *message = NULL;
+ GArray *headers;
+
+ g_return_val_if_fail (fp != NULL, NULL);
+
headers = get_header_block_from_file (fp);
- if (headers != NULL)
- {
- GMimePart * part;
+ if (headers != NULL) {
+ GMimePart *part;
ParserState state = -1;
-
+
message = g_mime_message_new ();
construct_headers (message, headers->data, headers->len, save_extra_headers);
- part = g_mime_parser_construct_part_from_file (headers->data, headers->len, fp, NULL, NULL, &state);
+ part = g_mime_parser_construct_part_from_file (headers->data, headers->len, fp,
+ NULL, NULL, &state);
g_mime_message_set_mime_part (message, part);
if (state != PARSER_EOF)
g_warning ("Didn't reach end of file - parser error?");
-
+
g_array_free (headers, TRUE);
}
diff --git a/gmime-table-private.h b/gmime-table-private.h
new file mode 100644
index 00000000..7350960a
--- /dev/null
+++ b/gmime-table-private.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximain, Inc. (www.ximian.com)
+ *
+ * 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 of the License, 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+static unsigned short gmime_special_table[256] = {
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,231, 7, 5, 5, 39, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 242,448, 76,192,192,192,192,192, 76, 76,448,448, 76,448, 72,324,
+ 448,448,448,448,448,448,448,448,448,448, 76, 76, 76, 4, 76, 68,
+ 76,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
+ 448,448,448,448,448,448,448,448,448,448,448,108,236,108,192, 64,
+ 192,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
+ 448,448,448,448,448,448,448,448,448,448,448,192,192,192,192, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+enum {
+ IS_CTRL = 1<<0,
+ IS_LWSP = 1<<1,
+ IS_TSPECIAL = 1<<2,
+ IS_SPECIAL = 1<<3,
+ IS_SPACE = 1<<4,
+ IS_DSPECIAL = 1<<5,
+ IS_QPSAFE = 1<<6,
+ IS_ESAFE = 1<<7, /* encoded word safe */
+ IS_PSAFE = 1<<8, /* encoded word in phrase safe */
+};
+
+#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)
+#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)
+#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)
+#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)
+#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)
+#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)
+#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)
+#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)
+#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
+#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
+#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
+
+#ifndef HAVE_ISBLANK
+#define isblank(c) ((c) == ' ' || (c) == '\t')
+#endif /* HAVE_ISBLANK */
+
+#define CHARS_LWSP " \t\n\r" /* linear whitespace chars */
+#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
+#define CHARS_SPECIAL "()<>@,;:\\\".[]"
+#define CHARS_CSPECIAL "()\\\r" /* not in comments */
+#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
+#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials (rfc2047 5.1) */
+#define CHARS_PSPECIAL "!*+-/" /* encoded phrase specials (rfc2047 5.3) */
diff --git a/gmime-utils.c b/gmime-utils.c
index 540ff670..f0c062bd 100644
--- a/gmime-utils.c
+++ b/gmime-utils.c
@@ -21,9 +21,14 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "gmime-utils.h"
+#include "gmime-table-private.h"
#include "gmime-part.h"
-#include <config.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,6 +40,10 @@
#define GMIME_FOLD_LEN 76
+#ifndef HAVE_ISBLANK
+#define isblank(c) (c == ' ' || c == '\t')
+#endif
+
static char *base64_alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -43,25 +52,6 @@ static unsigned char tohex[16] = {
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
-static unsigned short gmime_special_table[256] = {
- 5, 5, 5, 5, 5, 5, 5, 5, 5,231, 7, 5, 5, 39, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 242,448, 76,192,192,192,192,192, 76, 76,448,448, 76,448, 72,324,
- 448,448,448,448,448,448,448,448,448,448, 76, 76, 76, 4, 76, 68,
- 76,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
- 448,448,448,448,448,448,448,448,448,448,448,108,236,108,192, 64,
- 192,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
- 448,448,448,448,448,448,448,448,448,448,448,192,192,192,192, 5,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
static unsigned char gmime_base64_rank[256] = {
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
@@ -101,109 +91,6 @@ static unsigned char gmime_uu_rank[256] = {
};
-enum {
- IS_CTRL = 1<<0,
- IS_LWSP = 1<<1,
- IS_TSPECIAL = 1<<2,
- IS_SPECIAL = 1<<3,
- IS_SPACE = 1<<4,
- IS_DSPECIAL = 1<<5,
- IS_QPSAFE = 1<<6,
- IS_ESAFE = 1<<7, /* encoded word safe */
- IS_PSAFE = 1<<8, /* encoded word in phrase safe */
-};
-
-#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)
-#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)
-#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)
-#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)
-#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)
-#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)
-#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)
-#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)
-#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
-#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
-#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
-
-#ifndef HAVE_ISBLANK
-#define isblank(c) ((c) == ' ' || (c) == '\t')
-#endif /* HAVE_ISBLANK */
-
-#define CHARS_LWSP " \t\n\r" /* linear whitespace chars */
-#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
-#define CHARS_SPECIAL "()<>@,;:\\\".[]"
-#define CHARS_CSPECIAL "()\\\r" /* not in comments */
-#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
-#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials (rfc2047 5.1) */
-#define CHARS_PSPECIAL "!*+-/" /* encoded phrase specials (rfc2047 5.3) */
-
-#ifdef BUILD_TABLE
-/* code to rebuild the gmime_special_table */
-static void
-header_remove_bits (gushort bit, guchar *vals)
-{
- gint i;
-
- for (i = 0; vals[i]; i++)
- gmime_special_table[vals[i]] &= ~bit;
-}
-
-static void
-header_init_bits (gushort bit, gushort bitcopy, gboolean remove, guchar *vals)
-{
- gint i, len = strlen (vals);
-
- if (!remove) {
- for (i = 0; i < len; i++) {
- gmime_special_table[vals[i]] |= bit;
- }
- if (bitcopy) {
- for (i = 0; i < 256; i++) {
- if (gmime_special_table[i] & bitcopy)
- gmime_special_table[i] |= bit;
- }
- }
- } else {
- for (i = 0; i < 256; i++)
- gmime_special_table[i] |= bit;
- for (i = 0; i < len; i++) {
- gmime_special_table[vals[i]] &= ~bit;
- }
- if (bitcopy) {
- for (i = 0; i < 256; i++) {
- if (gmime_special_table[i] & bitcopy)
- gmime_special_table[i] &= ~bit;
- }
- }
- }
-}
-
-static void
-header_decode_init (void)
-{
- gint i;
-
- for (i = 0; i < 256; i++) {
- gmime_special_table[i] = 0;
- if (i < 32)
- gmime_special_table[i] |= IS_CTRL;
- if ((i >= 33 && i <= 60) || (i >= 62 && i <= 126) || i == 32 || i == 9)
- gmime_special_table[i] |= (IS_QPSAFE | IS_ESAFE);
- if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z'))
- gmime_special_table[i] |= IS_PSAFE;
- }
-
- gmime_special_table[127] |= IS_CTRL;
- gmime_special_table[' '] |= IS_SPACE;
- header_init_bits (IS_LWSP, 0, FALSE, CHARS_LWSP);
- header_init_bits (IS_TSPECIAL, IS_CTRL, FALSE, CHARS_TSPECIAL);
- header_init_bits (IS_SPECIAL, 0, FALSE, CHARS_SPECIAL);
- header_init_bits (IS_DSPECIAL, 0, FALSE, CHARS_DSPECIAL);
- header_remove_bits (IS_ESAFE, CHARS_ESPECIAL);
- header_init_bits (IS_PSAFE, 0, FALSE, CHARS_PSPECIAL);
-}
-#endif /* BUILD_TABLE */
-
/* hrm, is there a library for this shit? */
static struct {
char *name;
@@ -654,6 +541,28 @@ g_mime_utils_header_printf (const gchar *format, ...)
return ret;
}
+static gboolean
+need_quotes (const char *string)
+{
+ gboolean quoted = FALSE;
+ const char *inptr;
+
+ inptr = string;
+
+ while (*inptr) {
+ if (*inptr == '\\')
+ inptr++;
+ else if (*inptr == '"')
+ quoted = !quoted;
+ else if (!quoted && is_tspecial (*inptr))
+ return TRUE;
+
+ if (*inptr)
+ inptr++;
+ }
+
+ return FALSE;
+}
/**
* g_mime_utils_quote_string: Quote a string.
@@ -667,18 +576,16 @@ g_mime_utils_header_printf (const gchar *format, ...)
gchar *
g_mime_utils_quote_string (const gchar *string)
{
- GString *out;
+ gboolean quote;
+ const gchar *c;
gchar *qstring;
- guchar *c;
- gboolean quote = FALSE;
+ GString *out;
out = g_string_new ("");
+ quote = need_quotes (string);
- for (c = (guchar *) string; *c; c++) {
- if (is_tspecial (*c))
- quote = TRUE;
-
- if (*c == '"' || *c == '\\')
+ for (c = string; *c; c++) {
+ if ((*c == '"' && quote) || *c == '\\')
g_string_append_c (out, '\\');
g_string_append_c (out, *c);
diff --git a/gmime/gen-table.c b/gmime/gen-table.c
new file mode 100644
index 00000000..672ef9a9
--- /dev/null
+++ b/gmime/gen-table.c
@@ -0,0 +1,183 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximain, Inc. (www.ximian.com)
+ *
+ * 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 of the License, 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+enum {
+ FALSE,
+ TRUE
+};
+
+#define CHARS_LWSP " \t\n\r" /* linear whitespace chars */
+#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
+#define CHARS_SPECIAL "()<>@,;:\\\".[]"
+#define CHARS_CSPECIAL "()\\\r" /* not in comments */
+#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
+#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials (rfc2047 5.1) */
+#define CHARS_PSPECIAL "!*+-/" /* encoded phrase specials (rfc2047 5.3) */
+
+static unsigned char gmime_special_table[256];
+
+enum {
+ IS_CTRL = 1<<0,
+ IS_LWSP = 1<<1,
+ IS_TSPECIAL = 1<<2,
+ IS_SPECIAL = 1<<3,
+ IS_SPACE = 1<<4,
+ IS_DSPECIAL = 1<<5,
+ IS_QPSAFE = 1<<6,
+ IS_ESAFE = 1<<7, /* encoded word safe */
+ IS_PSAFE = 1<<8, /* encoded word in phrase safe */
+};
+
+#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)
+#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)
+#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)
+#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)
+#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)
+#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)
+#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)
+#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)
+#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
+#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
+#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
+
+/* code to rebuild the gmime_special_table */
+static void
+header_remove_bits (unsigned short bit, unsigned char *vals)
+{
+ int i;
+
+ for (i = 0; vals[i]; i++)
+ gmime_special_table[vals[i]] &= ~bit;
+}
+
+static void
+header_init_bits (unsigned short bit, unsigned short bitcopy, int remove, unsigned char *vals)
+{
+ int i, len = strlen (vals);
+
+ if (!remove) {
+ for (i = 0; i < len; i++) {
+ gmime_special_table[vals[i]] |= bit;
+ }
+ if (bitcopy) {
+ for (i = 0; i < 256; i++) {
+ if (gmime_special_table[i] & bitcopy)
+ gmime_special_table[i] |= bit;
+ }
+ }
+ } else {
+ for (i = 0; i < 256; i++)
+ gmime_special_table[i] |= bit;
+ for (i = 0; i < len; i++) {
+ gmime_special_table[vals[i]] &= ~bit;
+ }
+ if (bitcopy) {
+ for (i = 0; i < 256; i++) {
+ if (gmime_special_table[i] & bitcopy)
+ gmime_special_table[i] &= ~bit;
+ }
+ }
+ }
+}
+
+static void
+header_decode_init (void)
+{
+ int i;
+
+ for (i = 0; i < 256; i++) {
+ gmime_special_table[i] = 0;
+ if (i < 32)
+ gmime_special_table[i] |= IS_CTRL;
+ if ((i >= 33 && i <= 60) || (i >= 62 && i <= 126) || i == 32 || i == 9)
+ gmime_special_table[i] |= (IS_QPSAFE | IS_ESAFE);
+ if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z'))
+ gmime_special_table[i] |= IS_PSAFE;
+ }
+
+ gmime_special_table[127] |= IS_CTRL;
+ gmime_special_table[' '] |= IS_SPACE;
+ header_init_bits (IS_LWSP, 0, FALSE, CHARS_LWSP);
+ header_init_bits (IS_TSPECIAL, IS_CTRL, FALSE, CHARS_TSPECIAL);
+ header_init_bits (IS_SPECIAL, 0, FALSE, CHARS_SPECIAL);
+ header_init_bits (IS_DSPECIAL, 0, FALSE, CHARS_DSPECIAL);
+ header_remove_bits (IS_ESAFE, CHARS_ESPECIAL);
+ header_init_bits (IS_PSAFE, 0, FALSE, CHARS_PSPECIAL);
+}
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ header_decode_init ();
+
+ printf ("/* THIS FILE IS AUTOGENERATED: DO NOT EDIT! */\n\n");
+ printf ("/**\n * To regenerate:\n * make gen-table\n");
+ printf (" * ./gen-table > gmime-table-private.h\n **/\n\n");
+
+ /* print out the table */
+ printf ("static unsigned short gmime_special_table[256] = {");
+ for (i = 0; i < 256; i++) {
+ printf ("%s%3d%s", (i % 16) ? "" : "\n\t",
+ gmime_special_table[i], i != 255 ? "," : "\n");
+ }
+ printf ("};\n\n");
+
+ /* print out the enum */
+ printf ("enum {\n");
+ printf ("\tIS_CTRL \t= 1 << 0,\n");
+ printf ("\tIS_LWSP \t= 1 << 1,\n");
+ printf ("\tIS_TSPECIAL\t= 1 << 2,\n");
+ printf ("\tIS_SPECIAL \t= 1 << 3,\n");
+ printf ("\tIS_SPACE \t= 1 << 4,\n");
+ printf ("\tIS_DSPECIAL\t= 1 << 5,\n");
+ printf ("\tIS_QPSAFE \t= 1 << 6,\n");
+ printf ("\tIS_ESAFE \t= 1 << 7, /* encoded word safe */\n");
+ printf ("\tIS_PPSAFE \t= 1 << 8 /* encode word in phrase safe */\n");
+ printf ("};\n\n");
+
+ printf ("#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)\n");
+ printf ("#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)\n");
+ printf ("#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)\n");
+ printf ("#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)\n");
+ printf ("#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)\n");
+ printf ("#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)\n");
+ printf ("#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)\n");
+ printf ("#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)\n");
+ printf ("#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)\n");
+ printf ("#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)\n");
+ printf ("#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)\n\n");
+
+ printf ("#define CHARS_LWSP \" \\t\\n\\r\" /* linear whitespace chars */\n");
+ printf ("#define CHARS_TSPECIAL \"%s\"\n", CHARS_TSPECIAL);
+ printf ("#define CHARS_SPECIAL \"%s\"\n", CHARS_SPECIAL);
+ printf ("#define CHARS_CSPECIAL \"()\\\\\\r\" /* not in comments */\n");
+ printf ("#define CHARS_DSPECIAL \"[]\\\\\\r \\t\" /* not in domains */\n");
+ printf ("#define CHARS_ESPECIAL \"()<>@,;:\\\"/[]?.=\" /* encoded word specials (rfc2047 5.1) */\n");
+ printf ("#define CHARS_PSPECIAL \"!*+-/\" /* encoded phrase specials (rfc2047 5.3) */\n");
+
+ return 0;
+}
diff --git a/gmime/gmime-content-type.c b/gmime/gmime-content-type.c
index de4d76d2..a37b0974 100644
--- a/gmime/gmime-content-type.c
+++ b/gmime/gmime-content-type.c
@@ -49,10 +49,15 @@ g_mime_content_type_new (const gchar *type, const gchar *subtype)
} else {
if (type && *type) {
mime_type->type = g_strdup (type);
- if (!g_strcasecmp (type, "text"))
+ if (!g_strcasecmp (type, "text")) {
mime_type->subtype = g_strdup ("plain");
- else
+ } else if (!g_strcasecmp (type, "multipart")) {
+ mime_type->subtype = g_strdup ("mixed");
+ } else {
+ g_free (mime_type->type);
+ mime_type->type = g_strdup ("application");
mime_type->subtype = g_strdup ("octet-stream");
+ }
} else {
mime_type->type = g_strdup ("application");
mime_type->subtype = g_strdup ("octet-stream");
diff --git a/gmime/gmime-message.c b/gmime/gmime-message.c
index 726fdeeb..02f74eef 100644
--- a/gmime/gmime-message.c
+++ b/gmime/gmime-message.c
@@ -20,10 +20,14 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "gmime-message.h"
#include "gmime-utils.h"
#include "internet-address.h"
-#include <config.h>
+
#include <string.h>
#include <ctype.h>
#include <locale.h>
@@ -202,7 +206,7 @@ g_mime_message_add_recipient (GMimeMessage *message, gchar *type, const gchar *n
InternetAddress *ia;
GList *recipients;
- ia = internet_address_new (name, address);
+ ia = internet_address_new_name (name, address);
recipients = g_hash_table_lookup (message->header->recipients, type);
g_hash_table_remove (message->header->recipients, type);
@@ -227,9 +231,7 @@ g_mime_message_add_recipient (GMimeMessage *message, gchar *type, const gchar *n
void
g_mime_message_add_recipients_from_string (GMimeMessage *message, gchar *type, const gchar *string)
{
- InternetAddress *ia;
- GList *recipients;
- gchar *ptr, *eptr, *recipient;
+ GList *recipients, *addrlist;
g_return_if_fail (message != NULL);
g_return_if_fail (string != NULL);
@@ -237,38 +239,9 @@ g_mime_message_add_recipients_from_string (GMimeMessage *message, gchar *type, c
recipients = g_hash_table_lookup (message->header->recipients, type);
g_hash_table_remove (message->header->recipients, type);
- ptr = (gchar *) string;
-
- while (*ptr) {
- gboolean in_quotes = FALSE;
-
- /* skip through leading whitespace */
- for ( ; *ptr && isspace (*ptr); ptr++);
-
- if (*ptr == '"')
- in_quotes = TRUE;
-
- /* find the end of this address */
- eptr = ptr + 1;
- while (*eptr) {
- if (*eptr == '"' && *(eptr - 1) != '\\')
- in_quotes = !in_quotes;
- else if (*eptr == ',' && !in_quotes)
- break;
-
- eptr++;
- }
-
- recipient = g_strndup (ptr, (gint) (eptr - ptr));
- ia = internet_address_new_from_string (recipient);
- g_free (recipient);
- recipients = g_list_append (recipients, ia);
-
- if (*eptr)
- ptr = eptr + 1;
- else
- break;
- }
+ addrlist = internet_address_parse_string (string);
+ if (addrlist)
+ recipients = g_list_concat (recipients, addrlist);
g_hash_table_insert (message->header->recipients, type, recipients);
}
@@ -523,7 +496,7 @@ create_header (GMimeMessage *message)
GString *recip;
recip = g_string_new ("To: ");
- while (TRUE) {
+ while (recipients) {
InternetAddress *ia;
gchar *address;
@@ -535,8 +508,6 @@ create_header (GMimeMessage *message)
recipients = recipients->next;
if (recipients)
g_string_append (recip, ", ");
- else
- break;
}
g_string_append (recip, "\n");
buf = g_mime_utils_header_fold (recip->str);
@@ -551,7 +522,7 @@ create_header (GMimeMessage *message)
GString *recip;
recip = g_string_new ("Cc: ");
- while (TRUE) {
+ while (recipients) {
InternetAddress *ia;
gchar *address;
@@ -563,8 +534,6 @@ create_header (GMimeMessage *message)
recipients = recipients->next;
if (recipients)
g_string_append (recip, ", ");
- else
- break;
}
g_string_append (recip, "\n");
buf = g_mime_utils_header_fold (recip->str);
diff --git a/gmime/gmime-parser.c b/gmime/gmime-parser.c
index 98326ac0..f2c69a79 100644
--- a/gmime/gmime-parser.c
+++ b/gmime/gmime-parser.c
@@ -21,9 +21,13 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "gmime-parser.h"
#include "gmime-utils.h"
-#include <config.h>
+
#include <string.h>
#include <ctype.h>
@@ -114,51 +118,56 @@ g_strstrbound (const gchar *haystack, const gchar *needle, const gchar *end)
* leave fp_in pointing at the message body that comes after the
* headers.
**/
-static GArray*
+static GArray *
get_header_block_from_file (FILE *fp)
{
- GArray * a;
+ GArray *a;
gchar buf [GMIME_PARSER_MAX_LINE_WIDTH];
-
- g_return_val_if_fail (fp!=NULL, NULL);
-
+
+ g_return_val_if_fail (fp != NULL, NULL);
+
a = g_array_new (TRUE, FALSE, 1);
for (;;) {
- gchar * pch = fgets (buf, sizeof(buf), fp);
- if (pch == NULL) { /* eof reached before end-of-headers! */
+ gchar *pch;
+
+ pch = fgets (buf, sizeof (buf), fp);
+ if (pch == NULL) {
+ /* eof reached before end-of-headers! */
g_array_free (a, TRUE);
a = NULL;
break;
}
- if (!strcmp(buf,"\n")) /* empty line -- end of headers */
+
+ /* empty line -- end of headers */
+ if (!strcmp (buf,"\n"))
break;
-
+
g_array_append_vals (a, buf, strlen(buf));
}
-
+
return a;
}
/**
* get_header_block: Get the header block from a message.
- * @message the message text; that is, header + body.
+ * @message: the message text; that is, header + body.
*
* This will read all of the headers into an unparsed GArray.
**/
-static GArray*
+static GArray *
get_header_block (const gchar *pch)
{
- GArray * a = NULL;
- const gchar * header_end;
-
- g_return_val_if_fail (pch!=NULL, NULL);
-
+ GArray *a = NULL;
+ const gchar *header_end;
+
+ g_return_val_if_fail (pch != NULL, NULL);
+
header_end = strstr (pch, "\n\n");
if (header_end != NULL) {
a = g_array_new (TRUE, FALSE, 1);
- g_array_append_vals (a, pch, header_end-pch);
+ g_array_append_vals (a, pch, header_end - pch);
}
-
+
return a;
}
@@ -170,235 +179,234 @@ get_header_block (const gchar *pch)
*
* Returns a pointer to the end of a header.
**/
-static const gchar*
+static const gchar *
find_header_end (const gchar *header, const gchar *boundary)
{
const gchar * eptr;
-
- g_return_val_if_fail (header!=NULL, NULL);
- g_return_val_if_fail (boundary!=NULL, NULL);
-
- for (eptr=header; eptr<boundary; ++eptr)
- if (*eptr=='\n' && !isblank(eptr[1]))
+
+ g_return_val_if_fail (header != NULL, NULL);
+ g_return_val_if_fail (boundary != NULL, NULL);
+
+ for (eptr = header; eptr < boundary; eptr++)
+ if (*eptr == '\n' && !isblank (eptr[1]))
break;
-
- return (gchar*)eptr;
+
+ return eptr;
}
/**
- * parse_content_heaaders: picks the Content-* headers from a header block and extracts info from them.
+ * parse_content_heaaders: picks the Content-* headers from a header block
+ * and extracts info from them.
* @headers: string containing the zero-terminated header block.
* @headers_len: length of the header block.
- * @mime_part: mime_part to populate with the information we get from the Content-* headers.
- * @is_multipart: set to TRUE if the part is a multipart, FALSE otherwise
- * @boundary: if this is a multipart, *boundary is set with the boundary string, which must be g_free()d by the caller.
- * @end_boundary: if this is a multipart, *boundary is set with the end boundary string, which must be g_free()d by the caller.
+ * @mime_part: mime part to populate with the information we get from the Content-* headers.
+ * @is_multipart: set to TRUE if the part is a multipart, FALSE otherwise (to be set by function)
+ * @boundary: multipart boundary string (to be set by function)
+ * @end_boundary: multipart end boundary string (to be set by function)
*
* Parse a header block for content information.
*/
static void
-parse_content_headers (const gchar *headers,
- gint headers_len,
- GMimePart *mime_part,
- gboolean *is_multipart,
- gchar **boundary,
- gchar **end_boundary)
+parse_content_headers (const gchar *headers, gint headers_len,
+ GMimePart *mime_part, gboolean *is_multipart,
+ gchar **boundary, gchar **end_boundary)
{
- const gchar * headers_ptr = headers;
- const gchar * headers_end = headers + headers_len;
-
+ const gchar *headers_ptr = headers;
+ const gchar *headers_end = headers + headers_len;
+
while (headers_ptr < headers_end) {
const gint type = content_header (headers_ptr);
-
+
switch (type) {
- case CONTENT_DESCRIPTION: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *desc_enc = g_strndup (pch, (gint)(end - pch));
- gchar *desc_dec = g_mime_utils_8bit_header_decode (desc_enc);
- g_strstrip (desc_dec);
- g_mime_part_set_content_description (mime_part, desc_dec);
- g_free (desc_enc);
- g_free (desc_dec);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_LOCATION: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar * loc = g_strndup (pch, (gint)(end - pch));
- g_strstrip (loc);
- g_mime_part_set_content_location (mime_part, loc);
- g_free (loc);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_MD5: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *md5 = g_strndup (pch, (gint) (end - pch));
- g_strstrip (md5);
- g_mime_part_set_content_md5 (mime_part, md5);
- g_free (md5);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_ID: {
- const gchar* pch = headers_ptr + strlen(content_headers[type]);
- const gchar* end = find_header_end (pch, headers_end);
- gchar *id = g_strndup (pch, (gint) (end - pch));
- g_strstrip (id);
- g_mime_part_set_content_id (mime_part, id);
- g_free (id);
-
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_TRANSFER_ENCODING: {
- const gchar* pch = headers_ptr + strlen(content_headers[type]);
- const gchar* end = find_header_end (pch, headers_end);
- gchar *encoding = g_strndup (pch, (gint) (end - pch));
- g_strstrip (encoding);
- g_mime_part_set_encoding (mime_part, g_mime_part_encoding_from_string(encoding));
- g_free (encoding);
+ case CONTENT_DESCRIPTION: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *desc_enc = g_strndup (pch, (gint)(end - pch));
+ gchar *desc_dec = g_mime_utils_8bit_header_decode (desc_enc);
- headers_ptr = end + 1;
- break;
- }
- case CONTENT_TYPE: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *type = g_strndup (pch, (gint) (end - pch));
- GMimeContentType *mime_type;
- g_strstrip (type);
- mime_type = g_mime_content_type_new_from_string (type);
- g_free (type);
-
- *is_multipart = g_mime_content_type_is_type (mime_type, "multipart", "*");
- if (*is_multipart) {
- const gchar *b;
- b = g_mime_content_type_get_parameter (mime_type, "boundary");
- if (b != NULL) {
- /* create our temp boundary vars */
- *boundary = g_strdup_printf ("--%s\n", b);
- *end_boundary = g_strdup_printf ("--%s--\n", b);
- } else {
- g_warning ("Invalid MIME structure: boundary not found for multipart"
- " - defaulting to text/plain.");
-
- /* let's continue onward as if this was not a multipart */
- g_mime_content_type_destroy (mime_type);
- mime_type = g_mime_content_type_new ("text", "plain");
- is_multipart = FALSE;
- }
+ g_strstrip (desc_dec);
+ g_mime_part_set_content_description (mime_part, desc_dec);
+ g_free (desc_enc);
+ g_free (desc_dec);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_LOCATION: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar * loc = g_strndup (pch, (gint)(end - pch));
+
+ g_strstrip (loc);
+ g_mime_part_set_content_location (mime_part, loc);
+ g_free (loc);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_MD5: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *md5 = g_strndup (pch, (gint) (end - pch));
+
+ g_strstrip (md5);
+ g_mime_part_set_content_md5 (mime_part, md5);
+ g_free (md5);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_ID: {
+ const gchar* pch = headers_ptr + strlen (content_headers[type]);
+ const gchar* end = find_header_end (pch, headers_end);
+ gchar *id = g_strndup (pch, (gint) (end - pch));
+
+ g_strstrip (id);
+ g_mime_part_set_content_id (mime_part, id);
+ g_free (id);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_TRANSFER_ENCODING: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *encoding = g_strndup (pch, (gint) (end - pch));
+
+ g_strstrip (encoding);
+ g_mime_part_set_encoding (mime_part, g_mime_part_encoding_from_string (encoding));
+ g_free (encoding);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_TYPE: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *type = g_strndup (pch, (gint) (end - pch));
+ GMimeContentType *mime_type;
+
+ g_strstrip (type);
+ mime_type = g_mime_content_type_new_from_string (type);
+ g_free (type);
+
+ *is_multipart = g_mime_content_type_is_type (mime_type, "multipart", "*");
+ if (*is_multipart) {
+ const gchar *b;
+
+ b = g_mime_content_type_get_parameter (mime_type, "boundary");
+ if (b != NULL) {
+ /* create our temp boundary vars */
+ *boundary = g_strdup_printf ("--%s\n", b);
+ *end_boundary = g_strdup_printf ("--%s--\n", b);
+ } else {
+ g_warning ("Invalid MIME structure: boundary not found for multipart"
+ " - defaulting to text/plain.");
+
+ /* let's continue onward as if this was not a multipart */
+ g_mime_content_type_destroy (mime_type);
+ mime_type = g_mime_content_type_new ("text", "plain");
+ is_multipart = FALSE;
}
- g_mime_part_set_content_type (mime_part, mime_type);
-
- headers_ptr = end + 1;
- break;
}
- case CONTENT_DISPOSITION: {
- const gchar *pch = headers_ptr + strlen(content_headers[type]);
- const gchar *end = find_header_end (pch, headers_end);
- gchar *disposition = g_strndup (pch, (gint) (end - pch));
- gchar *ptr;
- gchar *disp;
-
- /* get content disposition part */
- for (ptr=disposition; *ptr && *ptr!=';'; ++ptr); /* find ; or \0 */
- disp = g_strndup (disposition, (gint)(ptr - disposition));
- g_strstrip (disp);
- g_mime_part_set_content_disposition (mime_part, disp);
- g_free (disp);
-
- /* parse the parameters, if any */
- while (*ptr==';') {
- gchar *name;
- gchar *value;
-
- /* get the param name */
- for (name = ptr + 1; *name && !isspace((int)*name); ++name);
- for (ptr = name; *ptr && *ptr != '='; ++ptr);
- name = g_strndup (name, (gint) (ptr - name));
- g_strstrip (name);
-
- /* convert param name to lowercase */
- g_strdown (name);
+ g_mime_part_set_content_type (mime_part, mime_type);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ case CONTENT_DISPOSITION: {
+ const gchar *pch = headers_ptr + strlen (content_headers[type]);
+ const gchar *end = find_header_end (pch, headers_end);
+ gchar *disposition = g_strndup (pch, (gint) (end - pch));
+ gchar *ptr;
+ gchar *disp;
+
+ /* get content disposition part */
+ for (ptr = disposition; *ptr && *ptr != ';'; ptr++); /* find ; or \0 */
+ disp = g_strndup (disposition, (gint)(ptr - disposition));
+ g_strstrip (disp);
+ g_mime_part_set_content_disposition (mime_part, disp);
+ g_free (disp);
+
+ /* parse the parameters, if any */
+ while (*ptr == ';') {
+ gchar *name;
+ gchar *value;
+
+ /* get the param name */
+ for (name = ptr + 1; *name && !isspace ((int)*name); name++);
+ for (ptr = name; *ptr && *ptr != '='; ptr++);
+ name = g_strndup (name, (gint) (ptr - name));
+ g_strstrip (name);
+
+ /* convert param name to lowercase */
+ g_strdown (name);
- /* skip any whitespace */
- for (value = ptr + 1; *value && isspace((int)*value); value++);
+ /* skip any whitespace */
+ for (value = ptr + 1; *value && isspace ((int)*value); value++);
- if (*value == '"') /* value is in quotes */
- {
- value++;
- for (ptr = value; *ptr; ptr++)
- if (*ptr == '"' && *(ptr - 1) != '\\')
- break;
- value = g_strndup (value, (gint) (ptr - value));
- g_strstrip (value);
- g_mime_utils_unquote_string (value);
+ if (*value == '"') {
+ /* value is in quotes */
+ value++;
+ for (ptr = value; *ptr; ptr++)
+ if (*ptr == '"' && *(ptr - 1) != '\\')
+ break;
+ value = g_strndup (value, (gint) (ptr - value));
+ g_strstrip (value);
+ g_mime_utils_unquote_string (value);
- for ( ; *ptr && *ptr != ';'; ptr++);
- }
- else /* value is not in quotes */
- {
- for (ptr = value; *ptr && *ptr != ';'; ptr++);
- value = g_strndup (value, (gint) (ptr - value));
- g_strstrip (value);
- }
-
- g_mime_part_add_content_disposition_parameter (mime_part, name, value);
-
- g_free (name);
- g_free (value);
+ for ( ; *ptr && *ptr != ';'; ptr++);
+ } else {
+ /* value is not in quotes */
+ for (ptr = value; *ptr && *ptr != ';'; ptr++);
+ value = g_strndup (value, (gint) (ptr - value));
+ g_strstrip (value);
}
-
- g_free (disposition);
- headers_ptr = end + 1;
- break;
- }
- default: { /* ignore this header */
- const gchar *pch = headers_ptr;
- const gchar *end = find_header_end (pch, headers_end);
- headers_ptr = end + 1;
- break;
+ g_mime_part_add_content_disposition_parameter (mime_part, name, value);
+
+ g_free (name);
+ g_free (value);
}
+
+ g_free (disposition);
+
+ headers_ptr = end + 1;
+ break;
+ }
+ default: { /* ignore this header */
+ const gchar *pch = headers_ptr;
+ const gchar *end = find_header_end (pch, headers_end);
+
+ headers_ptr = end + 1;
+ break;
+ }
}
}
}
-typedef enum
-{
+typedef enum {
PARSER_EOF,
PARSER_BOUNDARY,
PARSER_END_BOUNDARY,
PARSER_LINE
-}
-ParserState;
+} ParserState;
static ParserState
-get_next_line (gchar *buf,
- guint buf_len,
- FILE *fp,
- const gchar *boundary,
- const gchar *end_boundary)
+get_next_line (gchar *buf, guint buf_len, FILE *fp, const gchar *boundary, const gchar *end_boundary)
{
ParserState state;
-
+
*buf = '\0';
- if (fgets(buf, buf_len, fp) == NULL)
+ if (fgets (buf, buf_len, fp) == NULL)
state = PARSER_EOF;
- else if (boundary!=NULL && !strcmp (buf, boundary))
+ else if (boundary != NULL && !strcmp (buf, boundary))
state = PARSER_BOUNDARY;
- else if (end_boundary!=NULL && !strcmp (buf, end_boundary))
+ else if (end_boundary != NULL && !strcmp (buf, end_boundary))
state = PARSER_END_BOUNDARY;
else
state = PARSER_LINE;
-
+
return state;
}
@@ -420,49 +428,47 @@ g_mime_parser_construct_part_from_file (const gchar *headers,
gchar *end_boundary;
gboolean is_multipart;
GMimePart *mime_part;
-
- g_return_val_if_fail (headers!=NULL, NULL);
- g_return_val_if_fail (headers_len>0, NULL);
- g_return_val_if_fail (fp!=NULL, NULL);
- g_return_val_if_fail (setme_state!=NULL, NULL);
-
- /**
- *** Headers
- **/
-
+
+ g_return_val_if_fail (headers != NULL, NULL);
+ g_return_val_if_fail (headers_len > 0, NULL);
+ g_return_val_if_fail (fp != NULL, NULL);
+ g_return_val_if_fail (setme_state != NULL, NULL);
+
+ /* Headers */
boundary = NULL;
end_boundary = NULL;
is_multipart = FALSE;
mime_part = g_mime_part_new ();
parse_content_headers (headers, headers_len, mime_part, &is_multipart, &boundary, &end_boundary);
-
- /**
- *** Body
- **/
-
+
+ /* Body */
if (is_multipart && boundary!=NULL && end_boundary!=NULL) { /* is a multipart */
/* get all the subparts */
gchar buf[GMIME_PARSER_MAX_LINE_WIDTH];
-
+
for (;;) {
/* get the next line, we're looking for the beginning of a subpart */
- ParserState ps = get_next_line (buf, sizeof(buf), fp, parent_boundary, parent_end_boundary);
+ ParserState ps = get_next_line (buf, sizeof (buf), fp, parent_boundary,
+ parent_end_boundary);
if (ps != PARSER_LINE) {
*setme_state = ps;
break;
}
-
+
/* is the beginning of a subpart? */
if (strcmp (buf, boundary))
continue;
-
+
/* add subparts as long as we keep getting boundaries */
for (;;) {
GArray *h = get_header_block_from_file (fp);
if (h != NULL) {
ParserState ps = 0;
- GMimePart * part = g_mime_parser_construct_part_from_file (
- h->data, h->len, fp, boundary, end_boundary, &ps);
+ GMimePart *part;
+
+ part = g_mime_parser_construct_part_from_file (h->data, h->len,
+ fp, boundary,
+ end_boundary, &ps);
g_array_free (h, TRUE);
if (part != NULL)
g_mime_part_add_subpart (mime_part, part);
@@ -471,36 +477,38 @@ g_mime_parser_construct_part_from_file (const gchar *headers,
}
}
}
- }
- else { /* not a multipart */
+ } else {
+ /* not a multipart */
GMimePartEncodingType encoding = g_mime_part_get_encoding (mime_part);
- GArray * a = g_array_new (TRUE, FALSE, 1);
+ GArray *a = g_array_new (TRUE, FALSE, 1);
gchar buf [GMIME_PARSER_MAX_LINE_WIDTH];
-
+
/* keep reading lines until we reach a boundary or EOF, we're populating a part */
for (;;) {
- ParserState ps = get_next_line (buf, sizeof(buf), fp, parent_boundary, parent_end_boundary);
- if (ps == PARSER_LINE)
- g_array_append_vals (a, buf, strlen(buf));
- else {
+ ParserState ps = get_next_line (buf, sizeof (buf), fp,
+ parent_boundary,
+ parent_end_boundary);
+ if (ps == PARSER_LINE) {
+ g_array_append_vals (a, buf, strlen (buf));
+ } else {
*setme_state = ps;
break;
}
-
}
-
+
/* trim off excess trailing \n's */
- while (a->len>2 && a->data[a->len-1]=='\n' && a->data[a->len-2]=='\n')
- g_array_set_size (a, a->len-1);
-
+ while (a->len > 2 && a->data[a->len-1] == '\n' && a->data[a->len - 2] == '\n')
+ g_array_set_size (a, a->len - 1);
+
if (a->len > 0)
g_mime_part_set_pre_encoded_content (mime_part, a->data, a->len, encoding);
-
+
g_array_free (a, TRUE);
}
-
+
g_free (boundary);
g_free (end_boundary);
+
return mime_part;
}
@@ -523,33 +531,27 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
gboolean is_multipart;
const gchar *inptr;
const gchar *inend = in + inlen;
-
- g_return_val_if_fail (in!=NULL, NULL);
- g_return_val_if_fail (inlen!=0, NULL);
- /**
- *** Headers
- **/
-
+ g_return_val_if_fail (in != NULL, NULL);
+ g_return_val_if_fail (inlen != 0, NULL);
+
+ /* Headers */
headers = get_header_block (in);
mime_part = g_mime_part_new ();
is_multipart = FALSE;
boundary = NULL;
end_boundary = NULL;
- parse_content_headers (headers->data, headers->len, mime_part, &is_multipart, &boundary, &end_boundary);
-
- /**
- *** Body
- **/
-
+ parse_content_headers (headers->data, headers->len, mime_part,
+ &is_multipart, &boundary, &end_boundary);
+
+ /* Body */
inptr = in + headers->len;
-
- if (is_multipart && boundary && end_boundary)
- {
+
+ if (is_multipart && boundary && end_boundary) {
/* get all the subparts */
- GMimePart * subpart;
- const gchar * part_begin;
- const gchar * part_end;
+ GMimePart *subpart;
+ const gchar *part_begin;
+ const gchar *part_end;
part_begin = g_strstrbound (inptr, boundary, inend);
while (part_begin && part_begin < inend) {
@@ -560,7 +562,8 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
/* find the end of this part */
part_end = g_strstrbound (part_begin + strlen (boundary), boundary, inend);
if (!part_end || part_end >= inend) {
- part_end = g_strstrbound (part_begin + strlen (boundary), end_boundary, inend);
+ part_end = g_strstrbound (part_begin + strlen (boundary),
+ end_boundary, inend);
if (!part_end || part_end >= inend)
part_end = inend;
}
@@ -578,12 +581,12 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
g_free (end_boundary);
} else {
GMimePartEncodingType encoding;
- const gchar * content = NULL;
+ const gchar *content = NULL;
guint len = 0;
/* from here to the end is the content */
if (inptr < inend) {
- for (inptr++; inptr < inend && isspace((int)*inptr); inptr++);
+ for (inptr++; inptr < inend && isspace ((int)*inptr); inptr++);
len = inend - inptr;
content = inptr;
@@ -600,8 +603,9 @@ g_mime_parser_construct_part (const gchar *in, guint inlen)
if (len > 0)
g_mime_part_set_pre_encoded_content (mime_part, content, len, encoding);
}
-
+
g_array_free (headers, TRUE);
+
return mime_part;
}
@@ -734,21 +738,20 @@ construct_headers (GMimeMessage *message, const gchar *headers, gint inlen, gboo
GMimeMessage *
g_mime_parser_construct_message (const gchar *data, gboolean save_extra_headers)
{
- GMimeMessage * message = NULL;
- GArray * headers;
+ GMimeMessage *message = NULL;
+ GArray *headers;
g_return_val_if_fail (data != NULL, NULL);
-
+
headers = get_header_block (data);
- if (headers != NULL)
- {
+ if (headers != NULL) {
GMimePart * part;
-
+
message = g_mime_message_new ();
construct_headers (message, headers->data, headers->len, save_extra_headers);
part = g_mime_parser_construct_part (data, strlen(data));
g_mime_message_set_mime_part (message, part);
-
+
g_array_free (headers, TRUE);
}
@@ -765,24 +768,24 @@ g_mime_parser_construct_message (const gchar *data, gboolean save_extra_headers)
GMimeMessage *
g_mime_parser_construct_message_from_file (FILE *fp, gboolean save_extra_headers)
{
- GMimeMessage * message = NULL;
- GArray * headers;
-
- g_return_val_if_fail (fp!=NULL, NULL);
-
+ GMimeMessage *message = NULL;
+ GArray *headers;
+
+ g_return_val_if_fail (fp != NULL, NULL);
+
headers = get_header_block_from_file (fp);
- if (headers != NULL)
- {
- GMimePart * part;
+ if (headers != NULL) {
+ GMimePart *part;
ParserState state = -1;
-
+
message = g_mime_message_new ();
construct_headers (message, headers->data, headers->len, save_extra_headers);
- part = g_mime_parser_construct_part_from_file (headers->data, headers->len, fp, NULL, NULL, &state);
+ part = g_mime_parser_construct_part_from_file (headers->data, headers->len, fp,
+ NULL, NULL, &state);
g_mime_message_set_mime_part (message, part);
if (state != PARSER_EOF)
g_warning ("Didn't reach end of file - parser error?");
-
+
g_array_free (headers, TRUE);
}
diff --git a/gmime/gmime-table-private.h b/gmime/gmime-table-private.h
new file mode 100644
index 00000000..7350960a
--- /dev/null
+++ b/gmime/gmime-table-private.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2001 Ximain, Inc. (www.ximian.com)
+ *
+ * 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 of the License, 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., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+static unsigned short gmime_special_table[256] = {
+ 5, 5, 5, 5, 5, 5, 5, 5, 5,231, 7, 5, 5, 39, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 242,448, 76,192,192,192,192,192, 76, 76,448,448, 76,448, 72,324,
+ 448,448,448,448,448,448,448,448,448,448, 76, 76, 76, 4, 76, 68,
+ 76,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
+ 448,448,448,448,448,448,448,448,448,448,448,108,236,108,192, 64,
+ 192,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
+ 448,448,448,448,448,448,448,448,448,448,448,192,192,192,192, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+enum {
+ IS_CTRL = 1<<0,
+ IS_LWSP = 1<<1,
+ IS_TSPECIAL = 1<<2,
+ IS_SPECIAL = 1<<3,
+ IS_SPACE = 1<<4,
+ IS_DSPECIAL = 1<<5,
+ IS_QPSAFE = 1<<6,
+ IS_ESAFE = 1<<7, /* encoded word safe */
+ IS_PSAFE = 1<<8, /* encoded word in phrase safe */
+};
+
+#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)
+#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)
+#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)
+#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)
+#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)
+#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)
+#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)
+#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)
+#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
+#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
+#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
+
+#ifndef HAVE_ISBLANK
+#define isblank(c) ((c) == ' ' || (c) == '\t')
+#endif /* HAVE_ISBLANK */
+
+#define CHARS_LWSP " \t\n\r" /* linear whitespace chars */
+#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
+#define CHARS_SPECIAL "()<>@,;:\\\".[]"
+#define CHARS_CSPECIAL "()\\\r" /* not in comments */
+#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
+#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials (rfc2047 5.1) */
+#define CHARS_PSPECIAL "!*+-/" /* encoded phrase specials (rfc2047 5.3) */
diff --git a/gmime/gmime-utils.c b/gmime/gmime-utils.c
index 540ff670..f0c062bd 100644
--- a/gmime/gmime-utils.c
+++ b/gmime/gmime-utils.c
@@ -21,9 +21,14 @@
*
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include "gmime-utils.h"
+#include "gmime-table-private.h"
#include "gmime-part.h"
-#include <config.h>
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -35,6 +40,10 @@
#define GMIME_FOLD_LEN 76
+#ifndef HAVE_ISBLANK
+#define isblank(c) (c == ' ' || c == '\t')
+#endif
+
static char *base64_alphabet =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -43,25 +52,6 @@ static unsigned char tohex[16] = {
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
-static unsigned short gmime_special_table[256] = {
- 5, 5, 5, 5, 5, 5, 5, 5, 5,231, 7, 5, 5, 39, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
- 242,448, 76,192,192,192,192,192, 76, 76,448,448, 76,448, 72,324,
- 448,448,448,448,448,448,448,448,448,448, 76, 76, 76, 4, 76, 68,
- 76,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
- 448,448,448,448,448,448,448,448,448,448,448,108,236,108,192, 64,
- 192,448,448,448,448,448,448,448,448,448,448,448,448,448,448,448,
- 448,448,448,448,448,448,448,448,448,448,448,192,192,192,192, 5,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
static unsigned char gmime_base64_rank[256] = {
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
@@ -101,109 +91,6 @@ static unsigned char gmime_uu_rank[256] = {
};
-enum {
- IS_CTRL = 1<<0,
- IS_LWSP = 1<<1,
- IS_TSPECIAL = 1<<2,
- IS_SPECIAL = 1<<3,
- IS_SPACE = 1<<4,
- IS_DSPECIAL = 1<<5,
- IS_QPSAFE = 1<<6,
- IS_ESAFE = 1<<7, /* encoded word safe */
- IS_PSAFE = 1<<8, /* encoded word in phrase safe */
-};
-
-#define is_ctrl(x) ((gmime_special_table[(unsigned char)(x)] & IS_CTRL) != 0)
-#define is_lwsp(x) ((gmime_special_table[(unsigned char)(x)] & IS_LWSP) != 0)
-#define is_tspecial(x) ((gmime_special_table[(unsigned char)(x)] & IS_TSPECIAL) != 0)
-#define is_type(x, t) ((gmime_special_table[(unsigned char)(x)] & (t)) != 0)
-#define is_ttoken(x) ((gmime_special_table[(unsigned char)(x)] & (IS_TSPECIAL|IS_LWSP|IS_CTRL)) == 0)
-#define is_atom(x) ((gmime_special_table[(unsigned char)(x)] & (IS_SPECIAL|IS_SPACE|IS_CTRL)) == 0)
-#define is_dtext(x) ((gmime_special_table[(unsigned char)(x)] & IS_DSPECIAL) == 0)
-#define is_fieldname(x) ((gmime_special_table[(unsigned char)(x)] & (IS_CTRL|IS_SPACE)) == 0)
-#define is_qpsafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_QPSAFE) != 0)
-#define is_especial(x) ((gmime_special_table[(unsigned char)(x)] & IS_ESPECIAL) != 0)
-#define is_psafe(x) ((gmime_special_table[(unsigned char)(x)] & IS_PSAFE) != 0)
-
-#ifndef HAVE_ISBLANK
-#define isblank(c) ((c) == ' ' || (c) == '\t')
-#endif /* HAVE_ISBLANK */
-
-#define CHARS_LWSP " \t\n\r" /* linear whitespace chars */
-#define CHARS_TSPECIAL "()<>@,;:\\\"/[]?="
-#define CHARS_SPECIAL "()<>@,;:\\\".[]"
-#define CHARS_CSPECIAL "()\\\r" /* not in comments */
-#define CHARS_DSPECIAL "[]\\\r \t" /* not in domains */
-#define CHARS_ESPECIAL "()<>@,;:\"/[]?.=" /* encoded word specials (rfc2047 5.1) */
-#define CHARS_PSPECIAL "!*+-/" /* encoded phrase specials (rfc2047 5.3) */
-
-#ifdef BUILD_TABLE
-/* code to rebuild the gmime_special_table */
-static void
-header_remove_bits (gushort bit, guchar *vals)
-{
- gint i;
-
- for (i = 0; vals[i]; i++)
- gmime_special_table[vals[i]] &= ~bit;
-}
-
-static void
-header_init_bits (gushort bit, gushort bitcopy, gboolean remove, guchar *vals)
-{
- gint i, len = strlen (vals);
-
- if (!remove) {
- for (i = 0; i < len; i++) {
- gmime_special_table[vals[i]] |= bit;
- }
- if (bitcopy) {
- for (i = 0; i < 256; i++) {
- if (gmime_special_table[i] & bitcopy)
- gmime_special_table[i] |= bit;
- }
- }
- } else {
- for (i = 0; i < 256; i++)
- gmime_special_table[i] |= bit;
- for (i = 0; i < len; i++) {
- gmime_special_table[vals[i]] &= ~bit;
- }
- if (bitcopy) {
- for (i = 0; i < 256; i++) {
- if (gmime_special_table[i] & bitcopy)
- gmime_special_table[i] &= ~bit;
- }
- }
- }
-}
-
-static void
-header_decode_init (void)
-{
- gint i;
-
- for (i = 0; i < 256; i++) {
- gmime_special_table[i] = 0;
- if (i < 32)
- gmime_special_table[i] |= IS_CTRL;
- if ((i >= 33 && i <= 60) || (i >= 62 && i <= 126) || i == 32 || i == 9)
- gmime_special_table[i] |= (IS_QPSAFE | IS_ESAFE);
- if ((i >= '0' && i <= '9') || (i >= 'a' && i <= 'z') || (i >= 'A' && i <= 'Z'))
- gmime_special_table[i] |= IS_PSAFE;
- }
-
- gmime_special_table[127] |= IS_CTRL;
- gmime_special_table[' '] |= IS_SPACE;
- header_init_bits (IS_LWSP, 0, FALSE, CHARS_LWSP);
- header_init_bits (IS_TSPECIAL, IS_CTRL, FALSE, CHARS_TSPECIAL);
- header_init_bits (IS_SPECIAL, 0, FALSE, CHARS_SPECIAL);
- header_init_bits (IS_DSPECIAL, 0, FALSE, CHARS_DSPECIAL);
- header_remove_bits (IS_ESAFE, CHARS_ESPECIAL);
- header_init_bits (IS_PSAFE, 0, FALSE, CHARS_PSPECIAL);
-}
-#endif /* BUILD_TABLE */
-
/* hrm, is there a library for this shit? */
static struct {
char *name;
@@ -654,6 +541,28 @@ g_mime_utils_header_printf (const gchar *format, ...)
return ret;
}
+static gboolean
+need_quotes (const char *string)
+{
+ gboolean quoted = FALSE;
+ const char *inptr;
+
+ inptr = string;
+
+ while (*inptr) {
+ if (*inptr == '\\')
+ inptr++;
+ else if (*inptr == '"')
+ quoted = !quoted;
+ else if (!quoted && is_tspecial (*inptr))
+ return TRUE;
+
+ if (*inptr)
+ inptr++;
+ }
+
+ return FALSE;
+}
/**
* g_mime_utils_quote_string: Quote a string.
@@ -667,18 +576,16 @@ g_mime_utils_header_printf (const gchar *format, ...)
gchar *
g_mime_utils_quote_string (const gchar *string)
{
- GString *out;
+ gboolean quote;
+ const gchar *c;
gchar *qstring;
- guchar *c;
- gboolean quote = FALSE;
+ GString *out;
out = g_string_new ("");
+ quote = need_quotes (string);
- for (c = (guchar *) string; *c; c++) {
- if (is_tspecial (*c))
- quote = TRUE;
-
- if (*c == '"' || *c == '\\')
+ for (c = string; *c; c++) {
+ if ((*c == '"' && quote) || *c == '\\')
g_string_append_c (out, '\\');
g_string_append_c (out, *c);
diff --git a/gmime/internet-address.c b/gmime/internet-address.c
index 308327c5..f4a90493 100644
--- a/gmime/internet-address.c
+++ b/gmime/internet-address.c
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Authors: Jeffrey Stedfast <fejj@helixcode.com>
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
*
- * Copyright 2000 Helix Code, Inc. (www.helixcode.com)
+ * Copyright 2001 Ximain, Inc. (www.ximian.com)
*
* 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
@@ -20,235 +20,731 @@
*
*/
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
#include "internet-address.h"
+#include "gmime-table-private.h"
#include "gmime-utils.h"
-#include <stdio.h>
+
#include <string.h>
#include <ctype.h>
/**
* internet_address_new: Create a new Internet Address object
+ *
+ * Returns a new Internet Address object.
+ **/
+InternetAddress *
+internet_address_new ()
+{
+ return g_new0 (InternetAddress, 1);
+}
+
+
+/**
+ * internet_address_destroy: Destroy an Internet Address object
+ * @ia: Internet Address object to destroy
+ *
+ * Destroy the InternetAddress object pointed to by @ia.
+ **/
+void
+internet_address_destroy (InternetAddress *ia)
+{
+ if (ia) {
+ g_free (ia->name);
+
+ if (ia->type == INTERNET_ADDRESS_GROUP) {
+ GList *members;
+
+ members = ia->value.members;
+ while (members) {
+ InternetAddress *member;
+
+ member = members->data;
+ internet_address_destroy (member);
+ members = members->next;
+ }
+
+ g_list_free (ia->value.members);
+ } else {
+ g_free (ia->value.addr);
+ }
+
+ g_free (ia);
+ }
+}
+
+
+/**
+ * internet_address_new_name: Create a new Internet Address object
* @name: person's name
* @address: person's address
*
* Returns a new Internet Address object.
**/
InternetAddress *
-internet_address_new (const gchar *name, const gchar *address)
+internet_address_new_name (const char *name, const char *addr)
{
InternetAddress *ia;
- g_return_val_if_fail (address != NULL, NULL);
-
- ia = g_new (InternetAddress, 1);
+ g_return_val_if_fail (addr != NULL, NULL);
+ ia = internet_address_new ();
+ ia->type = INTERNET_ADDRESS_NAME;
if (name) {
ia->name = g_mime_utils_8bit_header_decode (name);
g_mime_utils_unquote_string (ia->name);
- } else {
- ia->name = NULL;
}
+ ia->value.addr = g_strdup (addr);
+
+ return ia;
+}
+
+
+/**
+ * internet_address_new_group: Create a new Internet Address object
+ * @name: group name
+ *
+ * Returns a new Internet Address object.
+ **/
+InternetAddress *
+internet_address_new_group (const char *name)
+{
+ InternetAddress *ia;
- ia->address = g_strdup (address);
+ ia = internet_address_new ();
+ ia->type = INTERNET_ADDRESS_GROUP;
+ if (name) {
+ ia->name = g_mime_utils_8bit_header_decode (name);
+ g_mime_utils_unquote_string (ia->name);
+ }
return ia;
}
-static gchar *
-get_next_token (const gchar *in, guint inlen, guint *len)
+
+/**
+ * internet_address_set_name:
+ * @ia: internet address
+ * @name: group or contact's name
+ *
+ * Set the name of the internet address.
+ **/
+void
+internet_address_set_name (InternetAddress *ia, const char *name)
{
- gchar *token;
- gchar *inptr, *inend, *end;
- gint depth = 0;
- gchar dp = '\0', dm = '\0';
+ g_return_if_fail (ia != NULL);
- inptr = (gchar *) in;
- inend = inptr + inlen;
+ g_free (ia->name);
+ if (name) {
+ ia->name = g_mime_utils_8bit_header_decode (name);
+ g_mime_utils_unquote_string (ia->name);
+ } else
+ ia->name = NULL;
+}
+
+
+/**
+ * internet_address_set_addr:
+ * @ia: internet address
+ * @addr: contact's email address
+ *
+ * Set the intenet address's address.
+ **/
+void
+internet_address_set_addr (InternetAddress *ia, const char *addr)
+{
+ g_return_if_fail (ia != NULL);
+ g_return_if_fail (ia->type != INTERNET_ADDRESS_GROUP);
- while (isspace (*inptr) && inptr < inend)
- inptr++;
+ ia->type = INTERNET_ADDRESS_NAME;
+ g_free (ia->value.addr);
+ ia->value.addr = g_strdup (addr);
+}
+
+
+/**
+ * internet_address_set_group:
+ * @ia: internet address
+ * @group: a list of internet addresses
+ *
+ * Set the members of the internet address group.
+ **/
+void
+internet_address_set_group (InternetAddress *ia, GList *group)
+{
+ GList *members;
- if (*inptr == '"') {
- dm = '"';
- depth = 1;
- } else if (*inptr == '(') {
- dp = '(';
- dm = ')';
- depth = 1;
- }
-
- end = inptr;
- while (end < inend) {
- end++;
-
- if (*end == dp)
- depth++;
- else if (*end == dm)
- depth--;
- else if (!depth && isspace (*end))
- break;
- }
+ g_return_if_fail (ia != NULL);
+ g_return_if_fail (ia->type != INTERNET_ADDRESS_NAME);
- token = g_strndup (inptr, end - inptr);
- *len = end - in;
+ ia->type = INTERNET_ADDRESS_GROUP;
+ members = ia->value.members;
+ while (members) {
+ InternetAddress *member;
+
+ member = members->data;
+ internet_address_destroy (member);
+ members = members->next;
+ }
- return token;
+ g_list_free (ia->value.members);
+ ia->value.members = group;
}
-static GPtrArray *
-rfc822_tokenize (const gchar *in, guint inlen)
+
+/**
+ * internet_address_add_member:
+ * @ia: internet address
+ * @member: group member's internet address
+ *
+ * Add a contact to the internet address group.
+ **/
+void
+internet_address_add_member (InternetAddress *ia, InternetAddress *member)
{
- GPtrArray *tokens;
- gchar *token, *inptr, *inend;
- guint len;
+ g_return_if_fail (ia != NULL);
+ g_return_if_fail (ia->type != INTERNET_ADDRESS_NAME);
- inptr = (gchar *) in;
- inend = inptr + inlen;
+ ia->type = INTERNET_ADDRESS_GROUP;
+ ia->value.members = g_list_append (ia->value.members, member);
+}
+
+static gchar *
+encoded_name (const gchar *raw, gboolean rfc2047_encode)
+{
+ gchar *name;
- tokens = g_ptr_array_new ();
+ g_return_val_if_fail (raw != NULL, NULL);
- while (inptr < inend) {
- token = get_next_token (inptr, inend - inptr, &len);
- inptr += len;
- g_ptr_array_add (tokens, token);
+ if (rfc2047_encode && g_mime_utils_text_is_8bit (raw, strlen (raw))) {
+ name = g_mime_utils_8bit_header_encode_phrase (raw);
+ } else {
+ name = g_mime_utils_quote_string (raw);
}
- return tokens;
+ return name;
}
/**
- * internet_address_new_from_string: Create a new Internet Address object
- * @string: rfc822 internet address string
+ * internet_address_to_string: Write the InternetAddress object to a string
+ * @ia: Internet Address object
+ * @encode: TRUE if the address should be rfc2047 encoded
*
- * Returns a new Internet Address object based upon the rfc822 address
- * string.
+ * Returns the InternetAddress object as an allocated string in rfc822
+ * format.
**/
-InternetAddress *
-internet_address_new_from_string (const gchar *string)
+gchar *
+internet_address_to_string (InternetAddress *ia, gboolean encode)
{
- InternetAddress *ia;
- GPtrArray *tokens;
- gchar *name = NULL, *address = NULL;
- int i;
-
- g_return_val_if_fail (string != NULL, NULL);
- g_return_val_if_fail (*string != '\0', NULL);
+ char *string = NULL;
- tokens = rfc822_tokenize (string, strlen (string));
- if (!tokens->len) {
- g_ptr_array_free (tokens, TRUE);
- return NULL;
+ if (ia->type == INTERNET_ADDRESS_NAME) {
+ if (ia->name) {
+ char *name;
+
+ name = encoded_name (ia->name, encode);
+ string = g_strdup_printf ("%s <%s>", name,
+ ia->value.addr);
+ g_free (name);
+ } else {
+ string = g_strdup (ia->value.addr);
+ }
+ } else if (ia->type == INTERNET_ADDRESS_GROUP) {
+ GList *members;
+ GString *gstr;
+
+ gstr = g_string_new (ia->name);
+ g_string_append (gstr, ": ");
+
+ members = ia->value.members;
+ while (members) {
+ InternetAddress *member;
+ char *addr;
+
+ member = members->data;
+ members = members->next;
+
+ addr = internet_address_to_string (member, encode);
+ if (addr) {
+ g_string_append (gstr, addr);
+ g_free (addr);
+ if (members)
+ g_string_append (gstr, ", ");
+ }
+ }
+
+ g_string_append (gstr, ";");
+
+ string = gstr->str;
+ g_string_free (gstr, FALSE);
}
- /* find the address */
- for (i = 0; i < tokens->len; i++) {
- gchar *token = tokens->pdata[i];
+ return string;
+}
+
+static void
+decode_lwsp (const char **in)
+{
+ const char *inptr = *in;
+
+ while (*inptr && (*inptr == '(' || is_lwsp (*inptr))) {
+ while (*inptr && is_lwsp (*inptr))
+ inptr++;
- if (*token == '<' && *(token + strlen (token) - 1) == '>') {
- address = token;
+ /* skip over any comments */
+ if (*inptr == '(') {
+ int depth = 1;
- /* strip the <>'s */
- memmove (address, address + 1, strlen (address));
- *(address + strlen (address) - 1) = '\0';
-
- /* remove the address from the list of tokens */
- g_ptr_array_remove_index (tokens, i);
- break;
+ inptr++;
+ while (*inptr && depth) {
+ if (*inptr == '\\' && *(inptr + 1))
+ inptr++;
+ else if (*inptr == '(')
+ depth++;
+ else if (*inptr == ')')
+ depth--;
+
+ inptr++;
+ }
}
}
- if (!address) {
- /* the first token should be the address if it wasn't surrounded in <>'s */
- address = tokens->pdata[0];
- g_ptr_array_remove_index (tokens, 0);
+ *in = inptr;
+}
+
+static char *
+decode_quoted_string (const char **in)
+{
+ const char *inptr = *in;
+ GString *string = NULL;
+ char *out = NULL;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ out = (char *) inptr;
+
+ inptr++;
+ while (*inptr && *inptr != '"') {
+ if (*inptr == '\\')
+ inptr++;
+
+ if (*inptr)
+ inptr++;
+ }
+
+ if (*inptr == '"')
+ inptr++;
+
+ out = g_strndup (out, inptr - out);
}
- /* recreate the name from the tokens */
- if (tokens->len) {
- char *token = tokens->pdata[0];
- char *end = token + strlen (token) - 1;
+ *in = inptr;
+
+ return out;
+}
+
+#if 0
+static char *
+decode_quoted_string (const char **in)
+{
+ const char *inptr = *in;
+ char *out = NULL, *outptr;
+ int outlen;
+ int c;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ const char *intmp;
+ int skip = 0;
- if (*token == '(' && *end == ')') {
- token++;
- *end = '\0';
+ /* first, calc length */
+ inptr++;
+ intmp = inptr + 1;
+ while ((c = *intmp++) && c != '"') {
+ if (c == '\\' && *intmp) {
+ intmp++;
+ skip++;
+ }
+ }
+
+ outlen = intmp - inptr - skip;
+ out = outptr = g_malloc (outlen + 1);
+
+ while ((c = *inptr++) && c != '"') {
+ if (c == '\\' && *inptr) {
+ c = *inptr++;
+ }
+ *outptr++ = c;
+ }
+ *outptr = '\0';
+ }
+
+ *in = inptr;
+
+ return out;
+}
+#endif
+
+static char *
+decode_atom (const char **in)
+{
+ const char *inptr = *in, *start;
+
+ decode_lwsp (&inptr);
+ start = inptr;
+ while (is_atom (*inptr))
+ inptr++;
+ *in = inptr;
+ if (inptr > start)
+ return g_strndup (start, inptr - start);
+ else
+ return NULL;
+}
+
+static char *
+decode_word (const char **in)
+{
+ const char *inptr = *in;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ *in = inptr;
+ return decode_quoted_string (in);
+ } else {
+ *in = inptr;
+ return decode_atom (in);
+ }
+}
+
+static gboolean
+decode_subliteral (const char **in, GString *domain)
+{
+ const char *inptr = *in;
+ gboolean got = FALSE;
+
+ while (*inptr && *inptr != '.' && *inptr != ']') {
+ if (is_dtext (*inptr)) {
+ g_string_append_c (domain, *inptr);
+ inptr++;
+ got = TRUE;
+ } else if (is_lwsp (*inptr))
+ decode_lwsp (&inptr);
+ else
+ break;
+ }
+
+ *in = inptr;
+
+ return got;
+}
+
+static void
+decode_domain_literal (const char **in, GString *domain)
+{
+ const char *inptr = *in;
+
+ decode_lwsp (&inptr);
+ while (*inptr && *inptr != ']') {
+ if (decode_subliteral (&inptr, domain) && *inptr == '.') {
+ g_string_append_c (domain, *inptr);
+ inptr++;
+ } else if (*inptr != ']') {
+ g_warning ("Malformed domain-literal, "
+ "unexpected char (%c): %s", *inptr, *in);
+
+ /* try and skip to the next char ?? */
+ inptr++;
+ }
+ }
+
+ *in = inptr;
+}
+
+static char *
+decode_domain (const char **in)
+{
+ const char *inptr, *save;
+ GString *domain;
+ char *dom, *atom;
+
+ domain = g_string_new ("");
+
+ inptr = *in;
+ while (TRUE) {
+ decode_lwsp (&inptr);
+ if (*inptr == '[') {
+ /* domain literal */
+ g_string_append_c (domain, '[');
+ inptr++;
- name = g_mime_utils_8bit_header_decode (token);
+ decode_domain_literal (&inptr, domain);
+
+ if (*inptr == ']') {
+ g_string_append_c (domain, ']');
+ inptr++;
+ } else
+ g_warning ("Missing ']' in domain-literal: %s", *in);
} else {
- name = g_strjoinv (" ", (gchar **) tokens->pdata);
+ atom = decode_atom (&inptr);
+ if (atom)
+ g_string_append (domain, atom);
+ g_free (atom);
+ }
+
+ save = inptr;
+ decode_lwsp (&inptr);
+ if (*inptr != '.') {
+ inptr = save;
+ break;
}
+
+ g_string_append_c (domain, '.');
+ inptr++;
}
- for (i = 0; i < tokens->len; i++)
- g_free (tokens->pdata[i]);
- g_ptr_array_free (tokens, TRUE);
+ dom = domain->str;
+ g_string_free (domain, FALSE);
- ia = internet_address_new (name, address);
- g_free (name);
- g_free (address);
+ *in = inptr;
- return ia;
+ return dom;
}
-
-/**
- * internet_address_destroy: Destroy an Internet Address object
- * @ia: Internet Address object to destroy
- *
- * Destroy the InternetAddress object pointed to by #ia.
- **/
-void
-internet_address_destroy (InternetAddress *ia)
+static InternetAddress *
+decode_mailbox (const char **in)
{
- g_return_if_fail (ia != NULL);
+ InternetAddress *mailbox = NULL;
+ const char *inptr;
+ gboolean bracket = FALSE;
+ GString *name = NULL;
+ GString *addr;
+ char *pre;
- g_free (ia->name);
- g_free (ia->address);
- g_free (ia);
+ addr = g_string_new ("");
+
+ decode_lwsp (in);
+ inptr = *in;
+
+ pre = decode_word (&inptr);
+ decode_lwsp (&inptr);
+ if (*inptr && !strchr (",.@", *inptr)) {
+ /* this mailbox has a name part, so get the name */
+ name = g_string_new ("");
+ while (pre) {
+ g_string_append (name, pre);
+ g_free (pre);
+ pre = decode_word (&inptr);
+ if (pre)
+ g_string_append_c (name, ' ');
+ }
+
+ decode_lwsp (&inptr);
+ if (*inptr == '<') {
+ inptr++;
+ bracket = TRUE;
+ pre = decode_word (&inptr);
+ } else {
+ g_string_free (name, TRUE);
+ g_string_free (addr, TRUE);
+ *in = inptr;
+
+ return NULL;
+ }
+ }
+
+ if (pre) {
+ g_string_append (addr, pre);
+ } else {
+ g_warning ("No local part for email address: %s", *in);
+ if (name)
+ g_string_free (name, TRUE);
+ g_string_free (addr, TRUE);
+ return NULL;
+ }
+
+ /* get the rest of the local-part */
+ decode_lwsp (&inptr);
+ while (*inptr == '.' && pre) {
+ inptr++;
+ g_free (pre);
+ pre = decode_word (&inptr);
+ if (pre) {
+ g_string_append_c (addr, '.');
+ g_string_append (addr, pre);
+ }
+ decode_lwsp (&inptr);
+ }
+ g_free (pre);
+
+ /* we should be at the '@' now... */
+ if (*inptr == '@') {
+ char *domain;
+
+ g_string_append_c (addr, '@');
+ inptr++;
+
+ domain = decode_domain (&inptr);
+ g_string_append (addr, domain);
+ g_free (domain);
+ } else {
+ g_warning ("No domain in email address: %s", *in);
+ }
+
+ if (bracket) {
+ decode_lwsp (&inptr);
+ if (*inptr == '>')
+ inptr++;
+ else
+ g_warning ("Missing closing '>' bracket for email address: %s", *in);
+ }
+
+ if (!name) {
+ /* look for a trailing comment to use as the name? */
+ char *comment;
+
+ comment = (char *) inptr;
+ decode_lwsp (&inptr);
+ if (inptr > comment) {
+ comment = memchr (comment, '(', inptr - comment);
+ if (comment) {
+ const char *cend;
+
+ /* find the end of the comment */
+ for (cend = inptr - 1; cend > comment && is_lwsp (*cend); cend--);
+ if (*cend == ')')
+ cend--;
+ comment = g_strndup (comment + 1, cend - comment);
+
+ name = g_string_new (comment);
+ g_free (comment);
+ }
+ }
+ }
+
+ *in = inptr;
+
+ if (addr->len)
+ mailbox = internet_address_new_name (name ? name->str : NULL, addr->str);
+
+ g_string_free (addr, TRUE);
+ if (name)
+ g_string_free (name, TRUE);
+
+ return mailbox;
}
-static gchar *
-encoded_name (const gchar *raw, gboolean rfc2047_encode)
+static InternetAddress *
+decode_address (const char **in)
{
- gchar *name;
+ InternetAddress *addr = NULL, *member;
+ const char *inptr, *start;
+ GString *name;
+ char *pre;
- g_return_val_if_fail (raw != NULL, NULL);
+ decode_lwsp (in);
+ start = inptr = *in;
- if (rfc2047_encode && g_mime_utils_text_is_8bit (raw, strlen (raw))) {
- name = g_mime_utils_8bit_header_encode_phrase (raw);
+ /* pre-scan */
+ name = g_string_new ("");
+ pre = decode_word (&inptr);
+ while (pre) {
+ g_string_append (name, pre);
+ g_free (pre);
+
+ pre = decode_word (&inptr);
+ if (pre)
+ g_string_append_c (name, ' ');
+ }
+
+ decode_lwsp (&inptr);
+ if (*inptr == ':') {
+ /* this is a group */
+ inptr++;
+ addr = internet_address_new_group (name->str);
+
+ decode_lwsp (&inptr);
+ while (*inptr && *inptr != ';') {
+ InternetAddress *member;
+
+ member = decode_mailbox (&inptr);
+ if (member)
+ internet_address_add_member (addr, member);
+
+ decode_lwsp (&inptr);
+ while (*inptr == ',') {
+ inptr++;
+ decode_lwsp (&inptr);
+ member = decode_mailbox (&inptr);
+ if (member)
+ internet_address_add_member (addr, member);
+
+ decode_lwsp (&inptr);
+ }
+ }
+
+ if (*inptr == ';')
+ inptr++;
+ else
+ g_warning ("Invalid group spec, missing closing ';': %.*s",
+ inptr - start, start);
+
+ *in = inptr;
} else {
- name = g_mime_utils_quote_string (raw);
+ /* this is a mailbox */
+ addr = decode_mailbox (in);
}
- return name;
+ g_string_free (name, TRUE);
+
+ return addr;
}
/**
- * internet_address_to_string: Write the InternetAddress object to a string
- * @ia: Internet Address object
- * @rfc2047_encode: TRUE if the address should be encoded
- *
- * Returns the InternetAddress object as an allocated string in rfc822
- * format.
+ * internet_address_paarse_string:
+ * @string: a string containing internet addresses
+ *
+ * Construct a list of internet addresses from the given string.
+ *
+ * Returns a linked list of internet addresses.
**/
-gchar *
-internet_address_to_string (InternetAddress *ia, gboolean rfc2047_encode)
+GList *
+internet_address_parse_string (const char *string)
{
- gchar *name, *string;
+ GList *addrlist = NULL;
+ const char *inptr;
- g_return_val_if_fail (ia != NULL, NULL);
+ inptr = string;
- if (ia->name) {
- name = encoded_name (ia->name, rfc2047_encode);
- string = g_strdup_printf ("%s <%s>", name, ia->address);
- g_free (name);
- } else {
- string = g_strdup (ia->address);
+ while (inptr && *inptr) {
+ InternetAddress *addr;
+ const char *start;
+
+ start = inptr;
+
+ addr = decode_address (&inptr);
+
+ if (addr)
+ addrlist = g_list_append (addrlist, addr);
+ else
+ g_warning ("Invalid or incomplete address: %.*s", inptr - start, start);
+
+ decode_lwsp (&inptr);
+ if (*inptr == ',')
+ inptr++;
+ else if (*inptr) {
+ g_warning ("Parse error at '%s': expected ','", inptr);
+ /* try skipping to the next address */
+ inptr = strchr (inptr, ',');
+ if (inptr)
+ inptr++;
+ }
}
- return string;
+ return addrlist;
}
diff --git a/gmime/internet-address.h b/gmime/internet-address.h
index 629ae11a..003f04da 100644
--- a/gmime/internet-address.h
+++ b/gmime/internet-address.h
@@ -30,18 +30,36 @@ extern "C" {
#include <glib.h>
+typedef enum {
+ INTERNET_ADDRESS_NONE,
+ INTERNET_ADDRESS_NAME,
+ INTERNET_ADDRESS_GROUP
+} InternetAddressType;
+
struct _InternetAddress {
+ InternetAddressType type;
gchar *name;
- gchar *address;
+ union {
+ gchar *addr;
+ GList *members;
+ } value;
};
typedef struct _InternetAddress InternetAddress;
-InternetAddress *internet_address_new (const gchar *name, const gchar *address);
-InternetAddress *internet_address_new_from_string (const gchar *string);
+InternetAddress *internet_address_new (void);
+InternetAddress *internet_address_new_name (const gchar *name, const gchar *addr);
+InternetAddress *internet_address_new_group (const gchar *name);
void internet_address_destroy (InternetAddress *ia);
+void internet_address_set_name (InternetAddress *ia, const gchar *name);
+void internet_address_set_addr (InternetAddress *ia, const gchar *addr);
+void internet_address_set_group (InternetAddress *ia, GList *group);
+void internet_address_add_member (InternetAddress *ia, InternetAddress *member);
+
+GList *internet_address_parse_string (const gchar *string);
+
gchar *internet_address_to_string (InternetAddress *ia, gboolean rfc2047_encode);
#ifdef __cplusplus
diff --git a/internet-address.c b/internet-address.c
index 308327c5..f4a90493 100644
--- a/internet-address.c
+++ b/internet-address.c
@@ -1,8 +1,8 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Authors: Jeffrey Stedfast <fejj@helixcode.com>
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
*
- * Copyright 2000 Helix Code, Inc. (www.helixcode.com)
+ * Copyright 2001 Ximain, Inc. (www.ximian.com)
*
* 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
@@ -20,235 +20,731 @@
*
*/
+#ifdef HAVE_CONFIG_H
#include <config.h>
+#endif
#include "internet-address.h"
+#include "gmime-table-private.h"
#include "gmime-utils.h"
-#include <stdio.h>
+
#include <string.h>
#include <ctype.h>
/**
* internet_address_new: Create a new Internet Address object
+ *
+ * Returns a new Internet Address object.
+ **/
+InternetAddress *
+internet_address_new ()
+{
+ return g_new0 (InternetAddress, 1);
+}
+
+
+/**
+ * internet_address_destroy: Destroy an Internet Address object
+ * @ia: Internet Address object to destroy
+ *
+ * Destroy the InternetAddress object pointed to by @ia.
+ **/
+void
+internet_address_destroy (InternetAddress *ia)
+{
+ if (ia) {
+ g_free (ia->name);
+
+ if (ia->type == INTERNET_ADDRESS_GROUP) {
+ GList *members;
+
+ members = ia->value.members;
+ while (members) {
+ InternetAddress *member;
+
+ member = members->data;
+ internet_address_destroy (member);
+ members = members->next;
+ }
+
+ g_list_free (ia->value.members);
+ } else {
+ g_free (ia->value.addr);
+ }
+
+ g_free (ia);
+ }
+}
+
+
+/**
+ * internet_address_new_name: Create a new Internet Address object
* @name: person's name
* @address: person's address
*
* Returns a new Internet Address object.
**/
InternetAddress *
-internet_address_new (const gchar *name, const gchar *address)
+internet_address_new_name (const char *name, const char *addr)
{
InternetAddress *ia;
- g_return_val_if_fail (address != NULL, NULL);
-
- ia = g_new (InternetAddress, 1);
+ g_return_val_if_fail (addr != NULL, NULL);
+ ia = internet_address_new ();
+ ia->type = INTERNET_ADDRESS_NAME;
if (name) {
ia->name = g_mime_utils_8bit_header_decode (name);
g_mime_utils_unquote_string (ia->name);
- } else {
- ia->name = NULL;
}
+ ia->value.addr = g_strdup (addr);
+
+ return ia;
+}
+
+
+/**
+ * internet_address_new_group: Create a new Internet Address object
+ * @name: group name
+ *
+ * Returns a new Internet Address object.
+ **/
+InternetAddress *
+internet_address_new_group (const char *name)
+{
+ InternetAddress *ia;
- ia->address = g_strdup (address);
+ ia = internet_address_new ();
+ ia->type = INTERNET_ADDRESS_GROUP;
+ if (name) {
+ ia->name = g_mime_utils_8bit_header_decode (name);
+ g_mime_utils_unquote_string (ia->name);
+ }
return ia;
}
-static gchar *
-get_next_token (const gchar *in, guint inlen, guint *len)
+
+/**
+ * internet_address_set_name:
+ * @ia: internet address
+ * @name: group or contact's name
+ *
+ * Set the name of the internet address.
+ **/
+void
+internet_address_set_name (InternetAddress *ia, const char *name)
{
- gchar *token;
- gchar *inptr, *inend, *end;
- gint depth = 0;
- gchar dp = '\0', dm = '\0';
+ g_return_if_fail (ia != NULL);
- inptr = (gchar *) in;
- inend = inptr + inlen;
+ g_free (ia->name);
+ if (name) {
+ ia->name = g_mime_utils_8bit_header_decode (name);
+ g_mime_utils_unquote_string (ia->name);
+ } else
+ ia->name = NULL;
+}
+
+
+/**
+ * internet_address_set_addr:
+ * @ia: internet address
+ * @addr: contact's email address
+ *
+ * Set the intenet address's address.
+ **/
+void
+internet_address_set_addr (InternetAddress *ia, const char *addr)
+{
+ g_return_if_fail (ia != NULL);
+ g_return_if_fail (ia->type != INTERNET_ADDRESS_GROUP);
- while (isspace (*inptr) && inptr < inend)
- inptr++;
+ ia->type = INTERNET_ADDRESS_NAME;
+ g_free (ia->value.addr);
+ ia->value.addr = g_strdup (addr);
+}
+
+
+/**
+ * internet_address_set_group:
+ * @ia: internet address
+ * @group: a list of internet addresses
+ *
+ * Set the members of the internet address group.
+ **/
+void
+internet_address_set_group (InternetAddress *ia, GList *group)
+{
+ GList *members;
- if (*inptr == '"') {
- dm = '"';
- depth = 1;
- } else if (*inptr == '(') {
- dp = '(';
- dm = ')';
- depth = 1;
- }
-
- end = inptr;
- while (end < inend) {
- end++;
-
- if (*end == dp)
- depth++;
- else if (*end == dm)
- depth--;
- else if (!depth && isspace (*end))
- break;
- }
+ g_return_if_fail (ia != NULL);
+ g_return_if_fail (ia->type != INTERNET_ADDRESS_NAME);
- token = g_strndup (inptr, end - inptr);
- *len = end - in;
+ ia->type = INTERNET_ADDRESS_GROUP;
+ members = ia->value.members;
+ while (members) {
+ InternetAddress *member;
+
+ member = members->data;
+ internet_address_destroy (member);
+ members = members->next;
+ }
- return token;
+ g_list_free (ia->value.members);
+ ia->value.members = group;
}
-static GPtrArray *
-rfc822_tokenize (const gchar *in, guint inlen)
+
+/**
+ * internet_address_add_member:
+ * @ia: internet address
+ * @member: group member's internet address
+ *
+ * Add a contact to the internet address group.
+ **/
+void
+internet_address_add_member (InternetAddress *ia, InternetAddress *member)
{
- GPtrArray *tokens;
- gchar *token, *inptr, *inend;
- guint len;
+ g_return_if_fail (ia != NULL);
+ g_return_if_fail (ia->type != INTERNET_ADDRESS_NAME);
- inptr = (gchar *) in;
- inend = inptr + inlen;
+ ia->type = INTERNET_ADDRESS_GROUP;
+ ia->value.members = g_list_append (ia->value.members, member);
+}
+
+static gchar *
+encoded_name (const gchar *raw, gboolean rfc2047_encode)
+{
+ gchar *name;
- tokens = g_ptr_array_new ();
+ g_return_val_if_fail (raw != NULL, NULL);
- while (inptr < inend) {
- token = get_next_token (inptr, inend - inptr, &len);
- inptr += len;
- g_ptr_array_add (tokens, token);
+ if (rfc2047_encode && g_mime_utils_text_is_8bit (raw, strlen (raw))) {
+ name = g_mime_utils_8bit_header_encode_phrase (raw);
+ } else {
+ name = g_mime_utils_quote_string (raw);
}
- return tokens;
+ return name;
}
/**
- * internet_address_new_from_string: Create a new Internet Address object
- * @string: rfc822 internet address string
+ * internet_address_to_string: Write the InternetAddress object to a string
+ * @ia: Internet Address object
+ * @encode: TRUE if the address should be rfc2047 encoded
*
- * Returns a new Internet Address object based upon the rfc822 address
- * string.
+ * Returns the InternetAddress object as an allocated string in rfc822
+ * format.
**/
-InternetAddress *
-internet_address_new_from_string (const gchar *string)
+gchar *
+internet_address_to_string (InternetAddress *ia, gboolean encode)
{
- InternetAddress *ia;
- GPtrArray *tokens;
- gchar *name = NULL, *address = NULL;
- int i;
-
- g_return_val_if_fail (string != NULL, NULL);
- g_return_val_if_fail (*string != '\0', NULL);
+ char *string = NULL;
- tokens = rfc822_tokenize (string, strlen (string));
- if (!tokens->len) {
- g_ptr_array_free (tokens, TRUE);
- return NULL;
+ if (ia->type == INTERNET_ADDRESS_NAME) {
+ if (ia->name) {
+ char *name;
+
+ name = encoded_name (ia->name, encode);
+ string = g_strdup_printf ("%s <%s>", name,
+ ia->value.addr);
+ g_free (name);
+ } else {
+ string = g_strdup (ia->value.addr);
+ }
+ } else if (ia->type == INTERNET_ADDRESS_GROUP) {
+ GList *members;
+ GString *gstr;
+
+ gstr = g_string_new (ia->name);
+ g_string_append (gstr, ": ");
+
+ members = ia->value.members;
+ while (members) {
+ InternetAddress *member;
+ char *addr;
+
+ member = members->data;
+ members = members->next;
+
+ addr = internet_address_to_string (member, encode);
+ if (addr) {
+ g_string_append (gstr, addr);
+ g_free (addr);
+ if (members)
+ g_string_append (gstr, ", ");
+ }
+ }
+
+ g_string_append (gstr, ";");
+
+ string = gstr->str;
+ g_string_free (gstr, FALSE);
}
- /* find the address */
- for (i = 0; i < tokens->len; i++) {
- gchar *token = tokens->pdata[i];
+ return string;
+}
+
+static void
+decode_lwsp (const char **in)
+{
+ const char *inptr = *in;
+
+ while (*inptr && (*inptr == '(' || is_lwsp (*inptr))) {
+ while (*inptr && is_lwsp (*inptr))
+ inptr++;
- if (*token == '<' && *(token + strlen (token) - 1) == '>') {
- address = token;
+ /* skip over any comments */
+ if (*inptr == '(') {
+ int depth = 1;
- /* strip the <>'s */
- memmove (address, address + 1, strlen (address));
- *(address + strlen (address) - 1) = '\0';
-
- /* remove the address from the list of tokens */
- g_ptr_array_remove_index (tokens, i);
- break;
+ inptr++;
+ while (*inptr && depth) {
+ if (*inptr == '\\' && *(inptr + 1))
+ inptr++;
+ else if (*inptr == '(')
+ depth++;
+ else if (*inptr == ')')
+ depth--;
+
+ inptr++;
+ }
}
}
- if (!address) {
- /* the first token should be the address if it wasn't surrounded in <>'s */
- address = tokens->pdata[0];
- g_ptr_array_remove_index (tokens, 0);
+ *in = inptr;
+}
+
+static char *
+decode_quoted_string (const char **in)
+{
+ const char *inptr = *in;
+ GString *string = NULL;
+ char *out = NULL;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ out = (char *) inptr;
+
+ inptr++;
+ while (*inptr && *inptr != '"') {
+ if (*inptr == '\\')
+ inptr++;
+
+ if (*inptr)
+ inptr++;
+ }
+
+ if (*inptr == '"')
+ inptr++;
+
+ out = g_strndup (out, inptr - out);
}
- /* recreate the name from the tokens */
- if (tokens->len) {
- char *token = tokens->pdata[0];
- char *end = token + strlen (token) - 1;
+ *in = inptr;
+
+ return out;
+}
+
+#if 0
+static char *
+decode_quoted_string (const char **in)
+{
+ const char *inptr = *in;
+ char *out = NULL, *outptr;
+ int outlen;
+ int c;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ const char *intmp;
+ int skip = 0;
- if (*token == '(' && *end == ')') {
- token++;
- *end = '\0';
+ /* first, calc length */
+ inptr++;
+ intmp = inptr + 1;
+ while ((c = *intmp++) && c != '"') {
+ if (c == '\\' && *intmp) {
+ intmp++;
+ skip++;
+ }
+ }
+
+ outlen = intmp - inptr - skip;
+ out = outptr = g_malloc (outlen + 1);
+
+ while ((c = *inptr++) && c != '"') {
+ if (c == '\\' && *inptr) {
+ c = *inptr++;
+ }
+ *outptr++ = c;
+ }
+ *outptr = '\0';
+ }
+
+ *in = inptr;
+
+ return out;
+}
+#endif
+
+static char *
+decode_atom (const char **in)
+{
+ const char *inptr = *in, *start;
+
+ decode_lwsp (&inptr);
+ start = inptr;
+ while (is_atom (*inptr))
+ inptr++;
+ *in = inptr;
+ if (inptr > start)
+ return g_strndup (start, inptr - start);
+ else
+ return NULL;
+}
+
+static char *
+decode_word (const char **in)
+{
+ const char *inptr = *in;
+
+ decode_lwsp (&inptr);
+ if (*inptr == '"') {
+ *in = inptr;
+ return decode_quoted_string (in);
+ } else {
+ *in = inptr;
+ return decode_atom (in);
+ }
+}
+
+static gboolean
+decode_subliteral (const char **in, GString *domain)
+{
+ const char *inptr = *in;
+ gboolean got = FALSE;
+
+ while (*inptr && *inptr != '.' && *inptr != ']') {
+ if (is_dtext (*inptr)) {
+ g_string_append_c (domain, *inptr);
+ inptr++;
+ got = TRUE;
+ } else if (is_lwsp (*inptr))
+ decode_lwsp (&inptr);
+ else
+ break;
+ }
+
+ *in = inptr;
+
+ return got;
+}
+
+static void
+decode_domain_literal (const char **in, GString *domain)
+{
+ const char *inptr = *in;
+
+ decode_lwsp (&inptr);
+ while (*inptr && *inptr != ']') {
+ if (decode_subliteral (&inptr, domain) && *inptr == '.') {
+ g_string_append_c (domain, *inptr);
+ inptr++;
+ } else if (*inptr != ']') {
+ g_warning ("Malformed domain-literal, "
+ "unexpected char (%c): %s", *inptr, *in);
+
+ /* try and skip to the next char ?? */
+ inptr++;
+ }
+ }
+
+ *in = inptr;
+}
+
+static char *
+decode_domain (const char **in)
+{
+ const char *inptr, *save;
+ GString *domain;
+ char *dom, *atom;
+
+ domain = g_string_new ("");
+
+ inptr = *in;
+ while (TRUE) {
+ decode_lwsp (&inptr);
+ if (*inptr == '[') {
+ /* domain literal */
+ g_string_append_c (domain, '[');
+ inptr++;
- name = g_mime_utils_8bit_header_decode (token);
+ decode_domain_literal (&inptr, domain);
+
+ if (*inptr == ']') {
+ g_string_append_c (domain, ']');
+ inptr++;
+ } else
+ g_warning ("Missing ']' in domain-literal: %s", *in);
} else {
- name = g_strjoinv (" ", (gchar **) tokens->pdata);
+ atom = decode_atom (&inptr);
+ if (atom)
+ g_string_append (domain, atom);
+ g_free (atom);
+ }
+
+ save = inptr;
+ decode_lwsp (&inptr);
+ if (*inptr != '.') {
+ inptr = save;
+ break;
}
+
+ g_string_append_c (domain, '.');
+ inptr++;
}
- for (i = 0; i < tokens->len; i++)
- g_free (tokens->pdata[i]);
- g_ptr_array_free (tokens, TRUE);
+ dom = domain->str;
+ g_string_free (domain, FALSE);
- ia = internet_address_new (name, address);
- g_free (name);
- g_free (address);
+ *in = inptr;
- return ia;
+ return dom;
}
-
-/**
- * internet_address_destroy: Destroy an Internet Address object
- * @ia: Internet Address object to destroy
- *
- * Destroy the InternetAddress object pointed to by #ia.
- **/
-void
-internet_address_destroy (InternetAddress *ia)
+static InternetAddress *
+decode_mailbox (const char **in)
{
- g_return_if_fail (ia != NULL);
+ InternetAddress *mailbox = NULL;
+ const char *inptr;
+ gboolean bracket = FALSE;
+ GString *name = NULL;
+ GString *addr;
+ char *pre;
- g_free (ia->name);
- g_free (ia->address);
- g_free (ia);
+ addr = g_string_new ("");
+
+ decode_lwsp (in);
+ inptr = *in;
+
+ pre = decode_word (&inptr);
+ decode_lwsp (&inptr);
+ if (*inptr && !strchr (",.@", *inptr)) {
+ /* this mailbox has a name part, so get the name */
+ name = g_string_new ("");
+ while (pre) {
+ g_string_append (name, pre);
+ g_free (pre);
+ pre = decode_word (&inptr);
+ if (pre)
+ g_string_append_c (name, ' ');
+ }
+
+ decode_lwsp (&inptr);
+ if (*inptr == '<') {
+ inptr++;
+ bracket = TRUE;
+ pre = decode_word (&inptr);
+ } else {
+ g_string_free (name, TRUE);
+ g_string_free (addr, TRUE);
+ *in = inptr;
+
+ return NULL;
+ }
+ }
+
+ if (pre) {
+ g_string_append (addr, pre);
+ } else {
+ g_warning ("No local part for email address: %s", *in);
+ if (name)
+ g_string_free (name, TRUE);
+ g_string_free (addr, TRUE);
+ return NULL;
+ }
+
+ /* get the rest of the local-part */
+ decode_lwsp (&inptr);
+ while (*inptr == '.' && pre) {
+ inptr++;
+ g_free (pre);
+ pre = decode_word (&inptr);
+ if (pre) {
+ g_string_append_c (addr, '.');
+ g_string_append (addr, pre);
+ }
+ decode_lwsp (&inptr);
+ }
+ g_free (pre);
+
+ /* we should be at the '@' now... */
+ if (*inptr == '@') {
+ char *domain;
+
+ g_string_append_c (addr, '@');
+ inptr++;
+
+ domain = decode_domain (&inptr);
+ g_string_append (addr, domain);
+ g_free (domain);
+ } else {
+ g_warning ("No domain in email address: %s", *in);
+ }
+
+ if (bracket) {
+ decode_lwsp (&inptr);
+ if (*inptr == '>')
+ inptr++;
+ else
+ g_warning ("Missing closing '>' bracket for email address: %s", *in);
+ }
+
+ if (!name) {
+ /* look for a trailing comment to use as the name? */
+ char *comment;
+
+ comment = (char *) inptr;
+ decode_lwsp (&inptr);
+ if (inptr > comment) {
+ comment = memchr (comment, '(', inptr - comment);
+ if (comment) {
+ const char *cend;
+
+ /* find the end of the comment */
+ for (cend = inptr - 1; cend > comment && is_lwsp (*cend); cend--);
+ if (*cend == ')')
+ cend--;
+ comment = g_strndup (comment + 1, cend - comment);
+
+ name = g_string_new (comment);
+ g_free (comment);
+ }
+ }
+ }
+
+ *in = inptr;
+
+ if (addr->len)
+ mailbox = internet_address_new_name (name ? name->str : NULL, addr->str);
+
+ g_string_free (addr, TRUE);
+ if (name)
+ g_string_free (name, TRUE);
+
+ return mailbox;
}
-static gchar *
-encoded_name (const gchar *raw, gboolean rfc2047_encode)
+static InternetAddress *
+decode_address (const char **in)
{
- gchar *name;
+ InternetAddress *addr = NULL, *member;
+ const char *inptr, *start;
+ GString *name;
+ char *pre;
- g_return_val_if_fail (raw != NULL, NULL);
+ decode_lwsp (in);
+ start = inptr = *in;
- if (rfc2047_encode && g_mime_utils_text_is_8bit (raw, strlen (raw))) {
- name = g_mime_utils_8bit_header_encode_phrase (raw);
+ /* pre-scan */
+ name = g_string_new ("");
+ pre = decode_word (&inptr);
+ while (pre) {
+ g_string_append (name, pre);
+ g_free (pre);
+
+ pre = decode_word (&inptr);
+ if (pre)
+ g_string_append_c (name, ' ');
+ }
+
+ decode_lwsp (&inptr);
+ if (*inptr == ':') {
+ /* this is a group */
+ inptr++;
+ addr = internet_address_new_group (name->str);
+
+ decode_lwsp (&inptr);
+ while (*inptr && *inptr != ';') {
+ InternetAddress *member;
+
+ member = decode_mailbox (&inptr);
+ if (member)
+ internet_address_add_member (addr, member);
+
+ decode_lwsp (&inptr);
+ while (*inptr == ',') {
+ inptr++;
+ decode_lwsp (&inptr);
+ member = decode_mailbox (&inptr);
+ if (member)
+ internet_address_add_member (addr, member);
+
+ decode_lwsp (&inptr);
+ }
+ }
+
+ if (*inptr == ';')
+ inptr++;
+ else
+ g_warning ("Invalid group spec, missing closing ';': %.*s",
+ inptr - start, start);
+
+ *in = inptr;
} else {
- name = g_mime_utils_quote_string (raw);
+ /* this is a mailbox */
+ addr = decode_mailbox (in);
}
- return name;
+ g_string_free (name, TRUE);
+
+ return addr;
}
/**
- * internet_address_to_string: Write the InternetAddress object to a string
- * @ia: Internet Address object
- * @rfc2047_encode: TRUE if the address should be encoded
- *
- * Returns the InternetAddress object as an allocated string in rfc822
- * format.
+ * internet_address_paarse_string:
+ * @string: a string containing internet addresses
+ *
+ * Construct a list of internet addresses from the given string.
+ *
+ * Returns a linked list of internet addresses.
**/
-gchar *
-internet_address_to_string (InternetAddress *ia, gboolean rfc2047_encode)
+GList *
+internet_address_parse_string (const char *string)
{
- gchar *name, *string;
+ GList *addrlist = NULL;
+ const char *inptr;
- g_return_val_if_fail (ia != NULL, NULL);
+ inptr = string;
- if (ia->name) {
- name = encoded_name (ia->name, rfc2047_encode);
- string = g_strdup_printf ("%s <%s>", name, ia->address);
- g_free (name);
- } else {
- string = g_strdup (ia->address);
+ while (inptr && *inptr) {
+ InternetAddress *addr;
+ const char *start;
+
+ start = inptr;
+
+ addr = decode_address (&inptr);
+
+ if (addr)
+ addrlist = g_list_append (addrlist, addr);
+ else
+ g_warning ("Invalid or incomplete address: %.*s", inptr - start, start);
+
+ decode_lwsp (&inptr);
+ if (*inptr == ',')
+ inptr++;
+ else if (*inptr) {
+ g_warning ("Parse error at '%s': expected ','", inptr);
+ /* try skipping to the next address */
+ inptr = strchr (inptr, ',');
+ if (inptr)
+ inptr++;
+ }
}
- return string;
+ return addrlist;
}
diff --git a/internet-address.h b/internet-address.h
index 629ae11a..003f04da 100644
--- a/internet-address.h
+++ b/internet-address.h
@@ -30,18 +30,36 @@ extern "C" {
#include <glib.h>
+typedef enum {
+ INTERNET_ADDRESS_NONE,
+ INTERNET_ADDRESS_NAME,
+ INTERNET_ADDRESS_GROUP
+} InternetAddressType;
+
struct _InternetAddress {
+ InternetAddressType type;
gchar *name;
- gchar *address;
+ union {
+ gchar *addr;
+ GList *members;
+ } value;
};
typedef struct _InternetAddress InternetAddress;
-InternetAddress *internet_address_new (const gchar *name, const gchar *address);
-InternetAddress *internet_address_new_from_string (const gchar *string);
+InternetAddress *internet_address_new (void);
+InternetAddress *internet_address_new_name (const gchar *name, const gchar *addr);
+InternetAddress *internet_address_new_group (const gchar *name);
void internet_address_destroy (InternetAddress *ia);
+void internet_address_set_name (InternetAddress *ia, const gchar *name);
+void internet_address_set_addr (InternetAddress *ia, const gchar *addr);
+void internet_address_set_group (InternetAddress *ia, GList *group);
+void internet_address_add_member (InternetAddress *ia, InternetAddress *member);
+
+GList *internet_address_parse_string (const gchar *string);
+
gchar *internet_address_to_string (InternetAddress *ia, gboolean rfc2047_encode);
#ifdef __cplusplus
diff --git a/test-mime.c b/test-mime.c
index d00e4b20..5ec2b94b 100644
--- a/test-mime.c
+++ b/test-mime.c
@@ -157,23 +157,14 @@ test_encodings (void)
{
char *enc, *dec;
int pos, state = -1, save = 0;
-
- fprintf (stderr, "hello\n");
-
- enc = g_strdup ("fpons@mandrakesoft.com (=?iso-8859-1?q?Fran=E7ois?= Pons)");
- fprintf (stderr, "encoded: %s\n", enc);
- dec = g_mime_utils_8bit_header_decode (enc);
- fprintf (stderr, "decoded: %s\n", dec);
- g_free (enc);
- g_free (dec);
-
+
enc = g_strdup ("=?iso-8859-1?q?blablah?=");
fprintf (stderr, "encoded: %s\n", enc);
dec = g_mime_utils_8bit_header_decode (enc);
fprintf (stderr, "decoded: %s\n", dec);
g_free (enc);
g_free (dec);
-
+
enc = g_strdup ("=?iso-8859-1?Q?blablah?=");
fprintf (stderr, "encoded: %s\n", enc);
dec = g_mime_utils_8bit_header_decode (enc);
@@ -250,32 +241,80 @@ static gchar *addresses[] = {
"Jeffrey \"fejj\" Stedfast <fejj@helixcode.com>",
"\"Stedfast, Jeffrey\" <fejj@helixcode.com>",
"fejj@helixcode.com (Jeffrey Stedfast)",
- "<fejj@helixcode.com> (Jeff)",
+ "Jeff <fejj(recursive (comment) block)@helixcode.(and a comment here)com>",
"=?iso-8859-1?q?Kristoffer=20Br=E5nemyr?= <ztion@swipenet.se>",
"fpons@mandrakesoft.com (=?iso-8859-1?q?Fran=E7ois?= Pons)",
+ "GNOME Hackers: miguel@gnome.org (Miguel de Icaza), Havoc Pennington <hp@redhat.com>;, fejj@helixcode.com",
+ "Local recipients: phil, joe, alex, bob",
+ "@develop:sblab!att!thumper.bellcore.com!nsb",
+ "\":sysmail\"@ Some-Group. Some-Org,\n Muhammed.(I am the greatest) Ali @(the)Vegas.WBA",
+ "Charles S. Kerr <charles@foo.com>",
+ "Charles \"Likes, to, put, commas, in, quoted, strings\" Kerr <charles@foo.com>",
+ "Charles Kerr, Pan Programmer <charles@superpimp.org>",
+ "Charles Kerr <charles@[127.0.0.1]>",
+ "Charles <charles@[127..0.1]>",
+ "<charles@>",
NULL
};
+static void
+dump_addrlist (GList *addrlist, int i, gboolean group, gboolean destroy)
+{
+ InternetAddress *ia;
+ GList *addr;
+
+ addr = addrlist;
+ while (addr) {
+ char *str;
+
+ ia = addr->data;
+ addr = addr->next;
+
+ if (i != -1)
+ fprintf (stderr, "Original: %s\n", addresses[i]);
+ if (ia->type == INTERNET_ADDRESS_GROUP) {
+ fprintf (stderr, "Address is a group:\n");
+ fprintf (stderr, "Name: %s\n", ia->name ? ia->name : "");
+ dump_addrlist (ia->value.members, -1, TRUE, FALSE);
+ fprintf (stderr, "End of group.\n");
+ } else if (ia->type == INTERNET_ADDRESS_NAME) {
+ fprintf (stderr, "%sName: %s\n", group ? "\t" : "",
+ ia->name ? ia->name : "");
+ fprintf (stderr, "%sEMail: %s\n", group ? "\t" : "",
+ ia->value.addr ? ia->value.addr : "");
+ }
+
+ str = internet_address_to_string (ia, FALSE);
+ fprintf (stderr, "%sRewritten (display): %s\n", group ? "\t" : "",
+ str ? str : "");
+ g_free (str);
+
+ str = internet_address_to_string (ia, TRUE);
+ fprintf (stderr, "%sRewritten (encoded): %s\n\n", group ? "\t" : "",
+ str ? str : "");
+ g_free (str);
+
+ if (destroy)
+ internet_address_destroy (ia);
+ }
+}
+
void
test_addresses (void)
{
- InternetAddress *ia;
- gchar *str;
int i;
for (i = 0; addresses[i]; i++) {
- ia = internet_address_new_from_string (addresses[i]);
- if (!ia) {
+ InternetAddress *ia;
+ GList *addrlist, *l;
+
+ addrlist = internet_address_parse_string (addresses[i]);
+ if (!addrlist) {
fprintf (stderr, "failed to parse '%s'.\n", addresses[i]);
continue;
}
- fprintf (stderr, "Original: %s\n", addresses[i]);
- fprintf (stderr, "Name: %s\n", ia->name ? ia->name : "");
- fprintf (stderr, "EMail: %s\n", ia->address ? ia->address : "");
- str = internet_address_to_string (ia, TRUE);
- internet_address_destroy (ia);
- fprintf (stderr, "Rewritten: %s\n\n", str ? str : "(null)");
- g_free (str);
+
+ dump_addrlist (addrlist, i, FALSE, TRUE);
}
}
diff --git a/tests/test-mime.c b/tests/test-mime.c
index d00e4b20..5ec2b94b 100644
--- a/tests/test-mime.c
+++ b/tests/test-mime.c
@@ -157,23 +157,14 @@ test_encodings (void)
{
char *enc, *dec;
int pos, state = -1, save = 0;
-
- fprintf (stderr, "hello\n");
-
- enc = g_strdup ("fpons@mandrakesoft.com (=?iso-8859-1?q?Fran=E7ois?= Pons)");
- fprintf (stderr, "encoded: %s\n", enc);
- dec = g_mime_utils_8bit_header_decode (enc);
- fprintf (stderr, "decoded: %s\n", dec);
- g_free (enc);
- g_free (dec);
-
+
enc = g_strdup ("=?iso-8859-1?q?blablah?=");
fprintf (stderr, "encoded: %s\n", enc);
dec = g_mime_utils_8bit_header_decode (enc);
fprintf (stderr, "decoded: %s\n", dec);
g_free (enc);
g_free (dec);
-
+
enc = g_strdup ("=?iso-8859-1?Q?blablah?=");
fprintf (stderr, "encoded: %s\n", enc);
dec = g_mime_utils_8bit_header_decode (enc);
@@ -250,32 +241,80 @@ static gchar *addresses[] = {
"Jeffrey \"fejj\" Stedfast <fejj@helixcode.com>",
"\"Stedfast, Jeffrey\" <fejj@helixcode.com>",
"fejj@helixcode.com (Jeffrey Stedfast)",
- "<fejj@helixcode.com> (Jeff)",
+ "Jeff <fejj(recursive (comment) block)@helixcode.(and a comment here)com>",
"=?iso-8859-1?q?Kristoffer=20Br=E5nemyr?= <ztion@swipenet.se>",
"fpons@mandrakesoft.com (=?iso-8859-1?q?Fran=E7ois?= Pons)",
+ "GNOME Hackers: miguel@gnome.org (Miguel de Icaza), Havoc Pennington <hp@redhat.com>;, fejj@helixcode.com",
+ "Local recipients: phil, joe, alex, bob",
+ "@develop:sblab!att!thumper.bellcore.com!nsb",
+ "\":sysmail\"@ Some-Group. Some-Org,\n Muhammed.(I am the greatest) Ali @(the)Vegas.WBA",
+ "Charles S. Kerr <charles@foo.com>",
+ "Charles \"Likes, to, put, commas, in, quoted, strings\" Kerr <charles@foo.com>",
+ "Charles Kerr, Pan Programmer <charles@superpimp.org>",
+ "Charles Kerr <charles@[127.0.0.1]>",
+ "Charles <charles@[127..0.1]>",
+ "<charles@>",
NULL
};
+static void
+dump_addrlist (GList *addrlist, int i, gboolean group, gboolean destroy)
+{
+ InternetAddress *ia;
+ GList *addr;
+
+ addr = addrlist;
+ while (addr) {
+ char *str;
+
+ ia = addr->data;
+ addr = addr->next;
+
+ if (i != -1)
+ fprintf (stderr, "Original: %s\n", addresses[i]);
+ if (ia->type == INTERNET_ADDRESS_GROUP) {
+ fprintf (stderr, "Address is a group:\n");
+ fprintf (stderr, "Name: %s\n", ia->name ? ia->name : "");
+ dump_addrlist (ia->value.members, -1, TRUE, FALSE);
+ fprintf (stderr, "End of group.\n");
+ } else if (ia->type == INTERNET_ADDRESS_NAME) {
+ fprintf (stderr, "%sName: %s\n", group ? "\t" : "",
+ ia->name ? ia->name : "");
+ fprintf (stderr, "%sEMail: %s\n", group ? "\t" : "",
+ ia->value.addr ? ia->value.addr : "");
+ }
+
+ str = internet_address_to_string (ia, FALSE);
+ fprintf (stderr, "%sRewritten (display): %s\n", group ? "\t" : "",
+ str ? str : "");
+ g_free (str);
+
+ str = internet_address_to_string (ia, TRUE);
+ fprintf (stderr, "%sRewritten (encoded): %s\n\n", group ? "\t" : "",
+ str ? str : "");
+ g_free (str);
+
+ if (destroy)
+ internet_address_destroy (ia);
+ }
+}
+
void
test_addresses (void)
{
- InternetAddress *ia;
- gchar *str;
int i;
for (i = 0; addresses[i]; i++) {
- ia = internet_address_new_from_string (addresses[i]);
- if (!ia) {
+ InternetAddress *ia;
+ GList *addrlist, *l;
+
+ addrlist = internet_address_parse_string (addresses[i]);
+ if (!addrlist) {
fprintf (stderr, "failed to parse '%s'.\n", addresses[i]);
continue;
}
- fprintf (stderr, "Original: %s\n", addresses[i]);
- fprintf (stderr, "Name: %s\n", ia->name ? ia->name : "");
- fprintf (stderr, "EMail: %s\n", ia->address ? ia->address : "");
- str = internet_address_to_string (ia, TRUE);
- internet_address_destroy (ia);
- fprintf (stderr, "Rewritten: %s\n\n", str ? str : "(null)");
- g_free (str);
+
+ dump_addrlist (addrlist, i, FALSE, TRUE);
}
}