bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
211c638d81d382517d196ad47565e0d85012c927klemens/* Implemented against draft-ietf-imapext-sort-10 and
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen draft-ietf-imapext-thread-12 */
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen#include "lib.h"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen#include "buffer.h"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen#include "charset-utf8.h"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen#include "message-header-decode.h"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen#include "imap-base-subject.h"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void pack_whitespace(buffer_t *buf)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen char *data, *dest;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool last_lwsp;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen data = buffer_get_modifiable_data(buf, NULL);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* check if we need to do anything */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen while (*data != '\0') {
d64e7a4e2aa694a4197c392e4531a9df13c95b36Timo Sirainen if (*data == '\t' || *data == '\n' || *data == '\r' ||
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen (*data == ' ' && (data[1] == ' ' || data[1] == '\t')))
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen break;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data == '\0')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* @UNSAFE: convert/pack the whitespace */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen dest = data; last_lwsp = FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen while (*data != '\0') {
d64e7a4e2aa694a4197c392e4531a9df13c95b36Timo Sirainen if (*data == '\t' || *data == ' ' ||
d64e7a4e2aa694a4197c392e4531a9df13c95b36Timo Sirainen *data == '\r' || *data == '\n') {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (!last_lwsp) {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen *dest++ = ' ';
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen last_lwsp = TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen } else {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen *dest++ = *data;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen last_lwsp = FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen *dest = '\0';
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen data = buffer_get_modifiable_data(buf, NULL);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen buffer_set_used_size(buf, (size_t) (dest - data)+1);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainenstatic void remove_subj_trailers(buffer_t *buf, size_t start_pos,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool *is_reply_or_forward_r)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen const char *data;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen size_t orig_size, size;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* subj-trailer = "(fwd)" / WSP */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data = buffer_get_data(buf, &orig_size);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen if (orig_size < 1) /* size includes trailing \0 */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen for (size = orig_size-1; size > start_pos; ) {
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen if (data[size-1] == ' ')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen size--;
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen else if (size >= 5 &&
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen memcmp(data + size - 5, "(FWD)", 5) == 0) {
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *is_reply_or_forward_r = TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen size -= 5;
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen } else {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen break;
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen if (size != orig_size-1) {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen buffer_set_used_size(buf, size);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen buffer_append_c(buf, '\0');
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool remove_blob(const char **datap)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen const char *data = *datap;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data != '[')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
606e46a0f251a2d766a3fb14749f139f4599ee41Timo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen while (*data != '\0' && *data != '[' && *data != ']')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data != ']')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data == ' ')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen *datap = data;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool remove_subj_leader(buffer_t *buf, size_t *start_pos,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool *is_reply_or_forward_r)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen const char *data, *orig_data;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool ret = FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* subj-leader = (*subj-blob subj-refwd) / WSP
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen subj-blob = "[" *BLOBCHAR "]" *WSP
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen BLOBCHAR = %x01-5a / %x5c / %x5e-7f
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen ; any CHAR except '[' and ']' */
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen orig_data = buf->data;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen orig_data += *start_pos;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen data = orig_data;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data == ' ') {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* independent from checks below - always removed */
e45df1587233dad47164123e9f74072520907f41Timo Sirainen data++; orig_data++;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen *start_pos += 1;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen ret = TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen while (*data == '[') {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (!remove_blob(&data))
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return ret;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen if (strncmp(data, "RE", 2) == 0)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data += 2;
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen else if (strncmp(data, "FWD", 3) == 0)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data += 3;
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen else if (strncmp(data, "FW", 2) == 0)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data += 2;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen else
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return ret;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data == ' ')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data == '[' && !remove_blob(&data))
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return ret;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data != ':')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return ret;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen data++;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen *start_pos += (size_t)(data - orig_data);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *is_reply_or_forward_r = TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool remove_blob_when_nonempty(buffer_t *buf, size_t *start_pos)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen const char *data, *orig_data;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen orig_data = buf->data;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen orig_data += *start_pos;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen data = orig_data;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (*data == '[' && remove_blob(&data) && *data != '\0') {
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen *start_pos += (size_t)(data - orig_data);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen }
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainenstatic bool remove_subj_fwd_hdr(buffer_t *buf, size_t *start_pos,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool *is_reply_or_forward_r)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen const char *data = buf->data;
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen size_t size = buf->used;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* subj-fwd = subj-fwd-hdr subject subj-fwd-trl
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen subj-fwd-hdr = "[fwd:"
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen subj-fwd-trl = "]" */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen if (strncmp(data + *start_pos, "[FWD:", 5) != 0)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen if (data[size-2] != ']')
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return FALSE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *is_reply_or_forward_r = TRUE;
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen buffer_set_used_size(buf, size-2);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen buffer_append_c(buf, '\0');
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen *start_pos += 5;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen return TRUE;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainenconst char *imap_get_base_subject_cased(pool_t pool, const char *subject,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool *is_reply_or_forward_r)
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen buffer_t *buf;
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen size_t start_pos, subject_len;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool found;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen *is_reply_or_forward_r = FALSE;
fd4632d0060b2e9eef513b544ccff1e26d1fc222Timo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen subject_len = strlen(subject);
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen buf = buffer_create_dynamic(pool, subject_len);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (1) Convert any RFC 2047 encoded-words in the subject to
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen UTF-8. Convert all tabs and continuations to space.
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen Convert all multiple spaces to a single space. */
bd05299ba9a77310d76cf8aca447d748aeeaa75aTimo Sirainen message_header_decode_utf8((const unsigned char *)subject, subject_len,
d9076f5939edf5d20a261494b1a861dcbb0d32e2Timo Sirainen buf, uni_utf8_to_decomposed_titlecase);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen buffer_append_c(buf, '\0');
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen pack_whitespace(buf);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen start_pos = 0;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen do {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (2) Remove all trailing text of the subject that matches
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen the subj-trailer ABNF, repeat until no more matches are
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen possible. */
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen remove_subj_trailers(buf, start_pos, is_reply_or_forward_r);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen do {
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (3) Remove all prefix text of the subject that
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen matches the subj-leader ABNF. */
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen found = remove_subj_leader(buf, &start_pos,
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen is_reply_or_forward_r);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (4) If there is prefix text of the subject that
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen matches the subj-blob ABNF, and removing that prefix
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen leaves a non-empty subj-base, then remove the prefix
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen text. */
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen found = remove_blob_when_nonempty(buf, &start_pos) ||
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen found;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (5) Repeat (3) and (4) until no matches remain. */
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen } while (found);
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (6) If the resulting text begins with the subj-fwd-hdr ABNF
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen and ends with the subj-fwd-trl ABNF, remove the
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen subj-fwd-hdr and subj-fwd-trl and repeat from step (2). */
ff7f956ac78bd665a536daf25b33266f2e33b7c0Timo Sirainen } while (remove_subj_fwd_hdr(buf, &start_pos, is_reply_or_forward_r));
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen /* (7) The resulting text is the "base subject" used in the
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen SORT. */
f72ce8a49e82ced95ea3b437b0e17f27982e617eTimo Sirainen return (const char *)buf->data + start_pos;
ffed94939ce223a7c801aec3d90b45198dd4462dTimo Sirainen}