1
/* Copyright (c) 2002-2015 Pigeonhole authors, see the included COPYING file
9
#include "istream-private.h"
10
#include "master-service.h"
11
#include "master-service-settings.h"
12
#include "message-parser.h"
13
#include "message-header-encode.h"
14
#include "message-header-decode.h"
15
#include "mail-user.h"
16
#include "mail-storage-private.h"
17
#include "index-mail.h"
18
#include "raw-storage.h"
22
#include "edit-mail.h"
25
* Forward declarations
28
struct _header_field_index;
33
static struct mail_vfuncs edit_mail_vfuncs;
35
struct edit_mail_istream;
36
struct istream *edit_mail_istream_create(struct edit_mail *edmail);
38
static struct _header_index *edit_mail_header_clone
39
(struct edit_mail *edmail, struct _header *header);
45
static struct mail_user *edit_mail_user = NULL;
46
static unsigned int edit_mail_refcount = 0;
48
static struct mail_user *edit_mail_raw_storage_get(struct mail_user *mail_user)
50
if ( edit_mail_user == NULL ) {
51
void **sets = master_service_settings_get_others(master_service);
53
edit_mail_user = raw_storage_create_from_set(mail_user->set_info, sets[0]);
58
return edit_mail_user;
61
static void edit_mail_raw_storage_drop(void)
63
i_assert(edit_mail_refcount > 0);
65
if ( --edit_mail_refcount != 0)
68
mail_user_unref(&edit_mail_user);
69
edit_mail_user = NULL;
76
struct _header_field {
77
struct _header *header;
79
unsigned int refcount;
92
struct _header_field_index {
93
struct _header_field_index *prev, *next;
95
struct _header_field *field;
96
struct _header_index *header;
100
unsigned int refcount;
105
struct _header_index {
106
struct _header_index *prev, *next;
108
struct _header *header;
110
struct _header_field_index *first, *last;
115
static inline struct _header *_header_create(const char *name)
117
struct _header *header;
119
header = i_new(struct _header, 1);
120
header->name = i_strdup(name);
121
header->refcount = 1;
126
static inline void _header_ref(struct _header *header)
131
static inline void _header_unref(struct _header *header)
133
i_assert( header->refcount > 0 );
134
if ( --header->refcount != 0 )
137
i_free(header->name);
141
static inline struct _header_field *_header_field_create(struct _header *header)
143
struct _header_field *hfield;
145
hfield = i_new(struct _header_field, 1);
146
hfield->refcount = 1;
147
hfield->header = header;
148
if ( header != NULL )
154
static inline void _header_field_ref(struct _header_field *hfield)
159
static inline void _header_field_unref(struct _header_field *hfield)
161
i_assert( hfield->refcount > 0 );
162
if ( --hfield->refcount != 0 )
165
if ( hfield->header != NULL )
166
_header_unref(hfield->header);
168
if ( hfield->data != NULL )
169
i_free(hfield->data);
170
if ( hfield->utf8_value != NULL )
171
i_free(hfield->utf8_value);
180
struct mail_private mail;
181
struct mail_private *wrapped;
183
struct edit_mail *parent;
184
unsigned int refcount;
186
struct istream *wrapped_stream;
187
struct istream *stream;
189
struct _header_index *headers_head, *headers_tail;
190
struct _header_field_index *header_fields_head, *header_fields_tail;
191
struct message_size hdr_size, body_size;
193
struct message_size wrapped_hdr_size, wrapped_body_size;
195
struct _header_field_index *header_fields_appended;
196
struct message_size appended_hdr_size;
198
unsigned int modified:1;
199
unsigned int snapshot_modified:1;
201
unsigned int eoh_crlf:1;
202
unsigned int headers_parsed:1;
203
unsigned int destroying_stream:1;
206
struct edit_mail *edit_mail_wrap(struct mail *mail)
208
struct mail_private *mailp = (struct mail_private *) mail;
209
struct edit_mail *edmail;
210
struct mail_user *raw_mail_user;
211
struct mailbox *raw_box = NULL;
212
struct mailbox_transaction_context *raw_trans;
213
struct message_size hdr_size, body_size;
214
struct istream *wrapped_stream;
218
if ( mail_get_stream(mail, &hdr_size, &body_size, &wrapped_stream) < 0 ) {
222
/* Create dummy raw mailbox for our wrapper */
224
raw_mail_user = edit_mail_raw_storage_get(mail->box->storage->user);
226
if ( raw_mailbox_alloc_stream(raw_mail_user, wrapped_stream, (time_t)-1,
227
"editor@example.com", &raw_box) < 0 ) {
228
i_error("edit-mail: failed to open raw box: %s",
229
mailbox_get_last_error(raw_box, NULL));
230
mailbox_free(&raw_box);
231
edit_mail_raw_storage_drop();
235
raw_trans = mailbox_transaction_begin(raw_box, 0);
237
/* Create the wrapper mail */
239
pool = pool_alloconly_create("edit_mail", 1024);
240
edmail = p_new(pool, struct edit_mail, 1);
241
edmail->refcount = 1;
242
edmail->mail.pool = pool;
244
edmail->wrapped = mailp;
245
edmail->wrapped_hdr_size = hdr_size;
246
edmail->wrapped_body_size = body_size;
248
edmail->wrapped_stream = wrapped_stream;
249
i_stream_ref(edmail->wrapped_stream);
251
/* Determine whether we should use CRLF or LF for the physical message */
252
size_diff = (hdr_size.virtual_size + body_size.virtual_size) -
253
(hdr_size.physical_size + body_size.physical_size);
254
if ( size_diff == 0 || size_diff <= (hdr_size.lines + body_size.lines)/2 )
255
edmail->crlf = edmail->eoh_crlf = TRUE;
257
array_create(&edmail->mail.module_contexts, pool, sizeof(void *), 5);
259
edmail->mail.v = edit_mail_vfuncs;
260
edmail->mail.mail.seq = 1;
261
edmail->mail.mail.box = raw_box;
262
edmail->mail.mail.transaction = raw_trans;
263
edmail->mail.wanted_fields = mailp->wanted_fields;
264
edmail->mail.wanted_headers = mailp->wanted_headers;
269
struct edit_mail *edit_mail_snapshot(struct edit_mail *edmail)
271
struct _header_field_index *field_idx, *field_idx_new;
272
struct edit_mail *edmail_new;
275
if ( !edmail->snapshot_modified ) {
279
pool = pool_alloconly_create("edit_mail", 1024);
280
edmail_new = p_new(pool, struct edit_mail, 1);
281
edmail_new->refcount = 1;
282
edmail_new->mail.pool = pool;
284
edmail_new->wrapped = edmail->wrapped;
285
edmail_new->wrapped_hdr_size = edmail->wrapped_hdr_size;
286
edmail_new->wrapped_body_size = edmail->wrapped_body_size;
287
edmail_new->hdr_size = edmail->hdr_size;
288
edmail_new->body_size = edmail->body_size;
289
edmail_new->appended_hdr_size = edmail->appended_hdr_size;
291
edmail_new->wrapped_stream = edmail->wrapped_stream;
292
i_stream_ref(edmail_new->wrapped_stream);
294
edmail_new->crlf = edmail->crlf;
295
edmail_new->eoh_crlf = edmail->eoh_crlf;
297
array_create(&edmail_new->mail.module_contexts, pool, sizeof(void *), 5);
299
edmail_new->mail.v = edit_mail_vfuncs;
300
edmail_new->mail.mail.seq = 1;
301
edmail_new->mail.mail.box = edmail->mail.mail.box;
302
edmail_new->mail.mail.transaction = edmail->mail.mail.transaction;
303
edmail_new->mail.wanted_fields = edmail->mail.wanted_fields;
304
edmail_new->mail.wanted_headers = edmail->mail.wanted_headers;
306
edmail_new->stream = NULL;
308
if ( edmail->modified ) {
309
field_idx = edmail->header_fields_head;
310
while ( field_idx != NULL ) {
311
struct _header_field_index *next = field_idx->next;
313
field_idx_new = i_new(struct _header_field_index, 1);
315
field_idx_new->header =
316
edit_mail_header_clone(edmail_new, field_idx->header->header);
318
field_idx_new->field = field_idx->field;
319
_header_field_ref(field_idx_new->field);
322
(&edmail_new->header_fields_head, &edmail_new->header_fields_tail,
325
field_idx_new->header->count++;
326
if ( field_idx->header->first == field_idx )
327
field_idx_new->header->first = field_idx_new;
328
if ( field_idx->header->last == field_idx )
329
field_idx_new->header->last = field_idx_new;
331
if ( field_idx == edmail->header_fields_appended )
332
edmail_new->header_fields_appended = field_idx_new;
337
edmail_new->modified = TRUE;
340
edmail_new->headers_parsed = edmail->headers_parsed;
342
edmail_new->parent = edmail;
343
//edmail->refcount++;
348
void edit_mail_reset(struct edit_mail *edmail)
350
struct _header_index *header_idx;
351
struct _header_field_index *field_idx;
353
if ( edmail->stream != NULL ) {
354
i_stream_unref(&edmail->stream);
355
edmail->stream = NULL;
358
field_idx = edmail->header_fields_head;
359
while ( field_idx != NULL ) {
360
struct _header_field_index *next = field_idx->next;
362
_header_field_unref(field_idx->field);
368
header_idx = edmail->headers_head;
369
while ( header_idx != NULL ) {
370
struct _header_index *next = header_idx->next;
372
_header_unref(header_idx->header);
378
edmail->modified = FALSE;
381
void edit_mail_unwrap(struct edit_mail **edmail)
383
struct edit_mail *parent;
385
i_assert( (*edmail)->refcount > 0 );
386
if ( --(*edmail)->refcount != 0 )
389
edit_mail_reset(*edmail);
391
if ( (*edmail)->wrapped_stream != NULL ) {
392
i_stream_unref(&(*edmail)->wrapped_stream);
393
(*edmail)->wrapped_stream = NULL;
396
parent = (*edmail)->parent;
398
if ( parent == NULL ) {
399
mailbox_transaction_rollback(&(*edmail)->mail.mail.transaction);
400
mailbox_free(&(*edmail)->mail.mail.box);
401
edit_mail_raw_storage_drop();
404
pool_unref(&(*edmail)->mail.pool);
407
if ( parent != NULL )
408
edit_mail_unwrap(&parent);
411
struct mail *edit_mail_get_mail(struct edit_mail *edmail)
413
/* Return wrapped mail when nothing is modified yet */
414
if ( !edmail->modified )
415
return &edmail->wrapped->mail;
417
return &edmail->mail.mail;
424
static inline void edit_mail_modify(struct edit_mail *edmail)
426
edmail->mail.mail.seq++;
427
edmail->modified = TRUE;
428
edmail->snapshot_modified = TRUE;
431
/* Header modification */
433
static inline char *_header_value_unfold
439
for ( i = 0; value[i] != '\0'; i++ ) {
440
if (value[i] == '\r' || value[i] == '\n')
443
if ( value[i] == '\0' ) {
444
return i_strdup(value);
447
out = t_str_new(i + strlen(value+i) + 10);
448
str_append_n(out, value, i);
449
for ( ; value[i] != '\0'; i++ ) {
450
if (value[i] == '\n') {
452
if (value[i] == '\0')
455
switch ( value[i] ) {
457
str_append_c(out, ' ');
461
str_append_c(out, '\t');
464
if (value[i] != '\r')
465
str_append_c(out, value[i]);
469
return i_strndup(str_c(out), str_len(out));
472
static struct _header_index *edit_mail_header_find
473
(struct edit_mail *edmail, const char *field_name)
475
struct _header_index *header_idx;
477
header_idx = edmail->headers_head;
478
while ( header_idx != NULL ) {
479
if ( strcasecmp(header_idx->header->name, field_name) == 0 )
482
header_idx = header_idx->next;
488
static struct _header_index *edit_mail_header_create
489
(struct edit_mail *edmail, const char *field_name)
491
struct _header_index *header_idx;
493
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ) {
494
header_idx = i_new(struct _header_index, 1);
495
header_idx->header = _header_create(field_name);
497
DLLIST2_APPEND(&edmail->headers_head, &edmail->headers_tail, header_idx);
503
static struct _header_index *edit_mail_header_clone
504
(struct edit_mail *edmail, struct _header *header)
506
struct _header_index *header_idx;
508
header_idx = edmail->headers_head;
509
while ( header_idx != NULL ) {
510
if ( header_idx->header == header )
513
header_idx = header_idx->next;
516
header_idx = i_new(struct _header_index, 1);
517
header_idx->header = header;
519
DLLIST2_APPEND(&edmail->headers_head, &edmail->headers_tail, header_idx);
524
static struct _header_field_index *
525
edit_mail_header_field_create
526
(struct edit_mail *edmail, const char *field_name, const char *value)
528
struct _header_index *header_idx;
529
struct _header *header;
530
struct _header_field_index *field_idx;
531
struct _header_field *field;
534
/* Get/create header index item */
535
header_idx = edit_mail_header_create(edmail, field_name);
536
header = header_idx->header;
538
/* Create new field index item */
539
field_idx = i_new(struct _header_field_index, 1);
540
field_idx->header = header_idx;
541
field_idx->field = field = _header_field_create(header);
543
/* Create header field data (folded if necessary) */
545
string_t *enc_value, *data;
547
enc_value = t_str_new(strlen(field_name) + strlen(value) + 64);
548
data = t_str_new(strlen(field_name) + strlen(value) + 128);
550
message_header_encode(value, enc_value);
552
lines = rfc2822_header_append
553
(data, field_name, str_c(enc_value), edmail->crlf, &field->body_offset);
555
/* Copy to new field */
556
field->data = i_strndup(str_data(data), str_len(data));
557
field->size = str_len(data);
558
field->virtual_size = ( edmail->crlf ? field->size : field->size + lines );
559
field->lines = lines;
562
/* Record original (utf8) value */
563
field->utf8_value = _header_value_unfold(value);
568
static void edit_mail_header_field_delete
569
(struct edit_mail *edmail, struct _header_field_index *field_idx,
572
struct _header_index *header_idx = field_idx->header;
573
struct _header_field *field = field_idx->field;
575
i_assert( header_idx != NULL );
577
edmail->hdr_size.physical_size -= field->size;
578
edmail->hdr_size.virtual_size -= field->virtual_size;
579
edmail->hdr_size.lines -= field->lines;
582
if ( update_index ) {
583
if ( header_idx->count == 0 ) {
584
DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail, header_idx);
585
_header_unref(header_idx->header);
587
} else if ( header_idx->first == field_idx ) {
588
struct _header_field_index *hfield = header_idx->first->next;
590
while ( hfield != NULL && hfield->header != header_idx ) {
591
hfield = hfield->next;
594
i_assert( hfield != NULL );
595
header_idx->first = hfield;
596
} else if ( header_idx->last == field_idx ) {
597
struct _header_field_index *hfield = header_idx->last->prev;
599
while ( hfield != NULL && hfield->header != header_idx ) {
600
hfield = hfield->prev;
603
i_assert( hfield != NULL );
604
header_idx->last = hfield;
609
(&edmail->header_fields_head, &edmail->header_fields_tail, field_idx);
610
_header_field_unref(field_idx->field);
614
static struct _header_field_index *
615
edit_mail_header_field_replace
616
(struct edit_mail *edmail, struct _header_field_index *field_idx,
617
const char *newname, const char *newvalue, bool update_index)
619
struct _header_field_index *field_idx_new;
620
struct _header_index *header_idx = field_idx->header, *header_idx_new;
621
struct _header_field *field = field_idx->field, *field_new;
623
i_assert( header_idx != NULL );
624
i_assert( newname != NULL || newvalue != NULL );
626
if ( newname == NULL )
627
newname = header_idx->header->name;
628
if ( newvalue == NULL )
629
newvalue = field_idx->field->utf8_value;
630
field_idx_new = edit_mail_header_field_create
631
(edmail, newname, newvalue);
632
field_new = field_idx_new->field;
633
header_idx_new = field_idx_new->header;
635
edmail->hdr_size.physical_size -= field->size;
636
edmail->hdr_size.virtual_size -= field->virtual_size;
637
edmail->hdr_size.lines -= field->lines;
639
edmail->hdr_size.physical_size += field_new->size;
640
edmail->hdr_size.virtual_size += field_new->virtual_size;
641
edmail->hdr_size.lines += field_new->lines;
643
/* Replace header field index */
644
field_idx_new->prev = field_idx->prev;
645
field_idx_new->next = field_idx->next;
646
if ( field_idx->prev != NULL )
647
field_idx->prev->next = field_idx_new;
648
if ( field_idx->next != NULL )
649
field_idx->next->prev = field_idx_new;
650
if (edmail->header_fields_head == field_idx)
651
edmail->header_fields_head = field_idx_new;
652
if (edmail->header_fields_tail == field_idx)
653
edmail->header_fields_tail = field_idx_new;
655
if ( header_idx_new == header_idx ) {
656
if (header_idx->first == field_idx)
657
header_idx->first = field_idx_new;
658
if (header_idx->last == field_idx)
659
header_idx->last = field_idx_new;
662
header_idx_new->count++;
664
if ( update_index ) {
665
if ( header_idx->count == 0 ) {
666
DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail, header_idx);
667
_header_unref(header_idx->header);
669
} else if ( header_idx->first == field_idx ) {
670
struct _header_field_index *hfield = header_idx->first->next;
672
while ( hfield != NULL && hfield->header != header_idx ) {
673
hfield = hfield->next;
676
i_assert( hfield != NULL );
677
header_idx->first = hfield;
678
} else if ( header_idx->last == field_idx ) {
679
struct _header_field_index *hfield = header_idx->last->prev;
681
while ( hfield != NULL && hfield->header != header_idx ) {
682
hfield = hfield->prev;
685
i_assert( hfield != NULL );
686
header_idx->last = hfield;
688
if ( header_idx_new->count > 0 ) {
689
struct _header_field_index *hfield;
691
hfield = edmail->header_fields_head;
692
while ( hfield != NULL && hfield->header != header_idx_new ) {
693
hfield = hfield->next;
696
i_assert( hfield != NULL );
697
header_idx_new->first = hfield;
699
hfield = edmail->header_fields_tail;
700
while ( hfield != NULL && hfield->header != header_idx_new ) {
701
hfield = hfield->prev;
704
i_assert( hfield != NULL );
705
header_idx_new->last = hfield;
710
_header_field_unref(field_idx->field);
712
return field_idx_new;
715
static inline char *_header_decode
716
(const unsigned char *hdr_data, size_t hdr_data_len)
718
string_t *str = t_str_new(512);
720
/* hdr_data is already unfolded */
722
/* Decode MIME encoded-words. */
723
message_header_decode_utf8
724
((const unsigned char *)hdr_data, hdr_data_len, str, FALSE);
725
return i_strdup(str_c(str));
728
static int edit_mail_headers_parse
729
(struct edit_mail *edmail)
731
struct message_header_parser_ctx *hparser;
732
enum message_header_parser_flags hparser_flags =
733
MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
734
MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
735
struct message_header_line *hdr;
736
struct _header_index *header_idx;
737
struct _header_field_index *head = NULL, *tail = NULL, *current;
739
uoff_t offset = 0, body_offset = 0, vsize_diff = 0;
740
unsigned int lines = 0;
743
if ( edmail->headers_parsed ) return 1;
745
i_stream_seek(edmail->wrapped_stream, 0);
746
hparser = message_parse_header_init
747
(edmail->wrapped_stream, NULL, hparser_flags);
750
hdr_data = t_str_new(1024);
751
while ( (ret=message_parse_header_next(hparser, &hdr)) > 0 ) {
752
struct _header_field_index *field_idx_new;
753
struct _header_field *field;
756
/* Record whether header ends in CRLF or LF */
757
edmail->eoh_crlf = hdr->crlf_newline;
760
if ( hdr == NULL || hdr->eoh ) break;
762
/* We deny the existence of any `Content-Length:' header. This header is
763
* non-standard and it can wreak havok when the message is modified.
765
if ( strcasecmp(hdr->name, "Content-Length" ) == 0 )
768
if ( hdr->continued ) {
769
/* Continued line of folded header */
770
buffer_append(hdr_data, hdr->value, hdr->value_len);
772
/* First line of header */
773
offset = hdr->name_offset;
774
body_offset = hdr->name_len + hdr->middle_len;
775
str_truncate(hdr_data, 0);
776
buffer_append(hdr_data, hdr->name, hdr->name_len);
777
buffer_append(hdr_data, hdr->middle, hdr->middle_len);
778
buffer_append(hdr_data, hdr->value, hdr->value_len);
783
if ( !hdr->no_newline ) {
786
if ( hdr->crlf_newline ) {
787
buffer_append(hdr_data, "\r\n", 2);
789
buffer_append(hdr_data, "\n", 1);
794
if ( hdr->continues ) {
795
hdr->use_full_value = TRUE;
799
/* Create new header field index entry */
801
field_idx_new = i_new(struct _header_field_index, 1);
803
header_idx = edit_mail_header_create(edmail, hdr->name);
805
field_idx_new->header = header_idx;
806
field_idx_new->field = field = _header_field_create(header_idx->header);
808
i_assert( body_offset > 0 );
809
field->body_offset = body_offset;
811
field->utf8_value = _header_decode(hdr->full_value, hdr->full_value_len);
813
field->size = str_len(hdr_data);
814
field->virtual_size = field->size + vsize_diff;
815
field->data = i_strndup(str_data(hdr_data), field->size);
816
field->offset = offset;
817
field->lines = lines;
819
DLLIST2_APPEND(&head, &tail, field_idx_new);
821
edmail->hdr_size.physical_size += field->size;
822
edmail->hdr_size.virtual_size += field->virtual_size;
823
edmail->hdr_size.lines += lines;
827
message_parse_header_deinit(&hparser);
830
/* blocking i/o required */
831
i_assert( ret != 0 );
833
/* Error; clean up */
835
while ( current != NULL ) {
836
struct _header_field_index *next = current->next;
838
_header_field_unref(current->field);
847
/* Insert header field index items in main list */
848
if ( head != NULL && tail != NULL ) {
849
if ( edmail->header_fields_appended != NULL ) {
850
if ( edmail->header_fields_head != edmail->header_fields_appended ) {
851
edmail->header_fields_appended->prev->next = head;
852
head->prev = edmail->header_fields_appended->prev;
854
edmail->header_fields_head = head;
857
tail->next = edmail->header_fields_appended;
858
edmail->header_fields_appended->prev = tail;
859
} else if ( edmail->header_fields_tail != NULL ) {
860
edmail->header_fields_tail->next = head;
861
head->prev = edmail->header_fields_tail;
862
edmail->header_fields_tail = tail;
864
edmail->header_fields_head = head;
865
edmail->header_fields_tail = tail;
869
/* Rebuild header index */
870
current = edmail->header_fields_head;
871
while ( current != NULL ) {
872
if ( current->header->first == NULL )
873
current->header->first = current;
874
current->header->last = current;
876
current = current->next;
879
/* Clear appended headers */
880
edmail->header_fields_appended = NULL;
881
edmail->appended_hdr_size.physical_size = 0;
882
edmail->appended_hdr_size.virtual_size = 0;
883
edmail->appended_hdr_size.lines = 0;
885
/* Do not parse headers again */
886
edmail->headers_parsed = TRUE;
891
void edit_mail_header_add
892
(struct edit_mail *edmail, const char *field_name, const char *value,
895
struct _header_index *header_idx;
896
struct _header_field_index *field_idx;
897
struct _header_field *field;
899
edit_mail_modify(edmail);
901
field_idx = edit_mail_header_field_create(edmail, field_name, value);
902
header_idx = field_idx->header;
903
field = field_idx->field;
905
/* Add it to the header field index */
908
(&edmail->header_fields_head, &edmail->header_fields_tail, field_idx);
910
header_idx->last = field_idx;
911
if ( header_idx->first == NULL )
912
header_idx->first = field_idx;
914
if ( !edmail->headers_parsed ) {
915
if ( edmail->header_fields_appended == NULL ) {
916
/* Record beginning of appended headers */
917
edmail->header_fields_appended = field_idx;
920
edmail->appended_hdr_size.physical_size += field->size;
921
edmail->appended_hdr_size.virtual_size += field->virtual_size;
922
edmail->appended_hdr_size.lines += field->lines;
926
(&edmail->header_fields_head, &edmail->header_fields_tail, field_idx);
928
header_idx->first = field_idx;
929
if ( header_idx->last == NULL )
930
header_idx->last = field_idx;
935
edmail->hdr_size.physical_size += field->size;
936
edmail->hdr_size.virtual_size += field->virtual_size;
937
edmail->hdr_size.lines += field->lines;
940
int edit_mail_header_delete
941
(struct edit_mail *edmail, const char *field_name, int index)
943
struct _header_index *header_idx;
944
struct _header_field_index *field_idx;
948
/* Make sure headers are parsed */
949
if ( edit_mail_headers_parse(edmail) <= 0 )
952
/* Find the header entry */
953
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ) {
958
/* Signal modification */
959
edit_mail_modify(edmail);
961
/* Iterate through all header fields and remove those that match */
962
field_idx = ( index >= 0 ? header_idx->first : header_idx->last );
963
while ( field_idx != NULL ) {
964
struct _header_field_index *next =
965
( index >= 0 ? field_idx->next : field_idx->prev );
967
if ( field_idx->field->header == header_idx->header ) {
972
final = ( header_idx->last == field_idx );
975
final = ( header_idx->first == field_idx );
978
if ( index == 0 || index == pos ) {
979
if ( header_idx->first == field_idx ) header_idx->first = NULL;
980
if ( header_idx->last == field_idx ) header_idx->last = NULL;
981
edit_mail_header_field_delete(edmail, field_idx, FALSE);
985
if ( final || (index != 0 && index == pos) )
992
if ( index == 0 || header_idx->count == 0 ) {
993
DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail, header_idx);
994
_header_unref(header_idx->header);
996
} else if ( header_idx->first == NULL || header_idx->last == NULL ) {
997
struct _header_field_index *current = edmail->header_fields_head;
999
while ( current != NULL ) {
1000
if ( current->header == header_idx ) {
1001
if ( header_idx->first == NULL )
1002
header_idx->first = current;
1003
header_idx->last = current;
1005
current = current->next;
1012
int edit_mail_header_replace
1013
(struct edit_mail *edmail, const char *field_name, int index,
1014
const char *newname, const char *newvalue)
1016
struct _header_index *header_idx, *header_idx_new;
1017
struct _header_field_index *field_idx, *field_idx_new;
1021
/* Make sure headers are parsed */
1022
if ( edit_mail_headers_parse(edmail) <= 0 )
1025
/* Find the header entry */
1026
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ) {
1031
/* Signal modification */
1032
edit_mail_modify(edmail);
1034
/* Iterate through all header fields and replace those that match */
1035
field_idx = ( index >= 0 ? header_idx->first : header_idx->last );
1036
field_idx_new = NULL;
1037
while ( field_idx != NULL ) {
1038
struct _header_field_index *next =
1039
( index >= 0 ? field_idx->next : field_idx->prev );
1041
if ( field_idx->field->header == header_idx->header ) {
1046
final = ( header_idx->last == field_idx );
1049
final = ( header_idx->first == field_idx );
1052
if ( index == 0 || index == pos ) {
1053
if ( header_idx->first == field_idx ) header_idx->first = NULL;
1054
if ( header_idx->last == field_idx ) header_idx->last = NULL;
1055
field_idx_new = edit_mail_header_field_replace
1056
(edmail, field_idx, newname, newvalue, FALSE);
1060
if ( final || (index != 0 && index == pos) )
1067
/* Update old header index */
1068
if ( header_idx->count == 0 ) {
1069
DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail, header_idx);
1070
_header_unref(header_idx->header);
1072
} else if ( header_idx->first == NULL || header_idx->last == NULL ) {
1073
struct _header_field_index *current = edmail->header_fields_head;
1075
while ( current != NULL ) {
1076
if ( current->header == header_idx ) {
1077
if ( header_idx->first == NULL )
1078
header_idx->first = current;
1079
header_idx->last = current;
1081
current = current->next;
1085
/* Update new header index */
1086
if ( field_idx_new != NULL ) {
1087
struct _header_field_index *current = edmail->header_fields_head;
1089
header_idx_new = field_idx_new->header;
1090
while ( current != NULL ) {
1091
if ( current->header == header_idx_new ) {
1092
if ( header_idx_new->first == NULL )
1093
header_idx_new->first = current;
1094
header_idx_new->last = current;
1096
current = current->next;
1103
struct edit_mail_header_iter
1105
struct edit_mail *mail;
1106
struct _header_index *header;
1107
struct _header_field_index *current;
1109
unsigned int reverse:1;
1112
int edit_mail_headers_iterate_init
1113
(struct edit_mail *edmail, const char *field_name, bool reverse,
1114
struct edit_mail_header_iter **edhiter_r)
1116
struct edit_mail_header_iter *edhiter;
1117
struct _header_index *header_idx = NULL;
1118
struct _header_field_index *current = NULL;
1120
/* Make sure headers are parsed */
1121
if ( edit_mail_headers_parse(edmail) <= 0 ) {
1126
header_idx = edit_mail_header_find(edmail, field_name);
1128
if ( field_name != NULL && header_idx == NULL ) {
1130
} else if ( !reverse ) {
1132
( header_idx != NULL ? header_idx->first : edmail->header_fields_head );
1135
( header_idx != NULL ? header_idx->last : edmail->header_fields_tail );
1136
if ( current->header == NULL )
1137
current = current->prev;
1140
if ( current == NULL )
1143
edhiter = i_new(struct edit_mail_header_iter, 1);
1144
edhiter->mail = edmail;
1145
edhiter->header = header_idx;
1146
edhiter->reverse = reverse;
1147
edhiter->current = current;
1149
*edhiter_r = edhiter;
1153
void edit_mail_headers_iterate_deinit
1154
(struct edit_mail_header_iter **edhiter)
1160
void edit_mail_headers_iterate_get
1161
(struct edit_mail_header_iter *edhiter, const char **value_r)
1166
i_assert( edhiter->current != NULL && edhiter->current->header != NULL);
1168
raw = edhiter->current->field->utf8_value;
1169
for ( i = strlen(raw)-1; i >= 0; i-- ) {
1170
if ( raw[i] != ' ' && raw[i] != '\t' ) break;
1173
*value_r = t_strndup(raw, i+1);
1176
bool edit_mail_headers_iterate_next
1177
(struct edit_mail_header_iter *edhiter)
1179
if ( edhiter->current == NULL )
1184
( !edhiter->reverse ? edhiter->current->next : edhiter->current->prev );
1185
} while ( edhiter->current != NULL && edhiter->current->header != NULL &&
1186
edhiter->header != NULL && edhiter->current->header != edhiter->header );
1188
return ( edhiter->current != NULL && edhiter->current->header != NULL);
1191
bool edit_mail_headers_iterate_remove
1192
(struct edit_mail_header_iter *edhiter)
1194
struct _header_field_index *field_idx;
1197
i_assert( edhiter->current != NULL && edhiter->current->header != NULL);
1199
edit_mail_modify(edhiter->mail);
1201
field_idx = edhiter->current;
1202
next = edit_mail_headers_iterate_next(edhiter);
1203
edit_mail_header_field_delete(edhiter->mail, field_idx, TRUE);
1208
bool edit_mail_headers_iterate_replace
1209
(struct edit_mail_header_iter *edhiter,
1210
const char *newname, const char *newvalue)
1212
struct _header_field_index *field_idx;
1215
i_assert( edhiter->current != NULL && edhiter->current->header != NULL);
1217
edit_mail_modify(edhiter->mail);
1219
field_idx = edhiter->current;
1220
next = edit_mail_headers_iterate_next(edhiter);
1221
edit_mail_header_field_replace
1222
(edhiter->mail, field_idx, newname, newvalue, TRUE);
1227
/* Body modification */
1235
static void edit_mail_close(struct mail *mail)
1237
struct edit_mail *edmail = (struct edit_mail *)mail;
1239
edmail->wrapped->v.close(&edmail->wrapped->mail);
1242
static void edit_mail_free(struct mail *mail)
1244
struct edit_mail *edmail = (struct edit_mail *)mail;
1246
edmail->wrapped->v.free(&edmail->wrapped->mail);
1248
edit_mail_unwrap(&edmail);
1251
static void edit_mail_set_seq
1252
(struct mail *mail ATTR_UNUSED, uint32_t seq ATTR_UNUSED,
1253
bool saving ATTR_UNUSED)
1255
i_panic("edit_mail_set_seq() not implemented");
1258
static bool ATTR_NORETURN edit_mail_set_uid
1259
(struct mail *mail ATTR_UNUSED, uint32_t uid ATTR_UNUSED)
1261
i_panic("edit_mail_set_uid() not implemented");
1264
static void edit_mail_set_uid_cache_updates(struct mail *mail, bool set)
1266
struct edit_mail *edmail = (struct edit_mail *)mail;
1268
edmail->wrapped->v.set_uid_cache_updates(&edmail->wrapped->mail, set);
1271
static void edit_mail_add_temp_wanted_fields
1272
(struct mail *mail ATTR_UNUSED, enum mail_fetch_field fields ATTR_UNUSED,
1273
struct mailbox_header_lookup_ctx *headers ATTR_UNUSED)
1278
static enum mail_flags edit_mail_get_flags(struct mail *mail)
1280
struct edit_mail *edmail = (struct edit_mail *)mail;
1282
return edmail->wrapped->v.get_flags(&edmail->wrapped->mail);
1285
static const char *const *edit_mail_get_keywords(struct mail *mail)
1287
struct edit_mail *edmail = (struct edit_mail *)mail;
1289
return edmail->wrapped->v.get_keywords(&edmail->wrapped->mail);
1292
static const ARRAY_TYPE(keyword_indexes) *edit_mail_get_keyword_indexes
1295
struct edit_mail *edmail = (struct edit_mail *)mail;
1297
return edmail->wrapped->v.get_keyword_indexes(&edmail->wrapped->mail);
1300
static uint64_t edit_mail_get_modseq(struct mail *mail)
1302
struct edit_mail *edmail = (struct edit_mail *)mail;
1304
return edmail->wrapped->v.get_modseq(&edmail->wrapped->mail);
1307
static uint64_t edit_mail_get_pvt_modseq(struct mail *mail)
1309
struct edit_mail *edmail = (struct edit_mail *)mail;
1311
return edmail->wrapped->v.get_pvt_modseq(&edmail->wrapped->mail);
1314
static int edit_mail_get_parts
1315
(struct mail *mail, struct message_part **parts_r)
1317
struct edit_mail *edmail = (struct edit_mail *)mail;
1319
return edmail->wrapped->v.get_parts(&edmail->wrapped->mail, parts_r);
1322
static int edit_mail_get_date
1323
(struct mail *mail, time_t *date_r, int *timezone_r)
1325
struct edit_mail *edmail = (struct edit_mail *)mail;
1327
return edmail->wrapped->v.get_date(&edmail->wrapped->mail, date_r, timezone_r);
1330
static int edit_mail_get_received_date(struct mail *mail, time_t *date_r)
1332
struct edit_mail *edmail = (struct edit_mail *)mail;
1334
return edmail->wrapped->v.get_received_date(&edmail->wrapped->mail, date_r);
1337
static int edit_mail_get_save_date(struct mail *mail, time_t *date_r)
1339
struct edit_mail *edmail = (struct edit_mail *)mail;
1341
return edmail->wrapped->v.get_save_date(&edmail->wrapped->mail, date_r);
1344
static int edit_mail_get_virtual_size(struct mail *mail, uoff_t *size_r)
1346
struct edit_mail *edmail = (struct edit_mail *)mail;
1348
if ( !edmail->headers_parsed ) {
1349
*size_r = edmail->wrapped_hdr_size.virtual_size +
1350
edmail->wrapped_body_size.virtual_size;
1352
if ( !edmail->modified )
1355
*size_r = edmail->wrapped_body_size.virtual_size + 2;
1358
*size_r += edmail->hdr_size.virtual_size + edmail->body_size.virtual_size;
1362
static int edit_mail_get_physical_size(struct mail *mail, uoff_t *size_r)
1364
struct edit_mail *edmail = (struct edit_mail *)mail;
1367
if ( !edmail->headers_parsed ) {
1368
*size_r = edmail->wrapped_hdr_size.physical_size +
1369
edmail->wrapped_body_size.physical_size;
1371
if ( !edmail->modified )
1374
*size_r = edmail->wrapped_body_size.physical_size +
1375
( edmail->eoh_crlf ? 2 : 1 );
1378
*size_r += edmail->hdr_size.physical_size + edmail->body_size.physical_size;
1382
static int edit_mail_get_first_header
1383
(struct mail *mail, const char *field_name, bool decode_to_utf8,
1384
const char **value_r)
1386
struct edit_mail *edmail = (struct edit_mail *)mail;
1387
struct _header_index *header_idx;
1388
struct _header_field *field;
1391
/* Check whether mail headers were modified at all */
1392
if ( !edmail->modified || edmail->headers_head == NULL ) {
1394
return edmail->wrapped->v.get_first_header
1395
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1398
/* Try to find modified header */
1399
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ||
1400
header_idx->count == 0 ) {
1402
if ( !edmail->headers_parsed ) {
1404
return edmail->wrapped->v.get_first_header
1405
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1412
/* Get the first occurrence */
1413
if ( edmail->header_fields_appended == NULL ) {
1414
/* There are no appended headers, so first is found directly */
1415
field = header_idx->first->field;
1417
struct _header_field_index *field_idx;
1419
/* Scan prepended headers */
1420
field_idx = edmail->header_fields_head;
1421
while ( field_idx != NULL ) {
1422
if ( field_idx->header == header_idx )
1425
if ( field_idx == edmail->header_fields_appended ) {
1429
field_idx = field_idx->next;
1432
if ( field_idx == NULL ) {
1433
/* Check original message */
1434
if ( (ret=edmail->wrapped->v.get_first_header
1435
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r)) != 0 )
1438
/* Use first (apparently appended) header */
1439
field = header_idx->first->field;
1441
field = field_idx->field;
1445
if ( decode_to_utf8 )
1446
*value_r = field->utf8_value;
1448
*value_r = (const char *) (field->data + field->body_offset);
1452
static int edit_mail_get_headers
1453
(struct mail *mail, const char *field_name, bool decode_to_utf8,
1454
const char *const **value_r)
1456
struct edit_mail *edmail = (struct edit_mail *)mail;
1457
struct _header_index *header_idx;
1458
struct _header_field_index *field_idx;
1459
const char *const *headers;
1460
ARRAY(const char *) header_values;
1462
if ( !edmail->modified || edmail->headers_head == NULL ) {
1464
return edmail->wrapped->v.get_headers
1465
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1468
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ||
1469
header_idx->count == 0 ) {
1470
if ( !edmail->headers_parsed ) {
1472
return edmail->wrapped->v.get_headers
1473
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1476
p_array_init(&header_values, edmail->mail.pool, 1);
1477
(void)array_append_space(&header_values);
1478
*value_r = array_idx(&header_values, 0);
1484
/* Read original headers too if message headers are not parsed */
1486
if ( !edmail->headers_parsed && edmail->wrapped->v.get_headers
1487
(&edmail->wrapped->mail, field_name, decode_to_utf8, &headers) < 0 ) {
1491
/* Fill result array */
1492
p_array_init(&header_values, edmail->mail.pool, 32);
1493
field_idx = header_idx->first;
1494
while ( field_idx != NULL ) {
1496
/* If current field is the first appended one, we need to add original
1499
if ( field_idx == edmail->header_fields_appended && headers != NULL ) {
1500
while ( *headers != NULL ) {
1501
array_append(&header_values, headers, 1);
1507
/* Add modified header to the list */
1508
if ( field_idx->field->header == header_idx->header ) {
1509
struct _header_field *field = field_idx->field;
1512
if ( decode_to_utf8 )
1513
value = field->utf8_value;
1515
value = (const char *)(field->data + field->body_offset);
1517
array_append(&header_values, &value, 1);
1519
if ( field_idx == header_idx->last )
1523
field_idx = field_idx->next;
1526
/* Add original headers if necessary */
1527
if ( headers != NULL ) {
1528
while ( *headers != NULL ) {
1529
array_append(&header_values, headers, 1);
1535
(void)array_append_space(&header_values);
1536
*value_r = array_idx(&header_values, 0);
1540
static int ATTR_NORETURN edit_mail_get_header_stream
1541
(struct mail *mail ATTR_UNUSED,
1542
struct mailbox_header_lookup_ctx *headers ATTR_UNUSED,
1543
struct istream **stream_r ATTR_UNUSED)
1545
// FIXME: implement!
1546
i_panic("edit_mail_get_header_stream() not implemented");
1549
static int edit_mail_get_stream
1550
(struct mail *mail, bool get_body ATTR_UNUSED, struct message_size *hdr_size,
1551
struct message_size *body_size, struct istream **stream_r)
1553
struct edit_mail *edmail = (struct edit_mail *)mail;
1555
if ( edmail->stream == NULL ) {
1556
edmail->stream = edit_mail_istream_create(edmail);
1559
if ( hdr_size != NULL ) {
1560
*hdr_size = edmail->wrapped_hdr_size;
1561
hdr_size->physical_size += edmail->hdr_size.physical_size;
1562
hdr_size->virtual_size += edmail->hdr_size.virtual_size;
1563
hdr_size->lines += edmail->hdr_size.lines;
1566
if ( body_size != NULL ) {
1567
*body_size = edmail->wrapped_body_size;
1570
*stream_r = edmail->stream;
1571
i_stream_seek(edmail->stream, 0);
1576
static int edit_mail_get_special
1577
(struct mail *mail, enum mail_fetch_field field, const char **value_r)
1579
struct edit_mail *edmail = (struct edit_mail *)mail;
1581
if ( edmail->modified ) {
1582
/* Block certain fields when modified */
1585
case MAIL_FETCH_GUID:
1586
/* This is in essence a new message */
1589
case MAIL_FETCH_UIDL_FILE_NAME:
1590
/* Prevent hardlink copying */
1598
return edmail->wrapped->v.get_special(&edmail->wrapped->mail, field, value_r);
1601
static struct mail *
1602
edit_mail_get_real_mail(struct mail *mail)
1604
struct edit_mail *edmail = (struct edit_mail *)mail;
1606
return edit_mail_get_mail(edmail);
1609
static void edit_mail_update_flags
1610
(struct mail *mail, enum modify_type modify_type, enum mail_flags flags)
1612
struct edit_mail *edmail = (struct edit_mail *)mail;
1614
edmail->wrapped->v.update_flags(&edmail->wrapped->mail, modify_type, flags);
1617
static void edit_mail_update_keywords
1618
(struct mail *mail, enum modify_type modify_type,
1619
struct mail_keywords *keywords)
1621
struct edit_mail *edmail = (struct edit_mail *)mail;
1623
edmail->wrapped->v.update_keywords
1624
(&edmail->wrapped->mail, modify_type, keywords);
1627
static void edit_mail_update_modseq(struct mail *mail, uint64_t min_modseq)
1629
struct edit_mail *edmail = (struct edit_mail *)mail;
1631
edmail->wrapped->v.update_modseq(&edmail->wrapped->mail, min_modseq);
1634
static void edit_mail_update_pvt_modseq(struct mail *mail, uint64_t min_pvt_modseq)
1636
struct edit_mail *edmail = (struct edit_mail *)mail;
1638
edmail->wrapped->v.update_pvt_modseq(&edmail->wrapped->mail, min_pvt_modseq);
1641
static void edit_mail_update_pop3_uidl(struct mail *mail, const char *uidl)
1643
struct edit_mail *edmail = (struct edit_mail *)mail;
1645
if ( edmail->wrapped->v.update_pop3_uidl != NULL )
1646
edmail->wrapped->v.update_pop3_uidl(&edmail->wrapped->mail, uidl);
1649
static void edit_mail_expunge(struct mail *mail ATTR_UNUSED)
1654
static void edit_mail_set_cache_corrupted
1655
(struct mail *mail, enum mail_fetch_field field)
1657
struct edit_mail *edmail = (struct edit_mail *)mail;
1659
edmail->wrapped->v.set_cache_corrupted(&edmail->wrapped->mail, field);
1662
static struct mail_vfuncs edit_mail_vfuncs = {
1667
edit_mail_set_uid_cache_updates,
1670
edit_mail_add_temp_wanted_fields,
1671
edit_mail_get_flags,
1672
edit_mail_get_keywords,
1673
edit_mail_get_keyword_indexes,
1674
edit_mail_get_modseq,
1675
edit_mail_get_pvt_modseq,
1676
edit_mail_get_parts,
1678
edit_mail_get_received_date,
1679
edit_mail_get_save_date,
1680
edit_mail_get_virtual_size,
1681
edit_mail_get_physical_size,
1682
edit_mail_get_first_header,
1683
edit_mail_get_headers,
1684
edit_mail_get_header_stream,
1685
edit_mail_get_stream,
1686
index_mail_get_binary_stream,
1687
edit_mail_get_special,
1688
edit_mail_get_real_mail,
1689
edit_mail_update_flags,
1690
edit_mail_update_keywords,
1691
edit_mail_update_modseq,
1692
edit_mail_update_pvt_modseq,
1693
edit_mail_update_pop3_uidl,
1695
edit_mail_set_cache_corrupted,
1703
struct edit_mail_istream {
1704
struct istream_private istream;
1708
struct edit_mail *mail;
1710
struct _header_field_index *cur_header;
1712
unsigned int header_read:1;
1715
static void edit_mail_istream_destroy(struct iostream_private *stream)
1717
struct edit_mail_istream *edstream =
1718
(struct edit_mail_istream *)stream;
1720
i_stream_unref(&edstream->istream.parent);
1721
pool_unref(&edstream->pool);
1724
static ssize_t merge_from_parent
1725
(struct edit_mail_istream *edstream, uoff_t parent_v_offset,
1726
uoff_t parent_end_v_offset, uoff_t copy_v_offset)
1728
struct istream_private *stream = &edstream->istream;
1729
uoff_t v_offset = stream->istream.v_offset;
1730
buffer_t *buffer = edstream->buffer;
1731
const unsigned char *data;
1732
size_t pos, cur_pos;
1735
if (v_offset < copy_v_offset) {
1736
i_assert(stream->skip == 0);
1737
if (buffer->used < copy_v_offset - v_offset) {
1738
copy_v_offset = v_offset + buffer->used;
1742
/* If we are still merging it with our local buffer, we need to update the
1743
* parent seek offset to point to where we left of.
1745
if (v_offset < copy_v_offset) {
1746
parent_v_offset += buffer->used - (copy_v_offset - v_offset) + stream->pos;
1747
if (parent_v_offset >= parent_end_v_offset)
1751
buffer_set_used_size(buffer, 0);
1752
stream->pos -= stream->skip;
1754
cur_pos = stream->pos;
1757
i_stream_seek(stream->parent, parent_v_offset);
1759
/* Read from parent */
1760
data = i_stream_get_data(stream->parent, &pos);
1764
if ((ret = i_stream_read(stream->parent)) == -2)
1767
stream->istream.stream_errno = stream->parent->stream_errno;
1768
stream->istream.eof = stream->parent->eof;
1769
data = i_stream_get_data(stream->parent, &pos);
1770
/* check again, in case the parent stream had been seeked
1771
backwards and the previous read() didn't get us far
1773
} while (pos <= cur_pos && ret > 0);
1775
/* Don't read beyond parent end offset */
1776
if (pos > (parent_end_v_offset - parent_v_offset))
1777
pos = parent_end_v_offset - parent_v_offset;
1779
if (v_offset < copy_v_offset) {
1780
/* Merging with our local buffer; copying data from parent */
1782
ret = (ssize_t)(pos);
1783
buffer_append(buffer, data, pos);
1784
stream->buffer = buffer_get_data(buffer, &pos);
1788
ret = (ret == 0 ? 0 : -1);
1791
/* Just passing buffers from parent; no copying */
1792
ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
1793
(ret == 0 ? 0 : -1);
1794
stream->buffer = data;
1798
i_assert(ret != -1 || stream->istream.eof ||
1799
stream->istream.stream_errno != 0);
1803
static ssize_t merge_modified_headers(struct edit_mail_istream *edstream)
1805
struct istream_private *stream = &edstream->istream;
1806
struct edit_mail *edmail = edstream->mail;
1810
if (edstream->cur_header != NULL) {
1811
/* Merge remaining parent buffer, if any */
1812
if (edstream->buffer->used == 0 && stream->skip < stream->pos ) {
1813
buffer_append(edstream->buffer,
1814
stream->buffer + stream->skip, stream->pos - stream->skip);
1817
/* Add modified headers to buffer */
1818
while ( edstream->cur_header != NULL && edstream->buffer->used < 1024 ) {
1819
buffer_append(edstream->buffer, edstream->cur_header->field->data,
1820
edstream->cur_header->field->size);
1822
edstream->cur_header = edstream->cur_header->next;
1824
/* Stop at end of prepended headers if original header is left unparsed */
1825
if ( !edmail->headers_parsed
1826
&& edstream->cur_header == edmail->header_fields_appended )
1827
edstream->cur_header = NULL;
1830
if ( edstream->buffer->used > 0 ) {
1831
/* Output current buffer */
1832
stream->buffer = buffer_get_data(edstream->buffer, &pos);
1833
ret = (ssize_t)pos + stream->skip - stream->pos;
1834
i_assert( ret >= 0 );
1841
if ( edstream->buffer->used >= 1024 )
1848
static ssize_t edit_mail_istream_read(struct istream_private *stream)
1850
struct edit_mail_istream *edstream =
1851
(struct edit_mail_istream *)stream;
1852
struct edit_mail *edmail = edstream->mail;
1853
uoff_t parent_v_offset, parent_end_v_offset, copy_v_offset;
1854
uoff_t v_offset = stream->istream.v_offset;
1855
uoff_t prep_hdr_size, hdr_size;
1858
if (stream->istream.eof)
1861
if ( edstream->buffer->used > 0 ) {
1862
if ( stream->skip > 0 ) {
1863
/* Remove skipped data from buffer */
1865
(edstream->buffer, 0, edstream->buffer, stream->skip, (size_t)-1);
1866
stream->pos -= stream->skip;
1868
buffer_set_used_size(edstream->buffer, stream->pos);
1872
/* Merge prepended headers */
1873
if (edstream->cur_header != NULL) {
1874
if ( (ret=merge_modified_headers(edstream)) != 0 )
1878
if ( !edmail->headers_parsed && !edstream->header_read &&
1879
edmail->header_fields_appended != NULL ) {
1880
/* Output headers from original stream */
1882
/* Size of the prepended header */
1883
prep_hdr_size = edmail->hdr_size.physical_size -
1884
edmail->appended_hdr_size.physical_size;
1886
/* Offset of header end or appended header
1887
* Any final CR is dealt with later
1889
hdr_size = prep_hdr_size + edmail->wrapped_hdr_size.physical_size;
1891
if ( v_offset < hdr_size - 1 ) {
1892
parent_v_offset = stream->parent_start_offset +
1893
(v_offset - prep_hdr_size);
1894
parent_end_v_offset = stream->parent_start_offset +
1895
edmail->wrapped_hdr_size.physical_size - 1;
1896
copy_v_offset = prep_hdr_size;
1898
if ( (ret=merge_from_parent(edstream, parent_v_offset,
1899
parent_end_v_offset, copy_v_offset)) < 0 ) {
1903
if ( stream->pos >= hdr_size - 1 - v_offset ) {
1904
/* Strip final CR too when it is present */
1905
if ( stream->buffer[stream->pos-1] == '\r' ) {
1908
if (edstream->buffer->used > 0)
1909
buffer_set_used_size(edstream->buffer, edstream->buffer->used-1);
1913
edstream->header_read = TRUE;
1914
edstream->cur_header = edmail->header_fields_appended;
1921
/* Merge Appended headers */
1922
if (edstream->cur_header != NULL) {
1923
if ( (ret=merge_modified_headers(edstream)) != 0 )
1928
/* Header does not come from original mail at all */
1929
if ( edmail->headers_parsed ) {
1930
parent_v_offset = stream->parent_start_offset +
1931
(v_offset - edmail->hdr_size.physical_size) +
1932
edmail->wrapped_hdr_size.physical_size - ( edmail->eoh_crlf ? 2 : 1);
1933
copy_v_offset = edmail->hdr_size.physical_size;
1935
/* Header comes partially from original mail and headers are added between
1938
} else if (edmail->header_fields_appended != NULL) {
1939
parent_v_offset = stream->parent_start_offset +
1940
(v_offset - edmail->hdr_size.physical_size);
1941
copy_v_offset = edmail->hdr_size.physical_size +
1942
edmail->wrapped_hdr_size.physical_size;
1944
/* Header comes partially from original mail, but headers are only prepended.
1947
parent_v_offset = stream->parent_start_offset
1948
+ (v_offset - edmail->hdr_size.physical_size);
1949
copy_v_offset = edmail->hdr_size.physical_size;
1952
return merge_from_parent
1953
(edstream, parent_v_offset, (uoff_t)-1, copy_v_offset);
1957
stream_reset_to(struct edit_mail_istream *edstream, uoff_t v_offset)
1959
edstream->istream.istream.v_offset = v_offset;
1960
edstream->istream.skip = 0;
1961
edstream->istream.pos = 0;
1962
edstream->istream.buffer = NULL;
1963
buffer_set_used_size(edstream->buffer, 0);
1964
i_stream_seek(edstream->istream.parent, 0);
1968
stream_skip_to_header
1969
(struct edit_mail_istream *edstream, struct _header_field_index *header,
1972
struct _header_field *field = header->field;
1973
edstream->cur_header = header;
1975
/* Partially fill the buffer if in the middle of the header */
1977
if ( skip < field->size ) {
1979
(edstream->buffer, field->data + skip, field->size-skip );
1982
skip -= field->size;
1985
i_assert( skip == 0 );
1989
static void edit_mail_istream_seek
1990
(struct istream_private *stream, uoff_t v_offset, bool mark ATTR_UNUSED)
1992
struct edit_mail_istream *edstream =
1993
(struct edit_mail_istream *)stream;
1994
struct _header_field_index *cur_header;
1995
struct edit_mail *edmail = edstream->mail;
1998
edstream->header_read = FALSE;
2001
if ( v_offset == 0 ) {
2002
stream_reset_to(edstream, 0);
2004
if ( edmail->header_fields_head != edmail->header_fields_appended )
2005
edstream->cur_header = edmail->header_fields_head;
2009
/* Inside (prepended) headers */
2010
if ( edmail->headers_parsed ) {
2011
offset = edmail->hdr_size.physical_size;
2013
offset = edmail->hdr_size.physical_size -
2014
edmail->appended_hdr_size.physical_size;
2017
if ( v_offset < offset ) {
2018
stream_reset_to(edstream, v_offset);
2020
/* Find the header */
2021
cur_header = edmail->header_fields_head;
2022
i_assert( cur_header != NULL &&
2023
cur_header != edmail->header_fields_appended );
2024
offset = cur_header->field->size;
2025
while ( v_offset > offset ) {
2026
cur_header = cur_header->next;
2027
i_assert( cur_header != NULL &&
2028
cur_header != edmail->header_fields_appended );
2030
offset += cur_header->field->size;
2033
stream_skip_to_header(edstream, cur_header, (offset - v_offset));
2037
if ( !edmail->headers_parsed ) {
2038
/* Inside original header */
2039
offset = edmail->hdr_size.physical_size -
2040
edmail->appended_hdr_size.physical_size +
2041
edmail->wrapped_hdr_size.physical_size;
2042
if ( v_offset < offset ) {
2043
stream_reset_to(edstream, v_offset);
2044
edstream->cur_header = NULL;
2048
edstream->header_read = TRUE;
2050
/* Inside appended header */
2051
offset = edmail->hdr_size.physical_size +
2052
edmail->wrapped_hdr_size.physical_size;
2053
if ( v_offset < offset ) {
2054
stream_reset_to(edstream, v_offset);
2056
offset -= edmail->appended_hdr_size.physical_size;
2058
cur_header = edmail->header_fields_appended;
2059
i_assert( cur_header != NULL );
2060
offset += cur_header->field->size;
2062
while ( cur_header != NULL && v_offset > offset ) {
2063
cur_header = edstream->cur_header->next;
2064
i_assert( cur_header != NULL );
2066
offset += cur_header->field->size;
2069
stream_skip_to_header(edstream, cur_header, (offset - v_offset));
2074
stream_reset_to(edstream, v_offset);
2075
edstream->cur_header = NULL;
2078
static void ATTR_NORETURN
2079
edit_mail_istream_sync(struct istream_private *stream ATTR_UNUSED)
2081
i_panic("edit-mail istream sync() not implemented");
2085
edit_mail_istream_stat(struct istream_private *stream, bool exact)
2087
struct edit_mail_istream *edstream =
2088
(struct edit_mail_istream *)stream;
2089
struct edit_mail *edmail = edstream->mail;
2090
const struct stat *st;
2092
/* Stat the original stream */
2093
if (i_stream_stat(stream->parent, exact, &st) < 0)
2096
stream->statbuf = *st;
2097
if (st->st_size == -1 || !exact)
2100
if ( !edmail->headers_parsed ) {
2101
if ( !edmail->modified )
2104
stream->statbuf.st_size = edmail->wrapped_body_size.physical_size +
2105
( edmail->eoh_crlf ? 2 : 1 );
2108
stream->statbuf.st_size += edmail->hdr_size.physical_size +
2109
edmail->body_size.physical_size;
2113
struct istream *edit_mail_istream_create
2114
(struct edit_mail *edmail)
2116
struct edit_mail_istream *edstream;
2117
struct istream *wrapped = edmail->wrapped_stream;
2119
edstream = i_new(struct edit_mail_istream, 1);
2120
edstream->pool = pool_alloconly_create(MEMPOOL_GROWING
2121
"edit mail stream", 4096);
2122
edstream->mail = edmail;
2123
edstream->buffer = buffer_create_dynamic(edstream->pool, 1024);
2125
edstream->istream.max_buffer_size = wrapped->real_stream->max_buffer_size;
2127
edstream->istream.iostream.destroy = edit_mail_istream_destroy;
2128
edstream->istream.read = edit_mail_istream_read;
2129
edstream->istream.seek = edit_mail_istream_seek;
2130
edstream->istream.sync = edit_mail_istream_sync;
2131
edstream->istream.stat = edit_mail_istream_stat;
2133
edstream->istream.istream.readable_fd = FALSE;
2134
edstream->istream.istream.blocking = wrapped->blocking;
2135
edstream->istream.istream.seekable = wrapped->seekable;
2137
if ( edmail->header_fields_head != edmail->header_fields_appended )
2138
edstream->cur_header = edmail->header_fields_head;
2140
i_stream_seek(wrapped, 0);
2142
return i_stream_create(&edstream->istream, wrapped, -1);