1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*- */
2 /* camel-stream.c : abstract class for a stream
3  *
4  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5  *
6  * This library is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Authors: Michael Zucchi <notzed@ximian.com>
19  */
20 
21 #include "evolution-data-server-config.h"
22 
23 #include <glib/gi18n-lib.h>
24 
25 #include "camel-stream-null.h"
26 
27 struct _CamelStreamNullPrivate {
28 	gsize written;
29 	gboolean ends_with_crlf;
30 	gboolean ends_with_cr; /* Just for cases when the CRLF is split into two writes, CR and LF */
31 };
32 
33 static void camel_stream_null_seekable_init (GSeekableIface *iface);
34 
G_DEFINE_TYPE_WITH_CODE(CamelStreamNull,camel_stream_null,CAMEL_TYPE_STREAM,G_ADD_PRIVATE (CamelStreamNull)G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE,camel_stream_null_seekable_init))35 G_DEFINE_TYPE_WITH_CODE (CamelStreamNull, camel_stream_null, CAMEL_TYPE_STREAM,
36 	G_ADD_PRIVATE (CamelStreamNull)
37 	G_IMPLEMENT_INTERFACE (G_TYPE_SEEKABLE, camel_stream_null_seekable_init))
38 
39 static gssize
40 stream_null_write (CamelStream *stream,
41                    const gchar *buffer,
42                    gsize n,
43                    GCancellable *cancellable,
44                    GError **error)
45 {
46 	CamelStreamNull *stream_null = CAMEL_STREAM_NULL (stream);
47 
48 	stream_null->priv->written += n;
49 
50 	if (n >= 2) {
51 		stream_null->priv->ends_with_crlf = buffer[n - 2] == '\r' && buffer[n - 1] == '\n';
52 		stream_null->priv->ends_with_cr = buffer[n - 1] == '\r';
53 	} else if (n == 1) {
54 		stream_null->priv->ends_with_crlf = stream_null->priv->ends_with_cr && buffer[n - 1] == '\n';
55 		stream_null->priv->ends_with_cr = buffer[n - 1] == '\r';
56 	}
57 
58 	return n;
59 }
60 
61 static gboolean
stream_null_eos(CamelStream * stream)62 stream_null_eos (CamelStream *stream)
63 {
64 	return TRUE;
65 }
66 
67 static goffset
stream_null_tell(GSeekable * seekable)68 stream_null_tell (GSeekable *seekable)
69 {
70 	return 0;
71 }
72 
73 static gboolean
stream_null_can_seek(GSeekable * seekable)74 stream_null_can_seek (GSeekable *seekable)
75 {
76 	return TRUE;
77 }
78 
79 static gboolean
stream_null_seek(GSeekable * seekable,goffset offset,GSeekType type,GCancellable * cancellable,GError ** error)80 stream_null_seek (GSeekable *seekable,
81                   goffset offset,
82                   GSeekType type,
83                   GCancellable *cancellable,
84                   GError **error)
85 {
86 	if (type != G_SEEK_SET || offset != 0) {
87 		g_set_error_literal (
88 			error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
89 			_("Only reset to beginning is supported with CamelHttpStream"));
90 		return FALSE;
91 	}
92 
93 	CAMEL_STREAM_NULL (seekable)->priv->written = 0;
94 
95 	return TRUE;
96 }
97 
98 static gboolean
stream_null_can_truncate(GSeekable * seekable)99 stream_null_can_truncate (GSeekable *seekable)
100 {
101 	return FALSE;
102 }
103 
104 static gboolean
stream_null_truncate_fn(GSeekable * seekable,goffset offset,GCancellable * cancellable,GError ** error)105 stream_null_truncate_fn (GSeekable *seekable,
106                          goffset offset,
107                          GCancellable *cancellable,
108                          GError **error)
109 {
110 	/* XXX Don't bother translating this.  Camel never calls it. */
111 	g_set_error_literal (
112 		error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
113 		"Truncation is not supported");
114 
115 	return FALSE;
116 }
117 
118 static void
camel_stream_null_class_init(CamelStreamNullClass * class)119 camel_stream_null_class_init (CamelStreamNullClass *class)
120 {
121 	CamelStreamClass *stream_class;
122 
123 	stream_class = CAMEL_STREAM_CLASS (class);
124 	stream_class->write = stream_null_write;
125 	stream_class->eos = stream_null_eos;
126 }
127 
128 static void
camel_stream_null_seekable_init(GSeekableIface * iface)129 camel_stream_null_seekable_init (GSeekableIface *iface)
130 {
131 	iface->tell = stream_null_tell;
132 	iface->can_seek = stream_null_can_seek;
133 	iface->seek = stream_null_seek;
134 	iface->can_truncate = stream_null_can_truncate;
135 	iface->truncate_fn = stream_null_truncate_fn;
136 }
137 
138 static void
camel_stream_null_init(CamelStreamNull * stream_null)139 camel_stream_null_init (CamelStreamNull *stream_null)
140 {
141 	stream_null->priv = camel_stream_null_get_instance_private (stream_null);
142 	stream_null->priv->ends_with_crlf = FALSE;
143 	stream_null->priv->ends_with_cr = FALSE;
144 }
145 
146 /**
147  * camel_stream_null_new:
148  *
149  * Returns a null stream.  A null stream is always at eof, and
150  * always returns success for all reads and writes.
151  *
152  * Returns: (transfer full): a new #CamelStreamNull
153  **/
154 CamelStream *
camel_stream_null_new(void)155 camel_stream_null_new (void)
156 {
157 	return g_object_new (CAMEL_TYPE_STREAM_NULL, NULL);
158 }
159 
160 /**
161  * camel_stream_null_get_bytes_written:
162  * @stream_null: a #CamelStreamNull
163  *
164  * Returns: how many bytes had been written to the @stream_null since
165  *   it was created or rewind to the beginning.
166  *
167  * Since: 3.24
168  **/
169 gsize
camel_stream_null_get_bytes_written(CamelStreamNull * stream_null)170 camel_stream_null_get_bytes_written (CamelStreamNull *stream_null)
171 {
172 	g_return_val_if_fail (CAMEL_IS_STREAM_NULL (stream_null), -1);
173 
174 	return stream_null->priv->written;
175 }
176 
177 /**
178  * camel_stream_null_get_ends_with_crlf:
179  * @stream_null: a #CamelStreamNull
180  *
181  * Returns: Whether the data being written to @stream_null ended with CRLF.
182  *
183  * Since: 3.30
184  **/
185 gboolean
camel_stream_null_get_ends_with_crlf(CamelStreamNull * stream_null)186 camel_stream_null_get_ends_with_crlf (CamelStreamNull *stream_null)
187 {
188 	g_return_val_if_fail (CAMEL_IS_STREAM_NULL (stream_null), FALSE);
189 
190 	return stream_null->priv->ends_with_crlf;
191 }
192