static bool proxy_client_worker_next_msg_get(struct proxy_client_dsync_worker *worker, const struct proxy_client_request *request, const char *line) { enum dsync_msg_get_result result = DSYNC_MSG_GET_RESULT_FAILED; const char *p, *error; uint32_t uid; p_clear(worker->msg_get_pool); switch (line[0]) { case '1': /* ok */ if (line[1] != '\t') break; line += 2; if ((p = strchr(line, '\t')) == NULL) break; uid = strtoul(t_strcut(line, '\t'), NULL, 10); line = p + 1; if (uid != request->uid) { i_error("msg-get returned invalid uid: %u != %u", uid, request->uid); proxy_client_fail(worker); return FALSE; } if (dsync_proxy_msg_static_import(worker->msg_get_pool, line, &worker->msg_get_data, &error) < 0) { i_error("Invalid msg-get static input: %s", error); proxy_client_fail(worker); return FALSE; } worker->msg_get_data.input = i_stream_create_dot(worker->input, FALSE); i_stream_set_destroy_callback(worker->msg_get_data.input, proxy_client_worker_msg_get_done, worker); io_remove(&worker->io); result = DSYNC_MSG_GET_RESULT_SUCCESS; break; case '0': /* expunged */ result = DSYNC_MSG_GET_RESULT_EXPUNGED; break; default: /* failure */ break; } request->callback.get(result, &worker->msg_get_data, request->context); return worker->io != NULL && worker->msg_get_data.input == NULL; }
static void test_istream_dot_error(const char *input_str, bool test_bufsize) { struct istream *test_input, *input; unsigned int i; size_t outsize, input_len; uoff_t offset; int ret; test_input = test_istream_create(input_str); input = i_stream_create_dot(test_input, FALSE); input_len = strlen(input_str); if (!test_bufsize) { outsize = 1; i = 0; i_stream_set_max_buffer_size(input, outsize); test_istream_set_size(test_input, 1); while ((ret = i_stream_read(input)) != -1) { switch (ret) { case -2: i_stream_set_max_buffer_size(input, ++outsize); offset = test_input->v_offset; /* seek one byte backwards so stream gets reset */ i_stream_seek(test_input, offset - 1); /* go back to original position */ test_istream_set_size(test_input, offset); i_stream_skip(test_input, 1); /* and finally allow reading one more byte */ test_istream_set_size(test_input, offset + 1); break; case 0: test_istream_set_size(test_input, ++i); break; default: test_assert(ret > 0); } } test_istream_set_size(test_input, input_len); (void)i_stream_read(test_input); } else { test_istream_set_size(test_input, input_len); for (i = 1; i <= input_len; i++) { i_stream_set_max_buffer_size(input, i); (void)i_stream_read(input); (void)i_stream_read(input); } i_stream_set_max_buffer_size(input, i+1); (void)i_stream_read(input); } test_assert(input->stream_errno == EPIPE); i_stream_unref(&test_input); i_stream_unref(&input); }
static void proxy_client_worker_msg_get_done(struct proxy_client_dsync_worker *worker) { struct istream *input = worker->msg_get_data.input; i_assert(worker->io == NULL); if (input->eof) proxy_client_worker_msg_get_finish(worker); else { /* saving read the message only partially. we'll need to read the input until EOF or we'll start treating the input as commands. */ worker->io = io_add(worker->fd_in, IO_READ, proxy_client_worker_read_to_eof, worker); worker->msg_get_data.input = i_stream_create_dot(worker->input, FALSE); } }
int pop3c_client_cmd_stream(struct pop3c_client *client, const char *cmd, struct istream **input_r, const char **error_r) { struct istream *inputs[2]; *input_r = NULL; /* read the +OK / -ERR */ if (pop3c_client_cmd_line(client, cmd, error_r) < 0) return -1; /* read the stream */ inputs[0] = i_stream_create_dot(client->input, TRUE); inputs[1] = NULL; client->dot_input = i_stream_create_seekable(inputs, POP3C_MAX_INBUF_SIZE, seekable_fd_callback, client); i_stream_unref(&inputs[0]); i_assert(client->io == NULL); client->io = io_add(client->fd, IO_READ, pop3c_client_dot_input, client); /* read any pending data from the stream */ pop3c_client_dot_input(client); if (!client->dot_input->eof) pop3c_client_run(client); if (client->input == NULL) { i_assert(client->io == NULL); i_stream_destroy(&client->dot_input); *error_r = "Disconnected"; return -1; } io_remove(&client->io); i_stream_seek(client->dot_input, 0); /* if this stream is used by some filter stream, make the filter stream blocking */ client->dot_input->blocking = TRUE; *input_r = client->dot_input; client->dot_input = NULL; return 0; }
static void test_istream_dot_one(const struct dot_test *test, bool send_last_lf, bool test_bufsize) { struct istream *test_input, *input; const unsigned char *data; size_t size; unsigned int i, outsize, input_len, output_len; string_t *str; uoff_t offset; int ret; test_input = test_istream_create(test->input); input = i_stream_create_dot(test_input, send_last_lf); input_len = strlen(test->input); output_len = strlen(test->output); if (!send_last_lf && (test->input[input_len-1] == '\n' || strstr(test->input, "\n.\n") != NULL || strstr(test->input, "\n.\r\n") != NULL)) { if (test->output[output_len-1] == '\n') { output_len--; if (output_len > 0 && test->output[output_len-1] == '\r') output_len--; } } str = t_str_new(256); if (!test_bufsize) { outsize = 1; i = 0; i_stream_set_max_buffer_size(input, outsize); test_istream_set_size(test_input, 1); while ((ret = i_stream_read(input)) != -1) { switch (ret) { case -2: i_stream_set_max_buffer_size(input, ++outsize); offset = test_input->v_offset; /* seek one byte backwards so stream gets reset */ i_stream_seek(test_input, offset - 1); /* go back to original position */ test_istream_set_size(test_input, offset); i_stream_skip(test_input, 1); /* and finally allow reading one more byte */ test_istream_set_size(test_input, offset + 1); break; case 0: test_istream_set_size(test_input, ++i); break; default: test_assert(ret > 0); data = i_stream_get_data(input, &size); str_append_n(str, data, size); i_stream_skip(input, size); } } test_istream_set_size(test_input, input_len); (void)i_stream_read(test_input); } else { test_istream_set_size(test_input, input_len); size = 0; for (i = 1; i < output_len; i++) { i_stream_set_max_buffer_size(input, i); test_assert(i_stream_read(input) == 1); test_assert(i_stream_read(input) == -2); data = i_stream_get_data(input, &size); test_assert(memcmp(data, test->output, size) == 0); } i_stream_set_max_buffer_size(input, i+2); if (size < output_len) test_assert(i_stream_read(input) == 1); test_assert(i_stream_read(input) == -1); data = i_stream_get_data(input, &size); str_append_n(str, data, size); } test_assert(str_len(str) == output_len); test_assert(memcmp(str_data(str), test->output, output_len) == 0); data = i_stream_get_data(test_input, &size); test_assert(size == strlen(test->parent_input)); test_assert(memcmp(data, test->parent_input, size) == 0); i_stream_unref(&test_input); i_stream_unref(&input); }