From 442cb01bee426d4a716485759ea093c773f5321a Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Wed, 15 May 2002 23:46:27 +0000 Subject: New function to parse a NAMESPACE response properly. 2002-05-15 Jeffrey Stedfast * providers/imap/camel-imap-utils.c (imap_parse_namespace_response): New function to parse a NAMESPACE response properly. (imap_namespaces_destroy): New function to destroy the returned structure from the above function. svn path=/trunk/; revision=16927 --- camel/providers/imap/camel-imap-folder.c | 6 +- camel/providers/imap/camel-imap-store.c | 12 +- camel/providers/imap/camel-imap-utils.c | 276 ++++++++++++++++++++++++++++--- camel/providers/imap/camel-imap-utils.h | 21 ++- 4 files changed, 283 insertions(+), 32 deletions(-) (limited to 'camel/providers/imap') diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index a957e1f776..f8d3a59594 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -1770,7 +1770,7 @@ imap_get_message (CamelFolder *folder, const char *uid, CamelException *ex) } if (body) - imap_parse_body (&body, folder, mi->content); + imap_parse_body ((const char **) &body, folder, mi->content); if (fetch_data) g_datalist_clear (&fetch_data); @@ -2326,7 +2326,7 @@ parse_fetch_response (CamelImapFolder *imap_folder, char *response) response += 7; } - body = imap_parse_nstring (&response, &body_len); + body = imap_parse_nstring ((const char **) &response, &body_len); if (!response) { g_free (part_spec); break; @@ -2341,7 +2341,7 @@ parse_fetch_response (CamelImapFolder *imap_folder, char *response) !g_strncasecmp (response, "BODYSTRUCTURE ", 14)) { response = strchr (response, ' ') + 1; start = response; - imap_skip_list (&response); + imap_skip_list ((const char **) &response); g_datalist_set_data_full (&data, "BODY", g_strndup (start, response - start), g_free); } else if (!g_strncasecmp (response, "UID ", 4)) { int len; diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index 6b7c293cca..4d983bebf0 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -745,6 +745,7 @@ imap_connect_online (CamelService *service, CamelException *ex) CamelImapStore *store = CAMEL_IMAP_STORE (service); CamelDiscoStore *disco_store = CAMEL_DISCO_STORE (service); CamelImapResponse *response; + struct _namespaces *namespaces; char *result, *name, *path; FILE *storeinfo; int i, flags; @@ -778,15 +779,20 @@ imap_connect_online (CamelService *service, CamelException *ex) result = camel_imap_response_extract (store, response, "NAMESPACE", ex); if (!result) goto done; - + + /* new code... */ + namespaces = imap_parse_namespace_response (result); + imap_namespaces_destroy (namespaces); + /* end new code */ + name = strstrcase (result, "NAMESPACE (("); if (name) { char *sep; name += 12; - store->namespace = imap_parse_string (&name, &len); + store->namespace = imap_parse_string ((const char **) &name, &len); if (name && *name++ == ' ') { - sep = imap_parse_string (&name, &len); + sep = imap_parse_string ((const char **) &name, &len); if (sep) { store->dir_sep = *sep; ((CamelStore *)store)->dir_sep = store->dir_sep; diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c index 304ef97448..753e341316 100644 --- a/camel/providers/imap/camel-imap-utils.c +++ b/camel/providers/imap/camel-imap-utils.c @@ -39,14 +39,243 @@ imap_next_word (const char *buf) const char *word; /* skip over current word */ - for (word = buf; *word && *word != ' '; word++); + word = buf; + while (*word && *word != ' ') + word++; /* skip over white space */ - for ( ; *word && *word == ' '; word++); + while (*word && *word == ' ') + word++; return word; } + +static void +imap_namespace_destroy (struct _namespace *namespace) +{ + struct _namespace *node, *next; + + node = namespace; + while (node) { + next = node->next; + g_free (node->prefix); + g_free (node); + node = next; + } +} + +void +imap_namespaces_destroy (struct _namespaces *namespaces) +{ + if (namespaces) { + imap_namespace_destroy (namespaces->personal); + imap_namespace_destroy (namespaces->other); + imap_namespace_destroy (namespaces->shared); + g_free (namespaces); + } +} + +static gboolean +imap_namespace_decode (const char **in, struct _namespace **namespace) +{ + struct _namespace *list, *tail, *node; + const char *inptr; + char *astring; + size_t len; + + inptr = *in; + + list = NULL; + tail = (struct _namespace *) &list; + + if (g_strncasecmp (inptr, "NIL", 3) != 0) { + if (*inptr++ != '(') + goto exception; + + while (*inptr && *inptr != ')') { + if (*inptr++ != '(') + goto exception; + + node = g_new (struct _namespace, 1); + node->next = NULL; + + /* get the namespace prefix */ + astring = imap_parse_astring (&inptr, &len); + if (!astring) { + g_free (node); + goto exception; + } + + /* decode IMAP's modified UTF-7 into UTF-8 */ + node->prefix = imap_mailbox_decode (astring, len); + g_free (astring); + if (!node->prefix) { + g_free (node); + goto exception; + } + + tail->next = node; + tail = node; + + /* get the namespace directory delimiter */ + inptr = imap_next_word (inptr); + + if (!g_strncasecmp (inptr, "NIL", 3)) { + inptr = imap_next_word (inptr); + node->delim = '\0'; + } else if (*inptr++ == '"') { + if (*inptr == '\\') + inptr++; + + node->delim = *inptr++; + + if (*inptr++ != '"') + goto exception; + } else + goto exception; + + if (*inptr == ' ') { + /* parse extra flags... for now we + don't save them, but in the future + we may want to? */ + while (*inptr == ' ') + inptr++; + + while (*inptr && *inptr != ')') { + /* this should be a QSTRING or ATOM */ + inptr = imap_next_word (inptr); + if (*inptr == '(') { + /* skip over the param list */ + imap_skip_list (&inptr); + } + + while (*inptr == ' ') + inptr++; + } + } + + if (*inptr++ != ')') + goto exception; + + /* there shouldn't be spaces according to the + ABNF grammar, but we all know how closely + people follow specs */ + while (*inptr == ' ') + inptr++; + } + + if (*inptr == ')') + inptr++; + } else { + inptr += 3; + } + + *in = inptr; + *namespace = list; + + return TRUE; + + exception: + + /* clean up any namespaces we may have allocated */ + imap_namespace_destroy (list); + + return FALSE; +} + +static void +namespace_dump (struct _namespace *namespace) +{ + struct _namespace *node; + + if (namespace) { + printf ("("); + node = namespace; + while (node) { + printf ("(\"%s\" ", node->prefix); + if (node->delim) + printf ("\"%c\")", node->delim); + else + printf ("NUL)"); + + node = node->next; + if (node) + printf (" "); + } + + printf (")"); + } else { + printf ("NIL"); + } +} + +static void +namespaces_dump (struct _namespaces *namespaces) +{ + printf ("namespace dump: "); + namespace_dump (namespaces->personal); + printf (" "); + namespace_dump (namespaces->other); + printf (" "); + namespace_dump (namespaces->shared); + printf ("\n"); +} + +struct _namespaces * +imap_parse_namespace_response (const char *response) +{ + struct _namespaces *namespaces; + const char *inptr; + + printf ("parsing: %s\n", response); + + if (*response != '*') + return NULL; + + inptr = imap_next_word (response); + if (g_strncasecmp (inptr, "NAMESPACE", 9) != 0) + return NULL; + + inptr = imap_next_word (inptr); + + namespaces = g_new (struct _namespaces, 1); + namespaces->personal = NULL; + namespaces->other = NULL; + namespaces->shared = NULL; + + if (!imap_namespace_decode (&inptr, &namespaces->personal)) + goto exception; + + if (*inptr != ' ') + goto exception; + + while (*inptr == ' ') + inptr++; + + if (!imap_namespace_decode (&inptr, &namespaces->other)) + goto exception; + + if (*inptr != ' ') + goto exception; + + while (*inptr == ' ') + inptr++; + + if (!imap_namespace_decode (&inptr, &namespaces->shared)) + goto exception; + + namespaces_dump (namespaces); + + return namespaces; + + exception: + + imap_namespaces_destroy (namespaces); + + return NULL; +} + /** * imap_parse_list_response: * @store: the IMAP store whose list response we're parsing @@ -122,7 +351,7 @@ imap_parse_list_response (CamelImapStore *store, const char *buf, int *flags, ch /* get the folder name */ word = imap_next_word (word); - astring = imap_parse_astring ((char **) &word, &len); + astring = imap_parse_astring (&word, &len); if (!astring) return FALSE; @@ -351,9 +580,9 @@ imap_is_atom(const char *in) * latter, it will point to the character after the NIL.) **/ char * -imap_parse_string_generic (char **str_p, size_t *len, int type) +imap_parse_string_generic (const char **str_p, size_t *len, int type) { - char *str = *str_p; + const char *str = *str_p; char *out; if (!str) @@ -401,13 +630,13 @@ imap_parse_string_generic (char **str_p, size_t *len, int type) *len = 0; return NULL; } else if (type == IMAP_ASTRING && imap_is_atom_char ((unsigned char)*str)) { - while (imap_is_atom_char ((unsigned char)*str)) + while (imap_is_atom_char ((unsigned char) *str)) str++; *len = str - *str_p; - str = g_strndup (*str_p, *len); + out = g_strndup (*str_p, *len); *str_p += *len; - return str; + return out; } else { *str_p = NULL; return NULL; @@ -415,19 +644,19 @@ imap_parse_string_generic (char **str_p, size_t *len, int type) } static inline void -skip_char (char **str_p, char ch) +skip_char (const char **in, char ch) { - if (*str_p && **str_p == ch) - *str_p = *str_p + 1; + if (*in && **in == ch) + *in = *in + 1; else - *str_p = NULL; + *in = NULL; } /* Skip atom, string, or number */ static void -skip_asn (char **str_p) +skip_asn (const char **str_p) { - char *str = *str_p; + const char *str = *str_p; if (!str) return; @@ -446,7 +675,7 @@ skip_asn (char **str_p) } else if (*str == '{') { unsigned long len; - len = strtoul (str + 1, &str, 10); + len = strtoul (str + 1, (char **) &str, 10); if (*str != '}' || *(str + 1) != '\n' || strlen (str + 2) < len) { *str_p = NULL; @@ -464,7 +693,7 @@ skip_asn (char **str_p) } void -imap_skip_list (char **str_p) +imap_skip_list (const char **str_p) { skip_char (str_p, '('); while (*str_p && **str_p != ')') { @@ -479,9 +708,10 @@ imap_skip_list (char **str_p) } static void -parse_params (char **parms_p, CamelContentType *type) +parse_params (const char **parms_p, CamelContentType *type) { - char *parms = *parms_p, *name, *value; + const char *parms = *parms_p; + char *name, *value; int len; if (!g_strncasecmp (parms, "nil", 3)) { @@ -526,10 +756,10 @@ parse_params (char **parms_p, CamelContentType *type) * set to %NULL and @ci will be unchanged. **/ void -imap_parse_body (char **body_p, CamelFolder *folder, +imap_parse_body (const char **body_p, CamelFolder *folder, CamelMessageContentInfo *ci) { - char *body = *body_p; + const char *body = *body_p; CamelMessageContentInfo *child; CamelContentType *type; size_t len; @@ -615,7 +845,7 @@ imap_parse_body (char **body_p, CamelFolder *folder, encoding = imap_parse_string (&body, &len); skip_char (&body, ' '); if (body) - size = strtoul (body, &body, 10); + size = strtoul (body, (char **) &body, 10); child = NULL; if (header_content_type_is (type, "message", "rfc822")) { @@ -628,11 +858,11 @@ imap_parse_body (char **body_p, CamelFolder *folder, camel_folder_summary_content_info_free (folder->summary, child); skip_char (&body, ' '); if (body) - strtoul (body, &body, 10); + strtoul (body, (char **) &body, 10); child->parent = ci; } else if (header_content_type_is (type, "text", "*")) { if (body) - strtoul (body, &body, 10); + strtoul (body, (char **) &body, 10); } if (body) { diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h index 7078e12335..9692cc4e38 100644 --- a/camel/providers/imap/camel-imap-utils.h +++ b/camel/providers/imap/camel-imap-utils.h @@ -35,6 +35,21 @@ extern "C" { const char *imap_next_word (const char *buf); +struct _namespace { + struct _namespace *next; + char *prefix; + char delim; +}; + +struct _namespaces { + struct _namespace *personal; + struct _namespace *other; + struct _namespace *shared; +}; + +void imap_namespaces_destroy (struct _namespaces *namespaces); +struct _namespaces *imap_parse_namespace_response (const char *response); + #define IMAP_LIST_FLAG_NOINFERIORS (1 << 0) #define IMAP_LIST_FLAG_NOSELECT (1 << 1) #define IMAP_LIST_FLAG_MARKED (1 << 2) @@ -51,7 +66,7 @@ guint32 imap_parse_flag_list (char **flag_list); enum { IMAP_STRING, IMAP_NSTRING, IMAP_ASTRING }; -char *imap_parse_string_generic (char **str_p, size_t *len, int type); +char *imap_parse_string_generic (const char **str_p, size_t *len, int type); #define imap_parse_string(str_p, len_p) \ imap_parse_string_generic (str_p, len_p, IMAP_STRING) @@ -60,13 +75,13 @@ char *imap_parse_string_generic (char **str_p, size_t *len, int type); #define imap_parse_astring(str_p, len_p) \ imap_parse_string_generic (str_p, len_p, IMAP_ASTRING) -void imap_parse_body (char **body_p, CamelFolder *folder, +void imap_parse_body (const char **body_p, CamelFolder *folder, CamelMessageContentInfo *ci); gboolean imap_is_atom (const char *in); char *imap_quote_string (const char *str); -void imap_skip_list (char **str_p); +void imap_skip_list (const char **str_p); char *imap_uid_array_to_set (CamelFolderSummary *summary, GPtrArray *uids, int uid, ssize_t maxlen, int *lastuid); GPtrArray *imap_uid_set_to_array (CamelFolderSummary *summary, const char *uids); -- cgit v1.2.3