diff --git a/src/Makefile.am b/src/Makefile.am index ad8552b..f1eb996 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ mbsync_SOURCES = \ driver.c drv_proxy.c \ drv_imap.c imap_msgs.c \ drv_maildir.c \ - sync.c sync_state.c \ + sync.c sync_state.c sync_msg_cvt.c \ main.c main_sync.c main_list.c noinst_HEADERS = \ common.h config.h socket.h \ diff --git a/src/sync.c b/src/sync.c index dd85d7e..f076241 100644 --- a/src/sync.c +++ b/src/sync.c @@ -79,15 +79,6 @@ sanitize_flags( uchar tflags, sync_vars_t *svars, int t ) } -typedef struct copy_vars { - void (*cb)( int sts, uint uid, struct copy_vars *vars ); - void *aux; - sync_rec_t *srec; /* also ->tuid */ - message_t *msg; - msg_data_t data; - int minimal; -} copy_vars_t; - static void msg_fetched( int sts, void *aux ); static void @@ -103,177 +94,6 @@ copy_msg( copy_vars_t *vars ) static void msg_stored( int sts, uint uid, void *aux ); -static void -copy_msg_bytes( char **out_ptr, const char *in_buf, uint *in_idx, uint in_len, int in_cr, int out_cr ) -{ - char *out = *out_ptr; - uint idx = *in_idx; - if (out_cr != in_cr) { - char c; - if (out_cr) { - for (; idx < in_len; idx++) { - if ((c = in_buf[idx]) != '\r') { - if (c == '\n') - *out++ = '\r'; - *out++ = c; - } - } - } else { - for (; idx < in_len; idx++) { - if ((c = in_buf[idx]) != '\r') - *out++ = c; - } - } - } else { - memcpy( out, in_buf + idx, in_len - idx ); - out += in_len - idx; - idx = in_len; - } - *out_ptr = out; - *in_idx = idx; -} - -static char * -copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars ) -{ - char *in_buf = vars->data.data; - uint in_len = vars->data.len; - uint idx = 0, sbreak = 0, ebreak = 0, break2 = UINT_MAX; - uint lines = 0, hdr_crs = 0, bdy_crs = 0, app_cr = 0, extra = 0; - uint add_subj = 0; - - if (vars->srec) { - nloop: ; - uint start = idx; - uint line_crs = 0; - while (idx < in_len) { - char c = in_buf[idx++]; - if (c == '\r') { - line_crs++; - } else if (c == '\n') { - if (!ebreak && starts_with_upper( in_buf + start, (int)(in_len - start), "X-TUID: ", 8 )) { - extra = (sbreak = start) - (ebreak = idx); - if (!vars->minimal) - goto oke; - } else { - if (break2 == UINT_MAX && vars->minimal && - starts_with_upper( in_buf + start, (int)(in_len - start), "SUBJECT:", 8 )) { - break2 = start + 8; - if (break2 < in_len && in_buf[break2] == ' ') - break2++; - } - lines++; - hdr_crs += line_crs; - } - if (idx - line_crs - 1 == start) { - if (!ebreak) - sbreak = ebreak = start; - if (vars->minimal) { - in_len = idx; - if (break2 == UINT_MAX) { - break2 = start; - add_subj = 1; - } - } - goto oke; - } - goto nloop; - } - } - free( in_buf ); - return "has incomplete header"; - oke: - app_cr = out_cr && (!in_cr || hdr_crs); - extra += 8 + TUIDL + app_cr + 1; - } - if (out_cr != in_cr) { - for (; idx < in_len; idx++) { - char c = in_buf[idx]; - if (c == '\r') - bdy_crs++; - else if (c == '\n') - lines++; - } - extra -= hdr_crs + bdy_crs; - if (out_cr) - extra += lines; - } - - uint dummy_msg_len = 0; - char dummy_msg_buf[256]; - static const char dummy_pfx[] = "[placeholder] "; - static const char dummy_subj[] = "Subject: [placeholder] (No Subject)"; - static const char dummy_msg[] = - "Having a size of %s, this message is over the MaxSize limit.%s" - "Flag it and sync again (Sync mode Upgrade) to fetch its real contents.%s"; - static const char dummy_flag[] = - "%s" - "The original message is flagged as important.%s"; - - if (vars->minimal) { - char sz[32]; - - if (vars->msg->size < 1024000) - sprintf( sz, "%dKiB", (int)(vars->msg->size >> 10) ); - else - sprintf( sz, "%.1fMiB", vars->msg->size / 1048576. ); - const char *nl = app_cr ? "\r\n" : "\n"; - dummy_msg_len = (uint)sprintf( dummy_msg_buf, dummy_msg, sz, nl, nl ); - if (vars->data.flags & F_FLAGGED) { - vars->data.flags &= ~F_FLAGGED; - dummy_msg_len += (uint)sprintf( dummy_msg_buf + dummy_msg_len, dummy_flag, nl, nl ); - } - extra += dummy_msg_len; - extra += add_subj ? strlen(dummy_subj) + app_cr + 1 : strlen(dummy_pfx); - } - - vars->data.len = in_len + extra; - if (vars->data.len > INT_MAX) { - free( in_buf ); - return "is too big after conversion"; - } - char *out_buf = vars->data.data = nfmalloc( vars->data.len ); - idx = 0; - if (vars->srec) { - if (break2 < sbreak) { - copy_msg_bytes( &out_buf, in_buf, &idx, break2, in_cr, out_cr ); - memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) ); - out_buf += strlen(dummy_pfx); - } - copy_msg_bytes( &out_buf, in_buf, &idx, sbreak, in_cr, out_cr ); - - memcpy( out_buf, "X-TUID: ", 8 ); - out_buf += 8; - memcpy( out_buf, vars->srec->tuid, TUIDL ); - out_buf += TUIDL; - if (app_cr) - *out_buf++ = '\r'; - *out_buf++ = '\n'; - idx = ebreak; - - if (break2 != UINT_MAX && break2 >= sbreak) { - copy_msg_bytes( &out_buf, in_buf, &idx, break2, in_cr, out_cr ); - if (!add_subj) { - memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) ); - out_buf += strlen(dummy_pfx); - } else { - memcpy( out_buf, dummy_subj, strlen(dummy_subj) ); - out_buf += strlen(dummy_subj); - if (app_cr) - *out_buf++ = '\r'; - *out_buf++ = '\n'; - } - } - } - copy_msg_bytes( &out_buf, in_buf, &idx, in_len, in_cr, out_cr ); - - if (vars->minimal) - memcpy( out_buf, dummy_msg_buf, dummy_msg_len ); - - free( in_buf ); - return NULL; -} - static void msg_fetched( int sts, void *aux ) { diff --git a/src/sync_msg_cvt.c b/src/sync_msg_cvt.c new file mode 100644 index 0000000..4f8403e --- /dev/null +++ b/src/sync_msg_cvt.c @@ -0,0 +1,179 @@ +// SPDX-FileCopyrightText: 2000-2002 Michael R. Elkins +// SPDX-FileCopyrightText: 2002-2022 Oswald Buddenhagen +// SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-isync-GPL-exception +// +// mbsync - mailbox synchronizer +// + +#include "sync_p.h" + +static void +copy_msg_bytes( char **out_ptr, const char *in_buf, uint *in_idx, uint in_len, int in_cr, int out_cr ) +{ + char *out = *out_ptr; + uint idx = *in_idx; + if (out_cr != in_cr) { + char c; + if (out_cr) { + for (; idx < in_len; idx++) { + if ((c = in_buf[idx]) != '\r') { + if (c == '\n') + *out++ = '\r'; + *out++ = c; + } + } + } else { + for (; idx < in_len; idx++) { + if ((c = in_buf[idx]) != '\r') + *out++ = c; + } + } + } else { + memcpy( out, in_buf + idx, in_len - idx ); + out += in_len - idx; + idx = in_len; + } + *out_ptr = out; + *in_idx = idx; +} + +char * +copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars ) +{ + char *in_buf = vars->data.data; + uint in_len = vars->data.len; + uint idx = 0, sbreak = 0, ebreak = 0, break2 = UINT_MAX; + uint lines = 0, hdr_crs = 0, bdy_crs = 0, app_cr = 0, extra = 0; + uint add_subj = 0; + + if (vars->srec) { + nloop: ; + uint start = idx; + uint line_crs = 0; + while (idx < in_len) { + char c = in_buf[idx++]; + if (c == '\r') { + line_crs++; + } else if (c == '\n') { + if (!ebreak && starts_with_upper( in_buf + start, (int)(in_len - start), "X-TUID: ", 8 )) { + extra = (sbreak = start) - (ebreak = idx); + if (!vars->minimal) + goto oke; + } else { + if (break2 == UINT_MAX && vars->minimal && + starts_with_upper( in_buf + start, (int)(in_len - start), "SUBJECT:", 8 )) { + break2 = start + 8; + if (break2 < in_len && in_buf[break2] == ' ') + break2++; + } + lines++; + hdr_crs += line_crs; + } + if (idx - line_crs - 1 == start) { + if (!ebreak) + sbreak = ebreak = start; + if (vars->minimal) { + in_len = idx; + if (break2 == UINT_MAX) { + break2 = start; + add_subj = 1; + } + } + goto oke; + } + goto nloop; + } + } + free( in_buf ); + return "has incomplete header"; + oke: + app_cr = out_cr && (!in_cr || hdr_crs); + extra += 8 + TUIDL + app_cr + 1; + } + if (out_cr != in_cr) { + for (; idx < in_len; idx++) { + char c = in_buf[idx]; + if (c == '\r') + bdy_crs++; + else if (c == '\n') + lines++; + } + extra -= hdr_crs + bdy_crs; + if (out_cr) + extra += lines; + } + + uint dummy_msg_len = 0; + char dummy_msg_buf[256]; + static const char dummy_pfx[] = "[placeholder] "; + static const char dummy_subj[] = "Subject: [placeholder] (No Subject)"; + static const char dummy_msg[] = + "Having a size of %s, this message is over the MaxSize limit.%s" + "Flag it and sync again (Sync mode Upgrade) to fetch its real contents.%s"; + static const char dummy_flag[] = + "%s" + "The original message is flagged as important.%s"; + + if (vars->minimal) { + char sz[32]; + + if (vars->msg->size < 1024000) + sprintf( sz, "%dKiB", (int)(vars->msg->size >> 10) ); + else + sprintf( sz, "%.1fMiB", vars->msg->size / 1048576. ); + const char *nl = app_cr ? "\r\n" : "\n"; + dummy_msg_len = (uint)sprintf( dummy_msg_buf, dummy_msg, sz, nl, nl ); + if (vars->data.flags & F_FLAGGED) { + vars->data.flags &= ~F_FLAGGED; + dummy_msg_len += (uint)sprintf( dummy_msg_buf + dummy_msg_len, dummy_flag, nl, nl ); + } + extra += dummy_msg_len; + extra += add_subj ? strlen(dummy_subj) + app_cr + 1 : strlen(dummy_pfx); + } + + vars->data.len = in_len + extra; + if (vars->data.len > INT_MAX) { + free( in_buf ); + return "is too big after conversion"; + } + char *out_buf = vars->data.data = nfmalloc( vars->data.len ); + idx = 0; + if (vars->srec) { + if (break2 < sbreak) { + copy_msg_bytes( &out_buf, in_buf, &idx, break2, in_cr, out_cr ); + memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) ); + out_buf += strlen(dummy_pfx); + } + copy_msg_bytes( &out_buf, in_buf, &idx, sbreak, in_cr, out_cr ); + + memcpy( out_buf, "X-TUID: ", 8 ); + out_buf += 8; + memcpy( out_buf, vars->srec->tuid, TUIDL ); + out_buf += TUIDL; + if (app_cr) + *out_buf++ = '\r'; + *out_buf++ = '\n'; + idx = ebreak; + + if (break2 != UINT_MAX && break2 >= sbreak) { + copy_msg_bytes( &out_buf, in_buf, &idx, break2, in_cr, out_cr ); + if (!add_subj) { + memcpy( out_buf, dummy_pfx, strlen(dummy_pfx) ); + out_buf += strlen(dummy_pfx); + } else { + memcpy( out_buf, dummy_subj, strlen(dummy_subj) ); + out_buf += strlen(dummy_subj); + if (app_cr) + *out_buf++ = '\r'; + *out_buf++ = '\n'; + } + } + } + copy_msg_bytes( &out_buf, in_buf, &idx, in_len, in_cr, out_cr ); + + if (vars->minimal) + memcpy( out_buf, dummy_msg_buf, dummy_msg_len ); + + free( in_buf ); + return NULL; +} diff --git a/src/sync_p.h b/src/sync_p.h index ada2084..66f09e4 100644 --- a/src/sync_p.h +++ b/src/sync_p.h @@ -103,3 +103,14 @@ void assign_tuid( sync_vars_t *svars, sync_rec_t *srec ); int match_tuids( sync_vars_t *svars, int t, message_t *msgs ); sync_rec_t *upgrade_srec( sync_vars_t *svars, sync_rec_t *srec, int t ); + +typedef struct copy_vars { + void (*cb)( int sts, uint uid, struct copy_vars *vars ); + void *aux; + sync_rec_t *srec; /* also ->tuid */ + message_t *msg; + msg_data_t data; + int minimal; +} copy_vars_t; + +char *copy_msg_convert( int in_cr, int out_cr, copy_vars_t *vars );