[evolution-data-server] I#13 - [IMAPx] Fails to append message to Yahoo! with no CRLF at the end
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] I#13 - [IMAPx] Fails to append message to Yahoo! with no CRLF at the end
- Date: Wed, 27 Jun 2018 15:22:00 +0000 (UTC)
commit a873c67b39b844dcaa719a1d2a3d026224165ad8
Author: Milan Crha <mcrha redhat com>
Date: Wed Jun 27 17:24:01 2018 +0200
I#13 - [IMAPx] Fails to append message to Yahoo! with no CRLF at the end
Closes https://gitlab.gnome.org/GNOME/evolution-data-server/issues/13
src/camel/camel-null-output-stream.c | 28 +++++++++++++++++++
src/camel/camel-null-output-stream.h | 2 ++
src/camel/camel-stream-null.c | 32 +++++++++++++++++++++-
src/camel/camel-stream-null.h | 2 ++
src/camel/providers/imapx/camel-imapx-command.c | 36 ++++++++++++++++++++++++-
src/camel/providers/imapx/camel-imapx-command.h | 1 +
src/camel/providers/imapx/camel-imapx-server.c | 9 +++++++
7 files changed, 108 insertions(+), 2 deletions(-)
---
diff --git a/src/camel/camel-null-output-stream.c b/src/camel/camel-null-output-stream.c
index aff36a310..37b034c1b 100644
--- a/src/camel/camel-null-output-stream.c
+++ b/src/camel/camel-null-output-stream.c
@@ -35,6 +35,8 @@
struct _CamelNullOutputStreamPrivate {
gsize bytes_written;
+ gboolean ends_with_crlf;
+ gboolean ends_with_cr; /* Just for cases when the CRLF is split into two writes, CR and LF */
};
G_DEFINE_TYPE (
@@ -50,11 +52,20 @@ null_output_stream_write (GOutputStream *stream,
GError **error)
{
CamelNullOutputStreamPrivate *priv;
+ const guchar *data = buffer;
priv = CAMEL_NULL_OUTPUT_STREAM_GET_PRIVATE (stream);
priv->bytes_written += count;
+ if (count >= 2) {
+ priv->ends_with_crlf = data[count - 2] == '\r' && data[count - 1] == '\n';
+ priv->ends_with_cr = data[count - 1] == '\r';
+ } else if (count == 1) {
+ priv->ends_with_crlf = priv->ends_with_cr && data[count - 1] == '\n';
+ priv->ends_with_cr = data[count - 1] == '\r';
+ }
+
return count;
}
@@ -74,6 +85,8 @@ static void
camel_null_output_stream_init (CamelNullOutputStream *null_stream)
{
null_stream->priv = CAMEL_NULL_OUTPUT_STREAM_GET_PRIVATE (null_stream);
+ null_stream->priv->ends_with_crlf = FALSE;
+ null_stream->priv->ends_with_cr = FALSE;
}
/**
@@ -109,3 +122,18 @@ camel_null_output_stream_get_bytes_written (CamelNullOutputStream *null_stream)
return null_stream->priv->bytes_written;
}
+/**
+ * camel_null_output_stream_get_ends_with_crlf:
+ * @null_stream: a #CamelNullOutputStream
+ *
+ * Returns: Whether the data being written to @null_stream ended with CRLF.
+ *
+ * Since: 3.30
+ **/
+gboolean
+camel_null_output_stream_get_ends_with_crlf (CamelNullOutputStream *null_stream)
+{
+ g_return_val_if_fail (CAMEL_IS_NULL_OUTPUT_STREAM (null_stream), FALSE);
+
+ return null_stream->priv->ends_with_crlf;
+}
diff --git a/src/camel/camel-null-output-stream.h b/src/camel/camel-null-output-stream.h
index 978763db9..99b44ab18 100644
--- a/src/camel/camel-null-output-stream.h
+++ b/src/camel/camel-null-output-stream.h
@@ -67,6 +67,8 @@ GOutputStream * camel_null_output_stream_new
(void);
gsize camel_null_output_stream_get_bytes_written
(CamelNullOutputStream *null_stream);
+gboolean camel_null_output_stream_get_ends_with_crlf
+ (CamelNullOutputStream *null_stream);
G_END_DECLS
diff --git a/src/camel/camel-stream-null.c b/src/camel/camel-stream-null.c
index 72aa6176c..c02574bc5 100644
--- a/src/camel/camel-stream-null.c
+++ b/src/camel/camel-stream-null.c
@@ -26,6 +26,8 @@
struct _CamelStreamNullPrivate {
gsize written;
+ gboolean ends_with_crlf;
+ gboolean ends_with_cr; /* Just for cases when the CRLF is split into two writes, CR and LF */
};
static void camel_stream_null_seekable_init (GSeekableIface *iface);
@@ -40,7 +42,17 @@ stream_null_write (CamelStream *stream,
GCancellable *cancellable,
GError **error)
{
- CAMEL_STREAM_NULL (stream)->priv->written += n;
+ CamelStreamNull *stream_null = CAMEL_STREAM_NULL (stream);
+
+ stream_null->priv->written += n;
+
+ if (n >= 2) {
+ stream_null->priv->ends_with_crlf = buffer[n - 2] == '\r' && buffer[n - 1] == '\n';
+ stream_null->priv->ends_with_cr = buffer[n - 1] == '\r';
+ } else if (n == 1) {
+ stream_null->priv->ends_with_crlf = stream_null->priv->ends_with_cr && buffer[n - 1] == '\n';
+ stream_null->priv->ends_with_cr = buffer[n - 1] == '\r';
+ }
return n;
}
@@ -128,6 +140,8 @@ static void
camel_stream_null_init (CamelStreamNull *stream_null)
{
stream_null->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream_null, CAMEL_TYPE_STREAM_NULL,
CamelStreamNullPrivate);
+ stream_null->priv->ends_with_crlf = FALSE;
+ stream_null->priv->ends_with_cr = FALSE;
}
/**
@@ -160,3 +174,19 @@ camel_stream_null_get_bytes_written (CamelStreamNull *stream_null)
return stream_null->priv->written;
}
+
+/**
+ * camel_stream_null_get_ends_with_crlf:
+ * @stream_null: a #CamelStreamNull
+ *
+ * Returns: Whether the data being written to @stream_null ended with CRLF.
+ *
+ * Since: 3.30
+ **/
+gboolean
+camel_stream_null_get_ends_with_crlf (CamelStreamNull *stream_null)
+{
+ g_return_val_if_fail (CAMEL_IS_STREAM_NULL (stream_null), FALSE);
+
+ return stream_null->priv->ends_with_crlf;
+}
diff --git a/src/camel/camel-stream-null.h b/src/camel/camel-stream-null.h
index 51b3da5a1..f7fc1b4cf 100644
--- a/src/camel/camel-stream-null.h
+++ b/src/camel/camel-stream-null.h
@@ -68,6 +68,8 @@ GType camel_stream_null_get_type (void);
CamelStream * camel_stream_null_new (void);
gsize camel_stream_null_get_bytes_written
(CamelStreamNull *stream_null);
+gboolean camel_stream_null_get_ends_with_crlf
+ (CamelStreamNull *stream_null);
G_END_DECLS
diff --git a/src/camel/providers/imapx/camel-imapx-command.c b/src/camel/providers/imapx/camel-imapx-command.c
index 5ef56a54f..dffa8f017 100644
--- a/src/camel/providers/imapx/camel-imapx-command.c
+++ b/src/camel/providers/imapx/camel-imapx-command.c
@@ -371,6 +371,30 @@ camel_imapx_command_addv (CamelIMAPXCommand *ic,
g_string_append_len (buffer, ps, p - ps - 1);
}
+static gboolean
+imapx_file_ends_with_crlf (const gchar *filename)
+{
+ CamelStream *null_stream, *input_stream;
+ gboolean ends_with_crlf;
+
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ input_stream = camel_stream_fs_new_with_name (filename, O_RDONLY, 0, NULL);
+ if (!input_stream)
+ return FALSE;
+
+ null_stream = camel_stream_null_new ();
+ camel_stream_write_to_stream (input_stream, null_stream, NULL, NULL);
+ camel_stream_flush (input_stream, NULL, NULL);
+ g_object_unref (input_stream);
+
+ ends_with_crlf = camel_stream_null_get_ends_with_crlf (CAMEL_STREAM_NULL (null_stream));
+
+ g_object_unref (null_stream);
+
+ return ends_with_crlf;
+}
+
void
camel_imapx_command_add_part (CamelIMAPXCommand *ic,
CamelIMAPXCommandPartType type,
@@ -379,6 +403,7 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
CamelIMAPXCommandPart *cp;
GString *buffer;
guint ob_size = 0;
+ gboolean ends_with_crlf = TRUE;
buffer = ((CamelIMAPXRealCommand *) ic)->buffer;
@@ -396,6 +421,7 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
g_object_ref (ob);
ob_size = camel_null_output_stream_get_bytes_written (
CAMEL_NULL_OUTPUT_STREAM (stream));
+ ends_with_crlf = camel_null_output_stream_get_ends_with_crlf (CAMEL_NULL_OUTPUT_STREAM
(stream));
g_object_unref (stream);
break;
}
@@ -420,6 +446,8 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
if (g_stat (path, &st) == 0) {
data = g_strdup (data);
ob_size = st.st_size;
+
+ ends_with_crlf = imapx_file_ends_with_crlf (data);
} else
data = NULL;
@@ -436,8 +464,13 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
}
if (type & CAMEL_IMAPX_COMMAND_LITERAL_PLUS) {
+ guint total_size = ob_size;
+
+ if (ic->job_kind == CAMEL_IMAPX_JOB_APPEND_MESSAGE && !ends_with_crlf)
+ total_size += 2;
+
g_string_append_c (buffer, '{');
- g_string_append_printf (buffer, "%u", ob_size);
+ g_string_append_printf (buffer, "%u", total_size);
if (camel_imapx_server_have_capability (ic->is, IMAPX_CAPABILITY_LITERALPLUS)) {
g_string_append_c (buffer, '+');
} else {
@@ -453,6 +486,7 @@ camel_imapx_command_add_part (CamelIMAPXCommand *ic,
cp->ob = data;
cp->data_size = buffer->len;
cp->data = g_strdup (buffer->str);
+ cp->ends_with_crlf = ends_with_crlf;
g_string_set_size (buffer, 0);
diff --git a/src/camel/providers/imapx/camel-imapx-command.h b/src/camel/providers/imapx/camel-imapx-command.h
index 1300c2531..b81a2a1f1 100644
--- a/src/camel/providers/imapx/camel-imapx-command.h
+++ b/src/camel/providers/imapx/camel-imapx-command.h
@@ -58,6 +58,7 @@ struct _CamelIMAPXCommandPart {
gint ob_size;
gpointer ob;
+ gboolean ends_with_crlf;
};
struct _CamelIMAPXCommand {
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index d4e250bba..af3d6147e 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -2289,6 +2289,15 @@ imapx_continuation (CamelIMAPXServer *is,
return FALSE;
}
+ if (ic->job_kind == CAMEL_IMAPX_JOB_APPEND_MESSAGE && !cp->ends_with_crlf) {
+ g_mutex_lock (&is->priv->stream_lock);
+ n_bytes_written = g_output_stream_write_all (
+ output_stream, "\r\n", 2, NULL, cancellable, error);
+ g_mutex_unlock (&is->priv->stream_lock);
+ if (n_bytes_written < 0)
+ return FALSE;
+ }
+
if (!litplus) {
success = camel_imapx_input_stream_skip (
CAMEL_IMAPX_INPUT_STREAM (input_stream),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]