]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
cleanups and fix for partial header fetching
authorTimo Sirainen <tss@iki.fi>
Sat, 8 Nov 2003 21:12:45 +0000 (23:12 +0200)
committerTimo Sirainen <tss@iki.fi>
Sat, 8 Nov 2003 21:12:45 +0000 (23:12 +0200)
--HG--
branch : HEAD

src/imap/imap-fetch-body-section.c

index fd021877ef0afdecb405df52853fbe400dcb8856..a466738f537f4ddaf3dfba6a1e6a47711940cc67 100644 (file)
@@ -85,45 +85,72 @@ static uoff_t get_send_size(const struct imap_fetch_body_data *body,
        return size <= body->max_size ? size : body->max_size;
 }
 
-/* fetch BODY[] or BODY[TEXT] */
-static int fetch_body(struct imap_fetch_context *ctx,
+static int fetch_data(struct imap_fetch_context *ctx,
                      const struct imap_fetch_body_data *body,
-                     struct mail *mail, int fetch_header)
+                     struct mail *mail, struct istream *input,
+                     uoff_t physical_start, const struct message_size *size)
 {
-       struct message_size hdr_size, body_size;
-       struct istream *stream;
        const char *str;
-       int skip_cr, last_cr;
        uoff_t send_size;
        off_t ret;
+       int skip_cr, last_cr;
 
-       stream = mail->get_stream(mail, &hdr_size, &body_size);
-       if (stream == NULL)
-               return FALSE;
-
-       if (fetch_header)
-               message_size_add(&body_size, &hdr_size);
+       send_size = get_send_size(body, size->virtual_size);
 
-       send_size = get_send_size(body, body_size.virtual_size);
        str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", ctx->prefix, send_size);
        if (o_stream_send_str(ctx->output, str) < 0)
                return FALSE;
 
        skip_cr = seek_partial(ctx->select_counter, mail->uid,
-                              &partial, stream,
-                              fetch_header ? 0 : hdr_size.physical_size,
-                              body->skip);
+                              &partial, input, physical_start, body->skip);
 
-       ret = message_send(ctx->output, stream, &body_size,
-                          skip_cr, send_size, &last_cr,
-                          !mail->has_no_nuls);
+       ret = message_send(ctx->output, input, size, skip_cr, send_size,
+                          &last_cr, !mail->has_no_nuls);
        if (ret > 0) {
                partial.cr_skipped = last_cr != 0;
                partial.pos.physical_size =
-                       stream->v_offset - partial.physical_start;
+                       input->v_offset - partial.physical_start;
                partial.pos.virtual_size += ret;
        }
-       return ret >= 0;
+
+       if (ret != (off_t)send_size) {
+               /* Input stream gave less data then we expected. Two choices
+                  here: either we fill the missing data with spaces or we
+                  disconnect the client.
+
+                  We shouldn't really ever get here. One reason is if mail
+                  was deleted from NFS server while we were reading it.
+                  Another is some temporary disk error.
+
+                  If we filled the missing data the client could cache it,
+                  and if it was just a temporary error the message would be
+                  permanently left corrupted in client's local cache. So, we
+                  disconnect the client and hope that next try works. */
+               o_stream_close(ctx->output);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/* fetch BODY[] or BODY[TEXT] */
+static int fetch_body(struct imap_fetch_context *ctx,
+                     const struct imap_fetch_body_data *body,
+                     struct mail *mail, int fetch_header)
+{
+       struct message_size hdr_size, body_size;
+       struct istream *stream;
+
+       stream = mail->get_stream(mail, &hdr_size, &body_size);
+       if (stream == NULL)
+               return FALSE;
+
+       if (fetch_header)
+               message_size_add(&body_size, &hdr_size);
+
+       return fetch_data(ctx, body, mail, stream,
+                         fetch_header ? 0 : hdr_size.physical_size,
+                         &body_size);
 }
 
 static int header_match(const char *const *fields,
@@ -304,25 +331,14 @@ static int fetch_header_from(struct imap_fetch_context *ctx,
        const char *str;
        const void *data;
        size_t data_size;
-       uoff_t start_offset, send_size;
-       int failed, skip_cr;
+       uoff_t start_offset;
+       int failed;
 
        /* HEADER, MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
 
        if (strcmp(header_section, "HEADER") == 0) {
                /* all headers */
-               send_size = get_send_size(body, size->virtual_size);
-               str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n",
-                                     ctx->prefix, send_size);
-               if (o_stream_send_str(ctx->output, str) < 0)
-                       return FALSE;
-
-               skip_cr = seek_partial(ctx->select_counter, mail->uid,
-                                      &partial, input, 0, body->skip);
-
-               return message_send(ctx->output, input, size,
-                                   skip_cr, send_size, NULL,
-                                   !mail->has_no_nuls) >= 0;
+               return fetch_data(ctx, body, mail, input, 0, size);
        }
 
        /* partial headers - copy the wanted fields into memory, inserting
@@ -457,36 +473,6 @@ static int part_find(struct mail *mail, const struct imap_fetch_body_data *body,
        return TRUE;
 }
 
-/* fetch BODY[1.2] or BODY[1.2.TEXT] */
-static int fetch_part_body(struct imap_fetch_context *ctx,
-                          struct istream *stream,
-                          const struct imap_fetch_body_data *body,
-                          struct mail *mail, const struct message_part *part)
-{
-       const char *str;
-       int skip_cr, last_cr;
-       uoff_t send_size;
-       off_t ret;
-
-       send_size = get_send_size(body, part->body_size.virtual_size);
-       str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", ctx->prefix, send_size);
-       if (o_stream_send_str(ctx->output, str) < 0)
-               return FALSE;
-
-       skip_cr = seek_partial(ctx->select_counter, mail->uid,
-                              &partial, stream, part->physical_pos +
-                              part->header_size.physical_size, body->skip);
-       ret = message_send(ctx->output, stream, &part->body_size,
-                          skip_cr, send_size, &last_cr, !mail->has_no_nuls);
-       if (ret > 0) {
-               partial.cr_skipped = last_cr != 0;
-               partial.pos.physical_size =
-                       stream->v_offset - partial.physical_start;
-               partial.pos.virtual_size += ret;
-       }
-       return ret >= 0;
-}
-
 static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail,
                      const struct imap_fetch_body_data *body)
 {
@@ -507,8 +493,12 @@ static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail,
        if (stream == NULL)
                return FALSE;
 
-       if (*section == '\0' || strcmp(section, "TEXT") == 0)
-               return fetch_part_body(ctx, stream, body, mail, part);
+       if (*section == '\0' || strcmp(section, "TEXT") == 0) {
+               return fetch_data(ctx, body, mail, stream,
+                                 part->physical_pos +
+                                 part->header_size.physical_size,
+                                 &part->body_size);
+       }
 
        if (strncmp(section, "HEADER", 6) == 0 ||
            strcmp(section, "MIME") == 0) {