static gint stream_fill (CamelPOP3Stream *is, GCancellable *cancellable, GError **error) { gint left = 0; GError *local_error = NULL; if (is->source) { left = is->end - is->ptr; memmove (is->buf, is->ptr, left); is->end = is->buf + left; is->ptr = is->buf; left = camel_stream_read ( is->source, (gchar *) is->end, CAMEL_POP3_STREAM_SIZE - (is->end - is->buf), cancellable, &local_error); if (local_error) { dd (printf ("POP3_STREAM_FILL: Failed to read bytes: %s\n", local_error->message)); g_propagate_error (error, local_error); } if (left > 0) { is->end += left; is->end[0] = '\n'; return is->end - is->ptr; } else return -1; } return 0; }
static gint nntp_stream_fill (CamelNNTPStream *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, CAMEL_NNTP_STREAM_SIZE - (is->end - is->buf), cancellable, error); if (left > 0) { is->end += left; is->end[0] = '\n'; return is->end - is->ptr; } else { if (left == 0) { errno = ECONNRESET; g_set_error ( error, G_IO_ERROR, g_io_error_from_errno (errno), "%s", g_strerror (errno)); } return -1; } } return 0; }
static ssize_t scalix_fill (CamelSCALIXStream *scalix) { unsigned char *inbuf, *inptr, *inend; ssize_t nread; size_t inlen; if (scalix->disconnected) { errno = EINVAL; return -1; } inbuf = scalix->inbuf; inptr = scalix->inptr; inend = scalix->inend; inlen = inend - inptr; g_assert (inptr <= inend); /* attempt to align 'inend' with realbuf + SCAN_HEAD */ if (inptr >= inbuf) { inbuf -= inlen < SCALIX_READ_PRELEN ? inlen : SCALIX_READ_PRELEN; memmove (inbuf, inptr, inlen); inptr = inbuf; inbuf += inlen; } else if (inptr > scalix->realbuf) { size_t shift; shift = MIN (inptr - scalix->realbuf, inend - inbuf); memmove (inptr - shift, inptr, inlen); inptr -= shift; inbuf = inptr + inlen; } else { /* we can't shift... */ inbuf = inend; } scalix->inptr = inptr; scalix->inend = inbuf; inend = scalix->realbuf + SCALIX_READ_PRELEN + SCALIX_READ_BUFLEN - 1; if ((nread = camel_stream_read (scalix->stream, inbuf, inend - inbuf)) == -1) return -1; else if (nread == 0) scalix->disconnected = TRUE; scalix->inend += nread; return scalix->inend - scalix->inptr; }
static ssize_t imap4_fill (CamelIMAP4Stream *imap4) { unsigned char *inbuf, *inptr, *inend; ssize_t nread; size_t inlen; if (imap4->disconnected) { errno = EINVAL; return -1; } inbuf = imap4->inbuf; inptr = imap4->inptr; inend = imap4->inend; inlen = inend - inptr; g_assert (inptr <= inend); /* attempt to align 'inend' with realbuf + SCAN_HEAD */ if (inptr >= inbuf) { inbuf -= inlen < IMAP4_READ_PRELEN ? inlen : IMAP4_READ_PRELEN; memmove (inbuf, inptr, inlen); inptr = inbuf; inbuf += inlen; } else if (inptr > imap4->realbuf) { size_t shift; shift = MIN (inptr - imap4->realbuf, inend - inbuf); memmove (inptr - shift, inptr, inlen); inptr -= shift; inbuf = inptr + inlen; } else { /* we can't shift... */ inbuf = inend; } imap4->inptr = inptr; imap4->inend = inbuf; inend = imap4->realbuf + IMAP4_READ_PRELEN + IMAP4_READ_BUFLEN - 1; if ((nread = camel_stream_read (imap4->stream, inbuf, inend - inbuf)) == -1) return -1; else if (nread == 0) imap4->disconnected = TRUE; imap4->inend += nread; return imap4->inend - imap4->inptr; }
static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n) { CamelSCALIXStream *scalix = (CamelSCALIXStream *) stream; ssize_t len, nread = 0; if (scalix->mode == CAMEL_SCALIX_STREAM_MODE_LITERAL) { /* don't let our caller read past the end of the literal */ n = MIN (n, scalix->literal); } if (scalix->inptr < scalix->inend) { len = MIN (n, scalix->inend - scalix->inptr); memcpy (buffer, scalix->inptr, len); scalix->inptr += len; nread = len; } if (nread < n) { if ((len = camel_stream_read (scalix->stream, buffer + nread, n - nread)) == 0) scalix->disconnected = TRUE; else if (len == -1) return -1; nread += len; } if (scalix->mode == CAMEL_SCALIX_STREAM_MODE_LITERAL) { scalix->literal -= nread; if (scalix->literal == 0) { scalix->mode = CAMEL_SCALIX_STREAM_MODE_TOKEN; scalix->eol = TRUE; } } return nread; }
static int stream_fill(CamelPOP3Stream *is) { int 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, (char *) is->end, CAMEL_POP3_STREAM_SIZE - (is->end - is->buf)); if (left > 0) { is->end += left; is->end[0] = '\n'; return is->end - is->ptr; } else { dd(printf("POP3_STREAM_FILL(ERROR): '%s'\n", strerror (errno))); return -1; } } return 0; }
static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n) { CamelSeekableStream *parent; CamelSeekableStream *seekable_stream = CAMEL_SEEKABLE_STREAM (stream); CamelSeekableSubstream *seekable_substream = CAMEL_SEEKABLE_SUBSTREAM (stream); ssize_t v; if (n == 0) return 0; parent = seekable_substream->parent_stream; /* Go to our position in the parent stream. */ if (!parent_reset (seekable_substream, parent)) { stream->eos = TRUE; return 0; } /* Compute how many bytes should be read. */ if (seekable_stream->bound_end != CAMEL_STREAM_UNBOUND) n = MIN (seekable_stream->bound_end - seekable_stream->position, n); if (n == 0) { stream->eos = TRUE; return 0; } v = camel_stream_read (CAMEL_STREAM (parent), buffer, n); /* ignore <0 - it's an error, let the caller deal */ if (v > 0) seekable_stream->position += v; return v; }
gint main (gint argc, gchar **argv) { CamelStream *source; CamelStream *correct; CamelStream *stream; CamelMimeFilter *sh; gchar *work; gint i; gssize comp_progress, comp_correct_chunk, comp_filter_chunk; gint comp_i; gchar comp_correct[CHUNK_SIZE], comp_filter[CHUNK_SIZE]; camel_test_init (argc, argv); for (i = 0; i < NUM_CASES; i++) { gint j; work = g_strdup_printf ("CRLF/DOT filter, test case %d", i); camel_test_start (work); g_free (work); for (j = CRLF_ENCODE; j < CRLF_DONE; j++) { CamelMimeFilterCRLFDirection direction; gchar *infile = NULL, *outfile = NULL; switch (j) { case CRLF_ENCODE: camel_test_push ("Test of the encoder"); direction = CAMEL_MIME_FILTER_CRLF_ENCODE; infile = g_strdup_printf ("%s/crlf-%d.in", SOURCEDIR, i + 1); outfile = g_strdup_printf ("%s/crlf-%d.out", SOURCEDIR, i + 1); break; case CRLF_DECODE: camel_test_push ("Test of the decoder"); direction = CAMEL_MIME_FILTER_CRLF_DECODE; infile = g_strdup_printf ("%s/crlf-%d.out", SOURCEDIR, i + 1); outfile = g_strdup_printf ("%s/crlf-%d.in", SOURCEDIR, i + 1); break; default: break; } camel_test_push ("Initializing objects"); source = camel_stream_fs_new_with_name (infile, 0, O_RDONLY, NULL); if (!source) { camel_test_fail ("Failed to open input case in \"%s\"", infile); g_free (infile); continue; } g_free (infile); correct = camel_stream_fs_new_with_name (outfile, 0, O_RDONLY, NULL); if (!correct) { camel_test_fail ("Failed to open correct output in \"%s\"", outfile); g_free (outfile); continue; } g_free (outfile); stream = camel_stream_filter_new (source); if (!stream) { camel_test_fail ("Couldn't create CamelStreamFilter??"); continue; } sh = camel_mime_filter_crlf_new (direction, CAMEL_MIME_FILTER_CRLF_MODE_CRLF_DOTS); if (!sh) { camel_test_fail ("Couldn't create CamelMimeFilterCrlf??"); continue; } camel_stream_filter_add ( CAMEL_STREAM_FILTER (stream), sh); camel_test_pull (); camel_test_push ("Running filter and comparing to correct result"); comp_progress = 0; while (1) { comp_correct_chunk = camel_stream_read ( correct, comp_correct, CHUNK_SIZE, NULL, NULL); comp_filter_chunk = 0; if (comp_correct_chunk == 0) break; while (comp_filter_chunk < comp_correct_chunk) { gssize delta; delta = camel_stream_read ( stream, comp_filter + comp_filter_chunk, CHUNK_SIZE - comp_filter_chunk, NULL, NULL); if (delta == 0) { camel_test_fail ("Chunks are different sizes: correct is %d, " "filter is %d, %d bytes into stream", comp_correct_chunk, comp_filter_chunk, comp_progress); } comp_filter_chunk += delta; } for (comp_i = 0; comp_i < comp_filter_chunk; comp_i++) { if (comp_correct[comp_i] != comp_filter[comp_i]) { camel_test_fail ("Difference: correct is %c, filter is %c, " "%d bytes into stream", comp_correct[comp_i], comp_filter[comp_i], comp_progress + comp_i); } } comp_progress += comp_filter_chunk; } camel_test_pull (); /* inefficient */ camel_test_push ("Cleaning up"); g_object_unref (stream); g_object_unref (correct); g_object_unref (source); g_object_unref (sh); camel_test_pull (); camel_test_pull (); } camel_test_end (); } return 0; }
/* Given a line that is the start of an untagged response, read and * return the complete response, which may include an arbitrary number * of literals. */ static char * imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex) { int fulllen, ldigits, nread, n, i, sexp = 0; unsigned int length; GPtrArray *data; GString *str; char *end, *p, *s, *d; p = strrchr (line, '{'); if (!p) return line; data = g_ptr_array_new (); fulllen = 0; while (1) { str = g_string_new (line); g_free (line); fulllen += str->len; g_ptr_array_add (data, str); if (!(p = strrchr (str->str, '{')) || p[1] == '-') break; /* HACK ALERT: We scan the non-literal part of the string, looking for possible s expression braces. This assumes we're getting s-expressions, which we should be. This is so if we get a blank line after a literal, in an s-expression, we can keep going, since we do no other parsing at this level. TODO: handle quoted strings? */ for (s=str->str; s<p; s++) { if (*s == '(') sexp++; else if (*s == ')') sexp--; } length = strtoul (p + 1, &end, 10); if (*end != '}' || *(end + 1) || end == p + 1 || length >= UINT_MAX - 2) break; ldigits = end - (p + 1); /* Read the literal */ str = g_string_sized_new (length + 2); str->str[0] = '\n'; nread = 0; do { if ((n = camel_stream_read (store->istream, str->str + nread + 1, length - nread)) == -1) { if (errno == EINTR) camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL, _("Operation cancelled")); else camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, g_strerror (errno)); camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); g_string_free (str, TRUE); goto lose; } nread += n; } while (n > 0 && nread < length); if (nread < length) { camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, _("Server response ended too soon.")); camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL); g_string_free (str, TRUE); goto lose; } str->str[length + 1] = '\0'; if (camel_debug("imap")) { printf("Literal: -->"); fwrite(str->str+1, 1, length, stdout); printf("<--\n"); } /* Fix up the literal, turning CRLFs into LF. Also, if * we find any embedded NULs, strip them. This is * dubious, but: * - The IMAP grammar says you can't have NULs here * anyway, so this will not affect our behavior * against any completely correct server. * - WU-imapd 12.264 (at least) will cheerily pass * NULs along if they are embedded in the message */ s = d = str->str + 1; end = str->str + 1 + length; while (s < end) { while (s < end && *s == '\0') { s++; length--; } if (*s == '\r' && *(s + 1) == '\n') { s++; length--; } *d++ = *s++; } *d = '\0'; str->len = length + 1; /* p points to the "{" in the line that starts the * literal. The length of the CR-less response must be * less than or equal to the length of the response * with CRs, therefore overwriting the old value with * the new value cannot cause an overrun. However, we * don't want it to be shorter either, because then the * GString's length would be off... */ sprintf (p, "{%0*u}", ldigits, length); fulllen += str->len; g_ptr_array_add (data, str); /* Read the next line. */ do { if (camel_imap_store_readline (store, &line, ex) < 0) goto lose; /* MAJOR HACK ALERT, gropuwise sometimes sends an extra blank line after literals, check that here But only do it if we're inside an sexpression */ if (line[0] == 0 && sexp > 0) g_warning("Server sent empty line after a literal, assuming in error"); } while (line[0] == 0 && sexp > 0); } /* Now reassemble the data. */ p = line = g_malloc (fulllen + 1); for (i = 0; i < data->len; i++) { str = data->pdata[i]; memcpy (p, str->str, str->len); p += str->len; g_string_free (str, TRUE); } *p = '\0'; g_ptr_array_free (data, TRUE); return line; lose: for (i = 0; i < data->len; i++) g_string_free (data->pdata[i], TRUE); g_ptr_array_free (data, TRUE); return NULL; }