diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/HISTORY ./HISTORY *** /var/tmp/postfix-2.5-20070516/HISTORY Tue May 15 15:51:27 2007 --- ./HISTORY Tue May 22 17:29:28 2007 *************** *** 13548,13553 **** --- 13548,13561 ---- transports. Cause: insufficient documentation. Files: error/error.c, discard/discard.c. + 20070522 + + Feature: recipient duplicate filter that sits between the + local(8) delivery agents and the cleanup(8) servers. This + eliminates duplicate recipients between distribution lists + that are implemented as local(8) aliases. It does not work + for list managers that re-inject mail into Postfix. + Wish list: Would there be a problem adding $smtpd_mumble_restrictions diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/Makefile.in ./Makefile.in *** /var/tmp/postfix-2.5-20070516/Makefile.in Fri Jul 21 14:43:15 2006 --- ./Makefile.in Tue May 22 10:47:38 2007 *************** *** 8,14 **** src/pipe src/showq src/postalias src/postcat src/postconf src/postdrop \ src/postkick src/postlock src/postlog src/postmap src/postqueue \ src/postsuper src/qmqpd src/spawn src/flush src/verify \ ! src/virtual src/proxymap src/anvil src/scache src/discard src/tlsmgr MANDIRS = proto man html default: update --- 8,15 ---- src/pipe src/showq src/postalias src/postcat src/postconf src/postdrop \ src/postkick src/postlock src/postlog src/postmap src/postqueue \ src/postsuper src/qmqpd src/spawn src/flush src/verify \ ! src/virtual src/proxymap src/anvil src/scache src/discard src/tlsmgr \ ! src/nodup MANDIRS = proto man html default: update diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/conf/post-install ./conf/post-install *** /var/tmp/postfix-2.5-20070516/conf/post-install Thu Mar 1 16:43:30 2007 --- ./conf/post-install Tue May 22 17:29:45 2007 *************** *** 659,664 **** --- 659,673 ---- EOF } + # Add missing nodup service to master.cf. + + grep '^nodup.*nodup' $config_directory/master.cf >/dev/null || { + echo Editing $config_directory/master.cf, adding missing entry for nodup service + cat >>$config_directory/master.cf <$&;g; s;\bdont_remove\b;$&;g; s;\bdouble_bounce_sender\b;$&;g; + s;\bglobal_dupli[-]*\n* *[]*cate_filter_limit\b;$&;g; s;\bdupli[-]*\n* *[]*cate_filter_limit\b;$&;g; + s;\bdupli[-]*\n* *[]*cate_filter_style\b;$&;g; s;\bempty_address_recip[-]*\n* *[]*ient\b;$&;g; s;\benable_original_recip[-]*\n* *[]*ient\b;$&;g; s;\benable_errors_to\b;$&;g; diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/proto/postconf.proto ./proto/postconf.proto *** /var/tmp/postfix-2.5-20070516/proto/postconf.proto Fri May 11 19:46:17 2007 --- ./proto/postconf.proto Tue May 22 17:33:09 2007 *************** *** 1213,1223 **** by the mail system. All mail to this address is silently discarded, in order to terminate mail bounce loops.

! %PARAM duplicate_filter_limit 1000

The maximal number of addresses remembered by the address duplicate filter for aliases(5) or virtual(5) alias expansion, or ! for showq(8) queue displays.

%PARAM enable_original_recipient yes --- 1213,1224 ---- by the mail system. All mail to this address is silently discarded, in order to terminate mail bounce loops.

! %PARAM duplicate_filter_limit 10000

The maximal number of addresses remembered by the address duplicate filter for aliases(5) or virtual(5) alias expansion, or ! for showq(8) queue displays (with earlier Postfix releases the ! default limit was 1000).

%PARAM enable_original_recipient yes *************** *** 10591,10595 **** --- 10592,10624 ----

Automatically detect 8BITMIME body content by looking at Content-Transfer-Encoding: message headers; historically, this behavior was hard-coded to be "always on".

+ +

This feature is available in Postfix 2.5 and later.

+ + %PARAM duplicate_filter_style strict + +

The duplicate recipient filter policy: strict or pragmatic. + With Postfix ≤ 2.2 use enable_original_recipient instead. With + Postfix 2.3 and 2.4, duplicate recipient elimination is currently + broken, because there is no option to ignore differences in DSN + (delivery status notification) attributes.

+ +
+ +
strict
Eliminate duplicate recipients only when + they have the exact same original recipient information, DSN (delivery + status notification) options, and the same envelope sender address. + This avoids loss of mail with "one domain per mailbox" applications, + and implements strict adherence to DSN standards. The X-Original-To: + header distinguishes between accounts within single-mailbox domains. +
+ +
pragmatic
Eliminate duplicate recipients even + when they have different original recipient information or DSN + (delivery status notification) options. This avoids duplicate + deliveries to users that subscribe to multiple distribution lists. +
+ +

This feature is available in Postfix 2.5 and later.

diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/Makefile.in ./src/cleanup/Makefile.in *** /var/tmp/postfix-2.5-20070516/src/cleanup/Makefile.in Sat Mar 17 13:51:40 2007 --- ./src/cleanup/Makefile.in Mon May 7 20:55:44 2007 *************** *** 310,315 **** --- 310,316 ---- cleanup.o: ../../include/attr.h cleanup.o: ../../include/been_here.h cleanup.o: ../../include/cleanup_user.h + cleanup.o: ../../include/ctable.h cleanup.o: ../../include/dict.h cleanup.o: ../../include/header_opts.h cleanup.o: ../../include/htable.h *************** *** 329,338 **** --- 330,341 ---- cleanup.o: ../../include/mymalloc.h cleanup.o: ../../include/nvtable.h cleanup.o: ../../include/rec_type.h + cleanup.o: ../../include/recipient_list.h cleanup.o: ../../include/record.h cleanup.o: ../../include/resolve_clnt.h cleanup.o: ../../include/string_list.h cleanup.o: ../../include/sys_defs.h + cleanup.o: ../../include/tcache.h cleanup.o: ../../include/tok822.h cleanup.o: ../../include/vbuf.h cleanup.o: ../../include/vstream.h *************** *** 344,349 **** --- 347,353 ---- cleanup_addr.o: ../../include/been_here.h cleanup_addr.o: ../../include/canon_addr.h cleanup_addr.o: ../../include/cleanup_user.h + cleanup_addr.o: ../../include/ctable.h cleanup_addr.o: ../../include/dict.h cleanup_addr.o: ../../include/dsn_mask.h cleanup_addr.o: ../../include/ext_prop.h *************** *** 365,374 **** --- 369,380 ---- cleanup_addr.o: ../../include/mymalloc.h cleanup_addr.o: ../../include/nvtable.h cleanup_addr.o: ../../include/rec_type.h + cleanup_addr.o: ../../include/recipient_list.h cleanup_addr.o: ../../include/resolve_clnt.h cleanup_addr.o: ../../include/string_list.h cleanup_addr.o: ../../include/stringops.h cleanup_addr.o: ../../include/sys_defs.h + cleanup_addr.o: ../../include/tcache.h cleanup_addr.o: ../../include/tok822.h cleanup_addr.o: ../../include/vbuf.h cleanup_addr.o: ../../include/vstream.h *************** *** 380,385 **** --- 386,392 ---- cleanup_api.o: ../../include/been_here.h cleanup_api.o: ../../include/bounce.h cleanup_api.o: ../../include/cleanup_user.h + cleanup_api.o: ../../include/ctable.h cleanup_api.o: ../../include/deliver_request.h cleanup_api.o: ../../include/dict.h cleanup_api.o: ../../include/dsn.h *************** *** 407,412 **** --- 414,420 ---- cleanup_api.o: ../../include/resolve_clnt.h cleanup_api.o: ../../include/string_list.h cleanup_api.o: ../../include/sys_defs.h + cleanup_api.o: ../../include/tcache.h cleanup_api.o: ../../include/tok822.h cleanup_api.o: ../../include/vbuf.h cleanup_api.o: ../../include/vstream.h *************** *** 416,421 **** --- 424,430 ---- cleanup_body_edit.o: ../../include/argv.h cleanup_body_edit.o: ../../include/been_here.h cleanup_body_edit.o: ../../include/cleanup_user.h + cleanup_body_edit.o: ../../include/ctable.h cleanup_body_edit.o: ../../include/dict.h cleanup_body_edit.o: ../../include/header_opts.h cleanup_body_edit.o: ../../include/htable.h *************** *** 430,439 **** --- 439,450 ---- cleanup_body_edit.o: ../../include/mymalloc.h cleanup_body_edit.o: ../../include/nvtable.h cleanup_body_edit.o: ../../include/rec_type.h + cleanup_body_edit.o: ../../include/recipient_list.h cleanup_body_edit.o: ../../include/record.h cleanup_body_edit.o: ../../include/resolve_clnt.h cleanup_body_edit.o: ../../include/string_list.h cleanup_body_edit.o: ../../include/sys_defs.h + cleanup_body_edit.o: ../../include/tcache.h cleanup_body_edit.o: ../../include/tok822.h cleanup_body_edit.o: ../../include/vbuf.h cleanup_body_edit.o: ../../include/vstream.h *************** *** 445,450 **** --- 456,462 ---- cleanup_bounce.o: ../../include/been_here.h cleanup_bounce.o: ../../include/bounce.h cleanup_bounce.o: ../../include/cleanup_user.h + cleanup_bounce.o: ../../include/ctable.h cleanup_bounce.o: ../../include/deliver_request.h cleanup_bounce.o: ../../include/dict.h cleanup_bounce.o: ../../include/dsn.h *************** *** 476,481 **** --- 488,494 ---- cleanup_bounce.o: ../../include/string_list.h cleanup_bounce.o: ../../include/stringops.h cleanup_bounce.o: ../../include/sys_defs.h + cleanup_bounce.o: ../../include/tcache.h cleanup_bounce.o: ../../include/tok822.h cleanup_bounce.o: ../../include/vbuf.h cleanup_bounce.o: ../../include/vstream.h *************** *** 486,491 **** --- 499,505 ---- cleanup_envelope.o: ../../include/attr.h cleanup_envelope.o: ../../include/been_here.h cleanup_envelope.o: ../../include/cleanup_user.h + cleanup_envelope.o: ../../include/ctable.h cleanup_envelope.o: ../../include/dict.h cleanup_envelope.o: ../../include/dsn_mask.h cleanup_envelope.o: ../../include/header_opts.h *************** *** 506,516 **** --- 520,532 ---- cleanup_envelope.o: ../../include/qmgr_user.h cleanup_envelope.o: ../../include/rec_attr_map.h cleanup_envelope.o: ../../include/rec_type.h + cleanup_envelope.o: ../../include/recipient_list.h cleanup_envelope.o: ../../include/record.h cleanup_envelope.o: ../../include/resolve_clnt.h cleanup_envelope.o: ../../include/string_list.h cleanup_envelope.o: ../../include/stringops.h cleanup_envelope.o: ../../include/sys_defs.h + cleanup_envelope.o: ../../include/tcache.h cleanup_envelope.o: ../../include/tok822.h cleanup_envelope.o: ../../include/vbuf.h cleanup_envelope.o: ../../include/verp_sender.h *************** *** 522,527 **** --- 538,544 ---- cleanup_extracted.o: ../../include/attr.h cleanup_extracted.o: ../../include/been_here.h cleanup_extracted.o: ../../include/cleanup_user.h + cleanup_extracted.o: ../../include/ctable.h cleanup_extracted.o: ../../include/dict.h cleanup_extracted.o: ../../include/dsn_mask.h cleanup_extracted.o: ../../include/header_opts.h *************** *** 542,552 **** --- 559,571 ---- cleanup_extracted.o: ../../include/qmgr_user.h cleanup_extracted.o: ../../include/rec_attr_map.h cleanup_extracted.o: ../../include/rec_type.h + cleanup_extracted.o: ../../include/recipient_list.h cleanup_extracted.o: ../../include/record.h cleanup_extracted.o: ../../include/resolve_clnt.h cleanup_extracted.o: ../../include/string_list.h cleanup_extracted.o: ../../include/stringops.h cleanup_extracted.o: ../../include/sys_defs.h + cleanup_extracted.o: ../../include/tcache.h cleanup_extracted.o: ../../include/tok822.h cleanup_extracted.o: ../../include/vbuf.h cleanup_extracted.o: ../../include/vstream.h *************** *** 556,561 **** --- 575,581 ---- cleanup_final.o: ../../include/argv.h cleanup_final.o: ../../include/been_here.h cleanup_final.o: ../../include/cleanup_user.h + cleanup_final.o: ../../include/ctable.h cleanup_final.o: ../../include/dict.h cleanup_final.o: ../../include/header_opts.h cleanup_final.o: ../../include/htable.h *************** *** 570,578 **** --- 590,600 ---- cleanup_final.o: ../../include/mymalloc.h cleanup_final.o: ../../include/nvtable.h cleanup_final.o: ../../include/rec_type.h + cleanup_final.o: ../../include/recipient_list.h cleanup_final.o: ../../include/resolve_clnt.h cleanup_final.o: ../../include/string_list.h cleanup_final.o: ../../include/sys_defs.h + cleanup_final.o: ../../include/tcache.h cleanup_final.o: ../../include/tok822.h cleanup_final.o: ../../include/vbuf.h cleanup_final.o: ../../include/vstream.h *************** *** 582,587 **** --- 604,610 ---- cleanup_init.o: ../../include/argv.h cleanup_init.o: ../../include/been_here.h cleanup_init.o: ../../include/cleanup_user.h + cleanup_init.o: ../../include/ctable.h cleanup_init.o: ../../include/dict.h cleanup_init.o: ../../include/ext_prop.h cleanup_init.o: ../../include/flush_clnt.h *************** *** 602,611 **** --- 625,637 ---- cleanup_init.o: ../../include/mymalloc.h cleanup_init.o: ../../include/name_mask.h cleanup_init.o: ../../include/nvtable.h + cleanup_init.o: ../../include/rcpt_key.h + cleanup_init.o: ../../include/recipient_list.h cleanup_init.o: ../../include/resolve_clnt.h cleanup_init.o: ../../include/string_list.h cleanup_init.o: ../../include/stringops.h cleanup_init.o: ../../include/sys_defs.h + cleanup_init.o: ../../include/tcache.h cleanup_init.o: ../../include/tok822.h cleanup_init.o: ../../include/vbuf.h cleanup_init.o: ../../include/vstream.h *************** *** 615,620 **** --- 641,647 ---- cleanup_map11.o: ../../include/argv.h cleanup_map11.o: ../../include/been_here.h cleanup_map11.o: ../../include/cleanup_user.h + cleanup_map11.o: ../../include/ctable.h cleanup_map11.o: ../../include/dict.h cleanup_map11.o: ../../include/header_opts.h cleanup_map11.o: ../../include/htable.h *************** *** 631,639 **** --- 658,668 ---- cleanup_map11.o: ../../include/nvtable.h cleanup_map11.o: ../../include/quote_822_local.h cleanup_map11.o: ../../include/quote_flags.h + cleanup_map11.o: ../../include/recipient_list.h cleanup_map11.o: ../../include/resolve_clnt.h cleanup_map11.o: ../../include/string_list.h cleanup_map11.o: ../../include/sys_defs.h + cleanup_map11.o: ../../include/tcache.h cleanup_map11.o: ../../include/tok822.h cleanup_map11.o: ../../include/vbuf.h cleanup_map11.o: ../../include/vstream.h *************** *** 643,648 **** --- 672,678 ---- cleanup_map1n.o: ../../include/argv.h cleanup_map1n.o: ../../include/been_here.h cleanup_map1n.o: ../../include/cleanup_user.h + cleanup_map1n.o: ../../include/ctable.h cleanup_map1n.o: ../../include/dict.h cleanup_map1n.o: ../../include/header_opts.h cleanup_map1n.o: ../../include/htable.h *************** *** 660,668 **** --- 690,700 ---- cleanup_map1n.o: ../../include/nvtable.h cleanup_map1n.o: ../../include/quote_822_local.h cleanup_map1n.o: ../../include/quote_flags.h + cleanup_map1n.o: ../../include/recipient_list.h cleanup_map1n.o: ../../include/resolve_clnt.h cleanup_map1n.o: ../../include/string_list.h cleanup_map1n.o: ../../include/sys_defs.h + cleanup_map1n.o: ../../include/tcache.h cleanup_map1n.o: ../../include/tok822.h cleanup_map1n.o: ../../include/vbuf.h cleanup_map1n.o: ../../include/vstream.h *************** *** 672,677 **** --- 704,710 ---- cleanup_masquerade.o: ../../include/argv.h cleanup_masquerade.o: ../../include/been_here.h cleanup_masquerade.o: ../../include/cleanup_user.h + cleanup_masquerade.o: ../../include/ctable.h cleanup_masquerade.o: ../../include/dict.h cleanup_masquerade.o: ../../include/header_opts.h cleanup_masquerade.o: ../../include/htable.h *************** *** 688,697 **** --- 721,732 ---- cleanup_masquerade.o: ../../include/nvtable.h cleanup_masquerade.o: ../../include/quote_822_local.h cleanup_masquerade.o: ../../include/quote_flags.h + cleanup_masquerade.o: ../../include/recipient_list.h cleanup_masquerade.o: ../../include/resolve_clnt.h cleanup_masquerade.o: ../../include/string_list.h cleanup_masquerade.o: ../../include/stringops.h cleanup_masquerade.o: ../../include/sys_defs.h + cleanup_masquerade.o: ../../include/tcache.h cleanup_masquerade.o: ../../include/tok822.h cleanup_masquerade.o: ../../include/vbuf.h cleanup_masquerade.o: ../../include/vstream.h *************** *** 703,708 **** --- 738,744 ---- cleanup_message.o: ../../include/been_here.h cleanup_message.o: ../../include/cleanup_user.h cleanup_message.o: ../../include/conv_time.h + cleanup_message.o: ../../include/ctable.h cleanup_message.o: ../../include/dict.h cleanup_message.o: ../../include/dsn_util.h cleanup_message.o: ../../include/ext_prop.h *************** *** 728,739 **** --- 764,777 ---- cleanup_message.o: ../../include/quote_822_local.h cleanup_message.o: ../../include/quote_flags.h cleanup_message.o: ../../include/rec_type.h + cleanup_message.o: ../../include/recipient_list.h cleanup_message.o: ../../include/record.h cleanup_message.o: ../../include/resolve_clnt.h cleanup_message.o: ../../include/split_at.h cleanup_message.o: ../../include/string_list.h cleanup_message.o: ../../include/stringops.h cleanup_message.o: ../../include/sys_defs.h + cleanup_message.o: ../../include/tcache.h cleanup_message.o: ../../include/tok822.h cleanup_message.o: ../../include/vbuf.h cleanup_message.o: ../../include/vstream.h *************** *** 744,749 **** --- 782,788 ---- cleanup_milter.o: ../../include/attr.h cleanup_milter.o: ../../include/been_here.h cleanup_milter.o: ../../include/cleanup_user.h + cleanup_milter.o: ../../include/ctable.h cleanup_milter.o: ../../include/dict.h cleanup_milter.o: ../../include/dsn_mask.h cleanup_milter.o: ../../include/header_opts.h *************** *** 768,778 **** --- 807,819 ---- cleanup_milter.o: ../../include/quote_flags.h cleanup_milter.o: ../../include/rec_attr_map.h cleanup_milter.o: ../../include/rec_type.h + cleanup_milter.o: ../../include/recipient_list.h cleanup_milter.o: ../../include/record.h cleanup_milter.o: ../../include/resolve_clnt.h cleanup_milter.o: ../../include/string_list.h cleanup_milter.o: ../../include/stringops.h cleanup_milter.o: ../../include/sys_defs.h + cleanup_milter.o: ../../include/tcache.h cleanup_milter.o: ../../include/tok822.h cleanup_milter.o: ../../include/vbuf.h cleanup_milter.o: ../../include/vstream.h *************** *** 782,787 **** --- 823,829 ---- cleanup_out.o: ../../include/argv.h cleanup_out.o: ../../include/been_here.h cleanup_out.o: ../../include/cleanup_user.h + cleanup_out.o: ../../include/ctable.h cleanup_out.o: ../../include/dict.h cleanup_out.o: ../../include/header_opts.h cleanup_out.o: ../../include/htable.h *************** *** 798,808 **** --- 840,852 ---- cleanup_out.o: ../../include/mymalloc.h cleanup_out.o: ../../include/nvtable.h cleanup_out.o: ../../include/rec_type.h + cleanup_out.o: ../../include/recipient_list.h cleanup_out.o: ../../include/record.h cleanup_out.o: ../../include/resolve_clnt.h cleanup_out.o: ../../include/split_at.h cleanup_out.o: ../../include/string_list.h cleanup_out.o: ../../include/sys_defs.h + cleanup_out.o: ../../include/tcache.h cleanup_out.o: ../../include/tok822.h cleanup_out.o: ../../include/vbuf.h cleanup_out.o: ../../include/vstream.h *************** *** 814,819 **** --- 858,864 ---- cleanup_out_recipient.o: ../../include/been_here.h cleanup_out_recipient.o: ../../include/bounce.h cleanup_out_recipient.o: ../../include/cleanup_user.h + cleanup_out_recipient.o: ../../include/ctable.h cleanup_out_recipient.o: ../../include/deliver_request.h cleanup_out_recipient.o: ../../include/dict.h cleanup_out_recipient.o: ../../include/dsn.h *************** *** 837,847 **** --- 882,894 ---- cleanup_out_recipient.o: ../../include/msg_stats.h cleanup_out_recipient.o: ../../include/mymalloc.h cleanup_out_recipient.o: ../../include/nvtable.h + cleanup_out_recipient.o: ../../include/rcpt_key.h cleanup_out_recipient.o: ../../include/rec_type.h cleanup_out_recipient.o: ../../include/recipient_list.h cleanup_out_recipient.o: ../../include/resolve_clnt.h cleanup_out_recipient.o: ../../include/string_list.h cleanup_out_recipient.o: ../../include/sys_defs.h + cleanup_out_recipient.o: ../../include/tcache.h cleanup_out_recipient.o: ../../include/tok822.h cleanup_out_recipient.o: ../../include/trace.h cleanup_out_recipient.o: ../../include/vbuf.h *************** *** 852,857 **** --- 899,905 ---- cleanup_region.o: ../../include/argv.h cleanup_region.o: ../../include/been_here.h cleanup_region.o: ../../include/cleanup_user.h + cleanup_region.o: ../../include/ctable.h cleanup_region.o: ../../include/dict.h cleanup_region.o: ../../include/header_opts.h cleanup_region.o: ../../include/htable.h *************** *** 865,873 **** --- 913,923 ---- cleanup_region.o: ../../include/msg.h cleanup_region.o: ../../include/mymalloc.h cleanup_region.o: ../../include/nvtable.h + cleanup_region.o: ../../include/recipient_list.h cleanup_region.o: ../../include/resolve_clnt.h cleanup_region.o: ../../include/string_list.h cleanup_region.o: ../../include/sys_defs.h + cleanup_region.o: ../../include/tcache.h cleanup_region.o: ../../include/tok822.h cleanup_region.o: ../../include/vbuf.h cleanup_region.o: ../../include/vstream.h *************** *** 878,883 **** --- 928,934 ---- cleanup_rewrite.o: ../../include/attr.h cleanup_rewrite.o: ../../include/been_here.h cleanup_rewrite.o: ../../include/cleanup_user.h + cleanup_rewrite.o: ../../include/ctable.h cleanup_rewrite.o: ../../include/dict.h cleanup_rewrite.o: ../../include/header_opts.h cleanup_rewrite.o: ../../include/htable.h *************** *** 895,904 **** --- 946,957 ---- cleanup_rewrite.o: ../../include/nvtable.h cleanup_rewrite.o: ../../include/quote_822_local.h cleanup_rewrite.o: ../../include/quote_flags.h + cleanup_rewrite.o: ../../include/recipient_list.h cleanup_rewrite.o: ../../include/resolve_clnt.h cleanup_rewrite.o: ../../include/rewrite_clnt.h cleanup_rewrite.o: ../../include/string_list.h cleanup_rewrite.o: ../../include/sys_defs.h + cleanup_rewrite.o: ../../include/tcache.h cleanup_rewrite.o: ../../include/tok822.h cleanup_rewrite.o: ../../include/vbuf.h cleanup_rewrite.o: ../../include/vstream.h *************** *** 909,914 **** --- 962,968 ---- cleanup_state.o: ../../include/attr.h cleanup_state.o: ../../include/been_here.h cleanup_state.o: ../../include/cleanup_user.h + cleanup_state.o: ../../include/ctable.h cleanup_state.o: ../../include/dict.h cleanup_state.o: ../../include/header_opts.h cleanup_state.o: ../../include/htable.h *************** *** 924,932 **** --- 978,988 ---- cleanup_state.o: ../../include/mime_state.h cleanup_state.o: ../../include/mymalloc.h cleanup_state.o: ../../include/nvtable.h + cleanup_state.o: ../../include/recipient_list.h cleanup_state.o: ../../include/resolve_clnt.h cleanup_state.o: ../../include/string_list.h cleanup_state.o: ../../include/sys_defs.h + cleanup_state.o: ../../include/tcache.h cleanup_state.o: ../../include/tok822.h cleanup_state.o: ../../include/vbuf.h cleanup_state.o: ../../include/vstream.h diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup.c ./src/cleanup/cleanup.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup.c Tue May 1 13:43:57 2007 --- ./src/cleanup/cleanup.c Tue May 22 17:32:14 2007 *************** *** 257,266 **** /* RESOURCE AND RATE CONTROLS /* .ad /* .fi ! /* .IP "\fBduplicate_filter_limit (1000)\fR" /* The maximal number of addresses remembered by the address /* duplicate filter for \fBaliases\fR(5) or \fBvirtual\fR(5) alias expansion, or ! /* for \fBshowq\fR(8) queue displays. /* .IP "\fBheader_size_limit (102400)\fR" /* The maximal amount of memory in bytes for storing a message header. /* .IP "\fBhopcount_limit (50)\fR" --- 257,267 ---- /* RESOURCE AND RATE CONTROLS /* .ad /* .fi ! /* .IP "\fBduplicate_filter_limit (10000)\fR" /* The maximal number of addresses remembered by the address /* duplicate filter for \fBaliases\fR(5) or \fBvirtual\fR(5) alias expansion, or ! /* for \fBshowq\fR(8) queue displays (with earlier Postfix releases the ! /* default limit was 1000). /* .IP "\fBheader_size_limit (102400)\fR" /* The maximal amount of memory in bytes for storing a message header. /* .IP "\fBhopcount_limit (50)\fR" *************** *** 290,295 **** --- 291,300 ---- /* from each original recipient. /* .IP "\fBvirtual_alias_recursion_limit (1000)\fR" /* The maximal nesting depth of virtual alias expansion. + /* .PP + /* Available in Postfix version 2.5 and later: + /* .IP "\fBduplicate_filter_style (strict)\fR" + /* The duplicate recipient filter policy: strict or pragmatic. /* MISCELLANEOUS CONTROLS /* .ad /* .fi diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup.h ./src/cleanup/cleanup.h *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup.h Thu Feb 15 14:34:34 2007 --- ./src/cleanup/cleanup.h Tue May 22 20:30:15 2007 *************** *** 52,57 **** --- 52,58 ---- MAIL_STREAM *handle; /* mail stream handle */ char *queue_name; /* queue name */ char *queue_id; /* queue file basename */ + char *org_tid; /* original transaction id */ struct timeval arrival_time; /* arrival time */ char *fullname; /* envelope sender full name */ char *sender; /* envelope sender address */ *************** *** 121,126 **** --- 122,134 ---- #define CLEANUP_FLAG_END_SEEN (1<<18) /* REC_TYPE_END record seen */ /* + * Special "recip" value for deleted recipients, to avoid false "no + * recipients specified" bounces when all recipients were already marked as + * deleted (before "postsuper -r" or after agressive duplicate elimination). + */ + extern char *cleanup_rcpt_deleted; + + /* * Mappings. */ extern MAPS *cleanup_comm_canon_maps; *************** *** 139,144 **** --- 147,154 ---- extern int cleanup_masq_flags; extern MAPS *cleanup_send_bcc_maps; extern MAPS *cleanup_rcpt_bcc_maps; + + extern int cleanup_rcpt_key_flags; /* * Character filters. diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_addr.c ./src/cleanup/cleanup_addr.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_addr.c Tue May 9 11:14:10 2006 --- ./src/cleanup/cleanup_addr.c Tue May 22 15:09:37 2007 *************** *** 166,172 **** } cleanup_out_recipient(state, state->dsn_orcpt, state->dsn_notify, state->orig_rcpt, STR(clean_addr)); ! if (state->recip == 0) state->recip = mystrdup(STR(clean_addr)); if ((state->flags & CLEANUP_FLAG_BCC_OK) && *STR(clean_addr) --- 166,172 ---- } cleanup_out_recipient(state, state->dsn_orcpt, state->dsn_notify, state->orig_rcpt, STR(clean_addr)); ! if (state->recip == 0 || state->recip == cleanup_rcpt_deleted) state->recip = mystrdup(STR(clean_addr)); if ((state->flags & CLEANUP_FLAG_BCC_OK) && *STR(clean_addr) diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_envelope.c ./src/cleanup/cleanup_envelope.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_envelope.c Tue Jan 16 14:08:07 2007 --- ./src/cleanup/cleanup_envelope.c Tue May 22 20:27:43 2007 *************** *** 236,241 **** --- 236,261 ---- } /* + * The invisible Postfix original and actual transaction IDs are + * assigned when mail enters the queue. The org_tid is propagated + * when mail is forwarded internally, and is generated when mail + * arrives from outside Postfix. + * + * XXX The queue_id is unique to within a second, but we include the + * time in microseconds anyway just in case the queue ID generating + * algorithm changes. + */ + if (state->org_tid == 0) { + vstring_sprintf(state->temp1, "%lx.%lx.%s", + (long) state->arrival_time.tv_sec, + (long) state->arrival_time.tv_usec, + state->queue_id); + state->org_tid = mystrdup(STR(state->temp1)); + } + cleanup_out_format(state, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_ORG_TID, state->org_tid); + + /* * XXX This works by accident, because the sender is recorded at the * beginning of the envelope segment. */ *************** *** 276,281 **** --- 296,303 ---- return; } if (type == REC_TYPE_DONE || type == REC_TYPE_DRCP) { + if (state->recip == 0) + state->recip = cleanup_rcpt_deleted; if (state->orig_rcpt != 0) { myfree(state->orig_rcpt); state->orig_rcpt = 0; *************** *** 357,362 **** --- 379,390 ---- /* Generate our own expiration time base record. */ cleanup_out_format(state, REC_TYPE_ATTR, "%s=%ld", MAIL_ATTR_CREATE_TIME, (long) time((time_t *) 0)); + return; + } + if (type == REC_TYPE_OTID) { + /* First instance wins. */ + if (state->org_tid == 0 && *buf) + state->org_tid = mystrdup(buf); return; } if (type == REC_TYPE_FULL) { diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_extracted.c ./src/cleanup/cleanup_extracted.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_extracted.c Sun May 6 20:09:23 2007 --- ./src/cleanup/cleanup_extracted.c Tue May 22 15:07:34 2007 *************** *** 217,222 **** --- 217,224 ---- return; } if (type == REC_TYPE_DONE || type == REC_TYPE_DRCP) { + if (state->recip == 0) + state->recip = cleanup_rcpt_deleted; if (state->orig_rcpt != 0) { myfree(state->orig_rcpt); state->orig_rcpt = 0; diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_init.c ./src/cleanup/cleanup_init.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_init.c Tue May 1 09:42:14 2007 --- ./src/cleanup/cleanup_init.c Tue May 22 20:31:22 2007 *************** *** 93,98 **** --- 93,99 ---- #include /* milter_macro_v */ #include #include + #include /* Application-specific. */ *************** *** 111,116 **** --- 112,129 ---- VSTRING *cleanup_trace_path; /* + * Control of recipient duplicate elimination. + */ + int cleanup_rcpt_key_flags = RCPT_KEY_FLAG_FOLD; + + /* + * Special "recip" value for deleted recipients, to avoid false "no + * recipients specified" bounces when all recipients were already marked as + * deleted (before "postsuper -r" or after agressive duplicate elimination). + */ + char *cleanup_rcpt_deleted = "(deleted recipient)"; + + /* * Tunable parameters. */ int var_hopcount_limit; /* max mailer hop count */ *************** *** 161,166 **** --- 174,180 ---- char *var_milt_unk_macros; /* unknown command macros */ char *var_cleanup_milters; /* non-SMTP mail */ int var_auto_8bit_enc_hdr; /* auto-detect 8bit encoding header */ + char *var_dup_filter_style; /* strict or pragmatic */ CONFIG_INT_TABLE cleanup_int_table[] = { VAR_HOPCOUNT_LIMIT, DEF_HOPCOUNT_LIMIT, &var_hopcount_limit, 1, 0, *************** *** 223,228 **** --- 237,243 ---- VAR_MILT_EOD_MACROS, DEF_MILT_EOD_MACROS, &var_milt_eod_macros, 0, 0, VAR_MILT_UNK_MACROS, DEF_MILT_UNK_MACROS, &var_milt_unk_macros, 0, 0, VAR_CLEANUP_MILTERS, DEF_CLEANUP_MILTERS, &var_cleanup_milters, 0, 0, + VAR_DUP_FILTER_STYLE, DEF_DUP_FILTER_STYLE, &var_dup_filter_style, 1, 0, 0, }; *************** *** 433,436 **** --- 448,457 ---- cleanup_strip_chars = vstring_alloc(strlen(var_msg_strip_chars)); unescape(cleanup_strip_chars, var_msg_strip_chars); } + + /* + * Duplicate filter style. + */ + cleanup_rcpt_key_flags |= + rcpt_key_style(VAR_DUP_FILTER_STYLE, var_dup_filter_style); } diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_out_recipient.c ./src/cleanup/cleanup_out_recipient.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_out_recipient.c Thu Jan 5 19:22:04 2006 --- ./src/cleanup/cleanup_out_recipient.c Tue May 22 17:18:29 2007 *************** *** 79,84 **** --- 79,85 ---- #include /* cleanup_trace_path */ #include #include + #include /* Application-specific. */ *************** *** 112,117 **** --- 113,120 ---- const char *orcpt, const char *recip) { + RECIPIENT rcpt; + char *key; ARGV *argv; char **cpp; *************** *** 124,129 **** --- 127,137 ---- dsn_orcpt = ""; /* + * Not elegant, but avoids up-stream damage. + */ + RECIPIENT_ASSIGN(&rcpt, (off_t) 0, dsn_orcpt, dsn_notify, orcpt, recip); + + /* * Distinguish between different original recipient addresses that map * onto the same mailbox. The recipient will use our original recipient * message header to figure things out. *************** *** 132,139 **** if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0 || cleanup_virt_alias_maps == 0) { ! if (been_here(state->dups, "%s\n%d\n%s\n%s", ! dsn_orcpt, dsn_notify, orcpt, recip) == 0) { if (dsn_notify) cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); --- 140,148 ---- if ((state->flags & CLEANUP_FLAG_MAP_OK) == 0 || cleanup_virt_alias_maps == 0) { ! key = vstring_str(rcpt_key_format(state->temp1, "", &rcpt, ! cleanup_rcpt_key_flags)); ! if (been_here_fixed(state->dups, key) == 0) { if (dsn_notify) cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); *************** *** 183,189 **** * notification records. */ else { - RECIPIENT rcpt; DSN dsn; argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps, --- 192,197 ---- *************** *** 192,205 **** && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) { (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded"); dsn.action = "expanded"; - RECIPIENT_ASSIGN(&rcpt, 0, dsn_orcpt, dsn_notify, orcpt, recip); cleanup_trace_append(state, &rcpt, &dsn); dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER : dsn_notify & ~DSN_NOTIFY_SUCCESS); } for (cpp = argv->argv; *cpp; cpp++) { ! if (been_here(state->dups, "%s\n%d\n%s\n%s", ! dsn_orcpt, dsn_notify, orcpt, *cpp) == 0) { if (dsn_notify) cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); --- 200,215 ---- && (argv->argc > 1 || strcmp(recip, argv->argv[0]) != 0)) { (void) DSN_SIMPLE(&dsn, "2.0.0", "alias expanded"); dsn.action = "expanded"; cleanup_trace_append(state, &rcpt, &dsn); dsn_notify = (dsn_notify == DSN_NOTIFY_SUCCESS ? DSN_NOTIFY_NEVER : dsn_notify & ~DSN_NOTIFY_SUCCESS); + rcpt.dsn_notify = dsn_notify; } for (cpp = argv->argv; *cpp; cpp++) { ! rcpt.address = *cpp; ! key = vstring_str(rcpt_key_format(state->temp1, "", &rcpt, ! cleanup_rcpt_key_flags)); ! if (been_here_fixed(state->dups, key) == 0) { if (dsn_notify) cleanup_out_format(state, REC_TYPE_ATTR, "%s=%d", MAIL_ATTR_DSN_NOTIFY, dsn_notify); diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_state.c ./src/cleanup/cleanup_state.c *** /var/tmp/postfix-2.5-20070516/src/cleanup/cleanup_state.c Wed Jan 17 19:38:29 2007 --- ./src/cleanup/cleanup_state.c Tue May 22 15:08:36 2007 *************** *** 71,76 **** --- 71,77 ---- state->handle = 0; state->queue_name = 0; state->queue_id = 0; + state->org_tid = 0; state->arrival_time.tv_sec = state->arrival_time.tv_usec = 0; state->fullname = 0; state->sender = 0; *************** *** 134,140 **** myfree(state->fullname); if (state->sender) myfree(state->sender); ! if (state->recip) myfree(state->recip); if (state->orig_rcpt) myfree(state->orig_rcpt); --- 135,141 ---- myfree(state->fullname); if (state->sender) myfree(state->sender); ! if (state->recip && state->recip != cleanup_rcpt_deleted) myfree(state->recip); if (state->orig_rcpt) myfree(state->orig_rcpt); *************** *** 146,151 **** --- 147,154 ---- myfree(state->queue_name); if (state->queue_id) myfree(state->queue_id); + if (state->org_tid) + myfree(state->org_tid); been_here_free(state->dups); if (state->reason) myfree(state->reason); diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/Makefile.in ./src/global/Makefile.in *** /var/tmp/postfix-2.5-20070516/src/global/Makefile.in Tue May 8 11:27:11 2007 --- ./src/global/Makefile.in Mon May 7 20:55:40 2007 *************** *** 28,34 **** tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c \ user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \ verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \ ! fold_addr.c OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \ --- 28,34 ---- tok822_resolve.c tok822_rewrite.c tok822_tree.c trace.c \ user_acl.c valid_mailhost_addr.c verify.c verify_clnt.c \ verp_sender.c wildcard_inet_addr.c xtext.c delivered_hdr.c \ ! fold_addr.c rcpt_key.c OBJS = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \ canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \ *************** *** 58,64 **** tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o \ user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \ verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \ ! fold_addr.o HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ --- 58,64 ---- tok822_resolve.o tok822_rewrite.o tok822_tree.o trace.o \ user_acl.o valid_mailhost_addr.o verify.o verify_clnt.o \ verp_sender.o wildcard_inet_addr.o xtext.o delivered_hdr.o \ ! fold_addr.o rcpt_key.o HDRS = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \ canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ conv_time.h db_common.h debug_peer.h debug_process.h defer.h \ *************** *** 82,88 **** string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \ trace.h user_acl.h valid_mailhost_addr.h verify.h verify_clnt.h \ verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \ ! fold_addr.h TESTSRC = rec2stream.c stream2rec.c recdump.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) --- 82,88 ---- string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \ trace.h user_acl.h valid_mailhost_addr.h verify.h verify_clnt.h \ verp_sender.h wildcard_inet_addr.h xtext.h delivered_hdr.h \ ! fold_addr.h rcpt_key.h TESTSRC = rec2stream.c stream2rec.c recdump.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) *************** *** 1525,1530 **** --- 1525,1540 ---- rcpt_buf.o: rcpt_buf.c rcpt_buf.o: rcpt_buf.h rcpt_buf.o: recipient_list.h + rcpt_key.o: ../../include/msg.h + rcpt_key.o: ../../include/name_code.h + rcpt_key.o: ../../include/stringops.h + rcpt_key.o: ../../include/sys_defs.h + rcpt_key.o: ../../include/vbuf.h + rcpt_key.o: ../../include/vstring.h + rcpt_key.o: mail_params.h + rcpt_key.o: rcpt_key.c + rcpt_key.o: rcpt_key.h + rcpt_key.o: recipient_list.h rcpt_print.o: ../../include/attr.h rcpt_print.o: ../../include/iostuff.h rcpt_print.o: ../../include/sys_defs.h diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/deliver_pass.c ./src/global/deliver_pass.c *** /var/tmp/postfix-2.5-20070516/src/global/deliver_pass.c Mon Jun 5 20:47:38 2006 --- ./src/global/deliver_pass.c Sun May 20 20:10:31 2007 *************** *** 101,106 **** --- 101,107 ---- ATTR_TYPE_INT, MAIL_ATTR_FLAGS, request->flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, request->queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, request->queue_id, + ATTR_TYPE_STR, MAIL_ATTR_ORG_TID, request->org_tid, ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, request->data_offset, ATTR_TYPE_LONG, MAIL_ATTR_SIZE, request->data_size, ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop, diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/deliver_request.c ./src/global/deliver_request.c *** /var/tmp/postfix-2.5-20070516/src/global/deliver_request.c Tue May 15 17:00:12 2007 --- ./src/global/deliver_request.c Tue May 22 14:21:22 2007 *************** *** 12,17 **** --- 12,18 ---- /* int flags; /* char *queue_name; /* char *queue_id; + /* char *org_tid; /* long data_offset; /* long data_size; /* char *nexthop; *************** *** 190,195 **** --- 191,197 ---- struct stat st; static VSTRING *queue_name; static VSTRING *queue_id; + static VSTRING *org_tid; static VSTRING *nexthop; static VSTRING *encoding; static VSTRING *address; *************** *** 214,219 **** --- 216,222 ---- if (queue_name == 0) { queue_name = vstring_alloc(10); queue_id = vstring_alloc(10); + org_tid = vstring_alloc(10); nexthop = vstring_alloc(10); encoding = vstring_alloc(10); address = vstring_alloc(10); *************** *** 237,242 **** --- 240,246 ---- ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &request->flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, queue_id, + ATTR_TYPE_STR, MAIL_ATTR_ORG_TID, org_tid, ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, &request->data_offset, ATTR_TYPE_LONG, MAIL_ATTR_SIZE, &request->data_size, ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, nexthop, *************** *** 254,260 **** ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, sasl_sender, ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, rewrite_context, ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, &rcpt_count, ! ATTR_TYPE_END) != 20) { msg_warn("%s: error receiving common attributes", myname); return (-1); } --- 258,264 ---- ATTR_TYPE_STR, MAIL_ATTR_SASL_SENDER, sasl_sender, ATTR_TYPE_STR, MAIL_ATTR_RWR_CONTEXT, rewrite_context, ATTR_TYPE_INT, MAIL_ATTR_RCPT_COUNT, &rcpt_count, ! ATTR_TYPE_END) != 21) { msg_warn("%s: error receiving common attributes", myname); return (-1); } *************** *** 268,273 **** --- 272,278 ---- request->queue_name = mystrdup(vstring_str(queue_name)); request->queue_id = mystrdup(vstring_str(queue_id)); + request->org_tid = mystrdup(vstring_str(org_tid)); request->nexthop = mystrdup(vstring_str(nexthop)); request->encoding = mystrdup(vstring_str(encoding)); request->sender = mystrdup(vstring_str(address)); *************** *** 344,349 **** --- 349,355 ---- request->fp = 0; request->queue_name = 0; request->queue_id = 0; + request->org_tid = 0; request->nexthop = 0; request->encoding = 0; request->sender = 0; *************** *** 373,378 **** --- 379,386 ---- myfree(request->queue_name); if (request->queue_id) myfree(request->queue_id); + if (request->org_tid) + myfree(request->org_tid); if (request->nexthop) myfree(request->nexthop); if (request->encoding) diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/deliver_request.h ./src/global/deliver_request.h *** /var/tmp/postfix-2.5-20070516/src/global/deliver_request.h Tue Feb 21 14:26:59 2006 --- ./src/global/deliver_request.h Sun May 20 20:12:03 2007 *************** *** 32,37 **** --- 32,38 ---- int flags; /* see below */ char *queue_name; /* message queue name */ char *queue_id; /* message queue id */ + char *org_tid; /* original transaction */ long data_offset; /* offset to message */ long data_size; /* message size */ char *nexthop; /* next hop name */ diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/mail_params.c ./src/global/mail_params.c *** /var/tmp/postfix-2.5-20070516/src/global/mail_params.c Tue May 1 14:55:43 2007 --- ./src/global/mail_params.c Sun May 20 13:16:08 2007 *************** *** 90,95 **** --- 90,96 ---- /* char *var_flush_service; /* char *var_verify_service; /* char *var_trace_service; + /* char *var_nodup_service; /* int var_db_create_buf; /* int var_db_read_buf; /* int var_mime_maxdepth; *************** *** 263,268 **** --- 264,270 ---- char *var_flush_service; char *var_verify_service; char *var_trace_service; + char *var_nodup_service; int var_db_create_buf; int var_db_read_buf; int var_mime_maxdepth; *************** *** 536,541 **** --- 538,544 ---- VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0, VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0, VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0, + VAR_NODUP_SERVICE, DEF_NODUP_SERVICE, &var_nodup_service, 1, 0, VAR_INT_FILT_CLASSES, DEF_INT_FILT_CLASSES, &var_int_filt_classes, 0, 0, 0, }; diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/mail_params.h ./src/global/mail_params.h *** /var/tmp/postfix-2.5-20070516/src/global/mail_params.h Thu May 3 15:54:55 2007 --- ./src/global/mail_params.h Sun May 20 20:16:20 2007 *************** *** 587,595 **** * default, we do graceful degradation with huge mailing lists. */ #define VAR_DUP_FILTER_LIMIT "duplicate_filter_limit" ! #define DEF_DUP_FILTER_LIMIT 1000 extern int var_dup_filter_limit; #define VAR_TLS_RAND_EXCH_NAME "tls_random_exchange_name" #define DEF_TLS_RAND_EXCH_NAME "${config_directory}/prng_exch" extern char *var_tls_rand_exch_name; --- 587,601 ---- * default, we do graceful degradation with huge mailing lists. */ #define VAR_DUP_FILTER_LIMIT "duplicate_filter_limit" ! #define DEF_DUP_FILTER_LIMIT 10000 extern int var_dup_filter_limit; + #define DUP_FILTER_STYLE_STRICT "strict" + #define DUP_FILTER_STYLE_PRAGMA "pragmatic" + #define VAR_DUP_FILTER_STYLE "duplicate_filter_style" + #define DEF_DUP_FILTER_STYLE DUP_FILTER_STYLE_STRICT + extern char *var_dup_filter_style; + #define VAR_TLS_RAND_EXCH_NAME "tls_random_exchange_name" #define DEF_TLS_RAND_EXCH_NAME "${config_directory}/prng_exch" extern char *var_tls_rand_exch_name; *************** *** 2293,2298 **** --- 2299,2308 ---- #define VAR_QUEUE_SERVICE "queue_service_name" #define DEF_QUEUE_SERVICE MAIL_SERVICE_QUEUE extern char *var_queue_service; + + #define VAR_NODUP_SERVICE "nodup_service_name" + #define DEF_NODUP_SERVICE MAIL_SERVICE_NODUP + extern char *var_nodup_service; /* XXX resolve does not exist as a separate service */ diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/mail_proto.h ./src/global/mail_proto.h *** /var/tmp/postfix-2.5-20070516/src/global/mail_proto.h Wed Nov 1 15:03:12 2006 --- ./src/global/mail_proto.h Sun May 20 13:07:17 2007 *************** *** 57,62 **** --- 57,63 ---- #define MAIL_SERVICE_RELAY "relay" #define MAIL_SERVICE_PROXYMAP "proxymap" #define MAIL_SERVICE_SCACHE "scache" + #define MAIL_SERVICE_NODUP "nodup" /* * Well-known socket or FIFO directories. The main difference is in file *************** *** 141,146 **** --- 142,152 ---- #define MAIL_ATTR_CRYPTO_PROTOCOL "encryption_protocol" #define MAIL_ATTR_CRYPTO_CIPHER "encryption_cipher" #define MAIL_ATTR_CRYPTO_KEYSIZE "encryption_keysize" + + /* + * Attributes for duplicate elimination. + */ + #define MAIL_ATTR_ORG_TID "original_tid" /* * Suffixes for sender_name, sender_domain etc. diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/rcpt_key.c ./src/global/rcpt_key.c *** /var/tmp/postfix-2.5-20070516/src/global/rcpt_key.c Wed Dec 31 19:00:00 1969 --- ./src/global/rcpt_key.c Tue May 22 17:17:00 2007 *************** *** 0 **** --- 1,142 ---- + /*++ + /* NAME + /* rcpt_key 3 + /* SUMMARY + /* format recipient lookup key + /* SYNOPSIS + /* #include + /* + /* VSTRING *rcpt_key_format(buf, sender, rcpt, flags) + /* VSTRING *buf; + /* const char *sender; + /* RECIPIENT *rcpt; + /* int flags; + /* + /* int rcpt_key_style(name, value) + /* const char *name; + /* const char *value; + /* DESCRIPTION + /* rcpt_key_format() formats envelope information, typically + /* for use in recipient duplicate filtering. + /* + /* rcpt_key_style() converts the specified style to a bit-mask. + /* + /* Arguments: + /* .IP buf + /* Storage for the result, and the function result value. + /* .IP sender + /* The envelope sender address. + /* .IP rcpt + /* Recipient information. Original recipients may be passed + /* as null pointers. + /* .IP flags + /* The bit-wise OR of zero or more of the following: + /* .RS + /* .IP RCPT_KEY_FLAG_APPEND + /* Do not truncate the buffer to zero length before updating. + /* .IP RCPT_KEY_FLAG_FOLD + /* Case fold the result. + /* .IP RCPT_KEY_FLAG_ADDR + /* Include the recipient address in the result. + /* This attribute is required. + /* .IP RCPT_KEY_FLAG_X_ORIG + /* Include the x-original-to address in the result. + /* .IP RCPT_KEY_FLAG_DSN_ORIG + /* Include the DSN original address in the result. + /* .IP RCPT_KEY_FLAG_DSN_NOTIFY + /* Include the DSN NOTIFY options in the result. + /* .IP RCPT_KEY_FLAG_FROM + /* Include the envelope sender in the result. + /* .RE + /* .IP name + /* Context for error messages. + /* .IP value + /* Recipient lookup key formatting style: "strict" or "pragmatic". + /* DIAGNOSTICS + /* Fatal: incorrect formatting style; out of memory. + /* SEE ALSO + /* rcpt_cache(3) recipient duplicate detector + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + /* System library. */ + + #include + #include + + #ifdef STRCASECMP_IN_STRINGS_H + #include + #endif + + /* Utility library. */ + + #include + #include + #include + + /* Global library. */ + + #include + #include + + /* rcpt_key_format - format recipient lookup key */ + + VSTRING *rcpt_key_format(VSTRING *buf, const char *sender, + RECIPIENT *rcpt, int flags) + { + int (*cmp) (const char *, const char *); + + cmp = (flags & RCPT_KEY_FLAG_FOLD) ? strcasecmp : strcmp; + + /* + * To save some memory, represent a repeated string by a control + * character; \1 means the string was the same as the first string + * attribute. + */ + #define RCPT_KEY_ADDR(str) \ + ((str) == 0 ? "" : cmp(rcpt->address, (str)) == 0 ? "\1" : (str)) + + if ((flags & RCPT_KEY_FLAG_APPEND) == 0) + VSTRING_RESET(buf); + if (flags & RCPT_KEY_FLAG_ADDR) + vstring_sprintf_append(buf, "%s\n", rcpt->address); + else + msg_panic("rcpt_key_format: recipient address attribute not requested"); + if (flags & RCPT_KEY_FLAG_X_ORIG) + vstring_sprintf_append(buf, "%s\n", RCPT_KEY_ADDR(rcpt->orig_addr)); + if (flags & RCPT_KEY_FLAG_DSN_NOTIFY) + vstring_sprintf_append(buf, "%d\n", rcpt->dsn_notify); + if (flags & RCPT_KEY_FLAG_DSN_ORIG) + vstring_sprintf_append(buf, "%s\n", RCPT_KEY_ADDR(rcpt->dsn_orcpt)); + if (flags & RCPT_KEY_FLAG_FROM) + vstring_sprintf_append(buf, "%s\n", sender ? sender : ""); + if (flags & RCPT_KEY_FLAG_FOLD) + lowercase(vstring_str(buf)); + + return (buf); + } + + /* rcpt_key_style - parse recipient lookup key style */ + + int rcpt_key_style(const char *name, const char *value) + { + static NAME_CODE styles[] = { + DUP_FILTER_STYLE_STRICT, RCPT_KEY_FLAG_STRICT, + DUP_FILTER_STYLE_PRAGMA, RCPT_KEY_FLAG_PRAGMA, + 0, 0, + }; + int style; + + if ((style = name_code(styles, NAME_CODE_FLAG_NONE, value)) == 0) + msg_fatal("%s: bad duplicate filter style: %s", + name, value); + return (style); + } diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/rcpt_key.h ./src/global/rcpt_key.h *** /var/tmp/postfix-2.5-20070516/src/global/rcpt_key.h Wed Dec 31 19:00:00 1969 --- ./src/global/rcpt_key.h Tue May 22 17:17:51 2007 *************** *** 0 **** --- 1,56 ---- + #ifndef _RCPT_KEY_H_INCLUDED_ + #define _RCPT_KEY_H_INCLUDED_ + + /*++ + /* NAME + /* rcpt_key 5 + /* SUMMARY + /* recipient lookup key formatter + /* SYNOPSIS + /* #include + /* DESCRIPTION + /* .nf + + /* + * Utility library. + */ + #include + + /* + * Global library. + */ + #include + + /* + * External interface. + */ + #define RCPT_KEY_FLAG_APPEND (1<<0) + #define RCPT_KEY_FLAG_FOLD (1<<1) + #define RCPT_KEY_FLAG_ADDR (1<<2) + #define RCPT_KEY_FLAG_X_ORIG (1<<3) + #define RCPT_KEY_FLAG_DSN_ORIG (1<<4) + #define RCPT_KEY_FLAG_DSN_NOTIFY (1<<5) + #define RCPT_KEY_FLAG_FROM (1<<6) + + #define RCPT_KEY_FLAG_STRICT (RCPT_KEY_FLAG_X_ORIG | \ + RCPT_KEY_FLAG_DSN_ORIG | \ + RCPT_KEY_FLAG_DSN_NOTIFY | \ + RCPT_KEY_FLAG_FROM | \ + RCPT_KEY_FLAG_ADDR) + #define RCPT_KEY_FLAG_PRAGMA (RCPT_KEY_FLAG_ADDR) + + extern VSTRING *rcpt_key_format(VSTRING *, const char *, RECIPIENT *, int); + extern int rcpt_key_style(const char *, const char *); + + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + #endif diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/rec_attr_map.c ./src/global/rec_attr_map.c *** /var/tmp/postfix-2.5-20070516/src/global/rec_attr_map.c Mon Mar 13 18:12:50 2006 --- ./src/global/rec_attr_map.c Sun May 20 13:00:49 2007 *************** *** 48,53 **** --- 48,55 ---- return (REC_TYPE_DSN_RET); } else if (strcmp(attr_name, MAIL_ATTR_CREATE_TIME) == 0) { return (REC_TYPE_CTIME); + } else if (strcmp(attr_name, MAIL_ATTR_ORG_TID) == 0) { + return (REC_TYPE_OTID); } else { return (0); } diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/global/rec_type.h ./src/global/rec_type.h *** /var/tmp/postfix-2.5-20070516/src/global/rec_type.h Tue Mar 20 11:25:10 2007 --- ./src/global/rec_type.h Sun May 20 13:00:23 2007 *************** *** 36,41 **** --- 36,42 ---- */ #define REC_TYPE_SIZE 'C' /* first record, created by cleanup */ #define REC_TYPE_TIME 'T' /* arrival time, required */ + #define REC_TYPE_OTID 't' /* original transaction id, optional */ #define REC_TYPE_CTIME 'c' /* create time, optional */ #define REC_TYPE_FULL 'F' /* full name, optional */ #define REC_TYPE_INSP 'I' /* inspector transport */ *************** *** 103,109 **** * Note: REC_TYPE_FILT and REC_TYPE_CONT are encoded with the same 'L' * constant, and it is too late to change that now. */ ! #define REC_TYPE_ENVELOPE "MCTcFILSDRO/WVA>KKon" --- 104,110 ---- * Note: REC_TYPE_FILT and REC_TYPE_CONT are encoded with the same 'L' * constant, and it is too late to change that now. */ ! #define REC_TYPE_ENVELOPE "MCTtcFILSDRO/WVA>KKon" diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/local/forward.c ./src/local/forward.c *** /var/tmp/postfix-2.5-20070516/src/local/forward.c Mon Jun 26 08:59:19 2006 --- ./src/local/forward.c Tue May 22 20:35:24 2007 *************** *** 127,133 **** * "message too large", perhaps some others. The reason not to bounce * ourselves is that we don't really know who the recipients are. */ ! cleanup = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING); if (cleanup == 0) return (0); close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC); --- 127,133 ---- * "message too large", perhaps some others. The reason not to bounce * ourselves is that we don't really know who the recipients are. */ ! cleanup = mail_connect(MAIL_CLASS_PRIVATE, var_nodup_service, BLOCKING); if (cleanup == 0) return (0); close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC); *************** *** 151,160 **** --- 151,166 ---- /* * Send initial message envelope information. For bounces, set the * designated sender: mailing list owner, posting user, whatever. + * + * Forward the original transaction ID, to enable duplicate recipient + * elimination. */ rec_fprintf(cleanup, REC_TYPE_TIME, REC_TYPE_TIME_FORMAT, REC_TYPE_TIME_ARG(info->posting_time)); rec_fputs(cleanup, REC_TYPE_FROM, sender); + if (request->org_tid[0]) + rec_fprintf(cleanup, REC_TYPE_ATTR, "%s=%s", + MAIL_ATTR_ORG_TID, request->org_tid); /* * Don't send the original envelope ID or full/headers return mask if it *************** *** 186,191 **** --- 192,202 ---- PASS_ATTR(cleanup, MAIL_ATTR_SASL_SENDER, request->sasl_sender); PASS_ATTR(cleanup, MAIL_ATTR_RWR_CONTEXT, request->rewrite_context); + /* + * Avoid select-thread blocking in the duplicate filter. + */ + (void) vstream_fflush(cleanup); + vstring_free(buffer); return (info); } *************** *** 234,239 **** --- 245,255 ---- if (*attr.rcpt.orig_addr) rec_fputs(info->cleanup, REC_TYPE_ORCP, attr.rcpt.orig_addr); rec_fputs(info->cleanup, REC_TYPE_RCPT, attr.rcpt.address); + + /* + * Avoid select-thread blocking in the duplicate filter. + */ + (void) vstream_fflush(info->cleanup); return (vstream_ferror(info->cleanup)); } diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/local/local.c ./src/local/local.c *** /var/tmp/postfix-2.5-20070516/src/local/local.c Sun Apr 29 11:49:34 2007 --- ./src/local/local.c Tue May 22 17:37:36 2007 *************** *** 443,452 **** /* .fi /* .IP "\fBcommand_time_limit (1000s)\fR" /* Time limit for delivery to external commands. ! /* .IP "\fBduplicate_filter_limit (1000)\fR" /* The maximal number of addresses remembered by the address /* duplicate filter for \fBaliases\fR(5) or \fBvirtual\fR(5) alias expansion, or ! /* for \fBshowq\fR(8) queue displays. /* .IP "\fBlocal_destination_concurrency_limit (2)\fR" /* The maximal number of parallel deliveries via the local mail /* delivery transport to the same recipient (when --- 443,453 ---- /* .fi /* .IP "\fBcommand_time_limit (1000s)\fR" /* Time limit for delivery to external commands. ! /* .IP "\fBduplicate_filter_limit (10000)\fR" /* The maximal number of addresses remembered by the address /* duplicate filter for \fBaliases\fR(5) or \fBvirtual\fR(5) alias expansion, or ! /* for \fBshowq\fR(8) queue displays (with earlier Postfix releases the ! /* default limit was 1000). /* .IP "\fBlocal_destination_concurrency_limit (2)\fR" /* The maximal number of parallel deliveries via the local mail /* delivery transport to the same recipient (when *************** *** 537,542 **** --- 538,544 ---- /* SEE ALSO /* qmgr(8), queue manager /* bounce(8), delivery status reports + /* nodup(8), duplicate recipient filter /* newaliases(1), create/update alias database /* postalias(1), create/update alias database /* aliases(5), format of alias database diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/master/mail_server.h ./src/master/mail_server.h *** /var/tmp/postfix-2.5-20070516/src/master/mail_server.h Thu Feb 3 13:38:25 2005 --- ./src/master/mail_server.h Tue May 22 12:51:17 2007 *************** *** 31,42 **** --- 31,44 ---- #define MAIL_SERVER_UNLIMITED 16 #define MAIL_SERVER_PRE_DISCONN 17 #define MAIL_SERVER_PRIVILEGED 18 + #define MAIL_SERVER_CONNECT 19 #define MAIL_SERVER_IN_FLOW_DELAY 20 typedef void (*MAIL_SERVER_INIT_FN) (char *, char **); typedef int (*MAIL_SERVER_LOOP_FN) (char *, char **); typedef void (*MAIL_SERVER_EXIT_FN) (char *, char **); + typedef void (*MAIL_SERVER_CONNECT_FN) (VSTREAM *, char *, char **); typedef void (*MAIL_SERVER_ACCEPT_FN) (char *, char **); typedef void (*MAIL_SERVER_DISCONN_FN) (VSTREAM *, char *, char **); diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/master/multi_server.c ./src/master/multi_server.c *** /var/tmp/postfix-2.5-20070516/src/master/multi_server.c Mon Apr 2 15:09:09 2007 --- ./src/master/multi_server.c Tue May 22 12:52:35 2007 *************** *** 34,41 **** /* A pointer to a function that is called by the skeleton each /* time a client sends data to the program's service port. The /* function is run after the program has optionally dropped its ! /* privileges. This function should not attempt to preserve state ! /* across calls. The stream initial state is non-blocking mode. /* The service name argument corresponds to the service name in the /* master.cf file. /* The argv argument specifies command-line arguments left over --- 34,40 ---- /* A pointer to a function that is called by the skeleton each /* time a client sends data to the program's service port. The /* function is run after the program has optionally dropped its ! /* privileges. The stream initial state is non-blocking mode. /* The service name argument corresponds to the service name in the /* master.cf file. /* The argv argument specifies command-line arguments left over *************** *** 90,95 **** --- 89,97 ---- /* the next event. Specify -1 to wait for "as long as it takes". /* .sp /* Only the last instance of this parameter type is remembered. + /* .IP "MAIL_SERVER_CONNECT (void (*service)(VSTREAM *stream, char *service_name, char **argv))" + /* A pointer to a function that is called by the skeleton each + /* time a client connects to the program's service port. /* .IP "MAIL_SERVER_EXIT (void *(char *service_name, char **argv))" /* A pointer to function that is executed immediately before normal /* process termination. *************** *** 221,226 **** --- 223,229 ---- static void (*multi_server_accept) (int, char *); static void (*multi_server_onexit) (char *, char **); static void (*multi_server_pre_accept) (char *, char **); + static void (*multi_server_connect) (VSTREAM *, char *, char **); static VSTREAM *multi_server_lock; static int multi_server_in_flow_delay; static unsigned multi_server_generation; *************** *** 367,372 **** --- 370,377 ---- var_in_flow_delay); else multi_server_enable_read(0, (char *) stream); + if (multi_server_connect) + multi_server_connect(stream, multi_server_name, multi_server_argv); } /* multi_server_accept_local - accept client connection request */ *************** *** 669,674 **** --- 674,682 ---- break; case MAIL_SERVER_EXIT: multi_server_onexit = va_arg(ap, MAIL_SERVER_EXIT_FN); + break; + case MAIL_SERVER_CONNECT: + multi_server_connect = va_arg(ap, MAIL_SERVER_CONNECT_FN); break; case MAIL_SERVER_PRE_ACCEPT: multi_server_pre_accept = va_arg(ap, MAIL_SERVER_ACCEPT_FN); diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/nodup/Makefile.in ./src/nodup/Makefile.in *** /var/tmp/postfix-2.5-20070516/src/nodup/Makefile.in Wed Dec 31 19:00:00 1969 --- ./src/nodup/Makefile.in Tue May 22 15:27:07 2007 *************** *** 0 **** --- 1,83 ---- + SHELL = /bin/sh + SRCS = nodup.c + OBJS = nodup.o + HDRS = + TESTSRC = + DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) + CFLAGS = $(DEBUG) $(OPT) $(DEFS) + TESTPROG= + PROG = nodup + INC_DIR = ../../include + LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a + + .c.o:; $(CC) $(CFLAGS) -c $*.c + + $(PROG): $(OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) + + $(OBJS): ../../conf/makedefs.out + + Makefile: Makefile.in + cat ../../conf/makedefs.out $? >$@ + + test: $(TESTPROG) + + tests: test + + root_tests: + + update: ../../libexec/$(PROG) + + ../../libexec/$(PROG): $(PROG) + cp $(PROG) ../../libexec + + printfck: $(OBJS) $(PROG) + rm -rf printfck + mkdir printfck + sed '1,/^# do not edit/!d' Makefile >printfck/Makefile + set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done + cd printfck; make "INC_DIR=../../../include" `cd ..; ls *.o` + + lint: + lint $(DEFS) $(SRCS) $(LINTFIX) + + clean: + rm -f *.o *core $(PROG) $(TESTPROG) junk + rm -rf printfck + + tidy: clean + + depend: $(MAKES) + (sed '1,/^# do not edit/!d' Makefile.in; \ + set -e; for i in [a-z][a-z0-9]*.c; do \ + $(CC) -E $(DEFS) $(INCL) $$i | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ + -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \ + -e 's/o: \.\//o: /' -e p -e '}' ; \ + done | sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in + @$(EXPORT) make -f Makefile.in Makefile 1>&2 + + # do not edit below this line - it is generated by 'make depend' + nodup.o: ../../include/attr.h + nodup.o: ../../include/ctable.h + nodup.o: ../../include/dsn_mask.h + nodup.o: ../../include/iostuff.h + nodup.o: ../../include/mail_conf.h + nodup.o: ../../include/mail_params.h + nodup.o: ../../include/mail_proto.h + nodup.o: ../../include/mail_server.h + nodup.o: ../../include/mail_stream.h + nodup.o: ../../include/mail_version.h + nodup.o: ../../include/msg.h + nodup.o: ../../include/mymalloc.h + nodup.o: ../../include/rcpt_key.h + nodup.o: ../../include/rec_attr_map.h + nodup.o: ../../include/rec_type.h + nodup.o: ../../include/recipient_list.h + nodup.o: ../../include/record.h + nodup.o: ../../include/stringops.h + nodup.o: ../../include/sys_defs.h + nodup.o: ../../include/tcache.h + nodup.o: ../../include/vbuf.h + nodup.o: ../../include/vstream.h + nodup.o: ../../include/vstring.h + nodup.o: nodup.c diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/nodup/nodup.c ./src/nodup/nodup.c *** /var/tmp/postfix-2.5-20070516/src/nodup/nodup.c Wed Dec 31 19:00:00 1969 --- ./src/nodup/nodup.c Tue May 22 20:40:52 2007 *************** *** 0 **** --- 1,554 ---- + /*++ + /* NAME + /* nodup 8 + /* SUMMARY + /* Postfix duplicate recipient filter + /* SYNOPSIS + /* \fBnodup\fR [generic Postfix daemon options] + /* DESCRIPTION + /* The \fBnodup\fR(8) server performs duplicate recipient + /* elimination for multiple \fBlocal\fR(8) distribution list + /* expansions of the same email message. It is implemented as + /* a multi-stream filter that sits between \fBlocal\fR(8) + /* delivery processes and \fBcleanup\fR(8) processes. + /* + /* To benefit from this service: + /* .IP \(bu + /* \fBlocal\fR(8) Distribution lists must be configured with + /* their own \fBowner-\fIlistname\fR alias (see aliases(5) for + /* details). \fBlocal\fR(8) Distribution lists without such + /* an alias are not processed by the \fBnodup\fR(8) server. + /* .sp + /* Note: when an \fBowner-\fIlistname\fR alias exists, it will + /* be used as the envelope sender address of the message that + /* is sent to the members of the distribution list. + /* .IP \(bu + /* \fBlocal\fR(8) Distribution lists must be expanded before + /* mail leaves the Postfix system. When a distribution list + /* expands after, for example, delivery to external command, + /* Postfix will treat the result as a different email message. + /* The duplicate filter never eliminates duplicate recipients + /* that appear in different email messages. + /* .IP \(bu + /* Specify "\fBduplicate_filter_style = pragmatic\fR". With + /* "\fBduplicate_filter_style = strict\fR", recipients would + /* not only need have the same email address if they are to + /* count as duplicate. They would also need to have identical + /* original recipient and DSN attributes, and the envelope + /* sender addresses of different distribution list expansions + /* would also have to be identical. This is clearly impossible. + /* .sp + /* Note: "\fBduplicate_filter_style = strict\fR" is required + /* when all recipients in a domain deliver to the same mailbox. + /* With "\fBduplicate_filter_style = pragmatic\fR", mail would + /* be lost when one message is sent to multiple recipients in + /* a single-mailbox domain; only one delivery would be made + /* instead of multiple. + /* SECURITY + /* .ad + /* .fi + /* The \fBnodup\fR service is not security-sensitive. It does + /* not talk to the network, and it does not talk to local + /* users. The server can run chrooted at fixed low privilege. + /* DIAGNOSTICS + /* Problems are logged to \fBsyslogd\fR(8). + /* BUGS + /* The \fBnodup\fR(8) server maintains a volatile cache to + /* remember what recipients it has seen recently. This state + /* is lost after "\fBpostfix reload\fR"; avoid this command + /* while Postfix is expanding multiple distribution lists. + /* CONFIGURATION PARAMETERS + /* .ad + /* .fi + /* Changes to \fBmain.cf\fR are picked up automatically, as + /* \fBnodup\fR(8) processes run for only a limited amount of + /* time. Use the command "\fBpostfix reload\fR" to speed up + /* a change. + /* + /* The text below provides only a parameter summary. See + /* \fBpostconf\fR(5) for more details including examples. + /* CACHE CONTROLS + /* .ad + /* .fi + /* The \fBnodup\fR(8) server maintains a volatile cache to + /* remember what recipients it has seen recently. To avoid + /* failure to eliminate duplicates under load, the duplicate + /* cache size should be several times the size of the largest + /* distribution list expansion. + /* .IP "\fBduplicate_filter_limit (10000)\fR" + /* The maximal number of addresses remembered by the address + /* duplicate filter for \fBaliases\fR(5) or \fBvirtual\fR(5) alias expansion, or + /* for \fBshowq\fR(8) queue displays (with earlier Postfix releases the + /* default limit was 1000). + /* .IP "\fBduplicate_filter_style (strict)\fR" + /* The duplicate recipient filter policy: strict or pragmatic. + /* MISCELLANEOUS CONTROLS + /* .ad + /* .fi + /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR" + /* The default location of the Postfix main.cf and master.cf + /* configuration files. + /* .IP "\fBdaemon_timeout (18000s)\fR" + /* How much time a Postfix daemon process may take to handle a + /* request before it is terminated by a built-in watchdog timer. + /* .IP "\fBipc_timeout (3600s)\fR" + /* The time limit for sending or receiving information over an internal + /* communication channel. + /* .IP "\fBprocess_id (read-only)\fR" + /* The process ID of a Postfix command or daemon process. + /* .IP "\fBprocess_name (read-only)\fR" + /* The process name of a Postfix command or daemon process. + /* .IP "\fBsyslog_facility (mail)\fR" + /* The syslog facility of Postfix logging. + /* .IP "\fBsyslog_name (postfix)\fR" + /* The mail system name that is prepended to the process name in syslog + /* records, so that "smtpd" becomes, for example, "postfix/smtpd". + /* SEE ALSO + /* cleanup(8), enqueue Postfix message + /* postconf(5), configuration parameters + /* syslogd(5), system logging + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* HISTORY + /* .ad + /* .fi + /* This service was introduced with Postfix version 2.5. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + /* System library. */ + + #include + #include + #include + #include + + /* Utility library. */ + + #include + #include + #include + #include + #include + + /* Global library. */ + + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + + /* Server skeleton. */ + + #include + + /* Application-specific. */ + + /* + * Tunable parameters. + */ + int var_dupfilter_limit; + char *var_dupfilter_style; + + /* + * State information per record stream. To avoid repeated memory allocation + * we use long-lived buffers for original recipient information. + */ + typedef struct { + MAIL_STREAM *cleanup_info; /* cleanup server state */ + VSTRING *dsn_orcpt_buf; /* DSN original recipient buffer */ + VSTRING *orig_addr_buf; /* Postfix original recipient buffer */ + RECIPIENT rcpt; /* Generic recipient state */ + char *sender; /* Envelope sender */ + char *org_tid; /* Invisible original transaction ID */ + } NODUP_STATE; + + /* + * This is a select-threaded process, so these buffers can be global. + */ + VSTRING *nodup_rec_buf; /* Record buffer */ + VSTRING *nodup_key_buf; /* Filter lookup key */ + + /* + * Support for the global duplicate filter. + */ + static int nodup_key_flags = RCPT_KEY_FLAG_FOLD; + TCACHE *nodup_rcpt_table; /* Recipient duplicate filter */ + + /* + * Silly little macros. + */ + #define STR(x) vstring_str(x) + #define LEN(x) VSTRING_LEN(x) + + static void nodup_receive(VSTREAM *, char *, char **); + + /* nodup_connect - handle connection event */ + + static void nodup_connect(VSTREAM *client_stream, char *unused_service, + char **argv) + { + NODUP_STATE *state; + int flags; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (vstream_context(client_stream) != 0) + msg_panic("nodup_connect: server stream exists"); + if (argv[0]) + msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * This routine runs whenever a client connects to the socket dedicated + * to the nodup service. All connection-management stuff is handled by + * the common code in multi_server.c. + * + * Set up the initial connection state: connect to the cleanup server and + * reply with the queue ID. + */ + state = (NODUP_STATE *) mymalloc(sizeof(*state)); + state->dsn_orcpt_buf = vstring_alloc(100); + state->orig_addr_buf = vstring_alloc(100); + state->rcpt.dsn_orcpt = 0; + state->rcpt.dsn_notify = 0; + state->rcpt.orig_addr = 0; + state->sender = 0; + state->org_tid = 0; + vstream_control(client_stream, + VSTREAM_CTL_CONTEXT, (char *) state, + VSTREAM_CTL_END); + + /* + * Act as aproxy for the initial handshake with the cleanup server. Note: + * this part of the conversation is in the form of named attributes, not + * queue file records. + */ + state->cleanup_info = + mail_stream_service(MAIL_CLASS_PUBLIC, var_cleanup_service); + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, state->cleanup_info->id, + ATTR_TYPE_END); + attr_scan(client_stream, ATTR_FLAG_STRICT, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, &flags, + ATTR_TYPE_END); + attr_print(state->cleanup_info->stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, + ATTR_TYPE_END); + + /* + * Don't lose the read event when input has already arrived in the + * VSTREAM buffer. + */ + if (vstream_peek(client_stream) > 0) + nodup_receive(client_stream, unused_service, argv); + } + + /* nodup_receive - perform service for client */ + + static void nodup_receive(VSTREAM *client_stream, char *unused_service, + char **argv) + { + NODUP_STATE *state = (NODUP_STATE *) vstream_context(client_stream); + int rec_type; + char *rec_val; + ssize_t rec_len; + VSTREAM *cleanup_stream; + RECIPIENT *rcpt; + char *queue_id; + + /* + * Sanity check. This service takes no command-line arguments. + */ + if (state == 0) + msg_panic("nodup_receive: no server stream"); + if (argv[0]) + msg_fatal("unexpected command-line argument: %s", argv[0]); + + /* + * This routine runs whenever a client sends queue file records over an + * already open socket. + */ + cleanup_stream = state->cleanup_info->stream; + rcpt = &state->rcpt; + queue_id = state->cleanup_info->id; + + /* + * Don't block when the socket drains. With a select-threaded server, + * this requires that the sender flushes the stream after each recipient. + */ + while (vstream_peek(client_stream) > 0 + || readable(vstream_fileno(client_stream))) { + if ((rec_type = rec_get(client_stream, nodup_rec_buf, 0)) < 0) { + /* This calls nodup_close() to destroy the cleanup handle. */ + multi_server_disconnect(client_stream); + return; + } + rec_val = STR(nodup_rec_buf); + rec_len = LEN(nodup_rec_buf); + + /* + * Attribute mapping, so we can avoid clumsy code later. Pass through + * any named attributes that we know we don't care about. + */ + if (rec_type == REC_TYPE_ATTR) { + const char *error_text; + char *attr_name; + char *attr_value; + int attr_type; + + error_text = split_nameval(rec_val, &attr_name, &attr_value); + if (error_text != 0) { + msg_warn("%s: ignoring bad attribute: %s: %.200s", + queue_id, error_text, rec_val); + continue; + } else if ((attr_type = rec_attr_map(attr_name)) == 0) { + rec_fprintf(cleanup_stream, REC_TYPE_ATTR, "%s=%s", + attr_name, attr_value); + continue; + } else { + rec_len -= (attr_value - rec_val); + rec_val = attr_value; + rec_type = attr_type; + } + } + + /* + * Save the envelope sender. + */ + if (rec_type == REC_TYPE_FROM) { + if (state->sender) + msg_warn("%s: ignoring out-of-order envelope sender" + " record <%.200s>", queue_id, rec_val); + else + state->sender = mystrdup(rec_val); + } + + /* + * Save original and DSN recipient attributes. + */ + if (rec_type == REC_TYPE_DSN_ORCPT) { + if (rcpt->dsn_orcpt) + msg_warn("%s: ignoring out-of-order DSN original recipient" + " record <%.200s>", queue_id, rcpt->dsn_orcpt); + rcpt->dsn_orcpt = + STR(vstring_strcpy(state->dsn_orcpt_buf, rec_val)); + continue; + } + if (rec_type == REC_TYPE_DSN_NOTIFY) { + int junk; + + if (rcpt->dsn_notify) + msg_warn("%s: ignoring out-of-order DSN notify record <%d>", + queue_id, rcpt->dsn_notify); + if (!alldig(rec_val) || (junk = atoi(rec_val)) == 0 + || DSN_NOTIFY_OK(junk) == 0) + msg_warn("%s: ignoring malformed DSN notify" + " record <%.200s>", queue_id, rec_val); + else + rcpt->dsn_notify = junk; + continue; + } + if (rec_type == REC_TYPE_ORCP) { + if (rcpt->orig_addr) + msg_warn("%s: ignoring out-of-order original recipient" + " record <%.200s>", queue_id, rcpt->orig_addr); + rcpt->orig_addr = + STR(vstring_strcpy(state->orig_addr_buf, rec_val)); + continue; + } + + /* + * Eliminate duplicate recipient, and reset the saved original and + * DSN recipient attributes. + */ + if (rec_type == REC_TYPE_RCPT) { + int dup; + + rcpt->address = rec_val; + + /* + * Compute cache lookup key and eliminate duplicate recipients. + */ + if (state->org_tid == 0 || state->org_tid[0] == 0) { + if (msg_verbose) + msg_info("%s: keep %s (no orig transaction id)", + queue_id, rcpt->address); + dup = 0; + } else { + rcpt_key_format(nodup_key_buf, state->sender, rcpt, + nodup_key_flags); + vstring_sprintf_append(nodup_key_buf, "\n%s", state->org_tid); + if (tcache_lookup(nodup_rcpt_table, STR(nodup_key_buf))) { + if (msg_verbose) + msg_info("%s: drop %s", + queue_id, STR(nodup_key_buf)); + dup = 1; + } else { + if (msg_verbose) + msg_info("%s: keep %s", + queue_id, STR(nodup_key_buf)); + TCACHE_ENTER(nodup_rcpt_table, STR(nodup_key_buf), ""); + dup = 0; + } + } + + /* + * If the recipient is not a duplicate, send the saved recipient + * information. There is no need to use REC_TYPE_ATTR here: we're + * not writing to queue file, so we don't need the Postfix 2.2 + * backwards compatibility. + */ + if (dup == 0) { + if (rcpt->dsn_orcpt) + REC_PUT_BUF(cleanup_stream, REC_TYPE_DSN_ORCPT, + state->dsn_orcpt_buf); + if (rcpt->dsn_notify) + rec_fprintf(cleanup_stream, REC_TYPE_DSN_NOTIFY, + "%d", rcpt->dsn_notify); + if (rcpt->orig_addr) + REC_PUT_BUF(cleanup_stream, REC_TYPE_ORCP, + state->orig_addr_buf); + REC_PUT_BUF(cleanup_stream, rec_type, nodup_rec_buf); + vstream_fflush(cleanup_stream); + } + + /* + * If the recipient is a duplicate, send SOME recipient + * information to the cleanup server, otherwise the cleanup + * server will not be able to see the difference with malformed + * mail that has no recipients. + */ + else { + REC_PUT_BUF(cleanup_stream, REC_TYPE_DONE, nodup_rec_buf); + } + rcpt->dsn_orcpt = 0; + rcpt->dsn_notify = 0; + rcpt->orig_addr = 0; + continue; + } + + /* + * XXX Add support to forward the file descriptor so we don't waste + * cycles with copying mail from one socket to another. + */ + if (rec_type == REC_TYPE_OTID) { + if (state->org_tid) + msg_warn("%s: ignoring duplicate original transaction ID" + " record <%.200s>", queue_id, rec_val); + else + state->org_tid = mystrdup(rec_val); + } + + /* + * Forward the record to the cleanup server. + */ + rec_put(cleanup_stream, rec_type, rec_val, rec_len); + + /* + * Act as proxy for the cleanup server's completion status. Note: + * this part of the conversation is in the form of named attributes, + * not queue file records. + */ + if (rec_type == REC_TYPE_END) { + int status; + + /* This kills cleanup_stream, queue_id, rec_val, rec_len. */ + status = mail_stream_finish(state->cleanup_info, nodup_rec_buf); + state->cleanup_info = 0; + attr_print(client_stream, ATTR_FLAG_NONE, + ATTR_TYPE_INT, MAIL_ATTR_STATUS, status, + ATTR_TYPE_STR, MAIL_ATTR_WHY, STR(nodup_rec_buf), + ATTR_TYPE_END); + vstream_fflush(client_stream); + return; + } + } + } + + /* nodup_close - clean up per-connection state */ + + static void nodup_close(VSTREAM *client_stream, int unused_name, + char **unused_argv) + { + NODUP_STATE *state = (NODUP_STATE *) vstream_context(client_stream); + + /* + * Abort transaction in progress. + */ + if (state != 0) { + if (state->cleanup_info) + mail_stream_cleanup(state->cleanup_info); + vstring_free(state->dsn_orcpt_buf); + vstring_free(state->orig_addr_buf); + if (state->sender) + myfree(state->sender); + if (state->org_tid) + myfree(state->org_tid); + myfree((char *) state); + } + } + + /* post_jail_init - post-jail initialization */ + + static void post_jail_init(char *unused_name, char **unused_argv) + { + + /* + * Initialize the global duplicate filter. + */ + nodup_key_flags |= + rcpt_key_style(VAR_DUP_FILTER_STYLE, var_dupfilter_style); + nodup_rcpt_table = tcache_create(var_dupfilter_limit, mystrdup, myfree); + + /* + * Initialize other global state. + */ + nodup_key_buf = vstring_alloc(100); + nodup_rec_buf = vstring_alloc(100); + } + + /* Fingerprint executables and core dumps */ + + MAIL_VERSION_STAMP_DECLARE; + + /* main - pass control to the multi-threaded skeleton */ + + int main(int argc, char **argv) + { + static CONFIG_INT_TABLE int_table[] = { + VAR_DUP_FILTER_LIMIT, DEF_DUP_FILTER_LIMIT, &var_dupfilter_limit, 0, 0, + 0, + }; + static CONFIG_STR_TABLE str_table[] = { + VAR_DUP_FILTER_STYLE, DEF_DUP_FILTER_STYLE, &var_dupfilter_style, 1, 0, + 0, + }; + + /* + * Fingerprint executables and core dumps. + */ + MAIL_VERSION_STAMP_ALLOCATE; + + multi_server_main(argc, argv, nodup_receive, + MAIL_SERVER_INT_TABLE, int_table, + MAIL_SERVER_STR_TABLE, str_table, + MAIL_SERVER_POST_INIT, post_jail_init, + MAIL_SERVER_CONNECT, nodup_connect, + MAIL_SERVER_PRE_DISCONN, nodup_close, + MAIL_SERVER_SOLITARY, + 0); + } diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/postfix/postfix.c ./src/postfix/postfix.c *** /var/tmp/postfix-2.5-20070516/src/postfix/postfix.c Sun Apr 29 11:57:24 2007 --- ./src/postfix/postfix.c Tue May 22 11:19:04 2007 *************** *** 200,205 **** --- 200,206 ---- /* flush(8), Postfix fast ETRN service /* local(8), Postfix local delivery agent /* master(8), Postfix master daemon + /* nodup(8), Postfix recipient duplicate filter /* oqmgr(8), old Postfix queue manager /* pickup(8), Postfix local mail pickup /* pipe(8), deliver mail to non-Postfix command diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr.c ./src/qmgr/qmgr.c *** /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr.c Sat Mar 17 13:59:38 2007 --- ./src/qmgr/qmgr.c Sun May 20 13:25:06 2007 *************** *** 238,252 **** /* OTHER RESOURCE AND RATE CONTROLS /* .ad /* .fi ! /* .IP "\fBminimal_backoff_time (version dependent)\fR" ! /* The minimal time between attempts to deliver a deferred message. /* .IP "\fBmaximal_backoff_time (4000s)\fR" /* The maximal time between attempts to deliver a deferred message. /* .IP "\fBmaximal_queue_lifetime (5d)\fR" /* The maximal time a message is queued before it is sent back as /* undeliverable. ! /* .IP "\fBqueue_run_delay (version dependent)\fR" ! /* The time between deferred queue scans by the queue manager. /* .IP "\fBtransport_retry_time (60s)\fR" /* The time between attempts by the Postfix queue manager to contact /* a malfunctioning message delivery transport. --- 238,254 ---- /* OTHER RESOURCE AND RATE CONTROLS /* .ad /* .fi ! /* .IP "\fBminimal_backoff_time (300s)\fR" ! /* The minimal time between attempts to deliver a deferred message; ! /* prior to Postfix 2.4 the default value was 1000s. /* .IP "\fBmaximal_backoff_time (4000s)\fR" /* The maximal time between attempts to deliver a deferred message. /* .IP "\fBmaximal_queue_lifetime (5d)\fR" /* The maximal time a message is queued before it is sent back as /* undeliverable. ! /* .IP "\fBqueue_run_delay (300s)\fR" ! /* The time between deferred queue scans by the queue manager; ! /* prior to Postfix 2.4 the default value was 1000s. /* .IP "\fBtransport_retry_time (60s)\fR" /* The time between attempts by the Postfix queue manager to contact /* a malfunctioning message delivery transport. diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr.h ./src/qmgr/qmgr.h *** /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr.h Tue Jan 16 14:25:10 2007 --- ./src/qmgr/qmgr.h Sun May 20 13:25:31 2007 *************** *** 268,273 **** --- 268,274 ---- char *queue_name; /* queue name */ char *queue_id; /* queue file */ char *encoding; /* content encoding */ + char *org_tid; /* original transaction id */ char *sender; /* complete address */ char *dsn_envid; /* DSN envelope ID */ int dsn_ret; /* DSN headers/full */ diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr_deliver.c ./src/qmgr/qmgr_deliver.c *** /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr_deliver.c Tue Jan 16 14:25:10 2007 --- ./src/qmgr/qmgr_deliver.c Mon May 7 10:12:48 2007 *************** *** 162,167 **** --- 162,168 ---- ATTR_TYPE_INT, MAIL_ATTR_FLAGS, flags, ATTR_TYPE_STR, MAIL_ATTR_QUEUE, message->queue_name, ATTR_TYPE_STR, MAIL_ATTR_QUEUEID, message->queue_id, + ATTR_TYPE_STR, MAIL_ATTR_ORG_TID, message->org_tid, ATTR_TYPE_LONG, MAIL_ATTR_OFFSET, message->data_offset, ATTR_TYPE_LONG, MAIL_ATTR_SIZE, message->cont_length, ATTR_TYPE_STR, MAIL_ATTR_NEXTHOP, entry->queue->nexthop, diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr_message.c ./src/qmgr/qmgr_message.c *** /var/tmp/postfix-2.5-20070516/src/qmgr/qmgr_message.c Tue Jan 16 14:25:10 2007 --- ./src/qmgr/qmgr_message.c Tue May 22 20:43:55 2007 *************** *** 176,181 **** --- 176,182 ---- message->queue_id = mystrdup(queue_id); message->queue_name = mystrdup(queue_name); message->encoding = 0; + message->org_tid = 0; message->sender = 0; message->dsn_envid = 0; message->dsn_ret = 0; *************** *** 615,620 **** --- 616,625 ---- message->redirect_addr = mystrdup(start); continue; } + if (rec_type == REC_TYPE_OTID) { + if (message->org_tid == 0) + message->org_tid = mystrdup(start); + } if (rec_type == REC_TYPE_FROM) { if (message->sender == 0) { message->sender = mystrdup(start); *************** *** 795,800 **** --- 800,807 ---- message->sasl_sender = mystrdup(""); if (message->rewrite_context == 0) message->rewrite_context = mystrdup(MAIL_ATTR_RWR_LOCAL); + if (message->org_tid == 0) + message->org_tid = mystrdup(""); /* Postfix < 2.3 compatibility. */ if (message->create_time == 0) message->create_time = message->arrival_time.tv_sec; *************** *** 1357,1362 **** --- 1364,1371 ---- myfree(message->dsn_envid); if (message->encoding) myfree(message->encoding); + if (message->org_tid) + myfree(message->org_tid); if (message->sender) myfree(message->sender); if (message->verp_delims) diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/util/Makefile.in ./src/util/Makefile.in *** /var/tmp/postfix-2.5-20070516/src/util/Makefile.in Sat Mar 17 13:51:33 2007 --- ./src/util/Makefile.in Mon May 7 20:55:36 2007 *************** *** 30,36 **** username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \ vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \ write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \ ! allascii.c load_file.c killme_after.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ --- 30,36 ---- username.c valid_hostname.c vbuf.c vbuf_print.c vstream.c \ vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \ write_buf.c write_wait.c sane_basename.c format_tv.c allspace.c \ ! allascii.c load_file.c killme_after.c tcache.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ *************** *** 62,68 **** username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \ vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \ write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \ ! allascii.o load_file.o killme_after.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ --- 62,68 ---- username.o valid_hostname.o vbuf.o vbuf_print.o vstream.o \ vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \ write_buf.o write_wait.o sane_basename.o format_tv.o allspace.o \ ! allascii.o load_file.o killme_after.o tcache.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ *************** *** 81,87 **** sigdelay.h sock_addr.h spawn_command.h split_at.h stat_as.h \ stringops.h sys_defs.h timed_connect.h timed_wait.h trigger.h \ username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \ ! vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c DEFS = -I. -D$(SYSTYPE) --- 81,88 ---- sigdelay.h sock_addr.h spawn_command.h split_at.h stat_as.h \ stringops.h sys_defs.h timed_connect.h timed_wait.h trigger.h \ username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \ ! vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \ ! tcache.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c DEFS = -I. -D$(SYSTYPE) *************** *** 1484,1489 **** --- 1485,1497 ---- sys_compat.o: iostuff.h sys_compat.o: sys_compat.c sys_compat.o: sys_defs.h + tcache.o: ctable.h + tcache.o: mymalloc.h + tcache.o: sys_defs.h + tcache.o: tcache.c + tcache.o: tcache.h + tcache.o: vbuf.h + tcache.o: vstring.h timed_connect.o: iostuff.h timed_connect.o: msg.h timed_connect.o: sane_connect.h diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/util/ctable.c ./src/util/ctable.c *** /var/tmp/postfix-2.5-20070516/src/util/ctable.c Thu Jun 15 14:07:16 2006 --- ./src/util/ctable.c Tue May 8 08:16:49 2007 *************** *** 2,8 **** /* NAME /* ctable 3 /* SUMMARY ! /* cache manager /* SYNOPSIS /* #include /* --- 2,8 ---- /* NAME /* ctable 3 /* SUMMARY ! /* push/pull cache manager /* SYNOPSIS /* #include /* *************** *** 12,17 **** --- 12,21 ---- /* void (*delete)(void *value, void *context); /* void *context; /* + /* const void *ctable_enter(cache, key, value) + /* CTABLE *cache; + /* const char *key; + /* /* const void *ctable_locate(cache, key) /* CTABLE *cache; /* const char *key; *************** *** 33,41 **** --- 37,56 ---- /* specify pointers to call-back functions that create a value, given /* a key, and delete a given value, respectively. The context argument /* is passed on to the call-back routines. + /* Specify CTABLE_NOCREATE or CTABLE_NOCREATE to suppress these + /* call-back actions. + /* + /* ctable_enter() stores the specified value into the cache + /* under the specified key. The result value is the value + /* argument. No attempt is made to detect duplicate cache + /* entries. Use ctable_locate() for that. /* /* ctable_locate() looks up or generates the value that corresponds to /* the specified key, and returns that value. + /* If the value is not present in the cache and the create() + /* call-back is not CTABLE_NOCREATE, that function is called + /* to create the requested value. Otherwise the result is a + /* null pointer. /* /* ctable_free() destroys the specified cache, including its contents. /* *************** *** 119,124 **** --- 134,165 ---- return (cache); } + /* ctable_enter - enter something into the cache */ + + const void *ctable_enter(CTABLE *cache, const char *key, void *value) + { + const char *myname = "ctable_enter"; + CTABLE_ENTRY *entry; + + if (cache->used >= cache->limit) { + entry = RING_TO_CTABLE_ENTRY(ring_pred(RING_PTR_OF(cache))); + if (msg_verbose) + msg_info("%s: purge entry key %s", myname, entry->key); + ring_detach(RING_PTR_OF(entry)); + cache->delete(entry->value, cache->context); + htable_delete(cache->table, entry->key, (void (*) (char *)) 0); + } else { + entry = (CTABLE_ENTRY *) mymalloc(sizeof(CTABLE_ENTRY)); + cache->used++; + } + entry->value = value; + entry->key = htable_enter(cache->table, key, (char *) entry)->key; + ring_append(RING_PTR_OF(cache), RING_PTR_OF(entry)); + if (msg_verbose) + msg_info("%s: install entry key %s", myname, entry->key); + return (value); + } + /* ctable_locate - look up or create cache item */ const void *ctable_locate(CTABLE *cache, const char *key) *************** *** 133,154 **** * All this means that the cache never shrinks. */ if ((entry = (CTABLE_ENTRY *) htable_find(cache->table, key)) == 0) { ! if (cache->used >= cache->limit) { ! entry = RING_TO_CTABLE_ENTRY(ring_pred(RING_PTR_OF(cache))); ! if (msg_verbose) ! msg_info("%s: purge entry key %s", myname, entry->key); ! ring_detach(RING_PTR_OF(entry)); ! cache->delete(entry->value, cache->context); ! htable_delete(cache->table, entry->key, (void (*) (char *)) 0); ! } else { ! entry = (CTABLE_ENTRY *) mymalloc(sizeof(CTABLE_ENTRY)); ! cache->used++; ! } ! entry->value = cache->create(key, cache->context); ! entry->key = htable_enter(cache->table, key, (char *) entry)->key; ! ring_append(RING_PTR_OF(cache), RING_PTR_OF(entry)); ! if (msg_verbose) ! msg_info("%s: install entry key %s", myname, entry->key); } else if (entry == RING_TO_CTABLE_ENTRY(ring_succ(RING_PTR_OF(cache)))) { if (msg_verbose) msg_info("%s: leave existing entry key %s", myname, entry->key); --- 174,184 ---- * All this means that the cache never shrinks. */ if ((entry = (CTABLE_ENTRY *) htable_find(cache->table, key)) == 0) { ! if (cache->create == 0) ! return (0); ! else ! return (ctable_enter(cache, key, ! cache->create(key, cache->context))); } else if (entry == RING_TO_CTABLE_ENTRY(ring_succ(RING_PTR_OF(cache)))) { if (msg_verbose) msg_info("%s: leave existing entry key %s", myname, entry->key); diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/util/ctable.h ./src/util/ctable.h *** /var/tmp/postfix-2.5-20070516/src/util/ctable.h Sun Jul 29 14:31:44 2001 --- ./src/util/ctable.h Mon May 7 11:27:30 2007 *************** *** 20,29 **** --- 20,33 ---- typedef void *(*CTABLE_CREATE_FN) (const char *, void *); typedef void (*CTABLE_DELETE_FN) (void *, void *); + #define CTABLE_NOCREATE ((CTABLE_CREATE_FN) 0) + #define CTABLE_NODELETE ((CTABLE_DELETE_FN) 0) + extern CTABLE *ctable_create(int, CTABLE_CREATE_FN, CTABLE_DELETE_FN, void *); extern void ctable_free(CTABLE *); extern void ctable_walk(CTABLE *, void (*) (const char *, const void *)); extern const void *ctable_locate(CTABLE *, const char *); + extern const void *ctable_enter(CTABLE *, const char *, void *); /* LICENSE /* .ad diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/util/ctable.ref ./src/util/ctable.ref *** /var/tmp/postfix-2.5-20070516/src/util/ctable.ref Sun Jul 29 12:15:20 2001 --- ./src/util/ctable.ref Fri May 4 20:13:29 2007 *************** *** 1,60 **** key = a ask: a = 1 ! ./ctable: ctable_locate: install entry key a result: 1 key = b ask: b = 2 ! ./ctable: ctable_locate: install entry key b result: 2 key = c ask: c = 3 ! ./ctable: ctable_locate: install entry key c result: 3 key = d ask: d = 4 ! ./ctable: ctable_locate: install entry key d result: 4 key = e ask: e = 5 ! ./ctable: ctable_locate: install entry key e result: 5 key = f - ./ctable: ctable_locate: purge entry key a ask: f = 6 ! ./ctable: ctable_locate: install entry key f result: 6 key = f ./ctable: ctable_locate: leave existing entry key f result: 6 key = a - ./ctable: ctable_locate: purge entry key b ask: a = 1 ! ./ctable: ctable_locate: install entry key a result: 1 key = b - ./ctable: ctable_locate: purge entry key c ask: b = 2 ! ./ctable: ctable_locate: install entry key b result: 2 key = c - ./ctable: ctable_locate: purge entry key d ask: c = 3 ! ./ctable: ctable_locate: install entry key c result: 3 key = d - ./ctable: ctable_locate: purge entry key e ask: d = 4 ! ./ctable: ctable_locate: install entry key d result: 4 key = e - ./ctable: ctable_locate: purge entry key f ask: e = 5 ! ./ctable: ctable_locate: install entry key e result: 5 key = f - ./ctable: ctable_locate: purge entry key a ask: f = 6 ! ./ctable: ctable_locate: install entry key f result: 6 key = f ./ctable: ctable_locate: leave existing entry key f --- 1,60 ---- key = a ask: a = 1 ! ./ctable: ctable_enter: install entry key a result: 1 key = b ask: b = 2 ! ./ctable: ctable_enter: install entry key b result: 2 key = c ask: c = 3 ! ./ctable: ctable_enter: install entry key c result: 3 key = d ask: d = 4 ! ./ctable: ctable_enter: install entry key d result: 4 key = e ask: e = 5 ! ./ctable: ctable_enter: install entry key e result: 5 key = f ask: f = 6 ! ./ctable: ctable_enter: purge entry key a ! ./ctable: ctable_enter: install entry key f result: 6 key = f ./ctable: ctable_locate: leave existing entry key f result: 6 key = a ask: a = 1 ! ./ctable: ctable_enter: purge entry key b ! ./ctable: ctable_enter: install entry key a result: 1 key = b ask: b = 2 ! ./ctable: ctable_enter: purge entry key c ! ./ctable: ctable_enter: install entry key b result: 2 key = c ask: c = 3 ! ./ctable: ctable_enter: purge entry key d ! ./ctable: ctable_enter: install entry key c result: 3 key = d ask: d = 4 ! ./ctable: ctable_enter: purge entry key e ! ./ctable: ctable_enter: install entry key d result: 4 key = e ask: e = 5 ! ./ctable: ctable_enter: purge entry key f ! ./ctable: ctable_enter: install entry key e result: 5 key = f ask: f = 6 ! ./ctable: ctable_enter: purge entry key a ! ./ctable: ctable_enter: install entry key f result: 6 key = f ./ctable: ctable_locate: leave existing entry key f *************** *** 72,80 **** ./ctable: ctable_locate: move existing entry key b result: 2 key = a - ./ctable: ctable_locate: purge entry key f ask: a = 1 ! ./ctable: ctable_locate: install entry key a result: 1 key = b ./ctable: ctable_locate: move existing entry key b --- 72,80 ---- ./ctable: ctable_locate: move existing entry key b result: 2 key = a ask: a = 1 ! ./ctable: ctable_enter: purge entry key f ! ./ctable: ctable_enter: install entry key a result: 1 key = b ./ctable: ctable_locate: move existing entry key b *************** *** 89,97 **** ./ctable: ctable_locate: move existing entry key e result: 5 key = f - ./ctable: ctable_locate: purge entry key a ask: f = 6 ! ./ctable: ctable_locate: install entry key f result: 6 key = f ./ctable: ctable_locate: leave existing entry key f --- 89,97 ---- ./ctable: ctable_locate: move existing entry key e result: 5 key = f ask: f = 6 ! ./ctable: ctable_enter: purge entry key a ! ./ctable: ctable_enter: install entry key f result: 6 key = f ./ctable: ctable_locate: leave existing entry key f diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/util/tcache.c ./src/util/tcache.c *** /var/tmp/postfix-2.5-20070516/src/util/tcache.c Wed Dec 31 19:00:00 1969 --- ./src/util/tcache.c Tue May 22 16:09:14 2007 *************** *** 0 **** --- 1,124 ---- + /*++ + /* NAME + /* tcache 3 + /* SUMMARY + /* trivial push-mode cache manager + /* SYNOPSIS + /* #include + /* + /* typedef struct TCACHE { + /* VSTRING *key_buf; + /* /* private members... */ + /* } TCACHE; + /* + /* TCACHE *tcache_create(size, save_fn, delete_fn) + /* int size; + /* char *(*save_fn)(const char *value); + /* void (*delete_fn)(char *value); + /* + /* const char *TCACHE_ENTER(tcache, key, value) + /* TCACHE *tcache; + /* const char *key; + /* const char *value; + /* + /* const char *tcache_lookup(tcache, key) + /* TCACHE *tcache; + /* const char *key; + /* + /* void tcache_free(tcache) + /* TCACHE *tcache; + /* DESCRIPTION + /* This module maintains a trivial push-mode cache, where the + /* caller pushes information into the cache and where the cache + /* manager silently throws information away. + /* + /* tcache_create() creates a trivial cache instance. + /* + /* TCACHE_ENTER() enters a value into the cache under the + /* specified key. No duplicate check is done: use tcache_lookup() + /* for that. + /* + /* tcache_lookup() looks up a value that was stored under the + /* specified key, or a null pointer value. + /* + /* tcache_free() destroys a trivial cache instance. + /* + /* Arguments: + /* .IP size + /* The number of cache entries. Old entries are removed when + /* new entries are added while the cache is full. + /* .IP save_fn + /* Null pointer, or pointer to function that saves a copy of + /* its value argument. + /* .IP delete_fn + /* Null pointer, or pointer to function that deletes a saved + /* value. + /* .IP key + /* Lookup key. For convenience, each TCACHE provides a buffer + /* that the application can (but does not have to) use to + /* save the key for the _lookup and _enter operations. + /* .IP delete + /* A null pointer, or pointer to call-back function that + /* receives as arguments a cached value and a pointer to the + /* TCACHE object. + /* BUGS + /* No tcache_delete() or tcache_update() operations. + /* SEE ALSO + /* rcpt_key(3) recipient lookup key formatter. + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + /* System library. */ + + #include + + /* Utility library. */ + + #include + + /* Global library. */ + + #include + + /* tcache_delete_cb - delete call-back adapter */ + + static void tcache_delete_cb(void *value, void *context) + { + TCACHE *tp = (TCACHE *) context; + + tp->delete_fn(value); + } + + /* tcache_create - create trivial cache */ + + TCACHE *tcache_create(int size, TCACHE_SAVE_FN save_fn, + TCACHE_DELETE_FN delete_fn) + { + TCACHE *tp; + + tp = (TCACHE *) mymalloc(sizeof(*tp)); + tp->key_buf = vstring_alloc(10); + tp->table = ctable_create(size, CTABLE_NOCREATE, delete_fn ? + tcache_delete_cb : CTABLE_NODELETE, + (void *) tp); + tp->save_fn = save_fn; + tp->delete_fn = delete_fn; + return (tp); + } + + /* tcache_free - destroy trivial cache */ + + void tcache_free(TCACHE *tp) + { + vstring_free(tp->key_buf); + ctable_free(tp->table); + myfree((char *) tp); + } diff -cr --exclude=man --exclude=html --exclude=.indent.pro --new-file /var/tmp/postfix-2.5-20070516/src/util/tcache.h ./src/util/tcache.h *** /var/tmp/postfix-2.5-20070516/src/util/tcache.h Wed Dec 31 19:00:00 1969 --- ./src/util/tcache.h Tue May 22 16:07:01 2007 *************** *** 0 **** --- 1,53 ---- + #ifndef _TCACHE_H_INCLUDED_ + #define _TCACHE_H_INCLUDED_ + + /*++ + /* NAME + /* tcache 5 + /* SUMMARY + /* trivial cache manager + /* SYNOPSIS + /* #include + /* DESCRIPTION + /* .nf + + /* + * Utility library. + */ + #include + #include + + /* + * External interface. + */ + typedef char *(*TCACHE_SAVE_FN) (const char *); + typedef void (*TCACHE_DELETE_FN) (char *); + + typedef struct { + VSTRING *key_buf; + CTABLE *table; + TCACHE_SAVE_FN save_fn; + TCACHE_DELETE_FN delete_fn; + } TCACHE; + + extern TCACHE *tcache_create(int, TCACHE_SAVE_FN, TCACHE_DELETE_FN); + extern void tcache_free(TCACHE *); + + #define tcache_lookup(tp, key) \ + ((char *) ctable_locate((tp)->table, (key))) + #define TCACHE_ENTER(tp, key, val) \ + ((char *) ctable_enter((tp)->table, (key), (tp)->save_fn ? \ + (tp)->save_fn(val) : (val))) + + /* LICENSE + /* .ad + /* .fi + /* The Secure Mailer license must be distributed with this software. + /* AUTHOR(S) + /* Wietse Venema + /* IBM T.J. Watson Research + /* P.O. Box 704 + /* Yorktown Heights, NY 10598, USA + /*--*/ + + #endif