9 /* #include "cleanup.h"
11 /* int cleanup_body_edit_start(state)
12 /* CLEANUP_STATE *state;
14 /* int cleanup_body_edit_write(state, type, buf)
15 /* CLEANUP_STATE *state;
19 /* int cleanup_body_edit_finish(state)
20 /* CLEANUP_STATE *state;
22 /* void cleanup_body_edit_free(state)
23 /* CLEANUP_STATE *state;
25 /* This module maintains queue file regions with body content.
26 /* Regions are created on the fly, and can be reused multiple
27 /* times. This module must not be called until the queue file
28 /* is complete, and there must be no other read/write access
29 /* to the queue file between the cleanup_body_edit_start() and
30 /* cleanup_body_edit_finish() calls.
32 /* cleanup_body_edit_start() performs initialization and sets
33 /* the queue file write pointer to the start of the first body
36 /* cleanup_body_edit_write() adds a queue file record to the
37 /* queue file. When the current body region fills up, some
38 /* unused region is reused, or a new region is created.
40 /* cleanup_body_edit_finish() makes some final adjustments
41 /* after the last body content record is written.
43 /* cleanup_body_edit_free() frees up memory that was allocated
44 /* by cleanup_body_edit_start() and cleanup_body_edit_write().
48 /* Queue file and message processing state. This state is updated
49 /* as records are processed and as errors happen.
57 /* The Secure Mailer license must be distributed with this software.
60 /* IBM T.J. Watson Research
62 /* Yorktown Heights, NY 10598, USA
69 /* Utility library. */
81 /* Application-specific. */
85 #define LEN(s) VSTRING_LEN(s)
87 static int cleanup_body_edit_ptr_rec_len
;
89 /* cleanup_body_edit_start - rewrite body region pool */
91 int cleanup_body_edit_start(CLEANUP_STATE
*state
)
93 const char *myname
= "cleanup_body_edit_start";
94 CLEANUP_REGION
*curr_rp
;
97 * Calculate the payload size sans body.
99 state
->cont_length
= state
->body_offset
- state
->data_offset
;
102 * One-time initialization.
104 if (state
->body_regions
== 0) {
105 REC_SPACE_NEED(REC_TYPE_PTR_PAYL_SIZE
, cleanup_body_edit_ptr_rec_len
);
106 cleanup_region_init(state
);
110 * Return all body regions to the free pool.
112 cleanup_region_return(state
, state
->body_regions
);
115 * Select the first region. XXX This will usally be the original body
116 * segment, but we must not count on that. Region assignments may change
117 * when header editing also uses queue file regions. XXX We don't really
118 * know if the first region will be large enough to hold the first body
119 * text record, but this problem is so rare that we will not complicate
120 * the code for it. If the first region is too small then we will simply
123 curr_rp
= state
->curr_body_region
= state
->body_regions
=
124 cleanup_region_open(state
, cleanup_body_edit_ptr_rec_len
);
127 * Link the first body region to the last message header.
129 if (vstream_fseek(state
->dst
, state
->append_hdr_pt_offset
, SEEK_SET
) < 0) {
130 msg_warn("%s: seek file %s: %m", myname
, cleanup_path
);
133 state
->append_hdr_pt_target
= curr_rp
->start
;
134 rec_fprintf(state
->dst
, REC_TYPE_PTR
, REC_TYPE_PTR_FORMAT
,
135 (long) state
->append_hdr_pt_target
);
138 * Move the file write pointer to the start of the current region.
140 if (vstream_ftell(state
->dst
) != curr_rp
->start
141 && vstream_fseek(state
->dst
, curr_rp
->start
, SEEK_SET
) < 0) {
142 msg_warn("%s: seek file %s: %m", myname
, cleanup_path
);
148 /* cleanup_body_edit_write - add record to body region pool */
150 int cleanup_body_edit_write(CLEANUP_STATE
*state
, int rec_type
,
153 const char *myname
= "cleanup_body_edit_write";
154 CLEANUP_REGION
*curr_rp
= state
->curr_body_region
;
155 CLEANUP_REGION
*next_rp
;
157 ssize_t space_needed
;
161 msg_info("%s: where %ld, buflen %ld region start %ld len %ld",
162 myname
, (long) curr_rp
->write_offs
, (long) LEN(buf
),
163 (long) curr_rp
->start
, (long) curr_rp
->len
);
166 * Switch to the next body region if we filled up the current one (we
167 * always append to an open-ended region). Besides space to write the
168 * specified record, we need to leave space for a final pointer record
169 * that will link this body region to the next region or to the content
172 if (curr_rp
->len
> 0) {
173 space_used
= curr_rp
->write_offs
- curr_rp
->start
;
174 REC_SPACE_NEED(LEN(buf
), rec_len
);
175 space_needed
= rec_len
+ cleanup_body_edit_ptr_rec_len
;
176 if (space_needed
> curr_rp
->len
- space_used
) {
179 * Update the payload size. Connect the filled up body region to
182 state
->cont_length
+= space_used
;
183 next_rp
= cleanup_region_open(state
, space_needed
);
185 msg_info("%s: link %ld -> %ld", myname
,
186 (long) curr_rp
->write_offs
, (long) next_rp
->start
);
187 rec_fprintf(state
->dst
, REC_TYPE_PTR
, REC_TYPE_PTR_FORMAT
,
188 (long) next_rp
->start
);
189 curr_rp
->write_offs
= vstream_ftell(state
->dst
);
190 cleanup_region_close(state
, curr_rp
);
191 curr_rp
->next
= next_rp
;
194 * Select the new body region.
196 state
->curr_body_region
= curr_rp
= next_rp
;
197 if (vstream_fseek(state
->dst
, curr_rp
->start
, SEEK_SET
) < 0) {
198 msg_warn("%s: seek file %s: %m", myname
, cleanup_path
);
205 * Finally, output the queue file record.
207 CLEANUP_OUT_BUF(state
, REC_TYPE_NORM
, buf
);
208 curr_rp
->write_offs
= vstream_ftell(state
->dst
);
213 /* cleanup_body_edit_finish - wrap up body region pool */
215 int cleanup_body_edit_finish(CLEANUP_STATE
*state
)
217 CLEANUP_REGION
*curr_rp
= state
->curr_body_region
;
220 * Update the payload size.
222 state
->cont_length
+= curr_rp
->write_offs
- curr_rp
->start
;
225 * Link the last body region to the content terminator record.
227 rec_fprintf(state
->dst
, REC_TYPE_PTR
, REC_TYPE_PTR_FORMAT
,
228 (long) state
->xtra_offset
);
229 curr_rp
->write_offs
= vstream_ftell(state
->dst
);
230 cleanup_region_close(state
, curr_rp
);
232 return (CLEANUP_OUT_OK(state
) ? 0 : -1);