diff options
author | Chenthill Palanisamy <pchenthill@novell.com> | 2012-05-08 14:47:04 +0530 |
---|---|---|
committer | Chenthill Palanisamy <pchenthill@novell.com> | 2012-05-08 14:47:16 +0530 |
commit | 7d7a889699586c092750638ac89da080eacb0129 (patch) | |
tree | d7abcc9cc0460b2312c9fa062e14aafbf45340b1 /camel/providers/imapx/camel-imapx-stream.c | |
parent | aa31c2a326bee13ea0f558dac05f1bcf73a10936 (diff) | |
download | evolution-data-server-7d7a889699586c092750638ac89da080eacb0129.tar.gz |
Split camel-imapx library and merge into camel so that providers can be written on top of imapx
Diffstat (limited to 'camel/providers/imapx/camel-imapx-stream.c')
-rw-r--r-- | camel/providers/imapx/camel-imapx-stream.c | 839 |
1 files changed, 0 insertions, 839 deletions
diff --git a/camel/providers/imapx/camel-imapx-stream.c b/camel/providers/imapx/camel-imapx-stream.c deleted file mode 100644 index a7c8a039a..000000000 --- a/camel/providers/imapx/camel-imapx-stream.c +++ /dev/null @@ -1,839 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- - * - * Author: - * Michael Zucchi <notzed@ximian.com> - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU Lesser General Public - * License as published by the Free Software Foundation. - * - * 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 Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <string.h> -#include <stdio.h> -#include <ctype.h> -#include <errno.h> - -#include <glib/gi18n-lib.h> - -#include "camel-imapx-utils.h" -#include "camel-imapx-stream.h" - -#define t(...) camel_imapx_debug(token, __VA_ARGS__) -#define io(...) camel_imapx_debug(io, __VA_ARGS__) - -G_DEFINE_TYPE (CamelIMAPXStream, camel_imapx_stream, CAMEL_TYPE_STREAM) - -static gint -imapx_stream_fill (CamelIMAPXStream *is, - GCancellable *cancellable, - GError **error) -{ - gint left = 0; - - if (is->source) { - left = is->end - is->ptr; - memcpy (is->buf, is->ptr, left); - is->end = is->buf + left; - is->ptr = is->buf; - left = camel_stream_read ( - is->source, (gchar *) is->end, - is->bufsize - (is->end - is->buf), - cancellable, error); - if (left > 0) { - is->end += left; - io(is->tagprefix, "camel_imapx_read: buffer is '%.*s'\n", (gint)(is->end - is->ptr), is->ptr); - return is->end - is->ptr; - } else { - io(is->tagprefix, "camel_imapx_read: -1\n"); - /* If returning zero, camel_stream_read() doesn't consider - * that to be an error. But we do -- we should only be here - * if we *know* there are data to receive. So set the error - * accordingly */ - if (!left) - g_set_error (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("Source stream returned no data")); - return -1; - } - } - - io(is->tagprefix, "camel_imapx_read: -1\n"); - - g_set_error ( - error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, - _("Source stream unavailable")); - - return -1; -} - -static void -imapx_stream_dispose (GObject *object) -{ - CamelIMAPXStream *stream = CAMEL_IMAPX_STREAM (object); - - if (stream->source != NULL) { - g_object_unref (stream->source); - stream->source = NULL; - } - - /* Chain up to parent's dispose() method. */ - G_OBJECT_CLASS (camel_imapx_stream_parent_class)->dispose (object); -} - -static void -imapx_stream_finalize (GObject *object) -{ - CamelIMAPXStream *stream = CAMEL_IMAPX_STREAM (object); - - g_free (stream->buf); - g_free (stream->tokenbuf); - - /* Chain up to parent's finalize() method. */ - G_OBJECT_CLASS (camel_imapx_stream_parent_class)->finalize (object); -} - -static gssize -imapx_stream_read (CamelStream *stream, - gchar *buffer, - gsize n, - GCancellable *cancellable, - GError **error) -{ - CamelIMAPXStream *is = (CamelIMAPXStream *) stream; - gssize max; - - if (is->literal == 0 || n == 0) - return 0; - - max = is->end - is->ptr; - if (max > 0) { - max = MIN (max, is->literal); - max = MIN (max, n); - memcpy (buffer, is->ptr, max); - is->ptr += max; - } else { - max = MIN (is->literal, n); - max = camel_stream_read (is->source, buffer, max, cancellable, error); - if (max <= 0) - return max; - } - - io(is->tagprefix, "camel_imapx_read(literal): '%.*s'\n", (gint)max, buffer); - - is->literal -= max; - - return max; -} - -static gssize -imapx_stream_write (CamelStream *stream, - const gchar *buffer, - gsize n, - GCancellable *cancellable, - GError **error) -{ - CamelIMAPXStream *is = (CamelIMAPXStream *) stream; - - if (g_strstr_len (buffer, n, "LOGIN")) { - io(is->tagprefix, "camel_imapx_write: 'LOGIN...'\n"); - } else { - io(is->tagprefix, "camel_imapx_write: '%.*s'\n", (gint)n, buffer); - } - - return camel_stream_write (is->source, buffer, n, cancellable, error); -} - -static gint -imapx_stream_close (CamelStream *stream, - GCancellable *cancellable, - GError **error) -{ - /* nop? */ - return 0; -} - -static gint -imapx_stream_flush (CamelStream *stream, - GCancellable *cancellable, - GError **error) -{ - /* nop? */ - return 0; -} - -static gboolean -imapx_stream_eos (CamelStream *stream) -{ - CamelIMAPXStream *is = (CamelIMAPXStream *) stream; - - return is->literal == 0; -} - -static void -camel_imapx_stream_class_init (CamelIMAPXStreamClass *class) -{ - GObjectClass *object_class; - CamelStreamClass *stream_class; - - object_class = G_OBJECT_CLASS (class); - object_class->dispose = imapx_stream_dispose; - object_class->finalize = imapx_stream_finalize; - - stream_class = CAMEL_STREAM_CLASS (class); - stream_class->read = imapx_stream_read; - stream_class->write = imapx_stream_write; - stream_class->close = imapx_stream_close; - stream_class->flush = imapx_stream_flush; - stream_class->eos = imapx_stream_eos; -} - -static void -camel_imapx_stream_init (CamelIMAPXStream *is) -{ - /* +1 is room for appending a 0 if we need to for a token */ - is->bufsize = 4096; - is->ptr = is->end = is->buf = g_malloc (is->bufsize + 1); - is->tokenbuf = g_malloc (is->bufsize + 1); -} - -static void camel_imapx_stream_grow (CamelIMAPXStream *is, guint len, guchar **bufptr, guchar **tokptr) -{ - guchar *oldtok = is->tokenbuf; - guchar *oldbuf = is->buf; - - do { - is->bufsize <<= 1; - } while (is->bufsize <= len); - - io(is->tagprefix, "Grow imapx buffers to %d bytes\n", is->bufsize); - - is->tokenbuf = g_realloc (is->tokenbuf, is->bufsize + 1); - if (tokptr) - *tokptr = is->tokenbuf + (*tokptr - oldtok); - if (is->unget) - is->unget_token = is->tokenbuf + (is->unget_token - oldtok); - - //io(is->tagprefix, "buf was %p, ptr %p end %p\n", is->buf, is->ptr, is->end); - is->buf = g_realloc (is->buf, is->bufsize + 1); - is->ptr = is->buf + (is->ptr - oldbuf); - is->end = is->buf + (is->end - oldbuf); - //io(is->tagprefix, "buf now %p, ptr %p end %p\n", is->buf, is->ptr, is->end); - if (bufptr) - *bufptr = is->buf + (*bufptr - oldbuf); -} - -/** - * camel_imapx_stream_new: - * - * Returns a NULL stream. A null stream is always at eof, and - * always returns success for all reads and writes. - * - * Returns: the stream - **/ -CamelStream * -camel_imapx_stream_new (CamelStream *source) -{ - CamelIMAPXStream *is; - - is = g_object_new (CAMEL_TYPE_IMAPX_STREAM, NULL); - is->source = g_object_ref (source); - - return (CamelStream *) is; -} - -GQuark -camel_imapx_error_quark (void) -{ - static GQuark quark = 0; - - if (G_UNLIKELY (quark == 0)) { - const gchar *string = "camel-imapx-error-quark"; - quark = g_quark_from_static_string (string); - } - - return quark; -} - -/* Returns if there is any data buffered that is ready for processing */ -gint -camel_imapx_stream_buffered (CamelIMAPXStream *is) -{ - return is->end - is->ptr; -} - -#if 0 - -static gint -skip_ws (CamelIMAPXStream *is, - guchar *pp, - guchar *pe) -{ - register guchar c, *p; - guchar *e; - - p = is->ptr; - e = is->end; - - do { - while (p >= e ) { - is->ptr = p; - if (imapx_stream_fill (is, NULL) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - c = *p++; - } while (c == ' ' || c == '\r'); - - is->ptr = p; - is->end = e; - - return c; -} -#endif - -/* FIXME: these should probably handle it themselves, - * and get rid of the token interface? */ -gint -camel_imapx_stream_atom (CamelIMAPXStream *is, - guchar **data, - guint *lenp, - GCancellable *cancellable, - GError **error) -{ - guchar *p, c; - GError *local_error = NULL; - - /* this is only 'approximate' atom */ - switch (camel_imapx_stream_token (is, data, lenp, cancellable, &local_error)) { - case IMAPX_TOK_TOKEN: - p = *data; - while ((c = *p)) - *p++ = toupper(c); - case IMAPX_TOK_INT: - return 0; - case IMAPX_TOK_ERROR: - if (local_error != NULL) - g_propagate_error (error, local_error); - return IMAPX_TOK_ERROR; - default: - if (local_error == NULL) - g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting atom"); - else - g_propagate_error (error, local_error); - io(is->tagprefix, "expecting atom!\n"); - return IMAPX_TOK_PROTOCOL; - } -} - -/* gets an atom, a quoted_string, or a literal */ -gint -camel_imapx_stream_astring (CamelIMAPXStream *is, - guchar **data, - GCancellable *cancellable, - GError **error) -{ - guchar *p, *start; - guint len, inlen; - gint ret; - GError *local_error = NULL; - - switch (camel_imapx_stream_token (is, data, &len, cancellable, &local_error)) { - case IMAPX_TOK_TOKEN: - case IMAPX_TOK_INT: - case IMAPX_TOK_STRING: - return 0; - case IMAPX_TOK_LITERAL: - if (len >= is->bufsize) - camel_imapx_stream_grow (is, len, NULL, NULL); - p = is->tokenbuf; - camel_imapx_stream_set_literal (is, len); - do { - ret = camel_imapx_stream_getl (is, &start, &inlen, cancellable, error); - if (ret < 0) - return ret; - memcpy (p, start, inlen); - p += inlen; - } while (ret > 0); - *p = 0; - *data = is->tokenbuf; - return 0; - case IMAPX_TOK_ERROR: - /* wont get unless no exception hanlder*/ - if (local_error != NULL) - g_propagate_error (error, local_error); - return IMAPX_TOK_ERROR; - default: - if (local_error == NULL) - g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting astring"); - else - g_propagate_error (error, local_error); - io(is->tagprefix, "expecting astring!\n"); - return IMAPX_TOK_PROTOCOL; - } -} - -/* check for NIL or (small) quoted_string or literal */ -gint -camel_imapx_stream_nstring (CamelIMAPXStream *is, - guchar **data, - GCancellable *cancellable, - GError **error) -{ - guchar *p, *start; - guint len, inlen; - gint ret; - GError *local_error = NULL; - - switch (camel_imapx_stream_token (is, data, &len, cancellable, &local_error)) { - case IMAPX_TOK_STRING: - return 0; - case IMAPX_TOK_LITERAL: - if (len >= is->bufsize) - camel_imapx_stream_grow (is, len, NULL, NULL); - p = is->tokenbuf; - camel_imapx_stream_set_literal (is, len); - do { - ret = camel_imapx_stream_getl (is, &start, &inlen, cancellable, error); - if (ret < 0) - return ret; - memcpy (p, start, inlen); - p += inlen; - } while (ret > 0); - *p = 0; - *data = is->tokenbuf; - return 0; - case IMAPX_TOK_TOKEN: - p = *data; - if (toupper (p[0]) == 'N' && toupper (p[1]) == 'I' && toupper (p[2]) == 'L' && p[3] == 0) { - *data = NULL; - return 0; - } - default: - if (local_error == NULL) - g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting nstring"); - else - g_propagate_error (error, local_error); - return IMAPX_TOK_PROTOCOL; - case IMAPX_TOK_ERROR: - /* we'll never get this unless there are no exception handlers anyway */ - if (local_error != NULL) - g_propagate_error (error, local_error); - return IMAPX_TOK_ERROR; - - } -} - -/* parse an nstring as a stream */ -gint -camel_imapx_stream_nstring_stream (CamelIMAPXStream *is, - CamelStream **stream, - GCancellable *cancellable, - GError **error) -/* throws IO,PARSE exception */ -{ - guchar *token; - guint len; - gint ret = 0; - CamelStream * mem = NULL; - GError *local_error = NULL; - - *stream = NULL; - - switch (camel_imapx_stream_token (is, &token, &len, cancellable, &local_error)) { - case IMAPX_TOK_STRING: - mem = camel_stream_mem_new_with_buffer ((gchar *) token, len); - *stream = mem; - break; - case IMAPX_TOK_LITERAL: - /* if len is big, we could automatically use a file backing */ - camel_imapx_stream_set_literal (is, len); - mem = camel_stream_mem_new (); - if (camel_stream_write_to_stream ((CamelStream *) is, mem, cancellable, error) == -1) { - g_object_unref (mem); - ret = -1; - break; - } - - g_seekable_seek ( - G_SEEKABLE (mem), 0, - G_SEEK_SET, NULL, NULL); - - *stream = mem; - break; - case IMAPX_TOK_TOKEN: - if (toupper (token[0]) == 'N' && toupper (token[1]) == 'I' && toupper (token[2]) == 'L' && token[3] == 0) { - *stream = NULL; - break; - } - default: - ret = -1; - if (local_error == NULL) - g_set_error (error, CAMEL_IMAPX_ERROR, 1, "nstring: token not string"); - else - g_propagate_error (error, local_error); - } - - return ret; -} - -guint64 -camel_imapx_stream_number (CamelIMAPXStream *is, - GCancellable *cancellable, - GError **error) -{ - guchar *token; - guint len; - GError *local_error = NULL; - - if (camel_imapx_stream_token (is, &token, &len, cancellable, &local_error) != IMAPX_TOK_INT) { - if (local_error == NULL) - g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting number"); - else - g_propagate_error (error, local_error); - return 0; - } - - return strtoull ((gchar *) token, 0, 10); -} - -gint -camel_imapx_stream_text (CamelIMAPXStream *is, - guchar **text, - GCancellable *cancellable, - GError **error) -{ - GByteArray *build = g_byte_array_new (); - guchar *token; - guint len; - gint tok; - - while (is->unget > 0) { - switch (is->unget_tok) { - case IMAPX_TOK_TOKEN: - case IMAPX_TOK_STRING: - case IMAPX_TOK_INT: - g_byte_array_append (build, (guint8 *) is->unget_token, is->unget_len); - g_byte_array_append(build, (guint8 *) " ", 1); - default: /* invalid, but we'll ignore */ - break; - } - is->unget--; - } - - do { - tok = camel_imapx_stream_gets (is, &token, &len, cancellable, error); - if (tok < 0) { - *text = NULL; - g_byte_array_free (build, TRUE); - return -1; - } - if (len) - g_byte_array_append (build, token, len); - } while (tok > 0); - - g_byte_array_append(build, (guint8 *) "", 1); - *text = build->data; - g_byte_array_free (build, FALSE); - - return 0; -} - -/* Get one token from the imap stream */ -camel_imapx_token_t -/* throws IO,PARSE exception */ -camel_imapx_stream_token (CamelIMAPXStream *is, - guchar **data, - guint *len, - GCancellable *cancellable, - GError **error) -{ - register guchar c, *oe; - guchar *o, *p, *e; - guint literal; - gint digits; - - if (is->unget > 0) { - is->unget--; - *data = is->unget_token; - *len = is->unget_len; - /*printf("token UNGET '%c' %s\n", is->unget_tok, is->unget_token);*/ - return is->unget_tok; - } - - if (is->literal > 0) - g_warning("stream_token called with literal %d", is->literal); - - p = is->ptr; - e = is->end; - - /* skip whitespace/prefill buffer */ - do { - while (p >= e ) { - is->ptr = p; - if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - c = *p++; - } while (c == ' ' || c == '\r'); - - /*strchr("\n*()[]+", c)*/ - if (imapx_is_token_char (c)) { - is->ptr = p; - t(is->tagprefix, "token '%c'\n", c); - return c; - } else if (c == '{') { - literal = 0; - *data = p; - while (1) { - while (p < e) { - c = *p++; - if (isdigit (c) && literal < (UINT_MAX / 10)) { - literal = literal * 10 + (c - '0'); - } else if (c == '}') { - while (1) { - while (p < e) { - c = *p++; - if (c == '\n') { - *len = literal; - is->ptr = p; - is->literal = literal; - t(is->tagprefix, "token LITERAL %d\n", literal); - return IMAPX_TOK_LITERAL; - } - } - is->ptr = p; - if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - } else { - if (isdigit (c)) { - io(is->tagprefix, "Protocol error: literal too big\n"); - } else { - io(is->tagprefix, "Protocol error: literal contains invalid gchar %02x '%c'\n", c, isprint(c)?c:c); - } - goto protocol_error; - } - } - is->ptr = p; - if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - } else if (c == '"') { - o = is->tokenbuf; - oe = is->tokenbuf + is->bufsize - 1; - while (1) { - while (p < e) { - c = *p++; - if (c == '\\') { - while (p >= e) { - is->ptr = p; - if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - c = *p++; - } else if (c == '\"') { - is->ptr = p; - *o = 0; - *data = is->tokenbuf; - *len = o - is->tokenbuf; - t(is->tagprefix, "token STRING '%s'\n", is->tokenbuf); - return IMAPX_TOK_STRING; - } - if (c == '\n' || c == '\r') { - io(is->tagprefix, "Protocol error: truncated string\n"); - goto protocol_error; - } - if (o >= oe) { - camel_imapx_stream_grow (is, 0, &p, &o); - oe = is->tokenbuf + is->bufsize - 1; - e = is->end; - } - *o++ = c; - } - is->ptr = p; - if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - } else { - o = is->tokenbuf; - oe = is->tokenbuf + is->bufsize - 1; - digits = isdigit (c); - *o++ = c; - while (1) { - while (p < e) { - c = *p++; - /*if (strchr(" \r\n*()[]+", c) != NULL) {*/ - if (imapx_is_notid_char (c)) { - if (c == ' ' || c == '\r') - is->ptr = p; - else - is->ptr = p - 1; - *o = 0; - *data = is->tokenbuf; - *len = o - is->tokenbuf; - t(is->tagprefix, "token TOKEN '%s'\n", is->tokenbuf); - return digits ? IMAPX_TOK_INT : IMAPX_TOK_TOKEN; - } - - if (o >= oe) { - camel_imapx_stream_grow (is, 0, &p, &o); - oe = is->tokenbuf + is->bufsize - 1; - e = is->end; - } - digits &= isdigit (c); - *o++ = c; - } - is->ptr = p; - if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR) - return IMAPX_TOK_ERROR; - p = is->ptr; - e = is->end; - } - } - - /* Protocol error, skip until next lf? */ -protocol_error: - io(is->tagprefix, "Got protocol error\n"); - - if (c == '\n') - is->ptr = p - 1; - else - is->ptr = p; - - g_set_error (error, CAMEL_IMAPX_ERROR, 1, "protocol error"); - return IMAPX_TOK_PROTOCOL; -} - -void -camel_imapx_stream_ungettoken (CamelIMAPXStream *is, - camel_imapx_token_t tok, - guchar *token, - guint len) -{ - /*printf("ungettoken: '%c' '%s'\n", tok, token);*/ - is->unget_tok = tok; - is->unget_token = token; - is->unget_len = len; - is->unget++; -} - -/* returns -1 on error, 0 if last lot of data, >0 if more remaining */ -gint -camel_imapx_stream_gets (CamelIMAPXStream *is, - guchar **start, - guint *len, - GCancellable *cancellable, - GError **error) -{ - gint max; - guchar *end; - - *len = 0; - - max = is->end - is->ptr; - if (max == 0) { - max = imapx_stream_fill (is, cancellable, error); - if (max <= 0) - return max; - } - - *start = is->ptr; - end = memchr (is->ptr, '\n', max); - if (end) - max = (end - is->ptr) + 1; - *start = is->ptr; - *len = max; - is->ptr += max; - - return end == NULL ? 1 : 0; -} - -void camel_imapx_stream_set_literal (CamelIMAPXStream *is, guint literal) -{ - is->literal = literal; -} - -/* returns -1 on erorr, 0 if last data, >0 if more data left */ -gint -camel_imapx_stream_getl (CamelIMAPXStream *is, - guchar **start, - guint *len, - GCancellable *cancellable, - GError **error) -{ - gint max; - - *len = 0; - - if (is->literal > 0) { - max = is->end - is->ptr; - if (max == 0) { - max = imapx_stream_fill (is, cancellable, error); - if (max <= 0) - return max; - } - - max = MIN (max, is->literal); - *start = is->ptr; - *len = max; - is->ptr += max; - is->literal -= max; - } - - if (is->literal > 0) - return 1; - - return 0; -} - -/* skip the rest of the line of tokens */ -gint -camel_imapx_stream_skip (CamelIMAPXStream *is, - GCancellable *cancellable, - GError **error) -{ - gint tok; - guchar *token; - guint len; - - do { - tok = camel_imapx_stream_token (is, &token, &len, cancellable, error); - if (tok == IMAPX_TOK_LITERAL) { - camel_imapx_stream_set_literal (is, len); - while ((tok = camel_imapx_stream_getl (is, &token, &len, cancellable, error)) > 0) { - io(is->tagprefix, "Skip literal data '%.*s'\n", (gint)len, token); - } - } - } while (tok != '\n' && tok >= 0); - - if (tok < 0) - return -1; - - return 0; -} |