I think I've found the bug. The attached patch fixes the problem for me. The first problem is that the wrong value is being returned by message_send() because ret is getting set to the wrong value (see above or patch). The second problem is that in the special case where physical_size == virtual_size (i.e., sendfile can be used) i_stream_skip(input, virtual_skip) is being called on the input stream. This is wrong because virtual_skip is supposed to indicate that \r was the last character seen and therefore \n needs to be sent before any of the input stream; but in the sendfile case this is not necessary.There is a bug in partial IMAP fetches where the following happens:
fetch ... <0.10240>
correctly returns bytes 0-10239
fetch ... <10240.10240>
incorrectly returns bytes 20479...
fetch ... <10240.10240> (a 2nd time)
correctly returns bytes 10240-20479
While the second fetch fails, the third fetch works correctly. I tracked this down to a problem with partial_cache. There seems to be a bug in lib-mail/message-send.c:39 (CVS):
ret = o_stream_send_istream(output, input) > 0;
This causes message_send() to return 0 or 1 (note the "> 0"), not the number of bytes sent. This in turn causes partial.pos.virtual_size to get a value of 1 rather than 10240 in fetch_body(), and this in turn results in the wrong portion of the message being returned for the subsequent fetch.
But then when I remove the "> 0" from the above line of code, I get off-by-one errors:
fetch ... <0.10240>
correctly returns bytes 0-10240
fetch ... <10240.10240>
incorrectly returns bytes 10241-20480
fetch ... <10240.10240> (a 2nd time)
correctly returns bytes 10240-20479
I'm guessing there is a bug in the interaction with message_skip_virtual(), but I haven't been able to find the problem yet.
Any ideas? I've attached the offending message.
Matt