aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap4/camel-imap4-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap4/camel-imap4-utils.c')
-rw-r--r--camel/providers/imap4/camel-imap4-utils.c315
1 files changed, 315 insertions, 0 deletions
diff --git a/camel/providers/imap4/camel-imap4-utils.c b/camel/providers/imap4/camel-imap4-utils.c
new file mode 100644
index 0000000000..67dd828134
--- /dev/null
+++ b/camel/providers/imap4/camel-imap4-utils.c
@@ -0,0 +1,315 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Camel
+ * Copyright (C) 1999-2004 Jeffrey Stedfast
+ *
+ * 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.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <camel/camel-store.h>
+
+#include "camel-imap4-engine.h"
+#include "camel-imap4-stream.h"
+#include "camel-imap4-command.h"
+
+#include "camel-imap4-utils.h"
+
+#define d(x) x
+
+
+void
+camel_imap4_flags_diff (flags_diff_t *diff, guint32 old, guint32 new)
+{
+ diff->changed = old ^ new;
+ diff->bits = new & diff->changed;
+}
+
+
+guint32
+camel_imap4_flags_merge (flags_diff_t *diff, guint32 flags)
+{
+ return (flags & ~diff->changed) | diff->bits;
+}
+
+
+/**
+ * camel_imap4_merge_flags:
+ * @original: original server flags
+ * @local: local flags (after changes)
+ * @server: new server flags (another client updated the server flags)
+ *
+ * Merge the local flag changes into the new server flags.
+ *
+ * Returns the merged flags.
+ **/
+guint32
+camel_imap4_merge_flags (guint32 original, guint32 local, guint32 server)
+{
+ flags_diff_t diff;
+
+ camel_imap4_flags_diff (&diff, original, local);
+
+ return camel_imap4_flags_merge (&diff, server);
+}
+
+
+void
+camel_imap4_utils_set_unexpected_token_error (CamelException *ex, CamelIMAP4Engine *engine, camel_imap4_token_t *token)
+{
+ GString *errmsg;
+
+ if (ex == NULL)
+ return;
+
+ errmsg = g_string_new ("");
+ g_string_append_printf (errmsg, _("Unexpected token in response from IMAP server %s: "),
+ engine->url->host);
+
+ switch (token->token) {
+ case CAMEL_IMAP4_TOKEN_NIL:
+ g_string_append (errmsg, "NIL");
+ break;
+ case CAMEL_IMAP4_TOKEN_ATOM:
+ g_string_append (errmsg, token->v.atom);
+ break;
+ case CAMEL_IMAP4_TOKEN_FLAG:
+ g_string_append (errmsg, token->v.flag);
+ break;
+ case CAMEL_IMAP4_TOKEN_QSTRING:
+ g_string_append (errmsg, token->v.qstring);
+ break;
+ case CAMEL_IMAP4_TOKEN_LITERAL:
+ g_string_append_printf (errmsg, "{%u}", token->v.literal);
+ break;
+ case CAMEL_IMAP4_TOKEN_NUMBER:
+ g_string_append_printf (errmsg, "%u", token->v.number);
+ break;
+ case CAMEL_IMAP4_TOKEN_NO_DATA:
+ g_string_append (errmsg, _("No data"));
+ break;
+ default:
+ g_string_append_c (errmsg, (unsigned char) (token->token & 0xff));
+ break;
+ }
+
+ camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, errmsg->str);
+
+ g_string_free (errmsg, TRUE);
+}
+
+
+static struct {
+ const char *name;
+ guint32 flag;
+} imap4_flags[] = {
+ { "\\Answered", CAMEL_MESSAGE_ANSWERED },
+ { "\\Deleted", CAMEL_MESSAGE_DELETED },
+ { "\\Draft", CAMEL_MESSAGE_DRAFT },
+ { "\\Flagged", CAMEL_MESSAGE_FLAGGED },
+ { "\\Seen", CAMEL_MESSAGE_SEEN },
+ /*{ "\\Recent", CAMEL_MESSAGE_RECENT },*/
+ { "\\*", CAMEL_MESSAGE_USER },
+};
+
+#if 0
+static struct {
+ const char *name;
+ guint32 flag;
+} imap4_user_flags[] = {
+ { "Forwarded", CAMEL_MESSAGE_FORWARDED },
+};
+#endif
+
+
+int
+camel_imap4_parse_flags_list (CamelIMAP4Engine *engine, guint32 *flags, CamelException *ex)
+{
+ camel_imap4_token_t token;
+ guint32 new = 0;
+ int i;
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ if (token.token != '(') {
+ d(fprintf (stderr, "Expected to find a '(' token starting the flags list\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ return -1;
+ }
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+
+ while (token.token == CAMEL_IMAP4_TOKEN_ATOM || token.token == CAMEL_IMAP4_TOKEN_FLAG) {
+ /* parse the flags list */
+ for (i = 0; i < G_N_ELEMENTS (imap4_flags); i++) {
+ if (!strcasecmp (imap4_flags[i].name, token.v.atom)) {
+ new |= imap4_flags[i].flag;
+ break;
+ }
+ }
+
+#if 0
+ if (i == G_N_ELEMENTS (imap4_flags)) {
+ for (i = 0; i < G_N_ELEMENTS (imap4_user_flags); i++) {
+ if (!strcasecmp (imap4_user_flags[i].name, token.v.atom)) {
+ new |= imap4_user_flags[i].flag;
+ break;
+ }
+ }
+
+ if (i == G_N_ELEMENTS (imap4_user_flags))
+ fprintf (stderr, "Encountered unknown flag: %s\n", token.v.atom);
+ }
+#else
+ if (i == G_N_ELEMENTS (imap4_flags))
+ fprintf (stderr, "Encountered unknown flag: %s\n", token.v.atom);
+#endif
+
+ if (camel_imap4_engine_next_token (engine, &token, ex) == -1)
+ return -1;
+ }
+
+ if (token.token != ')') {
+ d(fprintf (stderr, "Expected to find a ')' token terminating the flags list\n"));
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, &token);
+ return -1;
+ }
+
+ *flags = new;
+
+ return 0;
+}
+
+
+struct {
+ const char *name;
+ guint32 flag;
+} list_flags[] = {
+ { "\\Marked", CAMEL_IMAP4_FOLDER_MARKED },
+ { "\\Unmarked", CAMEL_IMAP4_FOLDER_UNMARKED },
+ { "\\Noselect", CAMEL_FOLDER_NOSELECT },
+ { "\\Noinferiors", CAMEL_FOLDER_NOINFERIORS },
+ { "\\HasChildren", CAMEL_FOLDER_CHILDREN },
+ { "\\HasNoChildren", CAMEL_FOLDER_NOCHILDREN },
+};
+
+int
+camel_imap4_untagged_list (CamelIMAP4Engine *engine, CamelIMAP4Command *ic, guint32 index, camel_imap4_token_t *token, CamelException *ex)
+{
+ GPtrArray *array = ic->user_data;
+ camel_imap4_list_t *list;
+ unsigned char *buf;
+ guint32 flags = 0;
+ GString *literal;
+ char delim;
+ size_t n;
+ int i;
+
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ /* parse the flag list */
+ if (token->token != '(')
+ goto unexpected;
+
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ while (token->token == CAMEL_IMAP4_TOKEN_FLAG || token->token == CAMEL_IMAP4_TOKEN_ATOM) {
+ for (i = 0; i < G_N_ELEMENTS (list_flags); i++) {
+ if (!g_ascii_strcasecmp (list_flags[i].name, token->v.atom)) {
+ flags |= list_flags[i].flag;
+ break;
+ }
+ }
+
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+ }
+
+ if (token->token != ')')
+ goto unexpected;
+
+ /* parse the path delimiter */
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ switch (token->token) {
+ case CAMEL_IMAP4_TOKEN_NIL:
+ delim = '\0';
+ break;
+ case CAMEL_IMAP4_TOKEN_QSTRING:
+ delim = *token->v.qstring;
+ break;
+ default:
+ goto unexpected;
+ }
+
+ /* parse the folder name */
+ if (camel_imap4_engine_next_token (engine, token, ex) == -1)
+ return -1;
+
+ list = g_new (camel_imap4_list_t, 1);
+ list->flags = flags;
+ list->delim = delim;
+
+ switch (token->token) {
+ case CAMEL_IMAP4_TOKEN_ATOM:
+ list->name = g_strdup (token->v.atom);
+ break;
+ case CAMEL_IMAP4_TOKEN_QSTRING:
+ list->name = g_strdup (token->v.qstring);
+ break;
+ case CAMEL_IMAP4_TOKEN_LITERAL:
+ literal = g_string_new ("");
+ while ((i = camel_imap4_stream_literal (engine->istream, &buf, &n)) == 1)
+ g_string_append_len (literal, buf, n);
+
+ if (i == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("IMAP server %s unexpectedly disconnected: %s"),
+ engine->url->host, errno ? g_strerror (errno) : _("Unknown"));
+ g_string_free (literal, TRUE);
+ return -1;
+ }
+
+ g_string_append_len (literal, buf, n);
+ list->name = literal->str;
+ g_string_free (literal, FALSE);
+ break;
+ default:
+ g_free (list);
+ goto unexpected;
+ }
+
+ g_ptr_array_add (array, list);
+
+ return camel_imap4_engine_eat_line (engine, ex);
+
+ unexpected:
+
+ camel_imap4_utils_set_unexpected_token_error (ex, engine, token);
+
+ return -1;
+}