169 #ifdef STRCASECMP_IN_STRINGS_H
204 #define HBC_HEADER_INDEX(class) ((class) - MIME_HDR_FIRST)
205 #define HBC_BODY_INDEX (0)
207 #define HBC_INIT(hbc, index, name, value) do { \
208 HBC_MAP_INFO *_mp = (hbc)->map_info + (index); \
209 if (*(value) != 0) { \
210 _mp->map_class = (name); \
211 _mp->maps = maps_create((name), (value), DICT_FLAG_LOCK); \
213 _mp->map_class = 0; \
220 #define HBC_CTXT_HEADER "header"
221 #define HBC_CTXT_BODY "body"
225 #define STR(x) vstring_str(x)
226 #define LEN(x) VSTRING_LEN(x)
231 const char *map_class,
const char *where,
232 const char *cmd,
const char *line,
233 ssize_t line_len, off_t offset)
235 const char *cmd_args = cmd + strcspn(cmd,
" \t");
236 ssize_t cmd_len = cmd_args - cmd;
244 while (*cmd_args &&
ISSPACE(*cmd_args))
247 #define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
250 && (ret = cb->
extend(context, cmd, cmd_len, cmd_args, where, line,
254 if (
STREQUAL(cmd,
"WARN", cmd_len)) {
255 cb->
logger(context,
"warning", where, line, cmd_args);
256 return ((
char *) line);
258 if (
STREQUAL(cmd,
"INFO", cmd_len)) {
259 cb->
logger(context,
"info", where, line, cmd_args);
260 return ((
char *) line);
262 if (
STREQUAL(cmd,
"REPLACE", cmd_len)) {
263 if (*cmd_args == 0) {
264 msg_warn(
"REPLACE action without text in %s map", map_class);
265 return ((
char *) line);
268 msg_warn(
"bad REPLACE header text \"%s\" in %s map -- "
269 "need \"headername: headervalue\"", cmd_args, map_class);
270 return ((
char *) line);
272 cb->
logger(context,
"replace", where, line, cmd_args);
277 if (*cmd_args == 0) {
278 msg_warn(
"PREPEND action without text in %s map", map_class);
281 msg_warn(
"bad PREPEND header text \"%s\" in %s map -- "
282 "need \"headername: headervalue\"", cmd_args, map_class);
284 cb->
logger(context,
"prepend", where, line, cmd_args);
287 return ((
char *) line);
289 if (
STREQUAL(cmd,
"STRIP", cmd_len)) {
290 cb->
logger(context,
"strip", where, line, cmd_args);
295 if (
STREQUAL(cmd,
"IGNORE", cmd_len))
301 return ((
char *) line);
303 msg_warn(
"unsupported command in %s map: %s", map_class, cmd);
304 return ((
char *) line);
313 const char *myname =
"hbc_header_checks";
331 STR(header),
LEN(header), offset));
335 return (
STR(header));
342 ssize_t len, off_t offset)
344 const char *myname =
"hbc_body_checks";
349 msg_info(
"%s: '%.30s'", myname, line);
360 return ((
char *) line);
367 const char *header_checks_value,
368 const char *mime_header_checks_name,
369 const char *mime_header_checks_value,
370 const char *nested_header_checks_name,
371 const char *nested_header_checks_value,
379 if (*header_checks_value == 0 && *mime_header_checks_value == 0
380 && *nested_header_checks_value == 0) {
387 header_checks_name, header_checks_value);
389 mime_header_checks_name, mime_header_checks_value);
391 nested_header_checks_name, nested_header_checks_value);
399 const char *body_checks_value,
407 if (*body_checks_value == 0) {
423 for (mp = hbc->
map_info; mp < hbc->map_info + len; mp++)
458 static void log_cb(
void *context,
const char *action,
const char *where,
459 const char *content,
const char *text)
461 const HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
465 dp->queueid, action, where, content, text);
468 dp->queueid, action, where, content);
474 static void out_cb(
void *context,
int rec_type,
const char *buf,
475 ssize_t len, off_t offset)
477 const HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
486 static void head_out(
void *context,
int header_class,
490 HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
493 if (dp->header_checks == 0
495 header_info, buf, offset)) ==
STR(buf)) {
501 "ERROR", (
long) offset,
STR(buf));
503 }
else if (out != 0) {
509 "ERROR", (
long) offset, out);
518 static void head_end(
void *context)
520 HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
522 out_cb(dp, 0,
"HEADER END",
sizeof(
"HEADER END") - 1, 0);
527 static void body_out(
void *context,
int rec_type,
const char *buf,
528 ssize_t len, off_t offset)
530 HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
533 if (dp->body_checks == 0
535 buf, len, offset)) == buf) {
537 dp->recno, rec_type, (
long) offset, buf);
538 out_cb(dp, rec_type,
STR(dp->buf),
LEN(dp->buf), offset);
539 }
else if (out != 0) {
541 dp->recno, rec_type, (
long) offset, out);
542 out_cb(dp, rec_type,
STR(dp->buf),
LEN(dp->buf), offset);
550 static void body_end(
void *context)
552 HBC_TEST_CONTEXT *dp = (HBC_TEST_CONTEXT *) context;
554 out_cb(dp, 0,
"BODY END",
sizeof(
"BODY END") - 1, 0);
559 static void err_print(
void *unused_context,
int err_flag,
560 const char *text, ssize_t len)
563 len < 100 ? (
int) len : 100, text);
571 int main(
int argc,
char **argv)
577 HBC_TEST_CONTEXT context;
587 msg_fatal(
"usage: %s header_checks mime_header_checks nested_header_checks body_checks", argv[0]);
592 #define MIME_OPTIONS \
593 (MIME_OPT_REPORT_8BIT_IN_7BIT_BODY \
594 | MIME_OPT_REPORT_8BIT_IN_HEADER \
595 | MIME_OPT_REPORT_ENCODING_DOMAIN \
596 | MIME_OPT_REPORT_TRUNC_HEADER \
597 | MIME_OPT_REPORT_NESTING \
598 | MIME_OPT_DOWNGRADE)
606 context.header_checks =
608 "mime_header_checks", argv[2],
609 "nested_header_checks", argv[3],
611 context.body_checks =
615 context.queueid =
"test-queueID";
626 }
while (rec_type > 0);
632 msg_warn(
"message header length exceeds safety limit");
634 msg_warn(
"MIME nesting exceeds safety limit");
636 msg_warn(
"improper use of 8-bit data in message header");
638 msg_warn(
"improper use of 8-bit data in message body");
640 msg_warn(
"improper message/* or multipart/* encoding domain");
645 if (context.header_checks)
647 if (context.body_checks)
#define HBC_CHECKS_STAT_UNKNOWN
char * mystrdup(const char *str)
MIME_STATE * mime_state_alloc(int flags, MIME_STATE_HEAD_OUT head_out, MIME_STATE_ANY_END head_end, MIME_STATE_BODY_OUT body_out, MIME_STATE_ANY_END body_end, MIME_STATE_ERR_PRINT err_print, void *context)
#define HBC_CHECKS_STAT_IGNORE
void(* prepend)(void *, int, const char *, ssize_t, off_t)
#define MIME_ERR_ENCODING_DOMAIN
int main(int argc, char **argv)
#define MIME_HDR_MULTIPART
#define MIME_ERR_8BIT_IN_HEADER
int rec_streamlf_get(VSTREAM *stream, VSTRING *buf, int maxlen)
#define VSTRING_TERMINATE(vp)
const char hbc_checks_unknown
int mime_state_update(MIME_STATE *state, int rec_type, const char *text, ssize_t len)
void(* logger)(void *, const char *, const char *, const char *, const char *)
MIME_STATE * mime_state_free(MIME_STATE *state)
#define MIME_ERR_TRUNC_HEADER
char *(* extend)(void *, const char *, ssize_t, const char *, const char *, const char *, ssize_t, off_t)
#define STREQUAL(x, y, l)
void msg_warn(const char *fmt,...)
char * hbc_header_checks(void *context, HBC_CHECKS *hbc, int header_class, const HEADER_OPTS *hdr_opts, VSTRING *header, off_t offset)
VSTRING * vstring_alloc(ssize_t len)
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
#define MIME_ERR_8BIT_IN_7BIT_BODY
NORETURN msg_fatal(const char *fmt,...)
#define HBC_INIT(hbc, index, name, value)
MAPS * maps_free(MAPS *maps)
const char * mime_state_error(int error_code)
#define hbc_body_checks_free(hbc)
int vstream_fflush(VSTREAM *stream)
#define vstream_fwrite(v, b, n)
HBC_CHECKS * hbc_header_checks_create(const char *header_checks_name, const char *header_checks_value, const char *mime_header_checks_name, const char *mime_header_checks_value, const char *nested_header_checks_name, const char *nested_header_checks_value, HBC_CALL_BACKS *call_backs)
void _hbc_checks_free(HBC_CHECKS *hbc, ssize_t len)
#define HBC_CHECKS_STAT_ERROR
HBC_CHECKS * hbc_body_checks_create(const char *body_checks_name, const char *body_checks_value, HBC_CALL_BACKS *call_backs)
VSTRING * vstring_free(VSTRING *vp)
HBC_CALL_BACKS * call_backs
void msg_vstream_init(const char *name, VSTREAM *vp)
#define VSTREAM_PUTC(ch, vp)
#define hbc_header_checks_free(hbc)
char * hbc_body_checks(void *context, HBC_CHECKS *hbc, const char *line, ssize_t len, off_t offset)
const char * maps_find(MAPS *maps, const char *name, int flags)
void * mymalloc(ssize_t len)
#define HBC_HEADER_INDEX(class)
void msg_info(const char *fmt,...)