1
/* Copyright (c) 2002-2012 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 "raw-storage.h"
21
#include "edit-mail.h"
24
* Forward declarations
27
struct _header_field_index;
32
static struct mail_vfuncs edit_mail_vfuncs;
34
struct edit_mail_istream;
35
struct istream *edit_mail_istream_create(struct edit_mail *edmail);
37
static struct _header_index *edit_mail_header_clone
38
(struct edit_mail *edmail, struct _header *header);
44
static struct mail_user *edit_mail_user = NULL;
45
static unsigned int edit_mail_refcount = 0;
47
static struct mail_user *edit_mail_raw_storage_get(struct mail_user *mail_user)
49
if ( edit_mail_user == NULL ) {
50
void **sets = master_service_settings_get_others(master_service);
52
edit_mail_user = raw_storage_create_from_set(mail_user->set_info, sets[0]);
57
return edit_mail_user;
60
static void edit_mail_raw_storage_drop(void)
62
i_assert(edit_mail_refcount > 0);
64
if ( --edit_mail_refcount != 0)
67
mail_user_unref(&edit_mail_user);
68
edit_mail_user = NULL;
75
struct _header_field {
76
struct _header *header;
78
unsigned int refcount;
91
struct _header_field_index {
92
struct _header_field_index *prev, *next;
94
struct _header_field *field;
95
struct _header_index *header;
99
unsigned int refcount;
104
struct _header_index {
105
struct _header_index *prev, *next;
107
struct _header *header;
109
struct _header_field_index *first, *last;
114
static inline struct _header *_header_create(const char *name)
116
struct _header *header;
118
header = i_new(struct _header, 1);
119
header->name = i_strdup(name);
120
header->refcount = 1;
125
static inline void _header_ref(struct _header *header)
130
static inline void _header_unref(struct _header *header)
132
i_assert( header->refcount > 0 );
133
if ( --header->refcount != 0 )
136
i_free(header->name);
140
static inline struct _header_field *_header_field_create(struct _header *header)
142
struct _header_field *hfield;
144
hfield = i_new(struct _header_field, 1);
145
hfield->refcount = 1;
146
hfield->header = header;
147
if ( header != NULL )
153
static inline void _header_field_ref(struct _header_field *hfield)
158
static inline void _header_field_unref(struct _header_field *hfield)
160
i_assert( hfield->refcount > 0 );
161
if ( --hfield->refcount != 0 )
164
if ( hfield->header != NULL )
165
_header_unref(hfield->header);
167
if ( hfield->data != NULL )
168
i_free(hfield->data);
169
if ( hfield->utf8_value != NULL )
170
i_free(hfield->utf8_value);
179
struct mail_private mail;
180
struct mail_private *wrapped;
182
struct edit_mail *parent;
183
unsigned int refcount;
185
struct istream *wrapped_stream;
186
struct istream *stream;
188
struct _header_index *headers_head, *headers_tail;
189
struct _header_field_index *header_fields_head, *header_fields_tail;
190
struct message_size hdr_size, body_size;
192
struct message_size wrapped_hdr_size, wrapped_body_size;
194
struct _header_field_index *header_fields_appended;
195
struct message_size appended_hdr_size;
197
unsigned int modified:1;
198
unsigned int snapshot_modified:1;
200
unsigned int eoh_crlf:1;
201
unsigned int headers_parsed:1;
202
unsigned int destroying_stream:1;
205
struct edit_mail *edit_mail_wrap(struct mail *mail)
207
struct mail_private *mailp = (struct mail_private *) mail;
208
struct edit_mail *edmail;
209
struct mail_user *raw_mail_user;
210
struct mailbox *raw_box = NULL;
211
struct mailbox_transaction_context *raw_trans;
212
struct message_size hdr_size, body_size;
213
struct istream *wrapped_stream;
217
if ( mail_get_stream(mail, &hdr_size, &body_size, &wrapped_stream) < 0 ) {
221
/* Create dummy raw mailbox for our wrapper */
223
raw_mail_user = edit_mail_raw_storage_get(mail->box->storage->user);
225
if ( raw_mailbox_alloc_stream(raw_mail_user, wrapped_stream, (time_t)-1,
226
"editor@example.com", &raw_box) < 0 ) {
227
i_error("edit-mail: failed to open raw box: %s",
228
mailbox_get_last_error(raw_box, NULL));
229
mailbox_free(&raw_box);
230
edit_mail_raw_storage_drop();
234
raw_trans = mailbox_transaction_begin(raw_box, 0);
236
/* Create the wrapper mail */
238
pool = pool_alloconly_create("edit_mail", 1024);
239
edmail = p_new(pool, struct edit_mail, 1);
240
edmail->refcount = 1;
241
edmail->mail.pool = pool;
243
edmail->wrapped = mailp;
244
edmail->wrapped_hdr_size = hdr_size;
245
edmail->wrapped_body_size = body_size;
247
edmail->wrapped_stream = wrapped_stream;
248
i_stream_ref(edmail->wrapped_stream);
250
/* Determine whether we should use CRLF or LF for the physical message */
251
size_diff = (hdr_size.virtual_size + body_size.virtual_size) -
252
(hdr_size.physical_size + body_size.physical_size);
253
if ( size_diff == 0 || size_diff <= (hdr_size.lines + body_size.lines)/2 )
254
edmail->crlf = edmail->eoh_crlf = TRUE;
256
array_create(&edmail->mail.module_contexts, pool, sizeof(void *), 5);
258
edmail->mail.v = edit_mail_vfuncs;
259
edmail->mail.mail.seq = 1;
260
edmail->mail.mail.box = raw_box;
261
edmail->mail.mail.transaction = raw_trans;
262
edmail->mail.wanted_fields = mailp->wanted_fields;
263
edmail->mail.wanted_headers = mailp->wanted_headers;
268
struct edit_mail *edit_mail_snapshot(struct edit_mail *edmail)
270
struct _header_field_index *field_idx, *field_idx_new;
271
struct edit_mail *edmail_new;
274
if ( !edmail->snapshot_modified ) {
278
pool = pool_alloconly_create("edit_mail", 1024);
279
edmail_new = p_new(pool, struct edit_mail, 1);
280
edmail_new->refcount = 1;
281
edmail_new->mail.pool = pool;
283
edmail_new->wrapped = edmail->wrapped;
284
edmail_new->wrapped_hdr_size = edmail->wrapped_hdr_size;
285
edmail_new->wrapped_body_size = edmail->wrapped_body_size;
286
edmail_new->hdr_size = edmail->hdr_size;
287
edmail_new->body_size = edmail->body_size;
288
edmail_new->appended_hdr_size = edmail->appended_hdr_size;
290
edmail_new->wrapped_stream = edmail->wrapped_stream;
291
i_stream_ref(edmail_new->wrapped_stream);
293
edmail_new->crlf = edmail->crlf;
294
edmail_new->eoh_crlf = edmail->eoh_crlf;
296
array_create(&edmail_new->mail.module_contexts, pool, sizeof(void *), 5);
298
edmail_new->mail.v = edit_mail_vfuncs;
299
edmail_new->mail.mail.seq = 1;
300
edmail_new->mail.mail.box = edmail->mail.mail.box;
301
edmail_new->mail.mail.transaction = edmail->mail.mail.transaction;
302
edmail_new->mail.wanted_fields = edmail->mail.wanted_fields;
303
edmail_new->mail.wanted_headers = edmail->mail.wanted_headers;
305
edmail_new->stream = NULL;
307
if ( edmail->modified ) {
308
field_idx = edmail->header_fields_head;
309
while ( field_idx != NULL ) {
310
struct _header_field_index *next = field_idx->next;
312
field_idx_new = i_new(struct _header_field_index, 1);
314
field_idx_new->header =
315
edit_mail_header_clone(edmail_new, field_idx->header->header);
317
field_idx_new->field = field_idx->field;
318
_header_field_ref(field_idx_new->field);
321
(&edmail_new->header_fields_head, &edmail_new->header_fields_tail,
324
if ( field_idx->header->first == field_idx )
325
field_idx_new->header->first = field_idx_new;
326
if ( field_idx->header->last == field_idx )
327
field_idx_new->header->last = field_idx_new;
329
if ( field_idx == edmail->header_fields_appended )
330
edmail_new->header_fields_appended = field_idx_new;
335
edmail_new->modified = TRUE;
338
edmail_new->headers_parsed = edmail->headers_parsed;
340
edmail_new->parent = edmail;
341
//edmail->refcount++;
346
void edit_mail_reset(struct edit_mail *edmail)
348
struct _header_index *header_idx;
349
struct _header_field_index *field_idx;
351
if ( edmail->stream != NULL ) {
352
i_stream_unref(&edmail->stream);
353
edmail->stream = NULL;
356
field_idx = edmail->header_fields_head;
357
while ( field_idx != NULL ) {
358
struct _header_field_index *next = field_idx->next;
360
_header_field_unref(field_idx->field);
366
header_idx = edmail->headers_head;
367
while ( header_idx != NULL ) {
368
struct _header_index *next = header_idx->next;
370
_header_unref(header_idx->header);
376
edmail->modified = FALSE;
379
void edit_mail_unwrap(struct edit_mail **edmail)
381
struct edit_mail *parent;
383
i_assert( (*edmail)->refcount > 0 );
384
if ( --(*edmail)->refcount != 0 )
387
edit_mail_reset(*edmail);
389
if ( (*edmail)->wrapped_stream != NULL ) {
390
i_stream_unref(&(*edmail)->wrapped_stream);
391
(*edmail)->wrapped_stream = NULL;
394
parent = (*edmail)->parent;
396
if ( parent == NULL ) {
397
mailbox_transaction_rollback(&(*edmail)->mail.mail.transaction);
398
mailbox_free(&(*edmail)->mail.mail.box);
399
edit_mail_raw_storage_drop();
402
pool_unref(&(*edmail)->mail.pool);
405
if ( parent != NULL )
406
edit_mail_unwrap(&parent);
409
struct mail *edit_mail_get_mail(struct edit_mail *edmail)
411
/* Return wrapped mail when nothing is modified yet */
412
if ( !edmail->modified )
413
return &edmail->wrapped->mail;
415
return &edmail->mail.mail;
422
static inline void edit_mail_modify(struct edit_mail *edmail)
424
edmail->mail.mail.seq++;
425
edmail->modified = TRUE;
426
edmail->snapshot_modified = TRUE;
429
/* Header modification */
431
static struct _header_index *edit_mail_header_find
432
(struct edit_mail *edmail, const char *field_name)
434
struct _header_index *header_idx;
436
header_idx = edmail->headers_head;
437
while ( header_idx != NULL ) {
438
if ( strcasecmp(header_idx->header->name, field_name) == 0 )
441
header_idx = header_idx->next;
447
static struct _header_index *edit_mail_header_create
448
(struct edit_mail *edmail, const char *field_name)
450
struct _header_index *header_idx;
452
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ) {
453
header_idx = i_new(struct _header_index, 1);
454
header_idx->header = _header_create(field_name);
456
DLLIST2_APPEND(&edmail->headers_head, &edmail->headers_tail, header_idx);
462
static struct _header_index *edit_mail_header_clone
463
(struct edit_mail *edmail, struct _header *header)
465
struct _header_index *header_idx;
467
header_idx = edmail->headers_head;
468
while ( header_idx != NULL ) {
469
if ( header_idx->header == header )
472
header_idx = header_idx->next;
475
header_idx = i_new(struct _header_index, 1);
476
header_idx->header = header;
478
DLLIST2_APPEND(&edmail->headers_head, &edmail->headers_tail, header_idx);
483
static void edit_mail_header_field_delete
484
(struct edit_mail *edmail, struct _header_field_index *field_idx,
487
struct _header_index *header_idx = field_idx->header;
488
struct _header_field *field = field_idx->field;
490
i_assert( header_idx != NULL );
492
edmail->hdr_size.physical_size -= field->size;
493
edmail->hdr_size.virtual_size -= field->virtual_size;
494
edmail->hdr_size.lines -= field->lines;
497
if ( update_index ) {
498
if ( header_idx->count == 0 ) {
499
DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail, header_idx);
500
_header_unref(header_idx->header);
502
} else if ( header_idx->first == field_idx ) {
503
struct _header_field_index *hfield = header_idx->first->next;
505
while ( hfield != NULL && hfield->header != header_idx ) {
506
hfield = hfield->next;
509
i_assert( hfield != NULL );
510
header_idx->first = hfield;
511
} else if ( header_idx->last == field_idx ) {
512
struct _header_field_index *hfield = header_idx->last->prev;
514
while ( hfield != NULL && hfield->header != header_idx ) {
515
hfield = hfield->prev;
518
i_assert( hfield != NULL );
519
header_idx->last = hfield;
524
(&edmail->header_fields_head, &edmail->header_fields_tail, field_idx);
525
_header_field_unref(field_idx->field);
529
static inline char *_header_decode
530
(const unsigned char *hdr_data, size_t hdr_data_len)
532
string_t *str = t_str_new(512);
534
/* hdr_data is already unfolded */
536
/* Decode MIME encoded-words. */
537
if ( message_header_decode_utf8
538
((const unsigned char *)hdr_data, hdr_data_len, str, FALSE))
539
return i_strdup(str_c(str));
541
return i_strndup(hdr_data, hdr_data_len);
544
static int edit_mail_headers_parse
545
(struct edit_mail *edmail)
547
struct message_header_parser_ctx *hparser;
548
enum message_header_parser_flags hparser_flags =
549
MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP |
550
MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE;
551
struct message_header_line *hdr;
552
struct _header_index *header_idx;
553
struct _header_field_index *head = NULL, *tail = NULL, *current;
555
uoff_t offset = 0, body_offset = 0, vsize_diff = 0;
556
unsigned int lines = 0;
559
if ( edmail->headers_parsed ) return 1;
561
hparser = message_parse_header_init
562
(edmail->wrapped_stream, NULL, hparser_flags);
565
hdr_data = t_str_new(1024);
566
while ( (ret=message_parse_header_next(hparser, &hdr)) > 0 ) {
567
struct _header_field_index *field_idx_new;
568
struct _header_field *field;
571
/* Record whether header ends in CRLF or LF */
572
edmail->eoh_crlf = hdr->crlf_newline;
575
if ( hdr == NULL || hdr->eoh ) break;
577
/* We deny the existence of any `Content-Length:' header. This header is
578
* non-standard and it can wreak havok when the message is modified.
580
if ( strcasecmp(hdr->name, "Content-Length" ) == 0 )
583
if ( hdr->continued ) {
584
/* Continued line of folded header */
585
buffer_append(hdr_data, hdr->value, hdr->value_len);
587
/* First line of header */
588
offset = hdr->name_offset;
589
body_offset = hdr->name_len + hdr->middle_len;
590
str_truncate(hdr_data, 0);
591
buffer_append(hdr_data, hdr->name, hdr->name_len);
592
buffer_append(hdr_data, hdr->middle, hdr->middle_len);
593
buffer_append(hdr_data, hdr->value, hdr->value_len);
598
if ( !hdr->no_newline ) {
601
if ( hdr->crlf_newline ) {
602
buffer_append(hdr_data, "\r\n", 2);
604
buffer_append(hdr_data, "\n", 1);
609
if ( hdr->continues ) {
610
hdr->use_full_value = TRUE;
614
/* Create new header field index entry */
616
field_idx_new = i_new(struct _header_field_index, 1);
618
header_idx = edit_mail_header_create(edmail, hdr->name);
620
field_idx_new->header = header_idx;
621
field_idx_new->field = field = _header_field_create(header_idx->header);
623
i_assert( body_offset > 0 );
624
field->body_offset = body_offset;
626
field->utf8_value = _header_decode(hdr->full_value, hdr->full_value_len);
628
field->size = str_len(hdr_data);
629
field->virtual_size = field->size + vsize_diff;
630
field->data = i_strndup(str_data(hdr_data), field->size);
631
field->offset = offset;
632
field->lines = lines;
634
DLLIST2_APPEND(&head, &tail, field_idx_new);
636
edmail->hdr_size.physical_size += field->size;
637
edmail->hdr_size.virtual_size += field->virtual_size;
638
edmail->hdr_size.lines += lines;
642
message_parse_header_deinit(&hparser);
645
/* Error; clean up */
647
while ( current != NULL ) {
648
struct _header_field_index *next = current->next;
650
_header_field_unref(current->field);
659
/* Insert header field index items in main list */
660
if ( edmail->header_fields_appended != NULL ) {
661
if ( edmail->header_fields_appended->prev != NULL ) {
662
edmail->header_fields_appended->prev->next = head;
663
head->prev = edmail->header_fields_appended->prev;
666
tail->next = edmail->header_fields_appended;
667
edmail->header_fields_appended->prev = tail;
668
} else if ( edmail->header_fields_tail != NULL ) {
669
edmail->header_fields_tail->next = head;
670
head->prev = edmail->header_fields_tail;
671
edmail->header_fields_tail = tail;
673
edmail->header_fields_head = head;
674
edmail->header_fields_tail = tail;
677
/* Rebuild header index */
678
current = edmail->header_fields_head;
679
while ( current != NULL ) {
680
if ( current->header->first == NULL )
681
current->header->first = current;
682
current->header->last = current;
684
current = current->next;
687
/* Clear appended headers */
688
edmail->header_fields_appended = NULL;
689
edmail->appended_hdr_size.physical_size = 0;
690
edmail->appended_hdr_size.virtual_size = 0;
691
edmail->appended_hdr_size.lines = 0;
693
/* Do not parse headers again */
694
edmail->headers_parsed = TRUE;
699
static inline char *_header_value_unfold
705
for ( i = 0; value[i] != '\0'; i++ ) {
706
if (value[i] == '\r' || value[i] == '\n')
709
if ( value[i] == '\0' ) {
710
return i_strdup(value);
713
out = t_str_new(i + strlen(value+i) + 10);
714
str_append_n(out, value, i);
715
for ( ; value[i] != '\0'; i++ ) {
716
if (value[i] == '\n') {
718
if (value[i] == '\0')
721
switch ( value[i] ) {
723
str_append_c(out, '\t');
725
str_append_c(out, value[i]);
728
if (value[i] != '\r')
729
str_append_c(out, value[i]);
733
return i_strndup(str_c(out), str_len(out));
736
void edit_mail_header_add
737
(struct edit_mail *edmail, const char *field_name, const char *value, bool last)
739
struct _header_index *header_idx;
740
struct _header *header;
741
struct _header_field_index *field_idx;
742
struct _header_field *field;
745
edit_mail_modify(edmail);
747
/* Get/create header index item */
748
header_idx = edit_mail_header_create(edmail, field_name);
749
header = header_idx->header;
751
/* Create new field index item */
752
field_idx = i_new(struct _header_field_index, 1);
753
field_idx->header = header_idx;
754
field_idx->field = field = _header_field_create(header);
756
/* Create header field data (folded if necessary) */
758
string_t *enc_value, *data;
760
enc_value = t_str_new(strlen(field_name) + strlen(value) + 64);
761
data = t_str_new(strlen(field_name) + strlen(value) + 128);
763
message_header_encode(value, enc_value);
765
lines = rfc2822_header_field_append
766
(data, field_name, str_c(enc_value), edmail->crlf, &field->body_offset);
768
/* Copy to new field */
769
field->data = i_strndup(str_data(data), str_len(data));
770
field->size = str_len(data);
771
field->virtual_size = ( edmail->crlf ? field->size : field->size + lines );
772
field->lines = lines;
775
/* Record original (utf8) value */
776
field->utf8_value = _header_value_unfold(value);
778
/* Add it to the header field index */
781
(&edmail->header_fields_head, &edmail->header_fields_tail, field_idx);
783
header_idx->last = field_idx;
784
if ( header_idx->first == NULL )
785
header_idx->first = field_idx;
787
if ( !edmail->headers_parsed ) {
788
if ( edmail->header_fields_appended == NULL ) {
789
/* Record beginning of appended headers */
790
edmail->header_fields_appended = field_idx;
793
edmail->appended_hdr_size.physical_size += field->size;
794
edmail->appended_hdr_size.virtual_size += field->virtual_size;
795
edmail->appended_hdr_size.lines += lines;
799
(&edmail->header_fields_head, &edmail->header_fields_tail, field_idx);
801
header_idx->first = field_idx;
802
if ( header_idx->last == NULL )
803
header_idx->last = field_idx;
808
edmail->hdr_size.physical_size += field->size;
809
edmail->hdr_size.virtual_size += field->virtual_size;
810
edmail->hdr_size.lines += lines;
813
int edit_mail_header_delete
814
(struct edit_mail *edmail, const char *field_name, int index)
816
struct _header_index *header_idx;
817
struct _header_field_index *field_idx;
821
/* Make sure headers are parsed */
822
if ( edit_mail_headers_parse(edmail) <= 0 )
825
/* Find the header entry */
826
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ) {
831
/* Signal modification */
832
edit_mail_modify(edmail);
834
/* Iterate through all header fields and remove those that match */
835
field_idx = ( index >= 0 ? header_idx->first : header_idx->last );
836
while ( field_idx != NULL ) {
837
struct _header_field_index *next =
838
( index >= 0 ? field_idx->next : field_idx->prev );
840
if ( field_idx->field->header == header_idx->header ) {
845
final = ( header_idx->last == field_idx );
846
} else if ( index < 0 ) {
848
final = ( header_idx->first == field_idx );
851
if ( index == 0 || index == pos ) {
852
if ( header_idx->first == field_idx ) header_idx->first = NULL;
853
if ( header_idx->last == field_idx ) header_idx->last = NULL;
854
edit_mail_header_field_delete(edmail, field_idx, FALSE);
858
if ( final || (index != 0 && index == pos) )
865
if ( index == 0 || header_idx->count == 0 ) {
866
DLLIST2_REMOVE(&edmail->headers_head, &edmail->headers_tail, header_idx);
867
_header_unref(header_idx->header);
869
} else if ( header_idx->first == NULL || header_idx->last == NULL ) {
870
struct _header_field_index *current = edmail->header_fields_head;
872
while ( current != NULL ) {
873
if ( current->header == header_idx ) {
874
if ( header_idx->first == NULL )
875
header_idx->first = current;
876
header_idx->last = current;
878
current = current->next;
885
struct edit_mail_header_iter
887
struct edit_mail *mail;
888
struct _header_index *header;
889
struct _header_field_index *current;
891
unsigned int reverse:1;
894
int edit_mail_headers_iterate_init
895
(struct edit_mail *edmail, const char *field_name, bool reverse,
896
struct edit_mail_header_iter **edhiter_r)
898
struct edit_mail_header_iter *edhiter;
899
struct _header_index *header_idx = NULL;
901
/* Make sure headers are parsed */
902
if ( edit_mail_headers_parse(edmail) <= 0 ) {
907
if ( field_name != NULL
908
&& (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ) {
912
edhiter = i_new(struct edit_mail_header_iter, 1);
913
edhiter->mail = edmail;
914
edhiter->header = header_idx;
915
edhiter->reverse = reverse;
917
if ( field_name != NULL && header_idx == NULL ) {
918
edhiter->current = NULL;
919
} else if ( !reverse ) {
921
( header_idx != NULL ? header_idx->first : edmail->header_fields_head );
924
( header_idx != NULL ? header_idx->last : edmail->header_fields_tail );
925
if ( edhiter->current->header == NULL )
926
edhiter->current = edhiter->current->prev;
929
*edhiter_r = edhiter;
933
void edit_mail_headers_iterate_deinit
934
(struct edit_mail_header_iter **edhiter)
940
static inline string_t *_header_right_trim(const char *raw)
945
for ( i = strlen(raw)-1; i >= 0; i-- ) {
946
if ( raw[i] != ' ' && raw[i] != '\t' ) break;
949
result = t_str_new(i+1);
950
str_append_n(result, raw, i + 1);
954
void edit_mail_headers_iterate_get
955
(struct edit_mail_header_iter *edhiter, const char **value_r)
960
i_assert( edhiter->current != NULL && edhiter->current->header != NULL);
962
raw = edhiter->current->field->utf8_value;
963
for ( i = strlen(raw)-1; i >= 0; i-- ) {
964
if ( raw[i] != ' ' && raw[i] != '\t' ) break;
967
*value_r = t_strndup(raw, i+1);
970
bool edit_mail_headers_iterate_next
971
(struct edit_mail_header_iter *edhiter)
975
( !edhiter->reverse ? edhiter->current->next : edhiter->current->next );
976
} while ( edhiter->current != NULL && edhiter->current->header != NULL &&
977
edhiter->header != NULL && edhiter->current->header != edhiter->header );
979
return ( edhiter->current != NULL && edhiter->current->header != NULL);
982
bool edit_mail_headers_iterate_remove
983
(struct edit_mail_header_iter *edhiter)
985
struct _header_field_index *field_idx;
988
i_assert( edhiter->current != NULL && edhiter->current->header != NULL);
990
edit_mail_modify(edhiter->mail);
992
field_idx = edhiter->current;
993
next = edit_mail_headers_iterate_next(edhiter);
994
edit_mail_header_field_delete(edhiter->mail, field_idx, TRUE);
1000
/* Body modification */
1008
static void edit_mail_close(struct mail *mail)
1010
struct edit_mail *edmail = (struct edit_mail *)mail;
1012
edmail->wrapped->v.close(&edmail->wrapped->mail);
1015
static void edit_mail_free(struct mail *mail)
1017
struct edit_mail *edmail = (struct edit_mail *)mail;
1019
edmail->wrapped->v.free(&edmail->wrapped->mail);
1021
edit_mail_unwrap(&edmail);
1024
static void edit_mail_set_seq
1025
(struct mail *mail ATTR_UNUSED, uint32_t seq ATTR_UNUSED,
1026
bool saving ATTR_UNUSED)
1028
i_panic("edit_mail_set_seq() not implemented");
1031
static bool ATTR_NORETURN edit_mail_set_uid
1032
(struct mail *mail ATTR_UNUSED, uint32_t uid ATTR_UNUSED)
1034
i_panic("edit_mail_set_uid() not implemented");
1037
static void edit_mail_set_uid_cache_updates(struct mail *mail, bool set)
1039
struct edit_mail *edmail = (struct edit_mail *)mail;
1041
edmail->wrapped->v.set_uid_cache_updates(&edmail->wrapped->mail, set);
1044
static void edit_mail_add_temp_wanted_fields
1045
(struct mail *mail ATTR_UNUSED, enum mail_fetch_field fields ATTR_UNUSED,
1046
struct mailbox_header_lookup_ctx *headers ATTR_UNUSED)
1051
static enum mail_flags edit_mail_get_flags(struct mail *mail)
1053
struct edit_mail *edmail = (struct edit_mail *)mail;
1055
return edmail->wrapped->v.get_flags(&edmail->wrapped->mail);
1058
static const char *const *edit_mail_get_keywords(struct mail *mail)
1060
struct edit_mail *edmail = (struct edit_mail *)mail;
1062
return edmail->wrapped->v.get_keywords(&edmail->wrapped->mail);
1065
static const ARRAY_TYPE(keyword_indexes) *edit_mail_get_keyword_indexes
1068
struct edit_mail *edmail = (struct edit_mail *)mail;
1070
return edmail->wrapped->v.get_keyword_indexes(&edmail->wrapped->mail);
1073
static uint64_t edit_mail_get_modseq(struct mail *mail)
1075
struct edit_mail *edmail = (struct edit_mail *)mail;
1077
return edmail->wrapped->v.get_modseq(&edmail->wrapped->mail);
1080
static int edit_mail_get_parts
1081
(struct mail *mail, struct message_part **parts_r)
1083
struct edit_mail *edmail = (struct edit_mail *)mail;
1085
return edmail->wrapped->v.get_parts(&edmail->wrapped->mail, parts_r);
1088
static int edit_mail_get_date
1089
(struct mail *mail, time_t *date_r, int *timezone_r)
1091
struct edit_mail *edmail = (struct edit_mail *)mail;
1093
return edmail->wrapped->v.get_date(&edmail->wrapped->mail, date_r, timezone_r);
1096
static int edit_mail_get_received_date(struct mail *mail, time_t *date_r)
1098
struct edit_mail *edmail = (struct edit_mail *)mail;
1100
return edmail->wrapped->v.get_received_date(&edmail->wrapped->mail, date_r);
1103
static int edit_mail_get_save_date(struct mail *mail, time_t *date_r)
1105
struct edit_mail *edmail = (struct edit_mail *)mail;
1107
return edmail->wrapped->v.get_save_date(&edmail->wrapped->mail, date_r);
1110
static int edit_mail_get_virtual_size(struct mail *mail, uoff_t *size_r)
1112
struct edit_mail *edmail = (struct edit_mail *)mail;
1114
if ( !edmail->headers_parsed ) {
1115
*size_r = edmail->wrapped_hdr_size.virtual_size +
1116
edmail->wrapped_body_size.virtual_size;
1118
if ( !edmail->modified )
1121
*size_r = edmail->wrapped_body_size.virtual_size + 2;
1124
*size_r += edmail->hdr_size.virtual_size + edmail->body_size.virtual_size;
1128
static int edit_mail_get_physical_size(struct mail *mail, uoff_t *size_r)
1130
struct edit_mail *edmail = (struct edit_mail *)mail;
1133
if ( !edmail->headers_parsed ) {
1134
*size_r = edmail->wrapped_hdr_size.physical_size +
1135
edmail->wrapped_body_size.physical_size;
1137
if ( !edmail->modified )
1140
*size_r = edmail->wrapped_body_size.physical_size +
1141
( edmail->eoh_crlf ? 2 : 1 );
1144
*size_r += edmail->hdr_size.physical_size + edmail->body_size.physical_size;
1148
static int edit_mail_get_first_header
1149
(struct mail *mail, const char *field_name, bool decode_to_utf8,
1150
const char **value_r)
1152
struct edit_mail *edmail = (struct edit_mail *)mail;
1153
struct _header_index *header_idx;
1154
struct _header_field *field;
1157
/* Check whether mail headers were modified at all */
1158
if ( !edmail->modified || edmail->headers_head == NULL ) {
1160
return edmail->wrapped->v.get_first_header
1161
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1164
/* Try to find modified header */
1165
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ||
1166
header_idx->count == 0 ) {
1168
if ( !edmail->headers_parsed ) {
1170
return edmail->wrapped->v.get_first_header
1171
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1178
/* Get the first occurence */
1179
if ( edmail->header_fields_appended == NULL ) {
1180
/* There are no appended headers, so first is found directly */
1181
field = header_idx->first->field;
1183
struct _header_field_index *field_idx;
1185
/* Scan prepended headers */
1186
field_idx = edmail->header_fields_head;
1187
while ( field_idx != NULL ) {
1188
if ( field_idx->header == header_idx )
1191
if ( field_idx == edmail->header_fields_appended ) {
1195
field_idx = field_idx->next;
1198
if ( field_idx == NULL ) {
1199
/* Check original message */
1200
if ( (ret=edmail->wrapped->v.get_first_header
1201
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r)) != 0 )
1204
/* Use first (apparently appended) header */
1205
field = header_idx->first->field;
1207
field = field_idx->field;
1211
if ( decode_to_utf8 )
1212
*value_r = field->utf8_value;
1214
*value_r = (const char *) (field->data + field->body_offset);
1218
static int edit_mail_get_headers
1219
(struct mail *mail, const char *field_name, bool decode_to_utf8,
1220
const char *const **value_r)
1222
struct edit_mail *edmail = (struct edit_mail *)mail;
1223
struct _header_index *header_idx;
1224
struct _header_field_index *field_idx;
1225
const char *const *headers;
1226
ARRAY_DEFINE(header_values, const char *);
1228
if ( !edmail->modified || edmail->headers_head == NULL ) {
1230
return edmail->wrapped->v.get_headers
1231
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1234
if ( (header_idx=edit_mail_header_find(edmail, field_name)) == NULL ||
1235
header_idx->count == 0 ) {
1236
if ( !edmail->headers_parsed ) {
1238
return edmail->wrapped->v.get_headers
1239
(&edmail->wrapped->mail, field_name, decode_to_utf8, value_r);
1242
t_array_init(&header_values, 1);
1243
(void)array_append_space(&header_values);
1244
*value_r = array_idx(&header_values, 0);
1250
/* Read original headers too if message headers are not parsed */
1252
if ( !edmail->headers_parsed && edmail->wrapped->v.get_headers
1253
(&edmail->wrapped->mail, field_name, decode_to_utf8, &headers) < 0 ) {
1257
/* Fill result array */
1258
t_array_init(&header_values, 32);
1259
field_idx = header_idx->first;
1260
while ( field_idx != NULL ) {
1262
/* If current field is the first appended one, we need to add original
1265
if ( field_idx == edmail->header_fields_appended && headers != NULL ) {
1266
while ( *headers != NULL ) {
1267
array_append(&header_values, headers, 1);
1273
/* Add modified header to the list */
1274
if ( field_idx->field->header == header_idx->header ) {
1275
struct _header_field *field = field_idx->field;
1278
if ( decode_to_utf8 )
1279
value = field->utf8_value;
1281
value = (const char *)(field->data + field->body_offset);
1283
array_append(&header_values, &value, 1);
1285
if ( field_idx == header_idx->last )
1289
field_idx = field_idx->next;
1292
/* Add original headers if necessary */
1293
if ( headers != NULL ) {
1294
while ( *headers != NULL ) {
1295
array_append(&header_values, headers, 1);
1301
(void)array_append_space(&header_values);
1302
*value_r = array_idx(&header_values, 0);
1306
static int ATTR_NORETURN edit_mail_get_header_stream
1307
(struct mail *mail ATTR_UNUSED,
1308
struct mailbox_header_lookup_ctx *headers ATTR_UNUSED,
1309
struct istream **stream_r ATTR_UNUSED)
1311
// FIXME: implement!
1312
i_panic("edit_mail_get_header_stream() not implemented");
1315
static int edit_mail_get_stream
1316
(struct mail *mail, bool get_body ATTR_UNUSED, struct message_size *hdr_size,
1317
struct message_size *body_size, struct istream **stream_r)
1319
struct edit_mail *edmail = (struct edit_mail *)mail;
1321
if ( edmail->stream == NULL ) {
1322
edmail->stream = edit_mail_istream_create(edmail);
1325
if ( hdr_size != NULL ) {
1326
*hdr_size = edmail->wrapped_hdr_size;
1327
hdr_size->physical_size += edmail->hdr_size.physical_size;
1328
hdr_size->virtual_size += edmail->hdr_size.virtual_size;
1329
hdr_size->lines += edmail->hdr_size.lines;
1332
if ( body_size != NULL ) {
1333
*body_size = edmail->wrapped_body_size;
1336
*stream_r = edmail->stream;
1337
i_stream_seek(edmail->stream, 0);
1342
static int edit_mail_get_special
1343
(struct mail *mail, enum mail_fetch_field field, const char **value_r)
1345
struct edit_mail *edmail = (struct edit_mail *)mail;
1347
if ( edmail->modified ) {
1348
/* Block certain fields when modified */
1351
case MAIL_FETCH_GUID:
1352
/* This is in essence a new message */
1355
case MAIL_FETCH_UIDL_FILE_NAME:
1356
/* Prevent hardlink copying */
1364
return edmail->wrapped->v.get_special(&edmail->wrapped->mail, field, value_r);
1367
static struct mail *edit_mail_get_real_mail(struct mail *mail)
1369
struct edit_mail *edmail = (struct edit_mail *)mail;
1371
return edit_mail_get_mail(edmail);
1374
static void edit_mail_update_flags
1375
(struct mail *mail, enum modify_type modify_type, enum mail_flags flags)
1377
struct edit_mail *edmail = (struct edit_mail *)mail;
1379
edmail->wrapped->v.update_flags(&edmail->wrapped->mail, modify_type, flags);
1382
static void edit_mail_update_keywords
1383
(struct mail *mail, enum modify_type modify_type,
1384
struct mail_keywords *keywords)
1386
struct edit_mail *edmail = (struct edit_mail *)mail;
1388
edmail->wrapped->v.update_keywords
1389
(&edmail->wrapped->mail, modify_type, keywords);
1392
static void edit_mail_update_modseq(struct mail *mail, uint64_t min_modseq)
1394
struct edit_mail *edmail = (struct edit_mail *)mail;
1396
edmail->wrapped->v.update_modseq(&edmail->wrapped->mail, min_modseq);
1399
static void edit_mail_update_pop3_uidl(struct mail *mail, const char *uidl)
1401
struct edit_mail *edmail = (struct edit_mail *)mail;
1403
if ( edmail->wrapped->v.update_pop3_uidl != NULL )
1404
edmail->wrapped->v.update_pop3_uidl(&edmail->wrapped->mail, uidl);
1407
static void edit_mail_expunge(struct mail *mail ATTR_UNUSED)
1412
static void edit_mail_set_cache_corrupted
1413
(struct mail *mail, enum mail_fetch_field field)
1415
struct edit_mail *edmail = (struct edit_mail *)mail;
1417
edmail->wrapped->v.set_cache_corrupted(&edmail->wrapped->mail, field);
1420
static struct mail_vfuncs edit_mail_vfuncs = {
1425
edit_mail_set_uid_cache_updates,
1428
edit_mail_add_temp_wanted_fields,
1429
edit_mail_get_flags,
1430
edit_mail_get_keywords,
1431
edit_mail_get_keyword_indexes,
1432
edit_mail_get_modseq,
1433
edit_mail_get_parts,
1435
edit_mail_get_received_date,
1436
edit_mail_get_save_date,
1437
edit_mail_get_virtual_size,
1438
edit_mail_get_physical_size,
1439
edit_mail_get_first_header,
1440
edit_mail_get_headers,
1441
edit_mail_get_header_stream,
1442
edit_mail_get_stream,
1443
edit_mail_get_special,
1444
edit_mail_get_real_mail,
1445
edit_mail_update_flags,
1446
edit_mail_update_keywords,
1447
edit_mail_update_modseq,
1448
edit_mail_update_pop3_uidl,
1450
edit_mail_set_cache_corrupted,
1458
struct edit_mail_istream {
1459
struct istream_private istream;
1463
struct edit_mail *mail;
1465
struct _header_field_index *cur_header;
1467
unsigned int read_header;
1470
static void edit_mail_istream_destroy(struct iostream_private *stream)
1472
struct edit_mail_istream *edstream =
1473
(struct edit_mail_istream *)stream;
1475
i_stream_unref(&edstream->istream.parent);
1476
pool_unref(&edstream->pool);
1479
static ssize_t edit_mail_istream_read(struct istream_private *stream)
1481
struct edit_mail_istream *edstream =
1482
(struct edit_mail_istream *)stream;
1483
struct edit_mail *edmail = edstream->mail;
1484
uoff_t parent_v_offset, hdr_size, v_offset = stream->istream.v_offset;
1488
if ( edstream->buffer->used > 0 ) {
1489
if ( stream->skip > 0 ) {
1491
(edstream->buffer, 0, edstream->buffer, stream->skip, (size_t)-1);
1492
stream->pos -= stream->skip;
1494
buffer_set_used_size(edstream->buffer, stream->pos);
1498
if ( edstream->buffer->used > 0 || stream->pos - stream->skip == 0 ) {
1499
if ( edstream->cur_header != NULL ) {
1500
while ( edstream->cur_header != NULL && edstream->buffer->used < 1024 ) {
1501
buffer_append(edstream->buffer, edstream->cur_header->field->data,
1502
edstream->cur_header->field->size);
1504
edstream->cur_header = edstream->cur_header->next;
1506
if ( !edmail->headers_parsed
1507
&& edstream->cur_header == edmail->header_fields_appended )
1508
edstream->cur_header = NULL;
1513
if ( edstream->buffer->used > 0 ) {
1514
stream->buffer = buffer_get_data(edstream->buffer, &pos);
1515
ret = (ssize_t)pos + stream->skip - stream->pos;
1516
i_assert( ret >= 0 );
1526
if ( !edmail->headers_parsed && edmail->header_fields_appended != NULL ) {
1527
/* Output headers from original stream */
1529
/* At what offset does the header end (not including LF of final empty line)
1530
* Any final CR is dealt with later
1532
hdr_size = edmail->wrapped_hdr_size.physical_size +
1533
edmail->hdr_size.physical_size -
1534
edmail->appended_hdr_size.physical_size - 1;
1536
if ( v_offset < hdr_size ) {
1537
parent_v_offset = stream->parent_start_offset +
1538
(v_offset + edmail->appended_hdr_size.physical_size -
1539
edmail->hdr_size.physical_size);
1541
i_stream_seek(stream->parent, parent_v_offset);
1543
if ( (ret=i_stream_read_copy_from_parent(&stream->istream)) < 0 )
1546
if ( stream->pos >= hdr_size - 1 - v_offset ) {
1547
/* Truncate buffer from original mail strictly to header */
1548
ret -= stream->pos - (hdr_size - v_offset);
1549
stream->pos = hdr_size - v_offset;
1551
/* Strip final CR too when it is present */
1552
if ( stream->buffer[stream->pos-1] == '\r' ) {
1558
edstream->cur_header = edmail->header_fields_appended;
1567
if ( !edmail->headers_parsed ) {
1568
if ( v_offset < edmail->hdr_size.physical_size )
1571
parent_v_offset = stream->parent_start_offset
1572
+ (v_offset - edmail->hdr_size.physical_size);
1574
if ( v_offset < edmail->hdr_size.physical_size )
1577
parent_v_offset = stream->parent_start_offset
1578
+ edmail->wrapped_hdr_size.physical_size
1579
+ (v_offset - edmail->hdr_size.physical_size)
1580
- ( edmail->eoh_crlf ? 2 : 1);
1583
i_stream_seek(stream->parent, parent_v_offset);
1584
return i_stream_read_copy_from_parent(&stream->istream);
1588
stream_reset_to(struct edit_mail_istream *edstream, uoff_t v_offset)
1590
edstream->istream.istream.v_offset = v_offset;
1591
edstream->istream.skip = 0;
1592
edstream->istream.pos = 0;
1593
edstream->istream.buffer = NULL;
1594
buffer_set_used_size(edstream->buffer, 0);
1595
i_stream_seek(edstream->istream.parent, 0);
1599
stream_skip_to_header
1600
(struct edit_mail_istream *edstream, struct _header_field_index *header,
1603
struct _header_field *field = header->field;
1604
edstream->cur_header = header;
1606
/* Partially fill the buffer if in the middle of the header */
1608
if ( skip < field->size ) {
1610
(edstream->buffer, field->data + skip, field->size-skip );
1613
skip -= field->size;
1616
i_assert( skip == 0 );
1620
static void edit_mail_istream_seek
1621
(struct istream_private *stream, uoff_t v_offset, bool mark ATTR_UNUSED)
1623
struct edit_mail_istream *edstream =
1624
(struct edit_mail_istream *)stream;
1625
struct _header_field_index *cur_header;
1626
struct edit_mail *edmail = edstream->mail;
1630
if ( v_offset == 0 ) {
1631
stream_reset_to(edstream, 0);
1633
if ( edmail->header_fields_head != edmail->header_fields_appended )
1634
edstream->cur_header = edmail->header_fields_head;
1638
/* Inside (prepended) headers */
1639
if ( edmail->headers_parsed ) {
1640
offset = edmail->hdr_size.physical_size;
1642
offset = edmail->hdr_size.physical_size -
1643
edmail->appended_hdr_size.physical_size;
1646
if ( v_offset < offset ) {
1647
stream_reset_to(edstream, v_offset);
1649
/* Find the header */
1650
cur_header = edmail->header_fields_head;
1651
i_assert( cur_header != NULL &&
1652
cur_header != edmail->header_fields_appended );
1653
offset = cur_header->field->size;
1654
while ( v_offset > offset ) {
1655
cur_header = cur_header->next;
1656
i_assert( cur_header != NULL &&
1657
cur_header != edmail->header_fields_appended );
1659
offset += cur_header->field->size;
1662
stream_skip_to_header(edstream, cur_header, (offset - v_offset));
1666
if ( !edmail->headers_parsed ) {
1667
/* Inside original header */
1668
offset = edmail->hdr_size.physical_size -
1669
edmail->appended_hdr_size.physical_size +
1670
edmail->wrapped_hdr_size.physical_size;
1671
if ( v_offset < offset ) {
1672
stream_reset_to(edstream, v_offset);
1673
edstream->cur_header = NULL;
1677
/* Inside appended header */
1678
offset = edmail->hdr_size.physical_size +
1679
edmail->wrapped_hdr_size.physical_size;
1680
if ( v_offset < offset ) {
1681
stream_reset_to(edstream, v_offset);
1683
offset -= edmail->appended_hdr_size.physical_size;
1685
cur_header = edmail->header_fields_appended;
1686
i_assert( cur_header != NULL );
1687
offset += cur_header->field->size;
1689
while ( cur_header != NULL && v_offset > offset ) {
1690
cur_header = edstream->cur_header->next;
1691
i_assert( cur_header != NULL );
1693
offset += cur_header->field->size;
1696
stream_skip_to_header(edstream, cur_header, (offset - v_offset));
1701
stream_reset_to(edstream, v_offset);
1702
edstream->cur_header = NULL;
1705
static void ATTR_NORETURN
1706
edit_mail_istream_sync(struct istream_private *stream ATTR_UNUSED)
1708
i_panic("edit-mail istream sync() not implemented");
1711
static const struct stat *
1712
edit_mail_istream_stat(struct istream_private *stream, bool exact)
1714
struct edit_mail_istream *edstream =
1715
(struct edit_mail_istream *)stream;
1716
struct edit_mail *edmail = edstream->mail;
1717
const struct stat *st;
1719
/* Stat the original stream */
1720
st = i_stream_stat(stream->parent, exact);
1721
if (st == NULL || st->st_size == -1 || !exact)
1724
/* Adjust stat data */
1725
stream->statbuf = *st;
1727
if ( !edmail->headers_parsed ) {
1728
if ( !edmail->modified )
1729
return &stream->statbuf;
1731
stream->statbuf.st_size = edmail->wrapped_body_size.physical_size +
1732
( edmail->eoh_crlf ? 2 : 1 );
1735
stream->statbuf.st_size += edmail->hdr_size.physical_size +
1736
edmail->body_size.physical_size;
1738
return &stream->statbuf;
1741
struct istream *edit_mail_istream_create
1742
(struct edit_mail *edmail)
1744
struct edit_mail_istream *edstream;
1745
struct istream *wrapped = edmail->wrapped_stream;
1747
edstream = i_new(struct edit_mail_istream, 1);
1748
edstream->pool = pool_alloconly_create(MEMPOOL_GROWING
1749
"edit mail stream", 4096);
1750
edstream->mail = edmail;
1751
edstream->buffer = buffer_create_dynamic(edstream->pool, 1024);
1753
edstream->istream.max_buffer_size = wrapped->real_stream->max_buffer_size;
1755
edstream->istream.iostream.destroy = edit_mail_istream_destroy;
1756
edstream->istream.read = edit_mail_istream_read;
1757
edstream->istream.seek = edit_mail_istream_seek;
1758
edstream->istream.sync = edit_mail_istream_sync;
1759
edstream->istream.stat = edit_mail_istream_stat;
1761
edstream->istream.istream.readable_fd = FALSE;
1762
edstream->istream.istream.blocking = wrapped->blocking;
1763
edstream->istream.istream.seekable = wrapped->seekable;
1765
if ( edmail->header_fields_head != edmail->header_fields_appended )
1766
edstream->cur_header = edmail->header_fields_head;
1768
i_stream_seek(wrapped, 0);
1770
return i_stream_create(&edstream->istream, wrapped, -1);