36
36
#include "camel-imapx-utils.h"
37
37
#include "camel-imapx-stream.h"
39
#define CAMEL_IMAPX_STREAM_GET_PRIVATE(obj) \
40
(G_TYPE_INSTANCE_GET_PRIVATE \
41
((obj), CAMEL_TYPE_IMAPX_STREAM, CamelIMAPXStreamPrivate))
39
43
#define t(...) camel_imapx_debug(token, __VA_ARGS__)
40
44
#define io(...) camel_imapx_debug(io, __VA_ARGS__)
46
struct _CamelIMAPXStreamPrivate {
49
guchar *buf, *ptr, *end;
53
camel_imapx_token_t unget_tok;
42
66
G_DEFINE_TYPE (CamelIMAPXStream, camel_imapx_stream, CAMEL_TYPE_STREAM)
52
left = is->end - is->ptr;
53
memcpy (is->buf, is->ptr, left);
54
is->end = is->buf + left;
75
if (is->priv->source != NULL) {
76
left = is->priv->end - is->priv->ptr;
77
memcpy (is->priv->buf, is->priv->ptr, left);
78
is->priv->end = is->priv->buf + left;
79
is->priv->ptr = is->priv->buf;
56
80
left = camel_stream_read (
57
is->source, (gchar *) is->end,
58
is->bufsize - (is->end - is->buf),
82
(gchar *) is->priv->end,
83
is->priv->bufsize - (is->priv->end - is->priv->buf),
59
84
cancellable, error);
62
io(is->tagprefix, "camel_imapx_read: buffer is '%.*s'\n", (gint)(is->end - is->ptr), is->ptr);
63
return is->end - is->ptr;
86
is->priv->end += left;
87
io (is->tagprefix, "camel_imapx_read: buffer is '%.*s'\n", (gint)(is->priv->end - is->priv->ptr), is->priv->ptr);
88
return is->priv->end - is->priv->ptr;
65
io(is->tagprefix, "camel_imapx_read: -1\n");
90
io (is->tagprefix, "camel_imapx_read: -1\n");
66
91
/* If returning zero, camel_stream_read() doesn't consider
67
92
* that to be an error. But we do -- we should only be here
68
93
* if we *know* there are data to receive. So set the error
112
imapx_stream_set_source (CamelIMAPXStream *stream,
115
g_return_if_fail (CAMEL_IS_STREAM (source));
116
g_return_if_fail (stream->priv->source == NULL);
118
stream->priv->source = g_object_ref (source);
122
imapx_stream_set_property (GObject *object,
127
switch (property_id) {
129
imapx_stream_set_source (
130
CAMEL_IMAPX_STREAM (object),
131
g_value_get_object (value));
135
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
139
imapx_stream_get_property (GObject *object,
144
switch (property_id) {
146
g_value_take_object (
148
camel_imapx_stream_ref_source (
149
CAMEL_IMAPX_STREAM (object)));
153
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
87
157
imapx_stream_dispose (GObject *object)
89
159
CamelIMAPXStream *stream = CAMEL_IMAPX_STREAM (object);
91
if (stream->source != NULL) {
92
g_object_unref (stream->source);
93
stream->source = NULL;
161
if (stream->priv->source != NULL) {
162
g_object_unref (stream->priv->source);
163
stream->priv->source = NULL;
96
166
/* Chain up to parent's dispose() method. */
119
189
CamelIMAPXStream *is = (CamelIMAPXStream *) stream;
122
if (is->literal == 0 || n == 0)
192
if (is->priv->literal == 0 || n == 0)
125
max = is->end - is->ptr;
195
max = is->priv->end - is->priv->ptr;
127
max = MIN (max, is->literal);
197
max = MIN (max, is->priv->literal);
128
198
max = MIN (max, n);
129
memcpy (buffer, is->ptr, max);
199
memcpy (buffer, is->priv->ptr, max);
200
is->priv->ptr += max;
132
max = MIN (is->literal, n);
133
max = camel_stream_read (is->source, buffer, max, cancellable, error);
202
max = MIN (is->priv->literal, n);
203
max = camel_stream_read (
205
buffer, max, cancellable, error);
138
io(is->tagprefix, "camel_imapx_read(literal): '%.*s'\n", (gint)max, buffer);
210
io (is->tagprefix, "camel_imapx_read(literal): '%.*s'\n", (gint) max, buffer);
212
is->priv->literal -= max;
152
224
CamelIMAPXStream *is = (CamelIMAPXStream *) stream;
154
226
if (g_strstr_len (buffer, n, "LOGIN")) {
155
io(is->tagprefix, "camel_imapx_write: 'LOGIN...'\n");
227
io (is->tagprefix, "camel_imapx_write: 'LOGIN...'\n");
157
io(is->tagprefix, "camel_imapx_write: '%.*s'\n", (gint)n, buffer);
229
io (is->tagprefix, "camel_imapx_write: '%.*s'\n", (gint) n, buffer);
160
return camel_stream_write (is->source, buffer, n, cancellable, error);
232
return camel_stream_write (
234
buffer, n, cancellable, error);
192
267
GObjectClass *object_class;
193
268
CamelStreamClass *stream_class;
270
g_type_class_add_private (class, sizeof (CamelIMAPXStreamPrivate));
195
272
object_class = G_OBJECT_CLASS (class);
273
object_class->set_property = imapx_stream_set_property;
274
object_class->get_property = imapx_stream_get_property;
196
275
object_class->dispose = imapx_stream_dispose;
197
276
object_class->finalize = imapx_stream_finalize;
202
281
stream_class->close = imapx_stream_close;
203
282
stream_class->flush = imapx_stream_flush;
204
283
stream_class->eos = imapx_stream_eos;
285
g_object_class_install_property (
288
g_param_spec_object (
294
G_PARAM_CONSTRUCT_ONLY |
295
G_PARAM_STATIC_STRINGS));
208
299
camel_imapx_stream_init (CamelIMAPXStream *is)
301
is->priv = CAMEL_IMAPX_STREAM_GET_PRIVATE (is);
210
303
/* +1 is room for appending a 0 if we need to for a token */
212
is->ptr = is->end = is->buf = g_malloc (is->bufsize + 1);
213
is->tokenbuf = g_malloc (is->bufsize + 1);
304
is->priv->bufsize = 4096;
305
is->priv->buf = g_malloc (is->priv->bufsize + 1);
306
is->priv->ptr = is->priv->end = is->priv->buf;
307
is->priv->tokenbuf = g_malloc (is->priv->bufsize + 1);
216
static void camel_imapx_stream_grow (CamelIMAPXStream *is, guint len, guchar **bufptr, guchar **tokptr)
311
camel_imapx_stream_grow (CamelIMAPXStream *is,
218
guchar *oldtok = is->tokenbuf;
219
guchar *oldbuf = is->buf;
316
guchar *oldtok = is->priv->tokenbuf;
317
guchar *oldbuf = is->priv->buf;
223
} while (is->bufsize <= len);
225
io(is->tagprefix, "Grow imapx buffers to %d bytes\n", is->bufsize);
227
is->tokenbuf = g_realloc (is->tokenbuf, is->bufsize + 1);
320
is->priv->bufsize <<= 1;
321
} while (is->priv->bufsize <= len);
323
io (is->tagprefix, "Grow imapx buffers to %d bytes\n", is->priv->bufsize);
325
is->priv->tokenbuf = g_realloc (
327
is->priv->bufsize + 1);
229
*tokptr = is->tokenbuf + (*tokptr - oldtok);
231
is->unget_token = is->tokenbuf + (is->unget_token - oldtok);
329
*tokptr = is->priv->tokenbuf + (*tokptr - oldtok);
331
is->priv->unget_token =
333
(is->priv->unget_token - oldtok);
233
//io(is->tagprefix, "buf was %p, ptr %p end %p\n", is->buf, is->ptr, is->end);
234
is->buf = g_realloc (is->buf, is->bufsize + 1);
235
is->ptr = is->buf + (is->ptr - oldbuf);
236
is->end = is->buf + (is->end - oldbuf);
237
//io(is->tagprefix, "buf now %p, ptr %p end %p\n", is->buf, is->ptr, is->end);
335
is->priv->buf = g_realloc (is->priv->buf, is->priv->bufsize + 1);
336
is->priv->ptr = is->priv->buf + (is->priv->ptr - oldbuf);
337
is->priv->end = is->priv->buf + (is->priv->end - oldbuf);
239
*bufptr = is->buf + (*bufptr - oldbuf);
339
*bufptr = is->priv->buf + (*bufptr - oldbuf);
343
camel_imapx_error_quark (void)
345
static GQuark quark = 0;
347
if (G_UNLIKELY (quark == 0)) {
348
const gchar *string = "camel-imapx-error-quark";
349
quark = g_quark_from_static_string (string);
251
364
camel_imapx_stream_new (CamelStream *source)
253
CamelIMAPXStream *is;
255
is = g_object_new (CAMEL_TYPE_IMAPX_STREAM, NULL);
256
is->source = g_object_ref (source);
258
return (CamelStream *) is;
366
g_return_val_if_fail (CAMEL_IS_STREAM (source), NULL);
368
return g_object_new (
369
CAMEL_TYPE_IMAPX_STREAM,
370
"source", source, NULL);
262
camel_imapx_error_quark (void)
374
camel_imapx_stream_ref_source (CamelIMAPXStream *is)
264
static GQuark quark = 0;
266
if (G_UNLIKELY (quark == 0)) {
267
const gchar *string = "camel-imapx-error-quark";
268
quark = g_quark_from_static_string (string);
376
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), NULL);
378
return g_object_ref (is->priv->source);
274
381
/* Returns if there is any data buffered that is ready for processing */
276
383
camel_imapx_stream_buffered (CamelIMAPXStream *is)
278
return is->end - is->ptr;
284
skip_ws (CamelIMAPXStream *is,
288
register guchar c, *p;
297
if (imapx_stream_fill (is, NULL) == IMAPX_TOK_ERROR)
298
return IMAPX_TOK_ERROR;
303
} while (c == ' ' || c == '\r');
385
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), 0);
387
return is->priv->end - is->priv->ptr;
312
390
/* FIXME: these should probably handle it themselves,
313
391
* and get rid of the token interface? */
322
400
GError *local_error = NULL;
402
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), IMAPX_TOK_ERROR);
403
g_return_val_if_fail (data != NULL, IMAPX_TOK_ERROR);
404
g_return_val_if_fail (lenp != NULL, IMAPX_TOK_ERROR);
324
406
/* this is only 'approximate' atom */
325
407
switch (camel_imapx_stream_token (is, data, lenp, cancellable, &local_error)) {
326
408
case IMAPX_TOK_TOKEN:
338
420
g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting atom");
340
422
g_propagate_error (error, local_error);
341
io(is->tagprefix, "expecting atom!\n");
423
io (is->tagprefix, "expecting atom!\n");
342
424
return IMAPX_TOK_PROTOCOL;
356
438
GError *local_error = NULL;
440
g_return_val_if_fail (CAMEL_IMAPX_STREAM (is), IMAPX_TOK_ERROR);
441
g_return_val_if_fail (data != NULL, IMAPX_TOK_ERROR);
358
443
switch (camel_imapx_stream_token (is, data, &len, cancellable, &local_error)) {
359
444
case IMAPX_TOK_TOKEN:
360
445
case IMAPX_TOK_INT:
361
446
case IMAPX_TOK_STRING:
363
448
case IMAPX_TOK_LITERAL:
364
if (len >= is->bufsize)
449
if (len >= is->priv->bufsize)
365
450
camel_imapx_stream_grow (is, len, NULL, NULL);
451
p = is->priv->tokenbuf;
367
452
camel_imapx_stream_set_literal (is, len);
369
454
ret = camel_imapx_stream_getl (is, &start, &inlen, cancellable, error);
385
470
g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting astring");
387
472
g_propagate_error (error, local_error);
388
io(is->tagprefix, "expecting astring!\n");
473
io (is->tagprefix, "expecting astring!\n");
389
474
return IMAPX_TOK_PROTOCOL;
403
488
GError *local_error = NULL;
490
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), IMAPX_TOK_ERROR);
491
g_return_val_if_fail (data != NULL, IMAPX_TOK_ERROR);
405
493
switch (camel_imapx_stream_token (is, data, &len, cancellable, &local_error)) {
406
494
case IMAPX_TOK_STRING:
408
496
case IMAPX_TOK_LITERAL:
409
if (len >= is->bufsize)
497
if (len >= is->priv->bufsize)
410
498
camel_imapx_stream_grow (is, len, NULL, NULL);
499
p = is->priv->tokenbuf;
412
500
camel_imapx_stream_set_literal (is, len);
414
502
ret = camel_imapx_stream_getl (is, &start, &inlen, cancellable, error);
455
542
CamelStream * mem = NULL;
456
543
GError *local_error = NULL;
545
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), -1);
546
g_return_val_if_fail (stream != NULL, -1);
460
550
switch (camel_imapx_stream_token (is, &token, &len, cancellable, &local_error)) {
504
594
GError *local_error = NULL;
596
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), 0);
506
598
if (camel_imapx_stream_token (is, &token, &len, cancellable, &local_error) != IMAPX_TOK_INT) {
507
599
if (local_error == NULL)
508
600
g_set_error (error, CAMEL_IMAPX_ERROR, 1, "expecting number");
528
while (is->unget > 0) {
529
switch (is->unget_tok) {
620
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), -1);
621
g_return_val_if_fail (text != NULL, -1);
623
while (is->priv->unget > 0) {
624
switch (is->priv->unget_tok) {
530
625
case IMAPX_TOK_TOKEN:
531
626
case IMAPX_TOK_STRING:
532
627
case IMAPX_TOK_INT:
533
g_byte_array_append (build, (guint8 *) is->unget_token, is->unget_len);
534
g_byte_array_append(build, (guint8 *) " ", 1);
628
g_byte_array_append (
630
is->priv->unget_token,
631
is->priv->unget_len);
632
g_byte_array_append (
633
build, (guint8 *) " ", 1);
535
634
default: /* invalid, but we'll ignore */
575
*data = is->unget_token;
576
*len = is->unget_len;
577
/*printf("token UNGET '%c' %s\n", is->unget_tok, is->unget_token);*/
578
return is->unget_tok;
671
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), IMAPX_TOK_ERROR);
672
g_return_val_if_fail (data != NULL, IMAPX_TOK_ERROR);
673
g_return_val_if_fail (len != NULL, IMAPX_TOK_ERROR);
675
if (is->priv->unget > 0) {
677
*data = is->priv->unget_token;
678
*len = is->priv->unget_len;
679
return is->priv->unget_tok;
582
g_warning("stream_token called with literal %d", is->literal);
682
if (is->priv->literal > 0)
684
"stream_token called with literal %d",
587
690
/* skip whitespace/prefill buffer */
589
692
while (p >= e ) {
591
694
if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
592
695
return IMAPX_TOK_ERROR;
597
700
} while (c == ' ' || c == '\r');
599
702
/*strchr("\n*()[]+", c)*/
600
703
if (imapx_is_token_char (c)) {
602
t(is->tagprefix, "token '%c'\n", c);
705
t (is->tagprefix, "token '%c'\n", c);
604
707
} else if (c == '{') {
619
is->literal = literal;
620
t(is->tagprefix, "token LITERAL %d\n", literal);
722
is->priv->literal = literal;
723
t (is->tagprefix, "token LITERAL %d\n", literal);
621
724
return IMAPX_TOK_LITERAL;
625
728
if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
626
729
return IMAPX_TOK_ERROR;
631
734
if (isdigit (c)) {
632
io(is->tagprefix, "Protocol error: literal too big\n");
735
io (is->tagprefix, "Protocol error: literal too big\n");
634
io(is->tagprefix, "Protocol error: literal contains invalid gchar %02x '%c'\n", c, isprint(c)?c:c);
737
io (is->tagprefix, "Protocol error: literal contains invalid gchar %02x '%c'\n", c, isprint (c) ? c : c);
636
739
goto protocol_error;
640
743
if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
641
744
return IMAPX_TOK_ERROR;
645
748
} else if (c == '"') {
647
oe = is->tokenbuf + is->bufsize - 1;
749
o = is->priv->tokenbuf;
750
oe = is->priv->tokenbuf + is->priv->bufsize - 1;
654
757
if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
655
758
return IMAPX_TOK_ERROR;
660
763
} else if (c == '\"') {
663
*data = is->tokenbuf;
664
*len = o - is->tokenbuf;
665
t(is->tagprefix, "token STRING '%s'\n", is->tokenbuf);
766
*data = is->priv->tokenbuf;
767
*len = o - is->priv->tokenbuf;
768
t (is->tagprefix, "token STRING '%s'\n", is->priv->tokenbuf);
666
769
return IMAPX_TOK_STRING;
668
771
if (c == '\n' || c == '\r') {
669
io(is->tagprefix, "Protocol error: truncated string\n");
772
io (is->tagprefix, "Protocol error: truncated string\n");
670
773
goto protocol_error;
673
776
camel_imapx_stream_grow (is, 0, &p, &o);
674
oe = is->tokenbuf + is->bufsize - 1;
777
oe = is->priv->tokenbuf + is->priv->bufsize - 1;
680
783
if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
681
784
return IMAPX_TOK_ERROR;
687
oe = is->tokenbuf + is->bufsize - 1;
789
o = is->priv->tokenbuf;
790
oe = is->priv->tokenbuf + is->priv->bufsize - 1;
688
791
digits = isdigit (c);
693
796
/*if (strchr(" \r\n*()[]+", c) != NULL) {*/
694
797
if (imapx_is_notid_char (c)) {
695
798
if (c == ' ' || c == '\r')
801
is->priv->ptr = p - 1;
700
*data = is->tokenbuf;
701
*len = o - is->tokenbuf;
702
t(is->tagprefix, "token TOKEN '%s'\n", is->tokenbuf);
803
*data = is->priv->tokenbuf;
804
*len = o - is->priv->tokenbuf;
805
t (is->tagprefix, "token TOKEN '%s'\n", is->priv->tokenbuf);
703
806
return digits ? IMAPX_TOK_INT : IMAPX_TOK_TOKEN;
707
810
camel_imapx_stream_grow (is, 0, &p, &o);
708
oe = is->tokenbuf + is->bufsize - 1;
811
oe = is->priv->tokenbuf + is->priv->bufsize - 1;
711
814
digits &= isdigit (c);
715
818
if (imapx_stream_fill (is, cancellable, error) == IMAPX_TOK_ERROR)
716
819
return IMAPX_TOK_ERROR;
722
825
/* Protocol error, skip until next lf? */
724
io(is->tagprefix, "Got protocol error\n");
827
io (is->tagprefix, "Got protocol error\n");
830
is->priv->ptr = p - 1;
731
834
g_set_error (error, CAMEL_IMAPX_ERROR, 1, "protocol error");
732
835
return IMAPX_TOK_PROTOCOL;
741
/*printf("ungettoken: '%c' '%s'\n", tok, token);*/
743
is->unget_token = token;
844
g_return_if_fail (CAMEL_IS_IMAPX_STREAM (is));
846
is->priv->unget_tok = tok;
847
is->priv->unget_token = token;
848
is->priv->unget_len = len;
748
852
/* returns -1 on error, 0 if last lot of data, >0 if more remaining */
863
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), -1);
864
g_return_val_if_fail (start != NULL, -1);
865
g_return_val_if_fail (len != NULL, -1);
761
max = is->end - is->ptr;
869
max = is->priv->end - is->priv->ptr;
763
871
max = imapx_stream_fill (is, cancellable, error);
769
end = memchr (is->ptr, '\n', max);
876
*start = is->priv->ptr;
877
end = memchr (is->priv->ptr, '\n', max);
771
max = (end - is->ptr) + 1;
879
max = (end - is->priv->ptr) + 1;
880
*start = is->priv->ptr;
882
is->priv->ptr += max;
776
884
return end == NULL ? 1 : 0;
779
void camel_imapx_stream_set_literal (CamelIMAPXStream *is, guint literal)
888
camel_imapx_stream_set_literal (CamelIMAPXStream *is,
781
is->literal = literal;
891
g_return_if_fail (CAMEL_IS_IMAPX_STREAM (is));
893
is->priv->literal = literal;
784
896
/* returns -1 on erorr, 0 if last data, >0 if more data left */
906
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), -1);
907
g_return_val_if_fail (start != NULL, -1);
908
g_return_val_if_fail (len != NULL, -1);
796
if (is->literal > 0) {
797
max = is->end - is->ptr;
912
if (is->priv->literal > 0) {
913
max = is->priv->end - is->priv->ptr;
799
915
max = imapx_stream_fill (is, cancellable, error);
804
max = MIN (max, is->literal);
920
max = MIN (max, is->priv->literal);
921
*start = is->priv->ptr;
923
is->priv->ptr += max;
924
is->priv->literal -= max;
927
if (is->priv->literal > 0)
943
g_return_val_if_fail (CAMEL_IS_IMAPX_STREAM (is), -1);
828
946
tok = camel_imapx_stream_token (is, &token, &len, cancellable, error);
829
947
if (tok == IMAPX_TOK_LITERAL) {
830
948
camel_imapx_stream_set_literal (is, len);
831
949
while ((tok = camel_imapx_stream_getl (is, &token, &len, cancellable, error)) > 0) {
832
io(is->tagprefix, "Skip literal data '%.*s'\n", (gint)len, token);
950
io (is->tagprefix, "Skip literal data '%.*s'\n", (gint) len, token);
835
953
} while (tok != '\n' && tok >= 0);