2 * camel-imapx-input-stream.h
4 * This library is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library. If not, see <http://www.gnu.org/licenses/>.
18 #include "evolution-data-server-config.h"
25 #include <glib/gi18n-lib.h>
27 #include <camel/camel.h>
29 #include "camel-imapx-server.h"
30 #include "camel-imapx-utils.h"
32 #include "camel-imapx-input-stream.h"
34 #define CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE(obj) \
35 (G_TYPE_INSTANCE_GET_PRIVATE \
36 ((obj), CAMEL_TYPE_IMAPX_INPUT_STREAM, CamelIMAPXInputStreamPrivate))
38 struct _CamelIMAPXInputStreamPrivate
{
39 guchar
*buf
, *ptr
, *end
;
43 camel_imapx_token_t unget_tok
;
51 /* Forward Declarations */
52 static void camel_imapx_input_stream_pollable_init
53 (GPollableInputStreamInterface
*iface
);
55 G_DEFINE_TYPE_WITH_CODE (
56 CamelIMAPXInputStream
,
57 camel_imapx_input_stream
,
58 G_TYPE_FILTER_INPUT_STREAM
,
59 G_IMPLEMENT_INTERFACE (
60 G_TYPE_POLLABLE_INPUT_STREAM
,
61 camel_imapx_input_stream_pollable_init
))
64 imapx_input_stream_fill (CamelIMAPXInputStream
*is
,
65 GCancellable
*cancellable
,
68 GInputStream
*base_stream
;
71 if (g_cancellable_is_cancelled (cancellable
))
74 base_stream
= g_filter_input_stream_get_base_stream (
75 G_FILTER_INPUT_STREAM (is
));
77 if (error
&& *error
) {
78 g_warning ("%s: Avoiding GIO call with a filled error '%s'", G_STRFUNC
, (*error
)->message
);
82 left
= is
->priv
->end
- is
->priv
->ptr
;
83 memcpy (is
->priv
->buf
, is
->priv
->ptr
, left
);
84 is
->priv
->end
= is
->priv
->buf
+ left
;
85 is
->priv
->ptr
= is
->priv
->buf
;
86 left
= g_input_stream_read (
89 is
->priv
->bufsize
- (is
->priv
->end
- is
->priv
->buf
),
92 is
->priv
->end
+= left
;
93 return is
->priv
->end
- is
->priv
->ptr
;
95 /* If returning zero, camel_stream_read() doesn't consider
96 * that to be an error. But we do -- we should only be here
97 * if we *know* there are data to receive. So set the error
101 error
, CAMEL_IMAPX_SERVER_ERROR
, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT
,
102 _("Source stream returned no data"));
108 imapx_input_stream_finalize (GObject
*object
)
110 CamelIMAPXInputStreamPrivate
*priv
;
112 priv
= CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE (object
);
115 g_free (priv
->tokenbuf
);
117 /* Chain up to parent's finalize() method. */
118 G_OBJECT_CLASS (camel_imapx_input_stream_parent_class
)->
123 imapx_input_stream_read (GInputStream
*stream
,
126 GCancellable
*cancellable
,
129 CamelIMAPXInputStreamPrivate
*priv
;
130 GInputStream
*base_stream
;
133 priv
= CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE (stream
);
135 base_stream
= g_filter_input_stream_get_base_stream (
136 G_FILTER_INPUT_STREAM (stream
));
138 if (priv
->literal
== 0 || count
== 0)
141 max
= priv
->end
- priv
->ptr
;
143 max
= MIN (max
, priv
->literal
);
144 max
= MIN (max
, count
);
145 memcpy (buffer
, priv
->ptr
, max
);
148 if (error
&& *error
) {
149 g_warning ("%s: Avoiding GIO call with a filled error '%s'", G_STRFUNC
, (*error
)->message
);
153 max
= MIN (priv
->literal
, count
);
154 max
= g_input_stream_read (
155 base_stream
, buffer
, max
, cancellable
, error
);
160 priv
->literal
-= max
;
166 imapx_input_stream_can_poll (GPollableInputStream
*pollable_stream
)
168 GInputStream
*base_stream
;
170 base_stream
= g_filter_input_stream_get_base_stream (
171 G_FILTER_INPUT_STREAM (pollable_stream
));
173 pollable_stream
= G_POLLABLE_INPUT_STREAM (base_stream
);
175 return g_pollable_input_stream_can_poll (pollable_stream
);
179 imapx_input_stream_is_readable (GPollableInputStream
*pollable_stream
)
181 GInputStream
*base_stream
;
183 base_stream
= g_filter_input_stream_get_base_stream (
184 G_FILTER_INPUT_STREAM (pollable_stream
));
186 pollable_stream
= G_POLLABLE_INPUT_STREAM (base_stream
);
188 return g_pollable_input_stream_is_readable (pollable_stream
);
192 imapx_input_stream_create_source (GPollableInputStream
*pollable_stream
,
193 GCancellable
*cancellable
)
195 GInputStream
*base_stream
;
197 base_stream
= g_filter_input_stream_get_base_stream (
198 G_FILTER_INPUT_STREAM (pollable_stream
));
200 pollable_stream
= G_POLLABLE_INPUT_STREAM (base_stream
);
202 return g_pollable_input_stream_create_source (
203 pollable_stream
, cancellable
);
207 imapx_input_stream_read_nonblocking (GPollableInputStream
*pollable_stream
,
212 GInputStream
*base_stream
;
214 base_stream
= g_filter_input_stream_get_base_stream (
215 G_FILTER_INPUT_STREAM (pollable_stream
));
217 pollable_stream
= G_POLLABLE_INPUT_STREAM (base_stream
);
219 if (error
&& *error
) {
220 g_warning ("%s: Avoiding GIO call with a filled error '%s'", G_STRFUNC
, (*error
)->message
);
224 /* XXX The function takes a GCancellable but the class method
225 * does not. Should be okay to pass NULL here since this
226 * is just a pass-through. */
227 return g_pollable_input_stream_read_nonblocking (
228 pollable_stream
, buffer
, count
, NULL
, error
);
232 camel_imapx_input_stream_class_init (CamelIMAPXInputStreamClass
*class)
234 GObjectClass
*object_class
;
235 GInputStreamClass
*input_stream_class
;
237 g_type_class_add_private (
238 class, sizeof (CamelIMAPXInputStreamPrivate
));
240 object_class
= G_OBJECT_CLASS (class);
241 object_class
->finalize
= imapx_input_stream_finalize
;
243 input_stream_class
= G_INPUT_STREAM_CLASS (class);
244 input_stream_class
->read_fn
= imapx_input_stream_read
;
248 camel_imapx_input_stream_pollable_init (GPollableInputStreamInterface
*iface
)
250 iface
->can_poll
= imapx_input_stream_can_poll
;
251 iface
->is_readable
= imapx_input_stream_is_readable
;
252 iface
->create_source
= imapx_input_stream_create_source
;
253 iface
->read_nonblocking
= imapx_input_stream_read_nonblocking
;
257 camel_imapx_input_stream_init (CamelIMAPXInputStream
*is
)
259 is
->priv
= CAMEL_IMAPX_INPUT_STREAM_GET_PRIVATE (is
);
261 /* +1 is room for appending a 0 if we need to for a token */
262 is
->priv
->bufsize
= 4096;
263 is
->priv
->buf
= g_malloc (is
->priv
->bufsize
+ 1);
264 is
->priv
->ptr
= is
->priv
->end
= is
->priv
->buf
;
265 is
->priv
->tokenbuf
= g_malloc (is
->priv
->bufsize
+ 1);
269 camel_imapx_input_stream_grow (CamelIMAPXInputStream
*is
,
274 guchar
*oldtok
= is
->priv
->tokenbuf
;
275 guchar
*oldbuf
= is
->priv
->buf
;
278 is
->priv
->bufsize
<<= 1;
279 } while (is
->priv
->bufsize
<= len
);
281 is
->priv
->tokenbuf
= g_realloc (
283 is
->priv
->bufsize
+ 1);
285 *tokptr
= is
->priv
->tokenbuf
+ (*tokptr
- oldtok
);
287 is
->priv
->unget_token
=
289 (is
->priv
->unget_token
- oldtok
);
291 is
->priv
->buf
= g_realloc (is
->priv
->buf
, is
->priv
->bufsize
+ 1);
292 is
->priv
->ptr
= is
->priv
->buf
+ (is
->priv
->ptr
- oldbuf
);
293 is
->priv
->end
= is
->priv
->buf
+ (is
->priv
->end
- oldbuf
);
295 *bufptr
= is
->priv
->buf
+ (*bufptr
- oldbuf
);
298 G_DEFINE_QUARK (camel
-imapx
-error
-quark
, camel_imapx_error
)
301 * camel_imapx_input_stream_new:
302 * @base_stream: a pollable #GInputStream
304 * Creates a new #CamelIMAPXInputStream which wraps @base_stream and
305 * parses incoming IMAP lines into tokens.
307 * Returns: a #CamelIMAPXInputStream
312 camel_imapx_input_stream_new (GInputStream
*base_stream
)
314 /* We implement GPollableInputStream by forwarding method calls
315 * to the base stream, so the base stream needs to be pollable. */
316 g_return_val_if_fail (G_IS_POLLABLE_INPUT_STREAM (base_stream
), NULL
);
318 return g_object_new (
319 CAMEL_TYPE_IMAPX_INPUT_STREAM
,
320 "base-stream", base_stream
, NULL
);
323 /* Returns if there is any data buffered that is ready for processing */
325 camel_imapx_input_stream_buffered (CamelIMAPXInputStream
*is
)
327 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), 0);
329 return is
->priv
->end
- is
->priv
->ptr
;
332 /* FIXME: these should probably handle it themselves,
333 * and get rid of the token interface? */
335 camel_imapx_input_stream_atom (CamelIMAPXInputStream
*is
,
338 GCancellable
*cancellable
,
341 camel_imapx_token_t tok
;
344 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
345 g_return_val_if_fail (data
!= NULL
, FALSE
);
346 g_return_val_if_fail (lenp
!= NULL
, FALSE
);
348 /* this is only 'approximate' atom */
349 tok
= camel_imapx_input_stream_token (is
, data
, lenp
, cancellable
, error
);
352 case IMAPX_TOK_ERROR
:
355 case IMAPX_TOK_TOKEN
:
366 error
, CAMEL_IMAPX_ERROR
, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED
,
372 /* gets an atom, a quoted_string, or a literal */
374 camel_imapx_input_stream_astring (CamelIMAPXInputStream
*is
,
376 GCancellable
*cancellable
,
379 camel_imapx_token_t tok
;
380 guchar
*p
, *e
, *start
, c
;
384 g_return_val_if_fail (CAMEL_IMAPX_INPUT_STREAM (is
), FALSE
);
385 g_return_val_if_fail (data
!= NULL
, FALSE
);
390 if (is
->priv
->unget
) {
391 tok
= camel_imapx_input_stream_token (is
, data
, &len
, cancellable
, error
);
393 /* skip whitespace/prefill buffer */
397 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
403 } while (c
== ' ' || c
== '\r');
405 if (c
== '\"' || c
== '{') {
406 tok
= camel_imapx_input_stream_token (is
, data
, &len
, cancellable
, error
);
410 tok
= IMAPX_TOK_STRING
;
412 /* <any %x01-7F except "(){ " / %x00-1F / %x7F > */
413 o
= is
->priv
->tokenbuf
;
414 oe
= is
->priv
->tokenbuf
+ is
->priv
->bufsize
- 1;
419 if (c
<= 0x1f || c
== 0x7f || c
== '(' || c
== ')' || c
== '{' || c
== ' ') {
420 if (c
== ' ' || c
== '\r')
423 is
->priv
->ptr
= p
- 1;
425 *data
= is
->priv
->tokenbuf
;
430 camel_imapx_input_stream_grow (is
, 0, &p
, &o
);
431 oe
= is
->priv
->tokenbuf
+ is
->priv
->bufsize
- 1;
437 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
446 case IMAPX_TOK_ERROR
:
449 case IMAPX_TOK_TOKEN
:
450 case IMAPX_TOK_STRING
:
454 case IMAPX_TOK_LITERAL
:
455 if (len
>= is
->priv
->bufsize
)
456 camel_imapx_input_stream_grow (is
, len
, NULL
, NULL
);
457 p
= is
->priv
->tokenbuf
;
458 camel_imapx_input_stream_set_literal (is
, len
);
460 ret
= camel_imapx_input_stream_getl (
461 is
, &start
, &inlen
, cancellable
, error
);
464 memcpy (p
, start
, inlen
);
468 *data
= is
->priv
->tokenbuf
;
473 error
, CAMEL_IMAPX_ERROR
, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED
,
474 "expecting astring");
479 /* check for NIL or (small) quoted_string or literal */
481 camel_imapx_input_stream_nstring (CamelIMAPXInputStream
*is
,
483 GCancellable
*cancellable
,
486 camel_imapx_token_t tok
;
491 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
492 g_return_val_if_fail (data
!= NULL
, FALSE
);
494 tok
= camel_imapx_input_stream_token (is
, data
, &len
, cancellable
, error
);
497 case IMAPX_TOK_ERROR
:
500 case IMAPX_TOK_STRING
:
503 case IMAPX_TOK_LITERAL
:
504 if (len
>= is
->priv
->bufsize
)
505 camel_imapx_input_stream_grow (is
, len
, NULL
, NULL
);
506 p
= is
->priv
->tokenbuf
;
507 camel_imapx_input_stream_set_literal (is
, len
);
509 ret
= camel_imapx_input_stream_getl (
510 is
, &start
, &inlen
, cancellable
, error
);
513 memcpy (p
, start
, inlen
);
517 *data
= is
->priv
->tokenbuf
;
520 case IMAPX_TOK_TOKEN
:
522 if (toupper (p
[0]) == 'N' &&
523 toupper (p
[1]) == 'I' &&
524 toupper (p
[2]) == 'L' &&
533 error
, CAMEL_IMAPX_ERROR
, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED
,
534 "expecting nstring");
539 /* parse an nstring as a GBytes */
541 camel_imapx_input_stream_nstring_bytes (CamelIMAPXInputStream
*is
,
543 gboolean with_progress
,
544 GCancellable
*cancellable
,
547 camel_imapx_token_t tok
;
550 GOutputStream
*output_stream
;
551 gssize bytes_written
;
554 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
555 g_return_val_if_fail (out_bytes
!= NULL
, FALSE
);
559 tok
= camel_imapx_input_stream_token (
560 is
, &token
, &len
, cancellable
, error
);
563 case IMAPX_TOK_ERROR
:
566 case IMAPX_TOK_STRING
:
567 *out_bytes
= g_bytes_new (token
, len
);
570 case IMAPX_TOK_LITERAL
:
571 /* If len is big, we could
572 * automatically use a file backing. */
573 camel_imapx_input_stream_set_literal (is
, len
);
574 output_stream
= g_memory_output_stream_new_resizable ();
575 if (with_progress
&& len
> 1024) {
576 bytes_written
= imapx_splice_with_progress (output_stream
, G_INPUT_STREAM (is
),
577 len
, cancellable
, error
);
578 if (!g_output_stream_close (output_stream
, cancellable
, error
))
581 bytes_written
= g_output_stream_splice (output_stream
, G_INPUT_STREAM (is
),
582 G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET
, cancellable
, error
);
584 success
= (bytes_written
>= 0);
587 g_memory_output_stream_steal_as_bytes (
588 G_MEMORY_OUTPUT_STREAM (output_stream
));
590 g_object_unref (output_stream
);
593 case IMAPX_TOK_TOKEN
:
594 if (toupper (token
[0]) == 'N' &&
595 toupper (token
[1]) == 'I' &&
596 toupper (token
[2]) == 'L' &&
605 error
, CAMEL_IMAPX_ERROR
, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED
,
606 "nstring: token not string");
612 camel_imapx_input_stream_number (CamelIMAPXInputStream
*is
,
614 GCancellable
*cancellable
,
617 camel_imapx_token_t tok
;
621 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
622 g_return_val_if_fail (number
!= NULL
, FALSE
);
624 tok
= camel_imapx_input_stream_token (
625 is
, &token
, &len
, cancellable
, error
);
628 case IMAPX_TOK_ERROR
:
632 *number
= g_ascii_strtoull ((gchar
*) token
, 0, 10);
637 error
, CAMEL_IMAPX_ERROR
, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED
,
644 camel_imapx_input_stream_text (CamelIMAPXInputStream
*is
,
646 GCancellable
*cancellable
,
649 GByteArray
*build
= g_byte_array_new ();
654 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
655 g_return_val_if_fail (text
!= NULL
, FALSE
);
657 while (is
->priv
->unget
> 0) {
658 switch (is
->priv
->unget_tok
) {
659 case IMAPX_TOK_TOKEN
:
660 case IMAPX_TOK_STRING
:
662 g_byte_array_append (
664 is
->priv
->unget_token
,
665 is
->priv
->unget_len
);
666 g_byte_array_append (
667 build
, (guint8
*) " ", 1);
668 default: /* invalid, but we'll ignore */
675 tok
= camel_imapx_input_stream_gets (
676 is
, &token
, &len
, cancellable
, error
);
679 g_byte_array_free (build
, TRUE
);
683 g_byte_array_append (build
, token
, len
);
686 g_byte_array_append (build
, (guint8
*) "", 1);
688 g_byte_array_free (build
, FALSE
);
693 /* Get one token from the imap stream */
695 camel_imapx_input_stream_token (CamelIMAPXInputStream
*is
,
698 GCancellable
*cancellable
,
701 register guchar c
, *oe
;
705 gboolean is_literal8
= FALSE
;
707 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), IMAPX_TOK_ERROR
);
708 g_return_val_if_fail (data
!= NULL
, IMAPX_TOK_ERROR
);
709 g_return_val_if_fail (len
!= NULL
, IMAPX_TOK_ERROR
);
711 if (is
->priv
->unget
> 0) {
713 *data
= is
->priv
->unget_token
;
714 *len
= is
->priv
->unget_len
;
715 return is
->priv
->unget_tok
;
721 if (is
->priv
->literal
> 0 && !g_cancellable_is_cancelled (cancellable
))
723 "stream_token called with literal %d",
729 /* skip whitespace/prefill buffer */
733 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
734 return IMAPX_TOK_ERROR
;
739 } while (c
== ' ' || c
== '\r');
744 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
745 return IMAPX_TOK_ERROR
;
756 /*strchr("\n*()[]+", c)*/
757 if (imapx_is_token_char (c
)) {
760 } else if (c
== '{') {
766 if (isdigit (c
) && literal
< (UINT_MAX
/ 10)) {
767 literal
= literal
* 10 + (c
- '0');
768 } else if (is_literal8
&& c
== '+') {
771 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
772 return IMAPX_TOK_ERROR
;
777 /* The '+' can be only at the end of the literal8 token */
780 } else if (c
== '}') {
787 is
->priv
->literal
= literal
;
788 return IMAPX_TOK_LITERAL
;
792 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
793 return IMAPX_TOK_ERROR
;
802 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
803 return IMAPX_TOK_ERROR
;
807 } else if (c
== '"') {
808 o
= is
->priv
->tokenbuf
;
809 oe
= is
->priv
->tokenbuf
+ is
->priv
->bufsize
- 1;
816 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
817 return IMAPX_TOK_ERROR
;
822 } else if (c
== '\"') {
825 *data
= is
->priv
->tokenbuf
;
826 *len
= o
- is
->priv
->tokenbuf
;
827 return IMAPX_TOK_STRING
;
830 camel_imapx_input_stream_grow (is
, 0, &p
, &o
);
831 oe
= is
->priv
->tokenbuf
+ is
->priv
->bufsize
- 1;
837 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
838 return IMAPX_TOK_ERROR
;
843 o
= is
->priv
->tokenbuf
;
844 oe
= is
->priv
->tokenbuf
+ is
->priv
->bufsize
- 1;
845 digits
= isdigit (c
);
850 /*if (strchr(" \r\n*()[]+", c) != NULL) {*/
851 if (imapx_is_notid_char (c
)) {
852 if (c
== ' ' || c
== '\r')
855 is
->priv
->ptr
= p
- 1;
857 *data
= is
->priv
->tokenbuf
;
858 *len
= o
- is
->priv
->tokenbuf
;
859 return digits
? IMAPX_TOK_INT
: IMAPX_TOK_TOKEN
;
863 camel_imapx_input_stream_grow (is
, 0, &p
, &o
);
864 oe
= is
->priv
->tokenbuf
+ is
->priv
->bufsize
- 1;
867 digits
&= isdigit (c
);
871 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
872 return IMAPX_TOK_ERROR
;
880 /* Protocol error, skip until next lf? */
882 is
->priv
->ptr
= p
- 1;
886 g_set_error (error
, CAMEL_IMAPX_ERROR
, CAMEL_IMAPX_ERROR_SERVER_RESPONSE_MALFORMED
, "protocol error");
888 return IMAPX_TOK_ERROR
;
892 camel_imapx_input_stream_ungettoken (CamelIMAPXInputStream
*is
,
893 camel_imapx_token_t tok
,
897 g_return_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
));
899 is
->priv
->unget_tok
= tok
;
900 is
->priv
->unget_token
= token
;
901 is
->priv
->unget_len
= len
;
905 /* returns -1 on error, 0 if last lot of data, >0 if more remaining */
907 camel_imapx_input_stream_gets (CamelIMAPXInputStream
*is
,
910 GCancellable
*cancellable
,
916 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), -1);
917 g_return_val_if_fail (start
!= NULL
, -1);
918 g_return_val_if_fail (len
!= NULL
, -1);
922 max
= is
->priv
->end
- is
->priv
->ptr
;
924 max
= imapx_input_stream_fill (is
, cancellable
, error
);
929 *start
= is
->priv
->ptr
;
930 end
= memchr (is
->priv
->ptr
, '\n', max
);
932 max
= (end
- is
->priv
->ptr
) + 1;
933 *start
= is
->priv
->ptr
;
935 is
->priv
->ptr
+= max
;
937 return end
== NULL
? 1 : 0;
941 camel_imapx_input_stream_set_literal (CamelIMAPXInputStream
*is
,
944 g_return_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
));
946 is
->priv
->literal
= literal
;
949 /* returns -1 on erorr, 0 if last data, >0 if more data left */
951 camel_imapx_input_stream_getl (CamelIMAPXInputStream
*is
,
954 GCancellable
*cancellable
,
959 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), -1);
960 g_return_val_if_fail (start
!= NULL
, -1);
961 g_return_val_if_fail (len
!= NULL
, -1);
965 if (is
->priv
->literal
> 0) {
966 max
= is
->priv
->end
- is
->priv
->ptr
;
968 max
= imapx_input_stream_fill (is
, cancellable
, error
);
973 max
= MIN (max
, is
->priv
->literal
);
974 *start
= is
->priv
->ptr
;
976 is
->priv
->ptr
+= max
;
977 is
->priv
->literal
-= max
;
980 if (is
->priv
->literal
> 0)
986 /* skip the rest of the line of tokens */
988 camel_imapx_input_stream_skip (CamelIMAPXInputStream
*is
,
989 GCancellable
*cancellable
,
992 camel_imapx_token_t tok
;
996 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
999 tok
= camel_imapx_input_stream_token (
1000 is
, &token
, &len
, cancellable
, error
);
1002 if (tok
== IMAPX_TOK_ERROR
)
1005 if (tok
== IMAPX_TOK_LITERAL
) {
1006 camel_imapx_input_stream_set_literal (is
, len
);
1008 tok
= camel_imapx_input_stream_getl (
1009 is
, &token
, &len
, cancellable
, error
);
1012 } while (tok
!= '\n' && tok
>= 0);
1014 return (tok
!= IMAPX_TOK_ERROR
);
1018 camel_imapx_input_stream_skip_until (CamelIMAPXInputStream
*is
,
1019 const gchar
*delimiters
,
1020 GCancellable
*cancellable
,
1026 g_return_val_if_fail (CAMEL_IS_IMAPX_INPUT_STREAM (is
), FALSE
);
1028 if (is
->priv
->unget
> 0) {
1033 if (is
->priv
->literal
> 0) {
1034 is
->priv
->literal
--;
1044 if (imapx_input_stream_fill (is
, cancellable
, error
) == IMAPX_TOK_ERROR
)
1050 } while (c
&& c
!= ' ' && c
!= '\r' && c
!= '\n' && (!delimiters
|| !strchr (delimiters
, c
)));