Merge lp:~ubuntu-branches/ubuntu/lucid/dovecot/lucid-201002122358 into lp:ubuntu/lucid/dovecot

Proposed by James Westby
Status: Needs review
Proposed branch: lp:~ubuntu-branches/ubuntu/lucid/dovecot/lucid-201002122358
Merge into: lp:ubuntu/lucid/dovecot
Diff against target: 3976 lines (+2060/-893) (has conflicts)
14 files modified
debian/patches/.dpkg-source-applied (+12/-0)
debian/patches/series (+12/-0)
src/deliver/Makefile.am (+60/-0)
src/deliver/Makefile.in (+657/-0)
src/deliver/auth-client.c (+0/-153)
src/deliver/auth-client.h (+0/-8)
src/deliver/deliver.c (+1319/-0)
src/deliver/deliver.h (+0/-50)
src/deliver/duplicate.c (+0/-324)
src/deliver/duplicate.h (+0/-15)
src/deliver/mail-send.c (+0/-208)
src/deliver/mail-send.h (+0/-10)
src/deliver/smtp-client.c (+0/-114)
src/deliver/smtp-client.h (+0/-11)
Text conflict in debian/patches/.dpkg-source-applied
Text conflict in debian/patches/series
Conflict adding files to src/deliver.  Created directory.
Conflict because src/deliver is not versioned, but has versioned children.  Versioned directory.
Conflict adding file src/deliver.  Moved existing file to src/deliver.moved.
Path conflict: src/deliver.moved/auth-client.c / src/deliver.moved/auth-client.c
Path conflict: src/deliver.moved/auth-client.h / src/deliver.moved/auth-client.h
Path conflict: src/deliver.moved/deliver.h / src/deliver.moved/deliver.h
Path conflict: src/deliver.moved/duplicate.c / src/deliver.moved/duplicate.c
Path conflict: src/deliver.moved/duplicate.h / src/deliver.moved/duplicate.h
Path conflict: src/deliver.moved/mail-send.c / src/deliver.moved/mail-send.c
Path conflict: src/deliver.moved/mail-send.h / src/deliver.moved/mail-send.h
Path conflict: src/deliver.moved/smtp-client.c / src/deliver.moved/smtp-client.c
Path conflict: src/deliver.moved/smtp-client.h / src/deliver.moved/smtp-client.h
To merge this branch: bzr merge lp:~ubuntu-branches/ubuntu/lucid/dovecot/lucid-201002122358
To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

The package history in the archive and the history in the bzr branch differ. As the archive is authoritative the history of lp:ubuntu/lucid/dovecot now reflects that and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/lucid/dovecot/lucid-201002122358. A merge should be performed if necessary.

Unmerged revisions

62. By Chuck Short

Fix FTBFS.

61. By Chuck Short

* Merge from debian testing, remaining changes:
  + Add new binary pkg dovecot-postfix that integrates postfix and dovecot
    automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restriction
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
  + debian/dovecot-postfix.dirs: create backup directory for postfix's config
    configuration
  + restart postfix and dovecot.
  + debian/dovecot-postfix.postrm:
    - remove all dovecot related configuration from postfix.
    - restart postfix and dovecot.
  + debian/dovecot-common.init:
    - check if /etc/dovecot/dovecot-postfix.conf exists and use it
      as the configuration file if so.
  + debian/patches/warning-ubuntu-postfix.dpatch
    - add warning about dovecot-postfix.conf in dovecot default
      configuration file
  + debian/patches/dovecot-postfix.conf.diff:
    - Ubuntu server custom changes to the default dovecot configuration for
      better interfation with postfix.
    - enable sieve plugin.
    - Ubuntu server custom changes to the default dovecot configuration for
      better integration with postfix:
      - enable imap, pop3, imaps, pop3s and managesieve by default.
      - enable dovecot LDA (deliver).
      - enable SASL auth socket in postfix private directory
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules: install profile.
     - debian/control: suggest ufw.
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). (LP: #254721)
   + debian/control: Update Vcs-* headers.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
* New upstream release.
* debian/patches/gold-fix.patch: Removed. Fixed upstream.
* Moved libexec to lib corrections in dovecot-managesieve.patch and
  dovecot-managesieve-dist.patch to dovecot-example.patch
* debian/patches/dovecot-mboxlocking.patch: Regenerated to avoid FTBFS
  when quilt isn't installed.
* debian/patches/quota-mountpoint.patch: Removed. Not needed anymore.
* debian/patches/dovecot-quota.patch: Removed. Quotas aren't properly
  enabled unless mail_plugins = quota imap_quota.
* debian/patches/gold-fix.patch: Fixed configure script to build even
  with binutils-gold or --no-add-needed linker flag (Closes: #554306)
* debian/dovecot-common.init: fixed LSB headers. Thanks to Pascal Volk.
  (Closes: #558040)
* debian/changelog: added CVE references to previous changelog entry.
* debian/rules: checked up the build system. It's not fragile anymore.
  (Closes: 493803)
* debian/dovecot-common.postinst: Now invoking dpkg-reconfigure
  on dovecot-common is enough to generate new certificates
  if the previous ones were removed. (Closes: #545582)
* debian/rules: No longer install convert-tool in /usr/bin.
  It isn't an user utility and it should stay in /usr/lib/dovecot
  like all other similar tool.
* New upstream release. (Closes: #557601)
* [SECURITY] Fixes local information disclosure and denial of service.
  (see: http://www.dovecot.org/list/dovecot-news/2009-November/000143.html
  and CVE-2009-3897)
* Added myself to uploaders.
* Switched to the new source format "3.0 (quilt)":
  - removed dpatch from build-depends
  - removed debian/README.source because now we use only standard
    dpkg features
  - regenerated all patches
* Prepared to switch to multi-origin source:
  - recreated dovecot-libsieve.patch and dovecot-managesieve-dist.patch
    starting from the upstream tarball
  - removed all autotools related build-depends and build-conflict
  - renamed dovecot-libsieve and dovecot-managesieve directories
    to libsieve and managesieve.
* debian/rules: Moved the configuration of libsieve and managesieve from
  the build phase to the configuration phase
* Added dovecot-dbg package with debugging symbols. Thanks Stephan Bosch.
  (Closes: #554710)
* Fixed some stray libexec'isms in the default configuration.
* New upstream release.
* debian/dovecot-common.init:
  - use $CONF when starting the daemon. (Closes: #549944)
  - always output start/stop messages. (Closes: #523810)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/patches/.dpkg-source-applied'
2--- debian/patches/.dpkg-source-applied 2010-01-21 20:02:02 +0000
3+++ debian/patches/.dpkg-source-applied 2010-02-13 00:05:29 +0000
4@@ -1,3 +1,4 @@
5+<<<<<<< TREE
6 dovecot-libsieve.patch
7 dovecot-managesieve-dist.patch
8 dovecot-managesieve.patch
9@@ -8,3 +9,14 @@
10 dovecot-ssl.patch
11 dovecot-mboxlocking.patch
12 debian-changes-1:1.2.9-1ubuntu2
13+=======
14+dovecot-libsieve.patch
15+dovecot-managesieve-dist.patch
16+dovecot-managesieve.patch
17+dovecot-example.patch
18+dovecot-sql.patch
19+dovecot-drac.patch
20+exec-check-for-none.patch
21+dovecot-ssl.patch
22+dovecot-mboxlocking.patch
23+>>>>>>> MERGE-SOURCE
24
25=== modified file 'debian/patches/series'
26--- debian/patches/series 2010-01-21 20:02:02 +0000
27+++ debian/patches/series 2010-02-13 00:05:29 +0000
28@@ -1,3 +1,4 @@
29+<<<<<<< TREE
30 dovecot-libsieve.patch
31 dovecot-managesieve-dist.patch
32 dovecot-managesieve.patch
33@@ -8,3 +9,14 @@
34 dovecot-ssl.patch
35 dovecot-mboxlocking.patch
36 debian-changes-1:1.2.9-1ubuntu2
37+=======
38+dovecot-libsieve.patch
39+dovecot-managesieve-dist.patch
40+dovecot-managesieve.patch
41+dovecot-example.patch
42+dovecot-sql.patch
43+dovecot-drac.patch
44+exec-check-for-none.patch
45+dovecot-ssl.patch
46+dovecot-mboxlocking.patch
47+>>>>>>> MERGE-SOURCE
48
49=== added directory 'src/deliver'
50=== renamed directory 'src/deliver' => 'src/deliver.moved'
51=== added file 'src/deliver/Makefile.am'
52--- src/deliver/Makefile.am 1970-01-01 00:00:00 +0000
53+++ src/deliver/Makefile.am 2010-02-13 00:05:29 +0000
54@@ -0,0 +1,60 @@
55+pkglibexecdir = $(libexecdir)/dovecot
56+
57+pkglibexec_PROGRAMS = deliver
58+
59+AM_CPPFLAGS = \
60+ -I$(top_srcdir)/src/lib \
61+ -I$(top_srcdir)/src/lib-auth \
62+ -I$(top_srcdir)/src/lib-dict \
63+ -I$(top_srcdir)/src/lib-mail \
64+ -I$(top_srcdir)/src/lib-imap \
65+ -I$(top_srcdir)/src/lib-index \
66+ -I$(top_srcdir)/src/lib-settings \
67+ -I$(top_srcdir)/src/lib-storage \
68+ -I$(top_srcdir)/src/lib-storage/index \
69+ -I$(top_srcdir)/src/lib-storage/index/raw \
70+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
71+ -DPKG_RUNDIR=\""$(rundir)"\" \
72+ -DMODULEDIR=\""$(moduledir)"\"
73+
74+deliver_LDFLAGS = -export-dynamic
75+
76+# get some functions included which only plugins use. liblib should probably
77+# be a shared library so this wouldn't be needed..
78+unused_objects = \
79+ ../lib/mountpoint.o \
80+ ../lib-mail/message-header-encode.o \
81+ ../lib-imap/imap-util.o
82+
83+libs = \
84+ $(STORAGE_LIBS) \
85+ ../lib-dict/libdict.a \
86+ $(unused_objects)
87+
88+deliver_LDADD = \
89+ $(libs) \
90+ $(LIBICONV) \
91+ $(MODULE_LIBS)
92+
93+deliver_DEPENDENCIES = $(libs)
94+
95+deliver_SOURCES = \
96+ auth-client.c \
97+ deliver.c \
98+ duplicate.c \
99+ mail-send.c \
100+ smtp-client.c
101+
102+headers = \
103+ auth-client.h \
104+ deliver.h \
105+ duplicate.h \
106+ mail-send.h \
107+ smtp-client.h
108+
109+if INSTALL_HEADERS
110+ pkginc_libdir=$(pkgincludedir)/src/deliver
111+ pkginc_lib_HEADERS = $(headers)
112+else
113+ noinst_HEADERS = $(headers)
114+endif
115
116=== added file 'src/deliver/Makefile.in'
117--- src/deliver/Makefile.in 1970-01-01 00:00:00 +0000
118+++ src/deliver/Makefile.in 2010-02-13 00:05:29 +0000
119@@ -0,0 +1,657 @@
120+# Makefile.in generated by automake 1.11 from Makefile.am.
121+# @configure_input@
122+
123+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
124+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
125+# Inc.
126+# This Makefile.in is free software; the Free Software Foundation
127+# gives unlimited permission to copy and/or distribute it,
128+# with or without modifications, as long as this notice is preserved.
129+
130+# This program is distributed in the hope that it will be useful,
131+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
132+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
133+# PARTICULAR PURPOSE.
134+
135+@SET_MAKE@
136+
137+
138+VPATH = @srcdir@
139+pkgdatadir = $(datadir)/@PACKAGE@
140+pkgincludedir = $(includedir)/@PACKAGE@
141+pkglibdir = $(libdir)/@PACKAGE@
142+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
143+install_sh_DATA = $(install_sh) -c -m 644
144+install_sh_PROGRAM = $(install_sh) -c
145+install_sh_SCRIPT = $(install_sh) -c
146+INSTALL_HEADER = $(INSTALL_DATA)
147+transform = $(program_transform_name)
148+NORMAL_INSTALL = :
149+PRE_INSTALL = :
150+POST_INSTALL = :
151+NORMAL_UNINSTALL = :
152+PRE_UNINSTALL = :
153+POST_UNINSTALL = :
154+build_triplet = @build@
155+host_triplet = @host@
156+pkglibexec_PROGRAMS = deliver$(EXEEXT)
157+subdir = src/deliver
158+DIST_COMMON = $(am__noinst_HEADERS_DIST) \
159+ $(am__pkginc_lib_HEADERS_DIST) $(srcdir)/Makefile.am \
160+ $(srcdir)/Makefile.in
161+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
162+am__aclocal_m4_deps = $(top_srcdir)/configure.in
163+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
164+ $(ACLOCAL_M4)
165+mkinstalldirs = $(install_sh) -d
166+CONFIG_HEADER = $(top_builddir)/config.h
167+CONFIG_CLEAN_FILES =
168+CONFIG_CLEAN_VPATH_FILES =
169+am__installdirs = "$(DESTDIR)$(pkglibexecdir)" \
170+ "$(DESTDIR)$(pkginc_libdir)"
171+PROGRAMS = $(pkglibexec_PROGRAMS)
172+am_deliver_OBJECTS = auth-client.$(OBJEXT) deliver.$(OBJEXT) \
173+ duplicate.$(OBJEXT) mail-send.$(OBJEXT) smtp-client.$(OBJEXT)
174+deliver_OBJECTS = $(am_deliver_OBJECTS)
175+am__DEPENDENCIES_1 =
176+am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) ../lib-dict/libdict.a \
177+ $(unused_objects)
178+deliver_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
179+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(deliver_LDFLAGS) \
180+ $(LDFLAGS) -o $@
181+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
182+depcomp = $(SHELL) $(top_srcdir)/depcomp
183+am__depfiles_maybe = depfiles
184+am__mv = mv -f
185+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
186+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
187+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
188+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
189+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
190+CCLD = $(CC)
191+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
192+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
193+ $(LDFLAGS) -o $@
194+SOURCES = $(deliver_SOURCES)
195+DIST_SOURCES = $(deliver_SOURCES)
196+am__noinst_HEADERS_DIST = auth-client.h deliver.h duplicate.h \
197+ mail-send.h smtp-client.h
198+am__pkginc_lib_HEADERS_DIST = auth-client.h deliver.h duplicate.h \
199+ mail-send.h smtp-client.h
200+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
201+am__vpath_adj = case $$p in \
202+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
203+ *) f=$$p;; \
204+ esac;
205+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
206+am__install_max = 40
207+am__nobase_strip_setup = \
208+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
209+am__nobase_strip = \
210+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
211+am__nobase_list = $(am__nobase_strip_setup); \
212+ for p in $$list; do echo "$$p $$p"; done | \
213+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
214+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
215+ if (++n[$$2] == $(am__install_max)) \
216+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
217+ END { for (dir in files) print dir, files[dir] }'
218+am__base_list = \
219+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
220+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
221+HEADERS = $(noinst_HEADERS) $(pkginc_lib_HEADERS)
222+ETAGS = etags
223+CTAGS = ctags
224+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
225+pkglibexecdir = $(libexecdir)/dovecot
226+ACLOCAL = @ACLOCAL@
227+AMTAR = @AMTAR@
228+AR = @AR@
229+AUTH_CFLAGS = @AUTH_CFLAGS@
230+AUTH_LIBS = @AUTH_LIBS@
231+AUTOCONF = @AUTOCONF@
232+AUTOHEADER = @AUTOHEADER@
233+AUTOMAKE = @AUTOMAKE@
234+AWK = @AWK@
235+CC = @CC@
236+CCDEPMODE = @CCDEPMODE@
237+CFLAGS = @CFLAGS@
238+CPP = @CPP@
239+CPPFLAGS = @CPPFLAGS@
240+CURLCONFIG = @CURLCONFIG@
241+CURL_CFLAGS = @CURL_CFLAGS@
242+CURL_LIBS = @CURL_LIBS@
243+CXX = @CXX@
244+CXXCPP = @CXXCPP@
245+CXXDEPMODE = @CXXDEPMODE@
246+CXXFLAGS = @CXXFLAGS@
247+CYGPATH_W = @CYGPATH_W@
248+DEFS = @DEFS@
249+DEPDIR = @DEPDIR@
250+DICT_LIBS = @DICT_LIBS@
251+DSYMUTIL = @DSYMUTIL@
252+DUMPBIN = @DUMPBIN@
253+ECHO_C = @ECHO_C@
254+ECHO_N = @ECHO_N@
255+ECHO_T = @ECHO_T@
256+EGREP = @EGREP@
257+EXEEXT = @EXEEXT@
258+FGREP = @FGREP@
259+GREP = @GREP@
260+INSTALL = @INSTALL@
261+INSTALL_DATA = @INSTALL_DATA@
262+INSTALL_PROGRAM = @INSTALL_PROGRAM@
263+INSTALL_SCRIPT = @INSTALL_SCRIPT@
264+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
265+KRB5CONFIG = @KRB5CONFIG@
266+KRB5_CFLAGS = @KRB5_CFLAGS@
267+KRB5_LIBS = @KRB5_LIBS@
268+LD = @LD@
269+LDAP_LIBS = @LDAP_LIBS@
270+LDFLAGS = @LDFLAGS@
271+LIBCAP = @LIBCAP@
272+LIBICONV = @LIBICONV@
273+LIBOBJS = @LIBOBJS@
274+LIBS = @LIBS@
275+LIBTOOL = @LIBTOOL@
276+LIPO = @LIPO@
277+LN_S = @LN_S@
278+LTLIBICONV = @LTLIBICONV@
279+LTLIBOBJS = @LTLIBOBJS@
280+MAINT = @MAINT@
281+MAKEINFO = @MAKEINFO@
282+MKDIR_P = @MKDIR_P@
283+MODULE_LIBS = @MODULE_LIBS@
284+MODULE_SUFFIX = @MODULE_SUFFIX@
285+MYSQL_CFLAGS = @MYSQL_CFLAGS@
286+MYSQL_LIBS = @MYSQL_LIBS@
287+NM = @NM@
288+NMEDIT = @NMEDIT@
289+OBJDUMP = @OBJDUMP@
290+OBJEXT = @OBJEXT@
291+OTOOL = @OTOOL@
292+OTOOL64 = @OTOOL64@
293+PACKAGE = @PACKAGE@
294+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
295+PACKAGE_NAME = @PACKAGE_NAME@
296+PACKAGE_STRING = @PACKAGE_STRING@
297+PACKAGE_TARNAME = @PACKAGE_TARNAME@
298+PACKAGE_URL = @PACKAGE_URL@
299+PACKAGE_VERSION = @PACKAGE_VERSION@
300+PATH_SEPARATOR = @PATH_SEPARATOR@
301+PGSQL_CFLAGS = @PGSQL_CFLAGS@
302+PGSQL_LIBS = @PGSQL_LIBS@
303+PG_CONFIG = @PG_CONFIG@
304+PKG_CONFIG = @PKG_CONFIG@
305+RANLIB = @RANLIB@
306+RPCGEN = @RPCGEN@
307+SED = @SED@
308+SET_MAKE = @SET_MAKE@
309+SHELL = @SHELL@
310+SQLITE_CFLAGS = @SQLITE_CFLAGS@
311+SQLITE_LIBS = @SQLITE_LIBS@
312+SQL_CFLAGS = @SQL_CFLAGS@
313+SQL_LIBS = @SQL_LIBS@
314+SSL_CFLAGS = @SSL_CFLAGS@
315+SSL_LIBS = @SSL_LIBS@
316+STORAGE_LIBS = @STORAGE_LIBS@
317+STRIP = @STRIP@
318+VERSION = @VERSION@
319+abs_builddir = @abs_builddir@
320+abs_srcdir = @abs_srcdir@
321+abs_top_builddir = @abs_top_builddir@
322+abs_top_srcdir = @abs_top_srcdir@
323+ac_ct_CC = @ac_ct_CC@
324+ac_ct_CXX = @ac_ct_CXX@
325+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
326+am__include = @am__include@
327+am__leading_dot = @am__leading_dot@
328+am__quote = @am__quote@
329+am__tar = @am__tar@
330+am__untar = @am__untar@
331+bindir = @bindir@
332+build = @build@
333+build_alias = @build_alias@
334+build_cpu = @build_cpu@
335+build_os = @build_os@
336+build_vendor = @build_vendor@
337+builddir = @builddir@
338+datadir = @datadir@
339+datarootdir = @datarootdir@
340+dict_drivers = @dict_drivers@
341+docdir = @docdir@
342+dvidir = @dvidir@
343+exec_prefix = @exec_prefix@
344+host = @host@
345+host_alias = @host_alias@
346+host_cpu = @host_cpu@
347+host_os = @host_os@
348+host_vendor = @host_vendor@
349+htmldir = @htmldir@
350+includedir = @includedir@
351+infodir = @infodir@
352+install_sh = @install_sh@
353+libdir = @libdir@
354+libexecdir = @libexecdir@
355+localedir = @localedir@
356+localstatedir = @localstatedir@
357+lt_ECHO = @lt_ECHO@
358+mail_storages = @mail_storages@
359+mandir = @mandir@
360+mkdir_p = @mkdir_p@
361+moduledir = @moduledir@
362+oldincludedir = @oldincludedir@
363+pdfdir = @pdfdir@
364+prefix = @prefix@
365+program_transform_name = @program_transform_name@
366+psdir = @psdir@
367+rundir = @rundir@
368+sbindir = @sbindir@
369+sharedstatedir = @sharedstatedir@
370+sql_drivers = @sql_drivers@
371+srcdir = @srcdir@
372+ssldir = @ssldir@
373+statedir = @statedir@
374+sysconfdir = @sysconfdir@
375+target_alias = @target_alias@
376+top_build_prefix = @top_build_prefix@
377+top_builddir = @top_builddir@
378+top_srcdir = @top_srcdir@
379+AM_CPPFLAGS = \
380+ -I$(top_srcdir)/src/lib \
381+ -I$(top_srcdir)/src/lib-auth \
382+ -I$(top_srcdir)/src/lib-dict \
383+ -I$(top_srcdir)/src/lib-mail \
384+ -I$(top_srcdir)/src/lib-imap \
385+ -I$(top_srcdir)/src/lib-index \
386+ -I$(top_srcdir)/src/lib-settings \
387+ -I$(top_srcdir)/src/lib-storage \
388+ -I$(top_srcdir)/src/lib-storage/index \
389+ -I$(top_srcdir)/src/lib-storage/index/raw \
390+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
391+ -DPKG_RUNDIR=\""$(rundir)"\" \
392+ -DMODULEDIR=\""$(moduledir)"\"
393+
394+deliver_LDFLAGS = -export-dynamic
395+
396+# get some functions included which only plugins use. liblib should probably
397+# be a shared library so this wouldn't be needed..
398+unused_objects = \
399+ ../lib/mountpoint.o \
400+ ../lib-mail/message-header-encode.o \
401+ ../lib-imap/imap-util.o
402+
403+libs = \
404+ $(STORAGE_LIBS) \
405+ ../lib-dict/libdict.a \
406+ $(unused_objects)
407+
408+deliver_LDADD = \
409+ $(libs) \
410+ $(LIBICONV) \
411+ $(MODULE_LIBS)
412+
413+deliver_DEPENDENCIES = $(libs)
414+deliver_SOURCES = \
415+ auth-client.c \
416+ deliver.c \
417+ duplicate.c \
418+ mail-send.c \
419+ smtp-client.c
420+
421+headers = \
422+ auth-client.h \
423+ deliver.h \
424+ duplicate.h \
425+ mail-send.h \
426+ smtp-client.h
427+
428+@INSTALL_HEADERS_TRUE@pkginc_libdir = $(pkgincludedir)/src/deliver
429+@INSTALL_HEADERS_TRUE@pkginc_lib_HEADERS = $(headers)
430+@INSTALL_HEADERS_FALSE@noinst_HEADERS = $(headers)
431+all: all-am
432+
433+.SUFFIXES:
434+.SUFFIXES: .c .lo .o .obj
435+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
436+ @for dep in $?; do \
437+ case '$(am__configure_deps)' in \
438+ *$$dep*) \
439+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
440+ && { if test -f $@; then exit 0; else break; fi; }; \
441+ exit 1;; \
442+ esac; \
443+ done; \
444+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/deliver/Makefile'; \
445+ $(am__cd) $(top_srcdir) && \
446+ $(AUTOMAKE) --foreign src/deliver/Makefile
447+.PRECIOUS: Makefile
448+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
449+ @case '$?' in \
450+ *config.status*) \
451+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
452+ *) \
453+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
454+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
455+ esac;
456+
457+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
458+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
459+
460+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
461+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
462+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
463+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
464+$(am__aclocal_m4_deps):
465+install-pkglibexecPROGRAMS: $(pkglibexec_PROGRAMS)
466+ @$(NORMAL_INSTALL)
467+ test -z "$(pkglibexecdir)" || $(MKDIR_P) "$(DESTDIR)$(pkglibexecdir)"
468+ @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
469+ for p in $$list; do echo "$$p $$p"; done | \
470+ sed 's/$(EXEEXT)$$//' | \
471+ while read p p1; do if test -f $$p || test -f $$p1; \
472+ then echo "$$p"; echo "$$p"; else :; fi; \
473+ done | \
474+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
475+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
476+ sed 'N;N;N;s,\n, ,g' | \
477+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
478+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
479+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
480+ else { print "f", $$3 "/" $$4, $$1; } } \
481+ END { for (d in files) print "f", d, files[d] }' | \
482+ while read type dir files; do \
483+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
484+ test -z "$$files" || { \
485+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(pkglibexecdir)$$dir'"; \
486+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(pkglibexecdir)$$dir" || exit $$?; \
487+ } \
488+ ; done
489+
490+uninstall-pkglibexecPROGRAMS:
491+ @$(NORMAL_UNINSTALL)
492+ @list='$(pkglibexec_PROGRAMS)'; test -n "$(pkglibexecdir)" || list=; \
493+ files=`for p in $$list; do echo "$$p"; done | \
494+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
495+ -e 's/$$/$(EXEEXT)/' `; \
496+ test -n "$$list" || exit 0; \
497+ echo " ( cd '$(DESTDIR)$(pkglibexecdir)' && rm -f" $$files ")"; \
498+ cd "$(DESTDIR)$(pkglibexecdir)" && rm -f $$files
499+
500+clean-pkglibexecPROGRAMS:
501+ @list='$(pkglibexec_PROGRAMS)'; test -n "$$list" || exit 0; \
502+ echo " rm -f" $$list; \
503+ rm -f $$list || exit $$?; \
504+ test -n "$(EXEEXT)" || exit 0; \
505+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
506+ echo " rm -f" $$list; \
507+ rm -f $$list
508+deliver$(EXEEXT): $(deliver_OBJECTS) $(deliver_DEPENDENCIES)
509+ @rm -f deliver$(EXEEXT)
510+ $(deliver_LINK) $(deliver_OBJECTS) $(deliver_LDADD) $(LIBS)
511+
512+mostlyclean-compile:
513+ -rm -f *.$(OBJEXT)
514+
515+distclean-compile:
516+ -rm -f *.tab.c
517+
518+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth-client.Po@am__quote@
519+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/deliver.Po@am__quote@
520+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/duplicate.Po@am__quote@
521+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mail-send.Po@am__quote@
522+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smtp-client.Po@am__quote@
523+
524+.c.o:
525+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
526+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
527+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
528+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
529+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
530+
531+.c.obj:
532+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
533+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
534+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
535+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
536+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
537+
538+.c.lo:
539+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
540+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
541+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
542+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
543+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
544+
545+mostlyclean-libtool:
546+ -rm -f *.lo
547+
548+clean-libtool:
549+ -rm -rf .libs _libs
550+install-pkginc_libHEADERS: $(pkginc_lib_HEADERS)
551+ @$(NORMAL_INSTALL)
552+ test -z "$(pkginc_libdir)" || $(MKDIR_P) "$(DESTDIR)$(pkginc_libdir)"
553+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
554+ for p in $$list; do \
555+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
556+ echo "$$d$$p"; \
557+ done | $(am__base_list) | \
558+ while read files; do \
559+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkginc_libdir)'"; \
560+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkginc_libdir)" || exit $$?; \
561+ done
562+
563+uninstall-pkginc_libHEADERS:
564+ @$(NORMAL_UNINSTALL)
565+ @list='$(pkginc_lib_HEADERS)'; test -n "$(pkginc_libdir)" || list=; \
566+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
567+ test -n "$$files" || exit 0; \
568+ echo " ( cd '$(DESTDIR)$(pkginc_libdir)' && rm -f" $$files ")"; \
569+ cd "$(DESTDIR)$(pkginc_libdir)" && rm -f $$files
570+
571+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
572+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
573+ unique=`for i in $$list; do \
574+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
575+ done | \
576+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
577+ END { if (nonempty) { for (i in files) print i; }; }'`; \
578+ mkid -fID $$unique
579+tags: TAGS
580+
581+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
582+ $(TAGS_FILES) $(LISP)
583+ set x; \
584+ here=`pwd`; \
585+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
586+ unique=`for i in $$list; do \
587+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
588+ done | \
589+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
590+ END { if (nonempty) { for (i in files) print i; }; }'`; \
591+ shift; \
592+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
593+ test -n "$$unique" || unique=$$empty_fix; \
594+ if test $$# -gt 0; then \
595+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
596+ "$$@" $$unique; \
597+ else \
598+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
599+ $$unique; \
600+ fi; \
601+ fi
602+ctags: CTAGS
603+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
604+ $(TAGS_FILES) $(LISP)
605+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
606+ unique=`for i in $$list; do \
607+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
608+ done | \
609+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
610+ END { if (nonempty) { for (i in files) print i; }; }'`; \
611+ test -z "$(CTAGS_ARGS)$$unique" \
612+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
613+ $$unique
614+
615+GTAGS:
616+ here=`$(am__cd) $(top_builddir) && pwd` \
617+ && $(am__cd) $(top_srcdir) \
618+ && gtags -i $(GTAGS_ARGS) "$$here"
619+
620+distclean-tags:
621+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
622+
623+distdir: $(DISTFILES)
624+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
625+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
626+ list='$(DISTFILES)'; \
627+ dist_files=`for file in $$list; do echo $$file; done | \
628+ sed -e "s|^$$srcdirstrip/||;t" \
629+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
630+ case $$dist_files in \
631+ */*) $(MKDIR_P) `echo "$$dist_files" | \
632+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
633+ sort -u` ;; \
634+ esac; \
635+ for file in $$dist_files; do \
636+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
637+ if test -d $$d/$$file; then \
638+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
639+ if test -d "$(distdir)/$$file"; then \
640+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
641+ fi; \
642+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
643+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
644+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
645+ fi; \
646+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
647+ else \
648+ test -f "$(distdir)/$$file" \
649+ || cp -p $$d/$$file "$(distdir)/$$file" \
650+ || exit 1; \
651+ fi; \
652+ done
653+check-am: all-am
654+check: check-am
655+all-am: Makefile $(PROGRAMS) $(HEADERS)
656+installdirs:
657+ for dir in "$(DESTDIR)$(pkglibexecdir)" "$(DESTDIR)$(pkginc_libdir)"; do \
658+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
659+ done
660+install: install-am
661+install-exec: install-exec-am
662+install-data: install-data-am
663+uninstall: uninstall-am
664+
665+install-am: all-am
666+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
667+
668+installcheck: installcheck-am
669+install-strip:
670+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
671+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
672+ `test -z '$(STRIP)' || \
673+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
674+mostlyclean-generic:
675+
676+clean-generic:
677+
678+distclean-generic:
679+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
680+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
681+
682+maintainer-clean-generic:
683+ @echo "This command is intended for maintainers to use"
684+ @echo "it deletes files that may require special tools to rebuild."
685+clean: clean-am
686+
687+clean-am: clean-generic clean-libtool clean-pkglibexecPROGRAMS \
688+ mostlyclean-am
689+
690+distclean: distclean-am
691+ -rm -rf ./$(DEPDIR)
692+ -rm -f Makefile
693+distclean-am: clean-am distclean-compile distclean-generic \
694+ distclean-tags
695+
696+dvi: dvi-am
697+
698+dvi-am:
699+
700+html: html-am
701+
702+html-am:
703+
704+info: info-am
705+
706+info-am:
707+
708+install-data-am: install-pkginc_libHEADERS
709+
710+install-dvi: install-dvi-am
711+
712+install-dvi-am:
713+
714+install-exec-am: install-pkglibexecPROGRAMS
715+
716+install-html: install-html-am
717+
718+install-html-am:
719+
720+install-info: install-info-am
721+
722+install-info-am:
723+
724+install-man:
725+
726+install-pdf: install-pdf-am
727+
728+install-pdf-am:
729+
730+install-ps: install-ps-am
731+
732+install-ps-am:
733+
734+installcheck-am:
735+
736+maintainer-clean: maintainer-clean-am
737+ -rm -rf ./$(DEPDIR)
738+ -rm -f Makefile
739+maintainer-clean-am: distclean-am maintainer-clean-generic
740+
741+mostlyclean: mostlyclean-am
742+
743+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
744+ mostlyclean-libtool
745+
746+pdf: pdf-am
747+
748+pdf-am:
749+
750+ps: ps-am
751+
752+ps-am:
753+
754+uninstall-am: uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
755+
756+.MAKE: install-am install-strip
757+
758+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
759+ clean-libtool clean-pkglibexecPROGRAMS ctags distclean \
760+ distclean-compile distclean-generic distclean-libtool \
761+ distclean-tags distdir dvi dvi-am html html-am info info-am \
762+ install install-am install-data install-data-am install-dvi \
763+ install-dvi-am install-exec install-exec-am install-html \
764+ install-html-am install-info install-info-am install-man \
765+ install-pdf install-pdf-am install-pkginc_libHEADERS \
766+ install-pkglibexecPROGRAMS install-ps install-ps-am \
767+ install-strip installcheck installcheck-am installdirs \
768+ maintainer-clean maintainer-clean-generic mostlyclean \
769+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
770+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
771+ uninstall-pkginc_libHEADERS uninstall-pkglibexecPROGRAMS
772+
773+
774+# Tell versions [3.59,3.63) of GNU make to not export all variables.
775+# Otherwise a system limit (for SysV at least) may be exceeded.
776+.NOEXPORT:
777
778=== added file 'src/deliver/auth-client.c'
779--- src/deliver/auth-client.c 1970-01-01 00:00:00 +0000
780+++ src/deliver/auth-client.c 2010-02-13 00:05:29 +0000
781@@ -0,0 +1,153 @@
782+/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
783+
784+#include "lib.h"
785+#include "array.h"
786+#include "ioloop.h"
787+#include "network.h"
788+#include "istream.h"
789+#include "ostream.h"
790+#include "env-util.h"
791+#include "restrict-access.h"
792+#include "auth-client.h"
793+#include "auth-master.h"
794+
795+#include <stdlib.h>
796+#include <unistd.h>
797+#include <pwd.h>
798+#include <grp.h>
799+#include <sysexits.h>
800+
801+static bool parse_uid(const char *str, uid_t *uid_r)
802+{
803+ struct passwd *pw;
804+ char *p;
805+
806+ if (*str >= '0' && *str <= '9') {
807+ *uid_r = (uid_t)strtoul(str, &p, 10);
808+ if (*p == '\0')
809+ return TRUE;
810+ }
811+
812+ pw = getpwnam(str);
813+ if (pw == NULL)
814+ return FALSE;
815+
816+ *uid_r = pw->pw_uid;
817+ return TRUE;
818+}
819+
820+static bool parse_gid(const char *str, gid_t *gid_r)
821+{
822+ struct group *gr;
823+ char *p;
824+
825+ if (*str >= '0' && *str <= '9') {
826+ *gid_r = (gid_t)strtoul(str, &p, 10);
827+ if (*p == '\0')
828+ return TRUE;
829+ }
830+
831+ gr = getgrnam(str);
832+ if (gr == NULL)
833+ return FALSE;
834+
835+ *gid_r = gr->gr_gid;
836+ return TRUE;
837+}
838+
839+static int set_env(struct auth_user_reply *reply,
840+ const char *user, uid_t euid)
841+{
842+ const char *extra_groups;
843+ unsigned int len;
844+
845+ if (reply->uid == 0) {
846+ i_error("userdb(%s) returned 0 as uid", user);
847+ return -1;
848+ } else if (reply->uid == (uid_t)-1) {
849+ if (getenv("MAIL_UID") != NULL) {
850+ if (!parse_uid(getenv("MAIL_UID"), &reply->uid) ||
851+ reply->uid == 0) {
852+ i_error("mail_uid setting is invalid");
853+ return -1;
854+ }
855+ } else {
856+ i_error("User %s is missing UID (set mail_uid)", user);
857+ return -1;
858+ }
859+ }
860+ if (reply->gid == 0) {
861+ i_error("userdb(%s) returned 0 as gid", user);
862+ return -1;
863+ } else if (reply->gid == (gid_t)-1) {
864+ if (getenv("MAIL_GID") != NULL) {
865+ if (!parse_gid(getenv("MAIL_GID"), &reply->gid) ||
866+ reply->gid == 0) {
867+ i_error("mail_gid setting is invalid");
868+ return -1;
869+ }
870+ } else {
871+ i_error("User %s is missing GID (set mail_gid)", user);
872+ return -1;
873+ }
874+ }
875+
876+ if (euid != reply->uid) {
877+ env_put(t_strconcat("RESTRICT_SETUID=",
878+ dec2str(reply->uid), NULL));
879+ }
880+ if (euid == 0 || getegid() != reply->gid) {
881+ env_put(t_strconcat("RESTRICT_SETGID=",
882+ dec2str(reply->gid), NULL));
883+ }
884+
885+ if (reply->chroot == NULL)
886+ reply->chroot = getenv("MAIL_CHROOT");
887+ if (reply->chroot != NULL) {
888+ len = strlen(reply->chroot);
889+ if (len > 2 && strcmp(reply->chroot + len - 2, "/.") == 0 &&
890+ reply->home != NULL &&
891+ strncmp(reply->home, reply->chroot, len - 2) == 0) {
892+ /* strip chroot dir from home dir */
893+ reply->home += len - 2;
894+ }
895+ env_put(t_strconcat("RESTRICT_CHROOT=", reply->chroot, NULL));
896+ }
897+ if (reply->home != NULL)
898+ env_put(t_strconcat("HOME=", reply->home, NULL));
899+
900+ extra_groups = getenv("MAIL_ACCESS_GROUPS");
901+ if (extra_groups != NULL) {
902+ env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
903+ extra_groups, NULL));
904+ }
905+ return 0;
906+}
907+
908+int auth_client_lookup_and_restrict(const char *auth_socket,
909+ const char **user, uid_t euid, pool_t pool,
910+ ARRAY_TYPE(const_string) *extra_fields_r)
911+{
912+ struct auth_master_connection *conn;
913+ struct auth_user_reply reply;
914+ bool debug = getenv("DEBUG") != NULL;
915+ int ret = EX_TEMPFAIL;
916+
917+ conn = auth_master_init(auth_socket, debug);
918+ switch (auth_master_user_lookup(conn, *user, "deliver", pool, &reply)) {
919+ case 0:
920+ ret = EX_NOUSER;
921+ break;
922+ case 1:
923+ if (set_env(&reply, *user, euid) == 0) {
924+ *user = p_strdup(pool, reply.user);
925+ restrict_access_by_env(TRUE);
926+ ret = EX_OK;
927+ }
928+ break;
929+ }
930+
931+ *extra_fields_r = reply.extra_fields;
932+ auth_master_deinit(&conn);
933+ return ret;
934+}
935
936=== removed file 'src/deliver/auth-client.c'
937--- src/deliver/auth-client.c 2009-11-06 00:47:29 +0000
938+++ src/deliver/auth-client.c 1970-01-01 00:00:00 +0000
939@@ -1,153 +0,0 @@
940-/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
941-
942-#include "lib.h"
943-#include "array.h"
944-#include "ioloop.h"
945-#include "network.h"
946-#include "istream.h"
947-#include "ostream.h"
948-#include "env-util.h"
949-#include "restrict-access.h"
950-#include "auth-client.h"
951-#include "auth-master.h"
952-
953-#include <stdlib.h>
954-#include <unistd.h>
955-#include <pwd.h>
956-#include <grp.h>
957-#include <sysexits.h>
958-
959-static bool parse_uid(const char *str, uid_t *uid_r)
960-{
961- struct passwd *pw;
962- char *p;
963-
964- if (*str >= '0' && *str <= '9') {
965- *uid_r = (uid_t)strtoul(str, &p, 10);
966- if (*p == '\0')
967- return TRUE;
968- }
969-
970- pw = getpwnam(str);
971- if (pw == NULL)
972- return FALSE;
973-
974- *uid_r = pw->pw_uid;
975- return TRUE;
976-}
977-
978-static bool parse_gid(const char *str, gid_t *gid_r)
979-{
980- struct group *gr;
981- char *p;
982-
983- if (*str >= '0' && *str <= '9') {
984- *gid_r = (gid_t)strtoul(str, &p, 10);
985- if (*p == '\0')
986- return TRUE;
987- }
988-
989- gr = getgrnam(str);
990- if (gr == NULL)
991- return FALSE;
992-
993- *gid_r = gr->gr_gid;
994- return TRUE;
995-}
996-
997-static int set_env(struct auth_user_reply *reply,
998- const char *user, uid_t euid)
999-{
1000- const char *extra_groups;
1001- unsigned int len;
1002-
1003- if (reply->uid == 0) {
1004- i_error("userdb(%s) returned 0 as uid", user);
1005- return -1;
1006- } else if (reply->uid == (uid_t)-1) {
1007- if (getenv("MAIL_UID") != NULL) {
1008- if (!parse_uid(getenv("MAIL_UID"), &reply->uid) ||
1009- reply->uid == 0) {
1010- i_error("mail_uid setting is invalid");
1011- return -1;
1012- }
1013- } else {
1014- i_error("User %s is missing UID (set mail_uid)", user);
1015- return -1;
1016- }
1017- }
1018- if (reply->gid == 0) {
1019- i_error("userdb(%s) returned 0 as gid", user);
1020- return -1;
1021- } else if (reply->gid == (gid_t)-1) {
1022- if (getenv("MAIL_GID") != NULL) {
1023- if (!parse_gid(getenv("MAIL_GID"), &reply->gid) ||
1024- reply->gid == 0) {
1025- i_error("mail_gid setting is invalid");
1026- return -1;
1027- }
1028- } else {
1029- i_error("User %s is missing GID (set mail_gid)", user);
1030- return -1;
1031- }
1032- }
1033-
1034- if (euid != reply->uid) {
1035- env_put(t_strconcat("RESTRICT_SETUID=",
1036- dec2str(reply->uid), NULL));
1037- }
1038- if (euid == 0 || getegid() != reply->gid) {
1039- env_put(t_strconcat("RESTRICT_SETGID=",
1040- dec2str(reply->gid), NULL));
1041- }
1042-
1043- if (reply->chroot == NULL)
1044- reply->chroot = getenv("MAIL_CHROOT");
1045- if (reply->chroot != NULL) {
1046- len = strlen(reply->chroot);
1047- if (len > 2 && strcmp(reply->chroot + len - 2, "/.") == 0 &&
1048- reply->home != NULL &&
1049- strncmp(reply->home, reply->chroot, len - 2) == 0) {
1050- /* strip chroot dir from home dir */
1051- reply->home += len - 2;
1052- }
1053- env_put(t_strconcat("RESTRICT_CHROOT=", reply->chroot, NULL));
1054- }
1055- if (reply->home != NULL)
1056- env_put(t_strconcat("HOME=", reply->home, NULL));
1057-
1058- extra_groups = getenv("MAIL_ACCESS_GROUPS");
1059- if (extra_groups != NULL) {
1060- env_put(t_strconcat("RESTRICT_SETEXTRAGROUPS=",
1061- extra_groups, NULL));
1062- }
1063- return 0;
1064-}
1065-
1066-int auth_client_lookup_and_restrict(const char *auth_socket,
1067- const char **user, uid_t euid, pool_t pool,
1068- ARRAY_TYPE(const_string) *extra_fields_r)
1069-{
1070- struct auth_master_connection *conn;
1071- struct auth_user_reply reply;
1072- bool debug = getenv("DEBUG") != NULL;
1073- int ret = EX_TEMPFAIL;
1074-
1075- conn = auth_master_init(auth_socket, debug);
1076- switch (auth_master_user_lookup(conn, *user, "deliver", pool, &reply)) {
1077- case 0:
1078- ret = EX_NOUSER;
1079- break;
1080- case 1:
1081- if (set_env(&reply, *user, euid) == 0) {
1082- *user = p_strdup(pool, reply.user);
1083- restrict_access_by_env(TRUE);
1084- ret = EX_OK;
1085- }
1086- break;
1087- }
1088-
1089- *extra_fields_r = reply.extra_fields;
1090- auth_master_deinit(&conn);
1091- return ret;
1092-}
1093
1094=== added file 'src/deliver/auth-client.h'
1095--- src/deliver/auth-client.h 1970-01-01 00:00:00 +0000
1096+++ src/deliver/auth-client.h 2010-02-13 00:05:29 +0000
1097@@ -0,0 +1,8 @@
1098+#ifndef AUTH_CLIENT_H
1099+#define AUTH_CLIENT_H
1100+
1101+int auth_client_lookup_and_restrict(const char *auth_socket,
1102+ const char **user, uid_t euid, pool_t pool,
1103+ ARRAY_TYPE(const_string) *extra_fields_r);
1104+
1105+#endif
1106
1107=== removed file 'src/deliver/auth-client.h'
1108--- src/deliver/auth-client.h 2009-11-06 00:47:29 +0000
1109+++ src/deliver/auth-client.h 1970-01-01 00:00:00 +0000
1110@@ -1,8 +0,0 @@
1111-#ifndef AUTH_CLIENT_H
1112-#define AUTH_CLIENT_H
1113-
1114-int auth_client_lookup_and_restrict(const char *auth_socket,
1115- const char **user, uid_t euid, pool_t pool,
1116- ARRAY_TYPE(const_string) *extra_fields_r);
1117-
1118-#endif
1119
1120=== added file 'src/deliver/deliver.c'
1121--- src/deliver/deliver.c 1970-01-01 00:00:00 +0000
1122+++ src/deliver/deliver.c 2010-02-13 00:05:29 +0000
1123@@ -0,0 +1,1319 @@
1124+/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
1125+
1126+/* This is getting pretty horrible. Especially the config file parsing.
1127+ Dovecot v2.0 should have a config file handling process which should help
1128+ with this.. */
1129+
1130+#include "lib.h"
1131+#include "lib-signals.h"
1132+#include "file-lock.h"
1133+#include "array.h"
1134+#include "ioloop.h"
1135+#include "hostpid.h"
1136+#include "home-expand.h"
1137+#include "env-util.h"
1138+#include "fd-set-nonblock.h"
1139+#include "istream.h"
1140+#include "istream-seekable.h"
1141+#include "module-dir.h"
1142+#include "str.h"
1143+#include "str-sanitize.h"
1144+#include "strescape.h"
1145+#include "safe-mkstemp.h"
1146+#include "mkdir-parents.h"
1147+#include "eacces-error.h"
1148+#include "close-keep-errno.h"
1149+#include "var-expand.h"
1150+#include "rfc822-parser.h"
1151+#include "message-address.h"
1152+#include "mail-namespace.h"
1153+#include "raw-storage.h"
1154+#include "imap-utf7.h"
1155+#include "dict.h"
1156+#include "auth-client.h"
1157+#include "mail-send.h"
1158+#include "duplicate.h"
1159+#include "mbox-from.h"
1160+#include "../master/syslog-util.h"
1161+#include "../master/syslog-util.c" /* ugly, ugly.. */
1162+#include "deliver.h"
1163+
1164+#include <stdio.h>
1165+#include <stdlib.h>
1166+#include <unistd.h>
1167+#include <fcntl.h>
1168+#include <pwd.h>
1169+#include <syslog.h>
1170+
1171+#define DEFAULT_CONFIG_FILE SYSCONFDIR"/dovecot.conf"
1172+#define DEFAULT_SENDMAIL_PATH "/usr/lib/sendmail"
1173+#define DEFAULT_ENVELOPE_SENDER "MAILER-DAEMON"
1174+
1175+/* After buffer grows larger than this, create a temporary file to /tmp
1176+ where to read the mail. */
1177+#define MAIL_MAX_MEMORY_BUFFER (1024*128)
1178+
1179+static const char *wanted_headers[] = {
1180+ "From", "Message-ID", "Subject", "Return-Path",
1181+ NULL
1182+};
1183+
1184+struct deliver_settings *deliver_set;
1185+deliver_mail_func_t *deliver_mail = NULL;
1186+bool tried_default_save = FALSE;
1187+
1188+/* FIXME: these two should be in some context struct instead of as globals.. */
1189+static const char *default_mailbox_name = NULL;
1190+static bool saved_mail = FALSE;
1191+static char *explicit_envelope_sender = NULL;
1192+
1193+static struct module *modules;
1194+static struct ioloop *ioloop;
1195+
1196+static pool_t plugin_pool;
1197+static ARRAY_DEFINE(lda_envs, const char *);
1198+static ARRAY_DEFINE(plugin_envs, const char *);
1199+
1200+static void sig_die(const siginfo_t *si, void *context ATTR_UNUSED)
1201+{
1202+ /* warn about being killed because of some signal, except SIGINT (^C)
1203+ which is too common at least while testing :) */
1204+ if (si->si_signo != SIGINT) {
1205+ i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
1206+ si->si_signo, dec2str(si->si_pid),
1207+ dec2str(si->si_uid),
1208+ lib_signal_code_to_str(si->si_signo, si->si_code));
1209+ }
1210+ io_loop_stop(current_ioloop);
1211+}
1212+
1213+static const char *deliver_get_address(struct mail *mail, const char *header)
1214+{
1215+ struct message_address *addr;
1216+ const char *str;
1217+
1218+ if (mail_get_first_header(mail, header, &str) <= 0)
1219+ return NULL;
1220+ addr = message_address_parse(pool_datastack_create(),
1221+ (const unsigned char *)str,
1222+ strlen(str), 1, FALSE);
1223+ return addr == NULL || addr->mailbox == NULL || addr->domain == NULL ||
1224+ *addr->mailbox == '\0' || *addr->domain == '\0' ?
1225+ NULL : t_strconcat(addr->mailbox, "@", addr->domain, NULL);
1226+}
1227+
1228+static const struct var_expand_table *
1229+get_log_var_expand_table(struct mail *mail, const char *message)
1230+{
1231+ static struct var_expand_table static_tab[] = {
1232+ { '$', NULL, NULL },
1233+ { 'm', NULL, "msgid" },
1234+ { 's', NULL, "subject" },
1235+ { 'f', NULL, "from" },
1236+ { '\0', NULL, NULL }
1237+ };
1238+ struct var_expand_table *tab;
1239+ unsigned int i;
1240+
1241+ tab = t_malloc(sizeof(static_tab));
1242+ memcpy(tab, static_tab, sizeof(static_tab));
1243+
1244+ tab[0].value = message;
1245+ (void)mail_get_first_header(mail, "Message-ID", &tab[1].value);
1246+ (void)mail_get_first_header_utf8(mail, "Subject", &tab[2].value);
1247+ tab[3].value = deliver_get_address(mail, "From");
1248+ for (i = 1; tab[i].key != '\0'; i++)
1249+ tab[i].value = str_sanitize(tab[i].value, 80);
1250+ return tab;
1251+}
1252+
1253+static void
1254+deliver_log(struct mail *mail, const char *fmt, ...) ATTR_FORMAT(2, 3);
1255+
1256+static void deliver_log(struct mail *mail, const char *fmt, ...)
1257+{
1258+ va_list args;
1259+ string_t *str;
1260+ const char *msg;
1261+
1262+ va_start(args, fmt);
1263+ msg = t_strdup_vprintf(fmt, args);
1264+
1265+ str = t_str_new(256);
1266+ var_expand(str, deliver_set->log_format,
1267+ get_log_var_expand_table(mail, msg));
1268+ i_info("%s", str_c(str));
1269+ va_end(args);
1270+}
1271+
1272+static struct mailbox *
1273+mailbox_open_or_create_synced(struct mail_namespace *namespaces,
1274+ struct mail_storage **storage_r,
1275+ const char *name)
1276+{
1277+ struct mail_namespace *ns;
1278+ struct mailbox *box;
1279+ enum mail_error error;
1280+ enum mailbox_open_flags open_flags = MAILBOX_OPEN_FAST |
1281+ MAILBOX_OPEN_KEEP_RECENT | MAILBOX_OPEN_SAVEONLY |
1282+ MAILBOX_OPEN_POST_SESSION;
1283+
1284+ if (strcasecmp(name, "INBOX") == 0) {
1285+ /* deliveries to INBOX must always succeed,
1286+ regardless of ACLs */
1287+ open_flags |= MAILBOX_OPEN_IGNORE_ACLS;
1288+ }
1289+
1290+ ns = mail_namespace_find(namespaces, &name);
1291+ if (ns == NULL) {
1292+ *storage_r = NULL;
1293+ return NULL;
1294+ }
1295+ *storage_r = ns->storage;
1296+
1297+ if (*name == '\0') {
1298+ /* delivering to a namespace prefix means we actually want to
1299+ deliver to the INBOX instead */
1300+ return NULL;
1301+ }
1302+
1303+ box = mailbox_open(storage_r, name, NULL, open_flags);
1304+ if (box != NULL || !deliver_set->mailbox_autocreate)
1305+ return box;
1306+
1307+ (void)mail_storage_get_last_error(*storage_r, &error);
1308+ if (error != MAIL_ERROR_NOTFOUND)
1309+ return NULL;
1310+
1311+ /* try creating it. */
1312+ if (mail_storage_mailbox_create(*storage_r, name, FALSE) < 0)
1313+ return NULL;
1314+ if (deliver_set->mailbox_autosubscribe) {
1315+ /* (try to) subscribe to it */
1316+ (void)mailbox_list_set_subscribed(ns->list, name, TRUE);
1317+ }
1318+
1319+ /* and try opening again */
1320+ box = mailbox_open(storage_r, name, NULL, open_flags);
1321+ if (box == NULL)
1322+ return NULL;
1323+
1324+ if (mailbox_sync(box, 0, 0, NULL) < 0) {
1325+ mailbox_close(&box);
1326+ return NULL;
1327+ }
1328+ return box;
1329+}
1330+
1331+static const char *mailbox_name_get_printable(const char *mailbox_mutf7)
1332+{
1333+ string_t *str = t_str_new(128);
1334+
1335+ if (imap_utf7_to_utf8(mailbox_mutf7, str) < 0) {
1336+ str_truncate(str, 0);
1337+ str_append(str, mailbox_mutf7);
1338+ }
1339+ return str_sanitize(str_c(str), 80);
1340+}
1341+
1342+int deliver_save(struct mail_namespace *namespaces,
1343+ struct mail_storage **storage_r, const char *mailbox,
1344+ struct mail *mail, enum mail_flags flags,
1345+ const char *const *keywords)
1346+{
1347+ struct mailbox *box;
1348+ struct mailbox_transaction_context *t;
1349+ struct mail_save_context *save_ctx;
1350+ struct mail_keywords *kw;
1351+ enum mail_error error;
1352+ const char *mailbox_name;
1353+ bool default_save;
1354+ int ret = 0;
1355+
1356+ default_save = strcmp(mailbox, default_mailbox_name) == 0;
1357+ if (default_save)
1358+ tried_default_save = TRUE;
1359+
1360+ mailbox_name = mailbox_name_get_printable(mailbox);
1361+ box = mailbox_open_or_create_synced(namespaces, storage_r, mailbox);
1362+ if (box == NULL) {
1363+ if (*storage_r == NULL) {
1364+ deliver_log(mail,
1365+ "save failed to %s: Unknown namespace",
1366+ mailbox_name);
1367+ return -1;
1368+ }
1369+ if (default_save &&
1370+ strcmp((*storage_r)->ns->prefix, mailbox) == 0) {
1371+ /* silently store to the INBOX instead */
1372+ return -1;
1373+ }
1374+ deliver_log(mail, "save failed to %s: %s", mailbox_name,
1375+ mail_storage_get_last_error(*storage_r, &error));
1376+ return -1;
1377+ }
1378+
1379+ t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_EXTERNAL);
1380+
1381+ kw = str_array_length(keywords) == 0 ? NULL :
1382+ mailbox_keywords_create_valid(box, keywords);
1383+ save_ctx = mailbox_save_alloc(t);
1384+ mailbox_save_set_flags(save_ctx, flags, kw);
1385+ if (mailbox_copy(&save_ctx, mail) < 0)
1386+ ret = -1;
1387+ mailbox_keywords_free(box, &kw);
1388+
1389+ if (ret < 0)
1390+ mailbox_transaction_rollback(&t);
1391+ else
1392+ ret = mailbox_transaction_commit(&t);
1393+
1394+ if (ret == 0) {
1395+ saved_mail = TRUE;
1396+ deliver_log(mail, "saved mail to %s", mailbox_name);
1397+ } else {
1398+ deliver_log(mail, "save failed to %s: %s", mailbox_name,
1399+ mail_storage_get_last_error(*storage_r, &error));
1400+ }
1401+
1402+ mailbox_close(&box);
1403+ return ret;
1404+}
1405+
1406+const char *deliver_get_return_address(struct mail *mail)
1407+{
1408+ if (explicit_envelope_sender != NULL)
1409+ return explicit_envelope_sender;
1410+
1411+ return deliver_get_address(mail, "Return-Path");
1412+}
1413+
1414+const char *deliver_get_new_message_id(void)
1415+{
1416+ static int count = 0;
1417+
1418+ return t_strdup_printf("<dovecot-%s-%s-%d@%s>",
1419+ dec2str(ioloop_timeval.tv_sec),
1420+ dec2str(ioloop_timeval.tv_usec),
1421+ count++, deliver_set->hostname);
1422+}
1423+
1424+#include "settings.h"
1425+#include "../master/master-settings.h"
1426+#include "../master/master-settings-defs.c"
1427+
1428+#define IS_WHITE(c) ((c) == ' ' || (c) == '\t')
1429+
1430+static bool setting_is_bool(const char *name)
1431+{
1432+ const struct setting_def *def;
1433+
1434+ for (def = setting_defs; def->name != NULL; def++) {
1435+ if (strcmp(def->name, name) == 0)
1436+ return def->type == SET_BOOL;
1437+ }
1438+ if (strncmp(name, "NAMESPACE_", 10) == 0) {
1439+ return strstr(name, "_list") != NULL ||
1440+ strstr(name, "_inbox") != NULL ||
1441+ strstr(name, "_hidden") != NULL ||
1442+ strstr(name, "_subscriptions") != NULL;
1443+ }
1444+ if (strcmp(name, "quota_full_tempfail") == 0)
1445+ return TRUE;
1446+ return FALSE;
1447+}
1448+
1449+/* more ugly kludging because we have our own config parsing code.
1450+ hopefully this goes away in v1.2. */
1451+static struct {
1452+ const char *name;
1453+ bool set;
1454+} default_yes_settings[] = {
1455+ { "dotlock_use_excl", TRUE },
1456+ { "maildir_copy_with_hardlinks", TRUE },
1457+ { "mbox_dirty_syncs", TRUE },
1458+ { "mbox_lazy_writes", TRUE }
1459+};
1460+
1461+static void config_file_init(const char *path)
1462+{
1463+ struct istream *input;
1464+ const char *key, *value, *str, *ukey;
1465+ char *line, *p, quote;
1466+ int fd, sections = 0;
1467+ bool lda_section = FALSE, pop3_section = FALSE, plugin_section = FALSE;
1468+ bool ns_section = FALSE, ns_location = FALSE, ns_list = FALSE;
1469+ bool ns_subscriptions = FALSE;
1470+ unsigned int i, ns_idx = 0;
1471+ size_t len;
1472+
1473+ plugin_pool = pool_alloconly_create("Plugin strings", 512);
1474+ i_array_init(&lda_envs, 16);
1475+ i_array_init(&plugin_envs, 16);
1476+
1477+ fd = open(path, O_RDONLY);
1478+ if (fd < 0)
1479+ i_fatal_status(EX_TEMPFAIL, "open(%s) failed: %m", path);
1480+
1481+ input = i_stream_create_fd(fd, (size_t)-1, TRUE);
1482+ i_stream_set_return_partial_line(input, TRUE);
1483+ while ((line = i_stream_read_next_line(input)) != NULL) {
1484+ /* @UNSAFE: line is modified */
1485+
1486+ /* skip whitespace */
1487+ while (IS_WHITE(*line))
1488+ line++;
1489+
1490+ /* ignore comments or empty lines */
1491+ if (*line == '#' || *line == '\0')
1492+ continue;
1493+
1494+ /* strip away comments. pretty kludgy way really.. */
1495+ for (p = line; *p != '\0'; p++) {
1496+ if (*p == '\'' || *p == '"') {
1497+ quote = *p;
1498+ for (p++; *p != quote && *p != '\0'; p++) {
1499+ if (*p == '\\' && p[1] != '\0')
1500+ p++;
1501+ }
1502+ if (*p == '\0')
1503+ break;
1504+ } else if (*p == '#') {
1505+ *p = '\0';
1506+ break;
1507+ }
1508+ }
1509+
1510+ /* remove whitespace from end of line */
1511+ len = strlen(line);
1512+ while (IS_WHITE(line[len-1]))
1513+ len--;
1514+ line[len] = '\0';
1515+
1516+ if (strncmp(line, "!include_try ", 13) == 0)
1517+ continue;
1518+ if (strncmp(line, "!include ", 9) == 0) {
1519+ i_fatal_status(EX_TEMPFAIL, "Error in config file %s: "
1520+ "deliver doesn't support !include directive", path);
1521+ }
1522+
1523+ value = p = strchr(line, '=');
1524+ if (value == NULL) {
1525+ if (strchr(line, '{') != NULL) {
1526+ if (strcmp(line, "protocol lda {") == 0)
1527+ lda_section = TRUE;
1528+ else if (strcmp(line, "plugin {") == 0)
1529+ plugin_section = TRUE;
1530+ else if (strcmp(line, "protocol pop3 {") == 0)
1531+ pop3_section = TRUE;
1532+ else if (strncmp(line, "namespace ", 10) == 0) {
1533+ ns_section = TRUE;
1534+ ns_idx++;
1535+ line += 10;
1536+ env_put(t_strdup_printf(
1537+ "NAMESPACE_%u_TYPE=%s", ns_idx,
1538+ t_strcut(line, ' ')));
1539+ }
1540+ sections++;
1541+ }
1542+ if (*line == '}') {
1543+ sections--;
1544+ lda_section = FALSE;
1545+ plugin_section = FALSE;
1546+ pop3_section = FALSE;
1547+ if (ns_section) {
1548+ ns_section = FALSE;
1549+ if (ns_location)
1550+ ns_location = FALSE;
1551+ else {
1552+ env_put(t_strdup_printf(
1553+ "NAMESPACE_%u=", ns_idx));
1554+ }
1555+ if (ns_list)
1556+ ns_list = FALSE;
1557+ else {
1558+ env_put(t_strdup_printf(
1559+ "NAMESPACE_%u_LIST=1", ns_idx));
1560+ }
1561+ if (ns_subscriptions)
1562+ ns_subscriptions = FALSE;
1563+ else {
1564+ env_put(t_strdup_printf(
1565+ "NAMESPACE_%u_SUBSCRIPTIONS=1",
1566+ ns_idx));
1567+ }
1568+ }
1569+ }
1570+ continue;
1571+ }
1572+
1573+ while (p > line && IS_WHITE(p[-1])) p--;
1574+ key = t_strdup_until(line, p);
1575+
1576+ if (sections > 0 && !lda_section && !plugin_section) {
1577+ if (pop3_section) {
1578+ if (strcmp(key, "pop3_uidl_format") != 0)
1579+ continue;
1580+ } else if (ns_section) {
1581+ if (strcmp(key, "separator") == 0) {
1582+ key = t_strdup_printf(
1583+ "NAMESPACE_%u_SEP", ns_idx);
1584+ } else if (strcmp(key, "location") == 0) {
1585+ ns_location = TRUE;
1586+ key = t_strdup_printf("NAMESPACE_%u",
1587+ ns_idx);
1588+ } else {
1589+ if (strcmp(key, "list") == 0)
1590+ ns_list = TRUE;
1591+ if (strcmp(key, "subscriptions") == 0)
1592+ ns_subscriptions = TRUE;
1593+ key = t_strdup_printf("NAMESPACE_%u_%s",
1594+ ns_idx, key);
1595+ }
1596+ } else {
1597+ /* unwanted section */
1598+ continue;
1599+ }
1600+ }
1601+
1602+ do {
1603+ value++;
1604+ } while (IS_WHITE(*value));
1605+
1606+ len = strlen(value);
1607+ if (len > 0 &&
1608+ ((*value == '"' && value[len-1] == '"') ||
1609+ (*value == '\'' && value[len-1] == '\''))) {
1610+ value = str_unescape(p_strndup(unsafe_data_stack_pool,
1611+ value+1, len - 2));
1612+ }
1613+ ukey = t_str_ucase(key);
1614+ if (setting_is_bool(key) && strcasecmp(value, "yes") != 0) {
1615+ for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
1616+ if (strcmp(default_yes_settings[i].name,
1617+ key) == 0)
1618+ default_yes_settings[i].set = FALSE;
1619+ }
1620+ env_remove(ukey);
1621+ continue;
1622+ }
1623+
1624+ if (lda_section) {
1625+ str = p_strconcat(plugin_pool, ukey, "=", value, NULL);
1626+ array_append(&lda_envs, &str, 1);
1627+ }
1628+ if (!plugin_section) {
1629+ env_put(t_strconcat(ukey, "=", value, NULL));
1630+ } else {
1631+ /* %variables need to be expanded.
1632+ store these for later. */
1633+ value = p_strconcat(plugin_pool,
1634+ ukey, "=", value, NULL);
1635+ array_append(&plugin_envs, &value, 1);
1636+ }
1637+ }
1638+ i_stream_unref(&input);
1639+
1640+ for (i = 0; i < N_ELEMENTS(default_yes_settings); i++) {
1641+ if (default_yes_settings[i].set) {
1642+ key = default_yes_settings[i].name;
1643+ env_put(t_strconcat(t_str_ucase(key), "=1", NULL));
1644+ }
1645+ }
1646+}
1647+
1648+static const struct var_expand_table *
1649+get_var_expand_table(const char *user, const char *home)
1650+{
1651+ static struct var_expand_table static_tab[] = {
1652+ { 'u', NULL, "user" },
1653+ { 'n', NULL, "username" },
1654+ { 'd', NULL, "domain" },
1655+ { 's', NULL, "service" },
1656+ { 'h', NULL, "home" },
1657+ { 'l', NULL, "lip" },
1658+ { 'r', NULL, "rip" },
1659+ { 'p', NULL, "pid" },
1660+ { 'i', NULL, "uid" },
1661+ { '\0', NULL, NULL }
1662+ };
1663+ struct var_expand_table *tab;
1664+
1665+ tab = t_malloc(sizeof(static_tab));
1666+ memcpy(tab, static_tab, sizeof(static_tab));
1667+
1668+ tab[0].value = user;
1669+ tab[1].value = t_strcut(user, '@');
1670+ tab[2].value = strchr(user, '@');
1671+ if (tab[2].value != NULL) tab[2].value++;
1672+ tab[3].value = "DELIVER";
1673+ tab[4].value = home != NULL ? home :
1674+ "/HOME_DIRECTORY_USED_BUT_NOT_GIVEN_BY_USERDB";
1675+ tab[5].value = NULL;
1676+ tab[6].value = NULL;
1677+ tab[7].value = my_pid;
1678+ tab[8].value = dec2str(geteuid());
1679+
1680+ return tab;
1681+}
1682+
1683+static const char *
1684+expand_mail_env(const char *env, const struct var_expand_table *table)
1685+{
1686+ string_t *str;
1687+ const char *p;
1688+
1689+ str = t_str_new(256);
1690+
1691+ /* it's either type:data or just data */
1692+ p = strchr(env, ':');
1693+ if (p != NULL) {
1694+ while (env != p) {
1695+ str_append_c(str, *env);
1696+ env++;
1697+ }
1698+
1699+ str_append_c(str, *env++);
1700+ }
1701+
1702+ if (env[0] == '~' && env[1] == '/') {
1703+ /* expand home */
1704+ env = t_strconcat("%h", env+1, NULL);
1705+ }
1706+
1707+ /* expand %vars */
1708+ var_expand(str, env, table);
1709+ return str_c(str);
1710+}
1711+
1712+static const char *escape_local_part(const char *local_part)
1713+{
1714+ const char *p;
1715+
1716+ /* if local_part isn't dot-atom-text, we need to return quoted-string
1717+ dot-atom-text = 1*atext *("." 1*atext) */
1718+ for (p = local_part; *p != '\0'; p++) {
1719+ if (!IS_ATEXT(*p) && *p != '.')
1720+ break;
1721+ }
1722+ if (*p != '\0' || *local_part == '.' ||
1723+ (p != local_part && p[-1] == '.'))
1724+ local_part = t_strdup_printf("\"%s\"", str_escape(local_part));
1725+ return local_part;
1726+}
1727+
1728+static const char *address_sanitize(const char *address)
1729+{
1730+ struct message_address *addr;
1731+ const char *ret, *mailbox;
1732+ pool_t pool;
1733+
1734+ pool = pool_alloconly_create("address sanitizer", 256);
1735+ addr = message_address_parse(pool, (const unsigned char *)address,
1736+ strlen(address), 1, FALSE);
1737+
1738+ if (addr == NULL || addr->mailbox == NULL || addr->domain == NULL ||
1739+ *addr->mailbox == '\0')
1740+ ret = DEFAULT_ENVELOPE_SENDER;
1741+ else {
1742+ mailbox = escape_local_part(addr->mailbox);
1743+ if (*addr->domain == '\0')
1744+ ret = t_strdup(mailbox);
1745+ else
1746+ ret = t_strdup_printf("%s@%s", mailbox, addr->domain);
1747+ }
1748+ pool_unref(&pool);
1749+ return ret;
1750+}
1751+
1752+static int deliver_create_dir(struct mail_user *user, const char *dir)
1753+{
1754+ struct mail_namespace *ns;
1755+ const char *origin;
1756+ mode_t mode;
1757+ gid_t gid;
1758+
1759+ ns = mail_namespace_find_inbox(user->namespaces);
1760+ if (ns == NULL)
1761+ ns = user->namespaces;
1762+
1763+ mailbox_list_get_dir_permissions(ns->list, NULL, &mode, &gid, &origin);
1764+ if (mkdir_parents_chgrp(dir, mode, gid, origin) == 0) {
1765+ return 0;
1766+ } else if (errno == EACCES) {
1767+ i_error("%s", eacces_error_get_creating("mkdir_parents_chown",
1768+ dir));
1769+ return -1;
1770+ } else {
1771+ i_error("mkdir_parents_chown(%s, gid=%s) failed: %m",
1772+ dir, dec2str(gid));
1773+ return -1;
1774+ }
1775+}
1776+
1777+static int seekable_fd_callback(const char **path_r, void *context)
1778+{
1779+ struct mail_user *user = context;
1780+ const char *dir, *p;
1781+ string_t *path;
1782+ int fd;
1783+
1784+ path = t_str_new(128);
1785+ str_append(path, mail_user_get_temp_prefix(user));
1786+ fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
1787+ if (fd == -1 && errno == ENOENT) {
1788+ dir = str_c(path);
1789+ p = strrchr(dir, '/');
1790+ if (p != NULL) {
1791+ dir = t_strdup_until(dir, p);
1792+ if (deliver_create_dir(user, dir) < 0)
1793+ return -1;
1794+ fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
1795+ }
1796+ }
1797+ if (fd == -1) {
1798+ i_error("safe_mkstemp(%s) failed: %m", str_c(path));
1799+ return -1;
1800+ }
1801+
1802+ /* we just want the fd, unlink it */
1803+ if (unlink(str_c(path)) < 0) {
1804+ /* shouldn't happen.. */
1805+ i_error("unlink(%s) failed: %m", str_c(path));
1806+ close_keep_errno(fd);
1807+ return -1;
1808+ }
1809+
1810+ *path_r = str_c(path);
1811+ return fd;
1812+}
1813+
1814+static struct istream *
1815+create_raw_stream(struct mail_user *user, int fd, time_t *mtime_r)
1816+{
1817+ struct istream *input, *input2, *input_list[2];
1818+ const unsigned char *data;
1819+ char *sender = NULL;
1820+ size_t i, size;
1821+ int ret, tz;
1822+
1823+ *mtime_r = (time_t)-1;
1824+ fd_set_nonblock(fd, FALSE);
1825+
1826+ input = i_stream_create_fd(fd, 4096, FALSE);
1827+ input->blocking = TRUE;
1828+ /* If input begins with a From-line, drop it */
1829+ ret = i_stream_read_data(input, &data, &size, 5);
1830+ if (ret > 0 && size >= 5 && memcmp(data, "From ", 5) == 0) {
1831+ /* skip until the first LF */
1832+ i_stream_skip(input, 5);
1833+ while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
1834+ for (i = 0; i < size; i++) {
1835+ if (data[i] == '\n')
1836+ break;
1837+ }
1838+ if (i != size) {
1839+ (void)mbox_from_parse(data, i, mtime_r, &tz,
1840+ &sender);
1841+ i_stream_skip(input, i + 1);
1842+ break;
1843+ }
1844+ i_stream_skip(input, size);
1845+ }
1846+ }
1847+
1848+ if (sender != NULL && explicit_envelope_sender == NULL) {
1849+ /* use the envelope sender from From_-line, but only if it
1850+ hasn't been specified with -f already. */
1851+ explicit_envelope_sender = i_strdup(sender);
1852+ }
1853+ i_free(sender);
1854+
1855+ if (input->v_offset == 0) {
1856+ input2 = input;
1857+ i_stream_ref(input2);
1858+ } else {
1859+ input2 = i_stream_create_limit(input, (uoff_t)-1);
1860+ }
1861+ i_stream_unref(&input);
1862+
1863+ input_list[0] = input2; input_list[1] = NULL;
1864+ input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER,
1865+ seekable_fd_callback, user);
1866+ i_stream_unref(&input2);
1867+ return input;
1868+}
1869+
1870+static void failure_exit_callback(int *status)
1871+{
1872+ /* we want all our exit codes to be sysexits.h compatible.
1873+ if we failed because of a logging related error, we most likely
1874+ aren't writing to stderr, so try writing there to give some kind of
1875+ a clue what's wrong. FATAL_LOGOPEN failure already wrote to
1876+ stderr, so don't duplicate it. */
1877+ switch (*status) {
1878+ case FATAL_LOGWRITE:
1879+ fputs("Failed to write to log file", stderr);
1880+ break;
1881+ case FATAL_LOGERROR:
1882+ fputs("Internal logging error", stderr);
1883+ break;
1884+ case FATAL_LOGOPEN:
1885+ case FATAL_OUTOFMEM:
1886+ case FATAL_EXEC:
1887+ case FATAL_DEFAULT:
1888+ break;
1889+ default:
1890+ return;
1891+ }
1892+ *status = EX_TEMPFAIL;
1893+}
1894+
1895+static void open_logfile(const char *username)
1896+{
1897+ const char *prefix, *log_path, *stamp;
1898+
1899+ prefix = t_strdup_printf("deliver(%s): ", username);
1900+ log_path = home_expand(getenv("LOG_PATH"));
1901+ if (log_path == NULL || *log_path == '\0') {
1902+ const char *env = getenv("SYSLOG_FACILITY");
1903+ int facility;
1904+
1905+ if (env == NULL || !syslog_facility_find(env, &facility))
1906+ facility = LOG_MAIL;
1907+ i_set_failure_prefix(prefix);
1908+ i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
1909+ } else {
1910+ /* log to file or stderr */
1911+ i_set_failure_file(log_path, prefix);
1912+ }
1913+
1914+ log_path = home_expand(getenv("INFO_LOG_PATH"));
1915+ if (log_path != NULL && *log_path != '\0')
1916+ i_set_info_file(log_path);
1917+
1918+ stamp = getenv("LOG_TIMESTAMP");
1919+ if (stamp == NULL)
1920+ stamp = DEFAULT_FAILURE_STAMP_FORMAT;
1921+ i_set_failure_timestamp_format(stamp);
1922+}
1923+
1924+static void print_help(void)
1925+{
1926+ printf(
1927+"Usage: deliver [-c <config file>] [-a <address>] [-d <username>] [-p <path>]\n"
1928+" [-f <envelope sender>] [-m <mailbox>] [-n] [-s] [-e] [-k]\n");
1929+}
1930+
1931+void deliver_env_clean(bool preserve_home)
1932+{
1933+ const char *tz, *home;
1934+
1935+ tz = getenv("TZ");
1936+ if (tz != NULL)
1937+ tz = t_strconcat("TZ=", tz, NULL);
1938+ home = preserve_home ? getenv("HOME") : NULL;
1939+ if (home != NULL)
1940+ home = t_strconcat("HOME=", home, NULL);
1941+
1942+ /* Note that if the original environment was set with env_put(), the
1943+ environment strings will be invalid after env_clean(). That's why
1944+ we t_strconcat() them above. */
1945+ env_clean();
1946+
1947+ if (tz != NULL) env_put(tz);
1948+ if (home != NULL) env_put(home);
1949+}
1950+
1951+static void expand_envs(const char *user)
1952+{
1953+ const struct var_expand_table *table;
1954+ const char *value, *const *envs, *home, *env_name;
1955+ unsigned int i, count;
1956+ string_t *str;
1957+
1958+ home = getenv("HOME");
1959+
1960+ str = t_str_new(256);
1961+ table = get_var_expand_table(user, home);
1962+ envs = array_get(&plugin_envs, &count);
1963+ for (i = 0; i < count; i++) {
1964+ str_truncate(str, 0);
1965+ var_expand(str, envs[i], table);
1966+ env_put(str_c(str));
1967+ }
1968+ /* add LDA envs again to make sure they override plugin settings */
1969+ envs = array_get(&lda_envs, &count);
1970+ for (i = 0; i < count; i++)
1971+ env_put(envs[i]);
1972+
1973+ /* get the table again in case plugin envs provided the home
1974+ directory (yea, kludgy) */
1975+ if (home == NULL)
1976+ home = getenv("HOME");
1977+ table = get_var_expand_table(user, home);
1978+
1979+ value = getenv("MAIL_LOCATION");
1980+ if (value != NULL)
1981+ value = expand_mail_env(value, table);
1982+ env_put(t_strconcat("MAIL=", value, NULL));
1983+
1984+ for (i = 1;; i++) {
1985+ env_name = t_strdup_printf("NAMESPACE_%u", i);
1986+ value = getenv(env_name);
1987+ if (value == NULL)
1988+ break;
1989+
1990+ value = expand_mail_env(value, table);
1991+ env_put(t_strconcat(env_name, "=", value, NULL));
1992+
1993+ env_name = t_strdup_printf("NAMESPACE_%u_PREFIX", i);
1994+ value = getenv(env_name);
1995+ if (value != NULL) {
1996+ str_truncate(str, 0);
1997+ var_expand(str, value, table);
1998+ env_put(t_strconcat(env_name, "=", str_c(str), NULL));
1999+ }
2000+ }
2001+}
2002+
2003+static void putenv_extra_fields(const ARRAY_TYPE(const_string) *extra_fields)
2004+{
2005+ const char *const *fields;
2006+ const char *key, *p;
2007+ unsigned int i, count;
2008+
2009+ fields = array_get(extra_fields, &count);
2010+ for (i = 0; i < count; i++) {
2011+ p = strchr(fields[i], '=');
2012+ if (p == NULL)
2013+ env_put(t_strconcat(fields[i], "=1", NULL));
2014+ else {
2015+ key = t_str_ucase(t_strdup_until(fields[i], p));
2016+ env_put(t_strconcat(key, p, NULL));
2017+ }
2018+ }
2019+}
2020+
2021+int main(int argc, char *argv[])
2022+{
2023+ const char *config_path = DEFAULT_CONFIG_FILE;
2024+ const char *mailbox = "INBOX";
2025+ const char *auth_socket;
2026+ const char *home, *destaddr, *user, *value, *errstr, *path, *orig_user;
2027+ ARRAY_TYPE(const_string) extra_fields = ARRAY_INIT;
2028+ struct mail_user *mail_user, *raw_mail_user;
2029+ struct mail_namespace *raw_ns;
2030+ struct mail_storage *storage;
2031+ struct mailbox *box;
2032+ struct raw_mailbox *raw_box;
2033+ struct istream *input;
2034+ struct mailbox_transaction_context *t;
2035+ struct mailbox_header_lookup_ctx *headers_ctx;
2036+ struct mail *mail;
2037+ char cwd[PATH_MAX];
2038+ uid_t process_euid;
2039+ bool stderr_rejection = FALSE;
2040+ bool keep_environment = FALSE;
2041+ bool user_auth = FALSE;
2042+ time_t mtime;
2043+ int i, ret;
2044+ pool_t userdb_pool = NULL;
2045+ string_t *str;
2046+ enum mail_error error;
2047+
2048+ if (getuid() != geteuid() && geteuid() == 0) {
2049+ /* running setuid - don't allow this if deliver is
2050+ executable by anyone */
2051+ struct stat st;
2052+
2053+ if (stat(argv[0], &st) < 0) {
2054+ fprintf(stderr, "stat(%s) failed: %s\n",
2055+ argv[0], strerror(errno));
2056+ return EX_TEMPFAIL;
2057+ } else if ((st.st_mode & 1) != 0 && (st.st_mode & 04000) != 0) {
2058+ fprintf(stderr, "%s must not be both world-executable "
2059+ "and setuid-root. This allows root exploits. "
2060+ "See http://wiki.dovecot.org/LDA#multipleuids\n",
2061+ argv[0]);
2062+ return EX_TEMPFAIL;
2063+ }
2064+ }
2065+
2066+ i_set_failure_exit_callback(failure_exit_callback);
2067+
2068+ lib_init();
2069+ ioloop = io_loop_create();
2070+
2071+ lib_signals_init();
2072+ lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
2073+ lib_signals_set_handler(SIGTERM, TRUE, sig_die, NULL);
2074+ lib_signals_ignore(SIGPIPE, TRUE);
2075+ lib_signals_ignore(SIGALRM, FALSE);
2076+#ifdef SIGXFSZ
2077+ lib_signals_ignore(SIGXFSZ, TRUE);
2078+#endif
2079+
2080+ deliver_set = i_new(struct deliver_settings, 1);
2081+ deliver_set->mailbox_autocreate = TRUE;
2082+
2083+ destaddr = user = path = NULL;
2084+ for (i = 1; i < argc; i++) {
2085+ if (strcmp(argv[i], "-a") == 0) {
2086+ /* destination address */
2087+ i++;
2088+ if (i == argc)
2089+ i_fatal_status(EX_USAGE, "Missing -a argument");
2090+ destaddr = argv[i];
2091+ } else if (strcmp(argv[i], "-d") == 0) {
2092+ /* destination user */
2093+ i++;
2094+ if (i == argc)
2095+ i_fatal_status(EX_USAGE, "Missing -d argument");
2096+ user = argv[i];
2097+ user_auth = TRUE;
2098+ } else if (strcmp(argv[i], "-p") == 0) {
2099+ /* input path */
2100+ i++;
2101+ if (i == argc)
2102+ i_fatal_status(EX_USAGE, "Missing -p argument");
2103+ path = argv[i];
2104+ if (*path != '/') {
2105+ /* expand relative paths before we chdir */
2106+ if (getcwd(cwd, sizeof(cwd)) == NULL)
2107+ i_fatal("getcwd() failed: %m");
2108+ path = t_strconcat(cwd, "/", path, NULL);
2109+ }
2110+ } else if (strcmp(argv[i], "-e") == 0) {
2111+ stderr_rejection = TRUE;
2112+ } else if (strcmp(argv[i], "-c") == 0) {
2113+ /* config file path */
2114+ i++;
2115+ if (i == argc) {
2116+ i_fatal_status(EX_USAGE,
2117+ "Missing config file path argument");
2118+ }
2119+ config_path = argv[i];
2120+ } else if (strcmp(argv[i], "-k") == 0) {
2121+ keep_environment = TRUE;
2122+ } else if (strcmp(argv[i], "-m") == 0) {
2123+ /* destination mailbox */
2124+ i++;
2125+ if (i == argc)
2126+ i_fatal_status(EX_USAGE, "Missing -m argument");
2127+ /* Ignore -m "". This allows doing -m ${extension}
2128+ in Postfix to handle user+mailbox */
2129+ if (*argv[i] != '\0') {
2130+ str = t_str_new(256);
2131+ if (imap_utf8_to_utf7(argv[i], str) < 0) {
2132+ i_fatal("Mailbox name not UTF-8: %s",
2133+ mailbox);
2134+ }
2135+ mailbox = str_c(str);
2136+ }
2137+ } else if (strcmp(argv[i], "-n") == 0) {
2138+ deliver_set->mailbox_autocreate = FALSE;
2139+ } else if (strcmp(argv[i], "-s") == 0) {
2140+ deliver_set->mailbox_autosubscribe = TRUE;
2141+ } else if (strcmp(argv[i], "-f") == 0) {
2142+ /* envelope sender address */
2143+ i++;
2144+ if (i == argc)
2145+ i_fatal_status(EX_USAGE, "Missing -f argument");
2146+ explicit_envelope_sender =
2147+ i_strdup(address_sanitize(argv[i]));
2148+ } else if (argv[i][0] != '\0') {
2149+ print_help();
2150+ i_fatal_status(EX_USAGE,
2151+ "Unknown argument: %s", argv[i]);
2152+ }
2153+ }
2154+
2155+ if (user == NULL)
2156+ user = getenv("USER");
2157+ if (!keep_environment)
2158+ deliver_env_clean(!user_auth);
2159+
2160+ process_euid = geteuid();
2161+ if (user_auth)
2162+ ;
2163+ else if (process_euid != 0) {
2164+ /* we're non-root. get our username and possibly our home. */
2165+ struct passwd *pw;
2166+
2167+ home = getenv("HOME");
2168+ if (user != NULL && home != NULL) {
2169+ /* no need for a pw lookup */
2170+ } else if ((pw = getpwuid(process_euid)) != NULL) {
2171+ user = t_strdup(pw->pw_name);
2172+ if (home == NULL)
2173+ env_put(t_strconcat("HOME=", pw->pw_dir, NULL));
2174+ } else if (user == NULL) {
2175+ i_fatal_status(EX_USAGE,
2176+ "Couldn't lookup our username (uid=%s)",
2177+ dec2str(process_euid));
2178+ }
2179+ } else {
2180+ i_fatal_status(EX_USAGE,
2181+ "destination user parameter (-d user) not given");
2182+ }
2183+
2184+ T_BEGIN {
2185+ config_file_init(config_path);
2186+ } T_END;
2187+ open_logfile(user);
2188+
2189+ if (getenv("MAIL_DEBUG") != NULL)
2190+ env_put("DEBUG=1");
2191+
2192+ if (getenv("MAIL_PLUGINS") == NULL)
2193+ modules = NULL;
2194+ else {
2195+ const char *plugin_dir = getenv("MAIL_PLUGIN_DIR");
2196+ const char *version;
2197+
2198+ if (plugin_dir == NULL)
2199+ plugin_dir = MODULEDIR"/lda";
2200+
2201+ version = getenv("VERSION_IGNORE") != NULL ?
2202+ NULL : PACKAGE_VERSION;
2203+ modules = module_dir_load(plugin_dir, getenv("MAIL_PLUGINS"),
2204+ TRUE, version);
2205+ }
2206+
2207+ if (user_auth) {
2208+ auth_socket = getenv("AUTH_SOCKET_PATH");
2209+ if (auth_socket == NULL) {
2210+ const char *base_dir = getenv("BASE_DIR");
2211+ if (base_dir == NULL)
2212+ base_dir = PKG_RUNDIR;
2213+ auth_socket = t_strconcat(base_dir, "/auth-master",
2214+ NULL);
2215+ }
2216+
2217+ userdb_pool = pool_alloconly_create("userdb lookup replys", 512);
2218+ orig_user = user;
2219+ ret = auth_client_lookup_and_restrict(auth_socket,
2220+ &user, process_euid,
2221+ userdb_pool,
2222+ &extra_fields);
2223+ if (ret != 0)
2224+ return ret;
2225+
2226+ if (strcmp(user, orig_user) != 0) {
2227+ /* auth lookup changed the user. */
2228+ if (getenv("DEBUG") != NULL)
2229+ i_info("userdb changed username to %s", user);
2230+ i_set_failure_prefix(t_strdup_printf("deliver(%s): ",
2231+ user));
2232+ }
2233+ /* if user was changed, it was allocated from userdb_pool
2234+ which we'll free soon. */
2235+ user = t_strdup(user);
2236+ }
2237+
2238+ expand_envs(user);
2239+ if (userdb_pool != NULL) {
2240+ putenv_extra_fields(&extra_fields);
2241+ pool_unref(&userdb_pool);
2242+ }
2243+
2244+ /* Fix namespaces with empty locations */
2245+ for (i = 1;; i++) {
2246+ value = getenv(t_strdup_printf("NAMESPACE_%u", i));
2247+ if (value == NULL)
2248+ break;
2249+
2250+ if (*value == '\0') {
2251+ env_put(t_strdup_printf("NAMESPACE_%u=%s", i,
2252+ getenv("MAIL")));
2253+ }
2254+ }
2255+
2256+ /* If possible chdir to home directory, so that core file
2257+ could be written in case we crash. */
2258+ home = getenv("HOME");
2259+ if (home != NULL) {
2260+ if (chdir(home) < 0) {
2261+ if (errno != ENOENT)
2262+ i_error("chdir(%s) failed: %m", home);
2263+ else if (getenv("DEBUG") != NULL)
2264+ i_info("Home dir not found: %s", home);
2265+ }
2266+ }
2267+
2268+ env_put(t_strconcat("USER=", user, NULL));
2269+ (void)umask(0077);
2270+
2271+ deliver_set->hostname = getenv("HOSTNAME");
2272+ if (deliver_set->hostname == NULL)
2273+ deliver_set->hostname = my_hostname;
2274+ deliver_set->postmaster_address = getenv("POSTMASTER_ADDRESS");
2275+ if (deliver_set->postmaster_address == NULL) {
2276+ i_fatal_status(EX_TEMPFAIL,
2277+ "postmaster_address setting not given");
2278+ }
2279+ deliver_set->sendmail_path = getenv("SENDMAIL_PATH");
2280+ if (deliver_set->sendmail_path == NULL)
2281+ deliver_set->sendmail_path = DEFAULT_SENDMAIL_PATH;
2282+ deliver_set->rejection_subject = getenv("REJECTION_SUBJECT");
2283+ if (deliver_set->rejection_subject == NULL)
2284+ deliver_set->rejection_subject = DEFAULT_MAIL_REJECTION_SUBJECT;
2285+ deliver_set->rejection_reason = getenv("REJECTION_REASON");
2286+ if (deliver_set->rejection_reason == NULL) {
2287+ deliver_set->rejection_reason =
2288+ DEFAULT_MAIL_REJECTION_HUMAN_REASON;
2289+ }
2290+ deliver_set->log_format = getenv("DELIVER_LOG_FORMAT");
2291+ if (deliver_set->log_format == NULL)
2292+ deliver_set->log_format = DEFAULT_LOG_FORMAT;
2293+
2294+ dict_drivers_register_builtin();
2295+ duplicate_init();
2296+ mail_users_init(getenv("AUTH_SOCKET_PATH"), getenv("DEBUG") != NULL);
2297+ mail_storage_init();
2298+ mail_storage_register_all();
2299+ mailbox_list_register_all();
2300+
2301+ module_dir_init(modules);
2302+
2303+ mail_user = mail_user_init(user);
2304+ mail_user_set_home(mail_user, home);
2305+ if (mail_namespaces_init(mail_user) < 0)
2306+ i_fatal("Namespace initialization failed");
2307+
2308+ /* create a separate mail user for the internal namespace */
2309+ raw_mail_user = mail_user_init(user);
2310+ mail_user_set_home(raw_mail_user, NULL);
2311+ raw_ns = mail_namespaces_init_empty(raw_mail_user);
2312+ raw_ns->flags |= NAMESPACE_FLAG_NOQUOTA | NAMESPACE_FLAG_NOACL;
2313+
2314+ if (mail_storage_create(raw_ns, "raw", "/tmp",
2315+ MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
2316+ FILE_LOCK_METHOD_FCNTL, &errstr) < 0)
2317+ i_fatal("Couldn't create internal raw storage: %s", errstr);
2318+ if (path == NULL) {
2319+ input = create_raw_stream(mail_user, 0, &mtime);
2320+ box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail",
2321+ input, MAILBOX_OPEN_NO_INDEX_FILES);
2322+ i_stream_unref(&input);
2323+ } else {
2324+ mtime = (time_t)-1;
2325+ box = mailbox_open(&raw_ns->storage, path, NULL,
2326+ MAILBOX_OPEN_NO_INDEX_FILES);
2327+ }
2328+ if (box == NULL) {
2329+ i_fatal("Can't open delivery mail as raw: %s",
2330+ mail_storage_get_last_error(raw_ns->storage, &error));
2331+ }
2332+ if (mailbox_sync(box, 0, 0, NULL) < 0) {
2333+ i_fatal("Can't sync delivery mail: %s",
2334+ mail_storage_get_last_error(raw_ns->storage, &error));
2335+ }
2336+ raw_box = (struct raw_mailbox *)box;
2337+ raw_box->envelope_sender = explicit_envelope_sender != NULL ?
2338+ explicit_envelope_sender : DEFAULT_ENVELOPE_SENDER;
2339+ raw_box->mtime = mtime;
2340+
2341+ t = mailbox_transaction_begin(box, 0);
2342+ headers_ctx = mailbox_header_lookup_init(box, wanted_headers);
2343+ mail = mail_alloc(t, 0, headers_ctx);
2344+ mail_set_seq(mail, 1);
2345+
2346+ if (destaddr == NULL) {
2347+ destaddr = deliver_get_address(mail, "Envelope-To");
2348+ if (destaddr == NULL) {
2349+ destaddr = strchr(user, '@') != NULL ? user :
2350+ t_strconcat(user, "@",
2351+ deliver_set->hostname, NULL);
2352+ }
2353+ }
2354+
2355+ storage = NULL;
2356+ default_mailbox_name = mailbox;
2357+ if (deliver_mail == NULL)
2358+ ret = -1;
2359+ else {
2360+ if (deliver_mail(mail_user->namespaces, &storage, mail,
2361+ destaddr, mailbox) <= 0) {
2362+ /* if message was saved, don't bounce it even though
2363+ the script failed later. */
2364+ ret = saved_mail ? 0 : -1;
2365+ } else {
2366+ /* success. message may or may not have been saved. */
2367+ ret = 0;
2368+ }
2369+ }
2370+
2371+ if (ret < 0 && !tried_default_save) {
2372+ /* plugins didn't handle this. save into the default mailbox. */
2373+ ret = deliver_save(mail_user->namespaces,
2374+ &storage, mailbox, mail, 0, NULL);
2375+ }
2376+ if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) {
2377+ /* still didn't work. try once more to save it
2378+ to INBOX. */
2379+ ret = deliver_save(mail_user->namespaces,
2380+ &storage, "INBOX", mail, 0, NULL);
2381+ }
2382+
2383+ if (ret < 0 ) {
2384+ const char *error_string;
2385+ enum mail_error error;
2386+
2387+ if (storage == NULL) {
2388+ /* This shouldn't happen */
2389+ i_error("BUG: Saving failed for unknown storage");
2390+ return EX_TEMPFAIL;
2391+ }
2392+
2393+ error_string = mail_storage_get_last_error(storage, &error);
2394+
2395+ if (stderr_rejection) {
2396+ /* write to stderr also for tempfails so that MTA
2397+ can log the reason if it wants to. */
2398+ fprintf(stderr, "%s\n", error_string);
2399+ }
2400+
2401+ if (error != MAIL_ERROR_NOSPACE ||
2402+ getenv("QUOTA_FULL_TEMPFAIL") != NULL) {
2403+ /* Saving to INBOX should always work unless
2404+ we're over quota. If it didn't, it's probably a
2405+ configuration problem. */
2406+ return EX_TEMPFAIL;
2407+ }
2408+
2409+ /* we'll have to reply with permanent failure */
2410+ deliver_log(mail, "rejected: %s",
2411+ str_sanitize(error_string, 512));
2412+
2413+ if (stderr_rejection)
2414+ return EX_NOPERM;
2415+ ret = mail_send_rejection(mail, user, error_string);
2416+ if (ret != 0)
2417+ return ret < 0 ? EX_TEMPFAIL : ret;
2418+ /* ok, rejection sent */
2419+ }
2420+ i_free(explicit_envelope_sender);
2421+
2422+ mail_free(&mail);
2423+ mailbox_header_lookup_unref(&headers_ctx);
2424+ mailbox_transaction_rollback(&t);
2425+ mailbox_close(&box);
2426+
2427+ mail_user_unref(&mail_user);
2428+ mail_user_unref(&raw_mail_user);
2429+
2430+ module_dir_unload(&modules);
2431+ mail_storage_deinit();
2432+ mail_users_deinit();
2433+
2434+ duplicate_deinit();
2435+ dict_drivers_unregister_builtin();
2436+ lib_signals_deinit();
2437+
2438+ io_loop_destroy(&ioloop);
2439+ lib_deinit();
2440+
2441+ return EX_OK;
2442+}
2443
2444=== added file 'src/deliver/deliver.h'
2445--- src/deliver/deliver.h 1970-01-01 00:00:00 +0000
2446+++ src/deliver/deliver.h 2010-02-13 00:05:29 +0000
2447@@ -0,0 +1,50 @@
2448+#ifndef DELIVER_H
2449+#define DELIVER_H
2450+
2451+#include <sysexits.h>
2452+
2453+#include "lib.h"
2454+#include "mail-storage.h"
2455+
2456+#define DEFAULT_MAIL_REJECTION_SUBJECT \
2457+ "Rejected: %s"
2458+#define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
2459+ "Your message to <%t> was automatically rejected:%n%r"
2460+#define DEFAULT_LOG_FORMAT "msgid=%m: %$"
2461+
2462+struct deliver_settings {
2463+ const char *hostname;
2464+ const char *postmaster_address;
2465+ const char *sendmail_path;
2466+ const char *rejection_subject;
2467+ const char *rejection_reason;
2468+ const char *log_format;
2469+ bool mailbox_autosubscribe;
2470+ bool mailbox_autocreate;
2471+};
2472+
2473+extern struct deliver_settings *deliver_set;
2474+extern bool tried_default_save;
2475+
2476+typedef int deliver_mail_func_t(struct mail_namespace *namespaces,
2477+ struct mail_storage **storage_r,
2478+ struct mail *mail,
2479+ const char *destaddr, const char *mailbox);
2480+
2481+extern deliver_mail_func_t *deliver_mail;
2482+
2483+void deliver_env_clean(bool preserve_home);
2484+
2485+/* Save a mail into given mailbox with given flags and keywords. */
2486+int deliver_save(struct mail_namespace *namespaces,
2487+ struct mail_storage **storage_r, const char *mailbox,
2488+ struct mail *mail, enum mail_flags flags,
2489+ const char *const *keywords);
2490+
2491+/* Extracts user@domain from Return-Path header. Returns NULL if not found. */
2492+const char *deliver_get_return_address(struct mail *mail);
2493+
2494+/* Returns a new unique Message-ID */
2495+const char *deliver_get_new_message_id(void);
2496+
2497+#endif
2498
2499=== removed file 'src/deliver/deliver.h'
2500--- src/deliver/deliver.h 2009-11-06 00:47:29 +0000
2501+++ src/deliver/deliver.h 1970-01-01 00:00:00 +0000
2502@@ -1,50 +0,0 @@
2503-#ifndef DELIVER_H
2504-#define DELIVER_H
2505-
2506-#include <sysexits.h>
2507-
2508-#include "lib.h"
2509-#include "mail-storage.h"
2510-
2511-#define DEFAULT_MAIL_REJECTION_SUBJECT \
2512- "Rejected: %s"
2513-#define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
2514- "Your message to <%t> was automatically rejected:%n%r"
2515-#define DEFAULT_LOG_FORMAT "msgid=%m: %$"
2516-
2517-struct deliver_settings {
2518- const char *hostname;
2519- const char *postmaster_address;
2520- const char *sendmail_path;
2521- const char *rejection_subject;
2522- const char *rejection_reason;
2523- const char *log_format;
2524- bool mailbox_autosubscribe;
2525- bool mailbox_autocreate;
2526-};
2527-
2528-extern struct deliver_settings *deliver_set;
2529-extern bool tried_default_save;
2530-
2531-typedef int deliver_mail_func_t(struct mail_namespace *namespaces,
2532- struct mail_storage **storage_r,
2533- struct mail *mail,
2534- const char *destaddr, const char *mailbox);
2535-
2536-extern deliver_mail_func_t *deliver_mail;
2537-
2538-void deliver_env_clean(bool preserve_home);
2539-
2540-/* Save a mail into given mailbox with given flags and keywords. */
2541-int deliver_save(struct mail_namespace *namespaces,
2542- struct mail_storage **storage_r, const char *mailbox,
2543- struct mail *mail, enum mail_flags flags,
2544- const char *const *keywords);
2545-
2546-/* Extracts user@domain from Return-Path header. Returns NULL if not found. */
2547-const char *deliver_get_return_address(struct mail *mail);
2548-
2549-/* Returns a new unique Message-ID */
2550-const char *deliver_get_new_message_id(void);
2551-
2552-#endif
2553
2554=== added file 'src/deliver/duplicate.c'
2555--- src/deliver/duplicate.c 1970-01-01 00:00:00 +0000
2556+++ src/deliver/duplicate.c 2010-02-13 00:05:29 +0000
2557@@ -0,0 +1,324 @@
2558+/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
2559+
2560+#include "lib.h"
2561+#include "ioloop.h"
2562+#include "istream.h"
2563+#include "ostream.h"
2564+#include "home-expand.h"
2565+#include "file-dotlock.h"
2566+#include "hash.h"
2567+#include "duplicate.h"
2568+
2569+#include <stdlib.h>
2570+#include <fcntl.h>
2571+#include <unistd.h>
2572+
2573+#define DUPLICATE_PATH "~/.dovecot.lda-dupes"
2574+#define COMPRESS_PERCENTAGE 10
2575+#define DUPLICATE_BUFSIZE 4096
2576+#define DUPLICATE_VERSION 2
2577+
2578+struct duplicate {
2579+ const void *id;
2580+ unsigned int id_size;
2581+
2582+ const char *user;
2583+ time_t time;
2584+};
2585+
2586+struct duplicate_file_header {
2587+ uint32_t version;
2588+};
2589+
2590+struct duplicate_record_header {
2591+ uint32_t stamp;
2592+ uint32_t id_size;
2593+ uint32_t user_size;
2594+};
2595+
2596+struct duplicate_file {
2597+ pool_t pool;
2598+ struct hash_table *hash;
2599+ const char *path;
2600+
2601+ int new_fd;
2602+ struct dotlock *dotlock;
2603+ unsigned int changed:1;
2604+};
2605+
2606+static struct dotlock_settings duplicate_dotlock_set = {
2607+ MEMBER(temp_prefix) NULL,
2608+ MEMBER(lock_suffix) NULL,
2609+
2610+ MEMBER(timeout) 20,
2611+ MEMBER(stale_timeout) 10,
2612+
2613+ MEMBER(callback) NULL,
2614+ MEMBER(context) NULL,
2615+
2616+ MEMBER(use_excl_lock) FALSE
2617+};
2618+static struct duplicate_file *duplicate_file = NULL;
2619+
2620+static int duplicate_cmp(const void *p1, const void *p2)
2621+{
2622+ const struct duplicate *d1 = p1, *d2 = p2;
2623+
2624+ return (d1->id_size == d2->id_size &&
2625+ memcmp(d1->id, d2->id, d1->id_size) == 0 &&
2626+ strcasecmp(d1->user, d2->user) == 0) ? 0 : 1;
2627+}
2628+
2629+static unsigned int duplicate_hash(const void *p)
2630+{
2631+ /* a char* hash function from ASU -- from glib */
2632+ const struct duplicate *d = p;
2633+ const unsigned char *s = d->id, *end = s + d->id_size;
2634+ unsigned int g, h = 0;
2635+
2636+ while (s != end) {
2637+ h = (h << 4) + *s;
2638+ if ((g = h & 0xf0000000UL)) {
2639+ h = h ^ (g >> 24);
2640+ h = h ^ g;
2641+ }
2642+ s++;
2643+ }
2644+
2645+ return h ^ strcase_hash(d->user);
2646+}
2647+
2648+static int
2649+duplicate_read_records(struct duplicate_file *file, struct istream *input,
2650+ unsigned int record_size)
2651+{
2652+ const unsigned char *data;
2653+ struct duplicate_record_header hdr;
2654+ size_t size;
2655+ unsigned int change_count;
2656+
2657+ change_count = 0;
2658+ while (i_stream_read_data(input, &data, &size, record_size) > 0) {
2659+ if (record_size == sizeof(hdr))
2660+ memcpy(&hdr, data, sizeof(hdr));
2661+ else {
2662+ /* FIXME: backwards compatibility with v1.0 */
2663+ time_t stamp;
2664+
2665+ i_assert(record_size ==
2666+ sizeof(time_t) + sizeof(uint32_t)*2);
2667+ memcpy(&stamp, data, sizeof(stamp));
2668+ hdr.stamp = stamp;
2669+ memcpy(&hdr.id_size, data + sizeof(time_t),
2670+ sizeof(hdr.id_size));
2671+ memcpy(&hdr.user_size,
2672+ data + sizeof(time_t) + sizeof(uint32_t),
2673+ sizeof(hdr.user_size));
2674+ }
2675+ i_stream_skip(input, record_size);
2676+
2677+ if (hdr.id_size == 0 || hdr.user_size == 0 ||
2678+ hdr.id_size > DUPLICATE_BUFSIZE ||
2679+ hdr.user_size > DUPLICATE_BUFSIZE) {
2680+ i_error("broken duplicate file %s", file->path);
2681+ return -1;
2682+ }
2683+
2684+ if (i_stream_read_data(input, &data, &size,
2685+ hdr.id_size + hdr.user_size - 1) <= 0) {
2686+ i_error("unexpected end of file in %s", file->path);
2687+ return -1;
2688+ }
2689+
2690+ if ((time_t)hdr.stamp >= ioloop_time) {
2691+ /* still valid, save it */
2692+ struct duplicate *d;
2693+ void *new_id;
2694+
2695+ new_id = p_malloc(file->pool, hdr.id_size);
2696+ memcpy(new_id, data, hdr.id_size);
2697+
2698+ d = p_new(file->pool, struct duplicate, 1);
2699+ d->id = new_id;
2700+ d->id_size = hdr.id_size;
2701+ d->user = p_strndup(file->pool,
2702+ data + hdr.id_size, hdr.user_size);
2703+ d->time = hdr.stamp;
2704+ hash_table_insert(file->hash, d, d);
2705+ } else {
2706+ change_count++;
2707+ }
2708+ i_stream_skip(input, hdr.id_size + hdr.user_size);
2709+ }
2710+
2711+ if (hash_table_count(file->hash) *
2712+ COMPRESS_PERCENTAGE / 100 > change_count)
2713+ file->changed = TRUE;
2714+ return 0;
2715+}
2716+
2717+static int duplicate_read(struct duplicate_file *file)
2718+{
2719+ struct istream *input;
2720+ struct duplicate_file_header hdr;
2721+ const unsigned char *data;
2722+ size_t size;
2723+ int fd;
2724+ unsigned int record_size = 0;
2725+
2726+ fd = open(file->path, O_RDONLY);
2727+ if (fd == -1) {
2728+ if (errno == ENOENT)
2729+ return 0;
2730+ i_error("open(%s) failed: %m", file->path);
2731+ return -1;
2732+ }
2733+
2734+ /* <timestamp> <id_size> <user_size> <id> <user> */
2735+ input = i_stream_create_fd(fd, DUPLICATE_BUFSIZE, FALSE);
2736+ if (i_stream_read_data(input, &data, &size, sizeof(hdr)) > 0) {
2737+ memcpy(&hdr, data, sizeof(hdr));
2738+ if (hdr.version == 0 || hdr.version > DUPLICATE_VERSION + 10) {
2739+ /* FIXME: backwards compatibility with v1.0 */
2740+ record_size = sizeof(time_t) + sizeof(uint32_t)*2;
2741+ } else if (hdr.version == DUPLICATE_VERSION) {
2742+ record_size = sizeof(struct duplicate_record_header);
2743+ i_stream_skip(input, sizeof(hdr));
2744+ }
2745+ }
2746+
2747+ if (record_size == 0 ||
2748+ duplicate_read_records(file, input, record_size) < 0) {
2749+ if (unlink(file->path) < 0 && errno != ENOENT)
2750+ i_error("unlink(%s) failed: %m", file->path);
2751+ }
2752+
2753+ i_stream_unref(&input);
2754+ if (close(fd) < 0)
2755+ i_error("close(%s) failed: %m", file->path);
2756+ return 0;
2757+}
2758+
2759+static struct duplicate_file *duplicate_new(const char *path)
2760+{
2761+ struct duplicate_file *file;
2762+ pool_t pool;
2763+
2764+ pool = pool_alloconly_create("duplicates", 10240);
2765+
2766+ file = p_new(pool, struct duplicate_file, 1);
2767+ file->pool = pool;
2768+ file->path = p_strdup(pool, path);
2769+ file->new_fd = file_dotlock_open(&duplicate_dotlock_set, path, 0,
2770+ &file->dotlock);
2771+ if (file->new_fd == -1)
2772+ i_error("file_dotlock_create(%s) failed: %m", path);
2773+ file->hash = hash_table_create(default_pool, pool, 0,
2774+ duplicate_hash, duplicate_cmp);
2775+ (void)duplicate_read(file);
2776+ return file;
2777+}
2778+
2779+static void duplicate_free(struct duplicate_file **_file)
2780+{
2781+ struct duplicate_file *file = *_file;
2782+
2783+ *_file = NULL;
2784+ if (file->dotlock != NULL)
2785+ file_dotlock_delete(&file->dotlock);
2786+
2787+ hash_table_destroy(&file->hash);
2788+ pool_unref(&file->pool);
2789+}
2790+
2791+int duplicate_check(const void *id, size_t id_size, const char *user)
2792+{
2793+ struct duplicate d;
2794+
2795+ if (duplicate_file == NULL)
2796+ duplicate_file = duplicate_new(home_expand(DUPLICATE_PATH));
2797+
2798+ d.id = id;
2799+ d.id_size = id_size;
2800+ d.user = user;
2801+
2802+ return hash_table_lookup(duplicate_file->hash, &d) != NULL;
2803+}
2804+
2805+void duplicate_mark(const void *id, size_t id_size,
2806+ const char *user, time_t timestamp)
2807+{
2808+ struct duplicate *d;
2809+ void *new_id;
2810+
2811+ if (duplicate_file == NULL)
2812+ duplicate_file = duplicate_new(home_expand(DUPLICATE_PATH));
2813+
2814+ new_id = p_malloc(duplicate_file->pool, id_size);
2815+ memcpy(new_id, id, id_size);
2816+
2817+ d = p_new(duplicate_file->pool, struct duplicate, 1);
2818+ d->id = new_id;
2819+ d->id_size = id_size;
2820+ d->user = p_strdup(duplicate_file->pool, user);
2821+ d->time = timestamp;
2822+
2823+ duplicate_file->changed = TRUE;
2824+ hash_table_insert(duplicate_file->hash, d, d);
2825+}
2826+
2827+void duplicate_flush(void)
2828+{
2829+ struct duplicate_file *file = duplicate_file;
2830+ struct duplicate_file_header hdr;
2831+ struct duplicate_record_header rec;
2832+ struct ostream *output;
2833+ struct hash_iterate_context *iter;
2834+ void *key, *value;
2835+
2836+ if (duplicate_file == NULL || !file->changed || file->new_fd == -1)
2837+ return;
2838+
2839+ memset(&hdr, 0, sizeof(hdr));
2840+ hdr.version = DUPLICATE_VERSION;
2841+
2842+ output = o_stream_create_fd_file(file->new_fd, 0, FALSE);
2843+ o_stream_send(output, &hdr, sizeof(hdr));
2844+
2845+ memset(&rec, 0, sizeof(rec));
2846+ iter = hash_table_iterate_init(file->hash);
2847+ while (hash_table_iterate(iter, &key, &value)) {
2848+ struct duplicate *d = value;
2849+
2850+ rec.stamp = d->time;
2851+ rec.id_size = d->id_size;
2852+ rec.user_size = strlen(d->user);
2853+
2854+ o_stream_send(output, &rec, sizeof(rec));
2855+ o_stream_send(output, d->id, rec.id_size);
2856+ o_stream_send(output, d->user, rec.user_size);
2857+ }
2858+ hash_table_iterate_deinit(&iter);
2859+ o_stream_unref(&output);
2860+
2861+ file->changed = FALSE;
2862+ if (file_dotlock_replace(&file->dotlock, 0) < 0)
2863+ i_error("file_dotlock_replace(%s) failed: %m", file->path);
2864+ file->new_fd = -1;
2865+}
2866+
2867+void duplicate_init(void)
2868+{
2869+ duplicate_dotlock_set.use_excl_lock =
2870+ getenv("DOTLOCK_USE_EXCL") != NULL;
2871+ duplicate_dotlock_set.nfs_flush =
2872+ getenv("MAIL_NFS_STORAGE") != NULL;
2873+}
2874+
2875+void duplicate_deinit(void)
2876+{
2877+ if (duplicate_file != NULL) {
2878+ duplicate_flush();
2879+ duplicate_free(&duplicate_file);
2880+ }
2881+}
2882
2883=== removed file 'src/deliver/duplicate.c'
2884--- src/deliver/duplicate.c 2009-11-06 00:47:29 +0000
2885+++ src/deliver/duplicate.c 1970-01-01 00:00:00 +0000
2886@@ -1,324 +0,0 @@
2887-/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
2888-
2889-#include "lib.h"
2890-#include "ioloop.h"
2891-#include "istream.h"
2892-#include "ostream.h"
2893-#include "home-expand.h"
2894-#include "file-dotlock.h"
2895-#include "hash.h"
2896-#include "duplicate.h"
2897-
2898-#include <stdlib.h>
2899-#include <fcntl.h>
2900-#include <unistd.h>
2901-
2902-#define DUPLICATE_PATH "~/.dovecot.lda-dupes"
2903-#define COMPRESS_PERCENTAGE 10
2904-#define DUPLICATE_BUFSIZE 4096
2905-#define DUPLICATE_VERSION 2
2906-
2907-struct duplicate {
2908- const void *id;
2909- unsigned int id_size;
2910-
2911- const char *user;
2912- time_t time;
2913-};
2914-
2915-struct duplicate_file_header {
2916- uint32_t version;
2917-};
2918-
2919-struct duplicate_record_header {
2920- uint32_t stamp;
2921- uint32_t id_size;
2922- uint32_t user_size;
2923-};
2924-
2925-struct duplicate_file {
2926- pool_t pool;
2927- struct hash_table *hash;
2928- const char *path;
2929-
2930- int new_fd;
2931- struct dotlock *dotlock;
2932- unsigned int changed:1;
2933-};
2934-
2935-static struct dotlock_settings duplicate_dotlock_set = {
2936- MEMBER(temp_prefix) NULL,
2937- MEMBER(lock_suffix) NULL,
2938-
2939- MEMBER(timeout) 20,
2940- MEMBER(stale_timeout) 10,
2941-
2942- MEMBER(callback) NULL,
2943- MEMBER(context) NULL,
2944-
2945- MEMBER(use_excl_lock) FALSE
2946-};
2947-static struct duplicate_file *duplicate_file = NULL;
2948-
2949-static int duplicate_cmp(const void *p1, const void *p2)
2950-{
2951- const struct duplicate *d1 = p1, *d2 = p2;
2952-
2953- return (d1->id_size == d2->id_size &&
2954- memcmp(d1->id, d2->id, d1->id_size) == 0 &&
2955- strcasecmp(d1->user, d2->user) == 0) ? 0 : 1;
2956-}
2957-
2958-static unsigned int duplicate_hash(const void *p)
2959-{
2960- /* a char* hash function from ASU -- from glib */
2961- const struct duplicate *d = p;
2962- const unsigned char *s = d->id, *end = s + d->id_size;
2963- unsigned int g, h = 0;
2964-
2965- while (s != end) {
2966- h = (h << 4) + *s;
2967- if ((g = h & 0xf0000000UL)) {
2968- h = h ^ (g >> 24);
2969- h = h ^ g;
2970- }
2971- s++;
2972- }
2973-
2974- return h ^ strcase_hash(d->user);
2975-}
2976-
2977-static int
2978-duplicate_read_records(struct duplicate_file *file, struct istream *input,
2979- unsigned int record_size)
2980-{
2981- const unsigned char *data;
2982- struct duplicate_record_header hdr;
2983- size_t size;
2984- unsigned int change_count;
2985-
2986- change_count = 0;
2987- while (i_stream_read_data(input, &data, &size, record_size) > 0) {
2988- if (record_size == sizeof(hdr))
2989- memcpy(&hdr, data, sizeof(hdr));
2990- else {
2991- /* FIXME: backwards compatibility with v1.0 */
2992- time_t stamp;
2993-
2994- i_assert(record_size ==
2995- sizeof(time_t) + sizeof(uint32_t)*2);
2996- memcpy(&stamp, data, sizeof(stamp));
2997- hdr.stamp = stamp;
2998- memcpy(&hdr.id_size, data + sizeof(time_t),
2999- sizeof(hdr.id_size));
3000- memcpy(&hdr.user_size,
3001- data + sizeof(time_t) + sizeof(uint32_t),
3002- sizeof(hdr.user_size));
3003- }
3004- i_stream_skip(input, record_size);
3005-
3006- if (hdr.id_size == 0 || hdr.user_size == 0 ||
3007- hdr.id_size > DUPLICATE_BUFSIZE ||
3008- hdr.user_size > DUPLICATE_BUFSIZE) {
3009- i_error("broken duplicate file %s", file->path);
3010- return -1;
3011- }
3012-
3013- if (i_stream_read_data(input, &data, &size,
3014- hdr.id_size + hdr.user_size - 1) <= 0) {
3015- i_error("unexpected end of file in %s", file->path);
3016- return -1;
3017- }
3018-
3019- if ((time_t)hdr.stamp >= ioloop_time) {
3020- /* still valid, save it */
3021- struct duplicate *d;
3022- void *new_id;
3023-
3024- new_id = p_malloc(file->pool, hdr.id_size);
3025- memcpy(new_id, data, hdr.id_size);
3026-
3027- d = p_new(file->pool, struct duplicate, 1);
3028- d->id = new_id;
3029- d->id_size = hdr.id_size;
3030- d->user = p_strndup(file->pool,
3031- data + hdr.id_size, hdr.user_size);
3032- d->time = hdr.stamp;
3033- hash_table_insert(file->hash, d, d);
3034- } else {
3035- change_count++;
3036- }
3037- i_stream_skip(input, hdr.id_size + hdr.user_size);
3038- }
3039-
3040- if (hash_table_count(file->hash) *
3041- COMPRESS_PERCENTAGE / 100 > change_count)
3042- file->changed = TRUE;
3043- return 0;
3044-}
3045-
3046-static int duplicate_read(struct duplicate_file *file)
3047-{
3048- struct istream *input;
3049- struct duplicate_file_header hdr;
3050- const unsigned char *data;
3051- size_t size;
3052- int fd;
3053- unsigned int record_size = 0;
3054-
3055- fd = open(file->path, O_RDONLY);
3056- if (fd == -1) {
3057- if (errno == ENOENT)
3058- return 0;
3059- i_error("open(%s) failed: %m", file->path);
3060- return -1;
3061- }
3062-
3063- /* <timestamp> <id_size> <user_size> <id> <user> */
3064- input = i_stream_create_fd(fd, DUPLICATE_BUFSIZE, FALSE);
3065- if (i_stream_read_data(input, &data, &size, sizeof(hdr)) > 0) {
3066- memcpy(&hdr, data, sizeof(hdr));
3067- if (hdr.version == 0 || hdr.version > DUPLICATE_VERSION + 10) {
3068- /* FIXME: backwards compatibility with v1.0 */
3069- record_size = sizeof(time_t) + sizeof(uint32_t)*2;
3070- } else if (hdr.version == DUPLICATE_VERSION) {
3071- record_size = sizeof(struct duplicate_record_header);
3072- i_stream_skip(input, sizeof(hdr));
3073- }
3074- }
3075-
3076- if (record_size == 0 ||
3077- duplicate_read_records(file, input, record_size) < 0) {
3078- if (unlink(file->path) < 0 && errno != ENOENT)
3079- i_error("unlink(%s) failed: %m", file->path);
3080- }
3081-
3082- i_stream_unref(&input);
3083- if (close(fd) < 0)
3084- i_error("close(%s) failed: %m", file->path);
3085- return 0;
3086-}
3087-
3088-static struct duplicate_file *duplicate_new(const char *path)
3089-{
3090- struct duplicate_file *file;
3091- pool_t pool;
3092-
3093- pool = pool_alloconly_create("duplicates", 10240);
3094-
3095- file = p_new(pool, struct duplicate_file, 1);
3096- file->pool = pool;
3097- file->path = p_strdup(pool, path);
3098- file->new_fd = file_dotlock_open(&duplicate_dotlock_set, path, 0,
3099- &file->dotlock);
3100- if (file->new_fd == -1)
3101- i_error("file_dotlock_create(%s) failed: %m", path);
3102- file->hash = hash_table_create(default_pool, pool, 0,
3103- duplicate_hash, duplicate_cmp);
3104- (void)duplicate_read(file);
3105- return file;
3106-}
3107-
3108-static void duplicate_free(struct duplicate_file **_file)
3109-{
3110- struct duplicate_file *file = *_file;
3111-
3112- *_file = NULL;
3113- if (file->dotlock != NULL)
3114- file_dotlock_delete(&file->dotlock);
3115-
3116- hash_table_destroy(&file->hash);
3117- pool_unref(&file->pool);
3118-}
3119-
3120-int duplicate_check(const void *id, size_t id_size, const char *user)
3121-{
3122- struct duplicate d;
3123-
3124- if (duplicate_file == NULL)
3125- duplicate_file = duplicate_new(home_expand(DUPLICATE_PATH));
3126-
3127- d.id = id;
3128- d.id_size = id_size;
3129- d.user = user;
3130-
3131- return hash_table_lookup(duplicate_file->hash, &d) != NULL;
3132-}
3133-
3134-void duplicate_mark(const void *id, size_t id_size,
3135- const char *user, time_t timestamp)
3136-{
3137- struct duplicate *d;
3138- void *new_id;
3139-
3140- if (duplicate_file == NULL)
3141- duplicate_file = duplicate_new(home_expand(DUPLICATE_PATH));
3142-
3143- new_id = p_malloc(duplicate_file->pool, id_size);
3144- memcpy(new_id, id, id_size);
3145-
3146- d = p_new(duplicate_file->pool, struct duplicate, 1);
3147- d->id = new_id;
3148- d->id_size = id_size;
3149- d->user = p_strdup(duplicate_file->pool, user);
3150- d->time = timestamp;
3151-
3152- duplicate_file->changed = TRUE;
3153- hash_table_insert(duplicate_file->hash, d, d);
3154-}
3155-
3156-void duplicate_flush(void)
3157-{
3158- struct duplicate_file *file = duplicate_file;
3159- struct duplicate_file_header hdr;
3160- struct duplicate_record_header rec;
3161- struct ostream *output;
3162- struct hash_iterate_context *iter;
3163- void *key, *value;
3164-
3165- if (duplicate_file == NULL || !file->changed || file->new_fd == -1)
3166- return;
3167-
3168- memset(&hdr, 0, sizeof(hdr));
3169- hdr.version = DUPLICATE_VERSION;
3170-
3171- output = o_stream_create_fd_file(file->new_fd, 0, FALSE);
3172- o_stream_send(output, &hdr, sizeof(hdr));
3173-
3174- memset(&rec, 0, sizeof(rec));
3175- iter = hash_table_iterate_init(file->hash);
3176- while (hash_table_iterate(iter, &key, &value)) {
3177- struct duplicate *d = value;
3178-
3179- rec.stamp = d->time;
3180- rec.id_size = d->id_size;
3181- rec.user_size = strlen(d->user);
3182-
3183- o_stream_send(output, &rec, sizeof(rec));
3184- o_stream_send(output, d->id, rec.id_size);
3185- o_stream_send(output, d->user, rec.user_size);
3186- }
3187- hash_table_iterate_deinit(&iter);
3188- o_stream_unref(&output);
3189-
3190- file->changed = FALSE;
3191- if (file_dotlock_replace(&file->dotlock, 0) < 0)
3192- i_error("file_dotlock_replace(%s) failed: %m", file->path);
3193- file->new_fd = -1;
3194-}
3195-
3196-void duplicate_init(void)
3197-{
3198- duplicate_dotlock_set.use_excl_lock =
3199- getenv("DOTLOCK_USE_EXCL") != NULL;
3200- duplicate_dotlock_set.nfs_flush =
3201- getenv("MAIL_NFS_STORAGE") != NULL;
3202-}
3203-
3204-void duplicate_deinit(void)
3205-{
3206- if (duplicate_file != NULL) {
3207- duplicate_flush();
3208- duplicate_free(&duplicate_file);
3209- }
3210-}
3211
3212=== added file 'src/deliver/duplicate.h'
3213--- src/deliver/duplicate.h 1970-01-01 00:00:00 +0000
3214+++ src/deliver/duplicate.h 2010-02-13 00:05:29 +0000
3215@@ -0,0 +1,15 @@
3216+#ifndef DUPLICATE_H
3217+#define DUPLICATE_H
3218+
3219+#define DUPLICATE_DEFAULT_KEEP (3600 * 24)
3220+
3221+int duplicate_check(const void *id, size_t id_size, const char *user);
3222+void duplicate_mark(const void *id, size_t id_size,
3223+ const char *user, time_t timestamp);
3224+
3225+void duplicate_flush(void);
3226+
3227+void duplicate_init(void);
3228+void duplicate_deinit(void);
3229+
3230+#endif
3231
3232=== removed file 'src/deliver/duplicate.h'
3233--- src/deliver/duplicate.h 2009-11-06 00:47:29 +0000
3234+++ src/deliver/duplicate.h 1970-01-01 00:00:00 +0000
3235@@ -1,15 +0,0 @@
3236-#ifndef DUPLICATE_H
3237-#define DUPLICATE_H
3238-
3239-#define DUPLICATE_DEFAULT_KEEP (3600 * 24)
3240-
3241-int duplicate_check(const void *id, size_t id_size, const char *user);
3242-void duplicate_mark(const void *id, size_t id_size,
3243- const char *user, time_t timestamp);
3244-
3245-void duplicate_flush(void);
3246-
3247-void duplicate_init(void);
3248-void duplicate_deinit(void);
3249-
3250-#endif
3251
3252=== added file 'src/deliver/mail-send.c'
3253--- src/deliver/mail-send.c 1970-01-01 00:00:00 +0000
3254+++ src/deliver/mail-send.c 2010-02-13 00:05:29 +0000
3255@@ -0,0 +1,208 @@
3256+/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
3257+
3258+#include "lib.h"
3259+#include "ioloop.h"
3260+#include "hostpid.h"
3261+#include "istream.h"
3262+#include "str.h"
3263+#include "str-sanitize.h"
3264+#include "var-expand.h"
3265+#include "message-date.h"
3266+#include "message-size.h"
3267+#include "duplicate.h"
3268+#include "istream-header-filter.h"
3269+#include "smtp-client.h"
3270+#include "deliver.h"
3271+#include "mail-send.h"
3272+
3273+#include <stdlib.h>
3274+#include <sys/wait.h>
3275+
3276+int global_outgoing_count = 0;
3277+
3278+static const struct var_expand_table *
3279+get_var_expand_table(struct mail *mail, const char *reason,
3280+ const char *recipient)
3281+{
3282+ static struct var_expand_table static_tab[] = {
3283+ { 'n', NULL, "crlf" },
3284+ { 'r', NULL, "reason" },
3285+ { 's', NULL, "subject" },
3286+ { 't', NULL, "to" },
3287+ { '\0', NULL, NULL }
3288+ };
3289+ struct var_expand_table *tab;
3290+ const char *subject;
3291+
3292+ tab = t_malloc(sizeof(static_tab));
3293+ memcpy(tab, static_tab, sizeof(static_tab));
3294+
3295+ tab[0].value = "\r\n";
3296+ tab[1].value = reason;
3297+ if (mail_get_first_header(mail, "Subject", &subject) <= 0)
3298+ subject = "";
3299+ tab[2].value = str_sanitize(subject, 80);
3300+ tab[3].value = recipient;
3301+
3302+ return tab;
3303+}
3304+
3305+int mail_send_rejection(struct mail *mail, const char *recipient,
3306+ const char *reason)
3307+{
3308+ struct istream *input;
3309+ struct smtp_client *smtp_client;
3310+ FILE *f;
3311+ struct message_size hdr_size;
3312+ const char *return_addr, *hdr;
3313+ const unsigned char *data;
3314+ const char *value, *msgid, *orig_msgid, *boundary;
3315+ string_t *str;
3316+ size_t size;
3317+ int ret;
3318+
3319+ if (mail_get_first_header(mail, "Auto-Submitted", &value) > 0 &&
3320+ strcasecmp(value, "no") != 0) {
3321+ i_info("msgid=%s: Auto-submitted message discarded: %s",
3322+ orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
3323+ str_sanitize(reason, 512));
3324+ return 0;
3325+ }
3326+
3327+ if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0)
3328+ orig_msgid = NULL;
3329+ return_addr = deliver_get_return_address(mail);
3330+ if (return_addr == NULL) {
3331+ i_info("msgid=%s: Return-Path missing, rejection reason: %s",
3332+ orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
3333+ str_sanitize(reason, 512));
3334+ return 0;
3335+ }
3336+
3337+ if (getenv("DEBUG") != NULL) {
3338+ i_info("Sending a rejection to %s: %s", recipient,
3339+ str_sanitize(reason, 512));
3340+ }
3341+
3342+ smtp_client = smtp_client_open(return_addr, NULL, &f);
3343+
3344+ msgid = deliver_get_new_message_id();
3345+ boundary = t_strdup_printf("%s/%s", my_pid, deliver_set->hostname);
3346+
3347+ fprintf(f, "Message-ID: %s\r\n", msgid);
3348+ fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time));
3349+ fprintf(f, "From: Mail Delivery Subsystem <%s>\r\n",
3350+ deliver_set->postmaster_address);
3351+ fprintf(f, "To: <%s>\r\n", return_addr);
3352+ fprintf(f, "MIME-Version: 1.0\r\n");
3353+ fprintf(f, "Content-Type: "
3354+ "multipart/report; report-type=disposition-notification;\r\n"
3355+ "\tboundary=\"%s\"\r\n", boundary);
3356+
3357+ str = t_str_new(256);
3358+ var_expand(str, deliver_set->rejection_subject,
3359+ get_var_expand_table(mail, reason, recipient));
3360+ fprintf(f, "Subject: %s\r\n", str_c(str));
3361+
3362+ fprintf(f, "Auto-Submitted: auto-replied (rejected)\r\n");
3363+ fprintf(f, "Precedence: bulk\r\n");
3364+ fprintf(f, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
3365+
3366+ /* human readable status report */
3367+ fprintf(f, "--%s\r\n", boundary);
3368+ fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
3369+ fprintf(f, "Content-Disposition: inline\r\n");
3370+ fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n");
3371+
3372+ str_truncate(str, 0);
3373+ var_expand(str, deliver_set->rejection_reason,
3374+ get_var_expand_table(mail, reason, recipient));
3375+ fprintf(f, "%s\r\n", str_c(str));
3376+
3377+ /* MDN status report */
3378+ fprintf(f, "--%s\r\n"
3379+ "Content-Type: message/disposition-notification\r\n\r\n",
3380+ boundary);
3381+ fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n",
3382+ deliver_set->hostname);
3383+ if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0)
3384+ fprintf(f, "Original-Recipient: rfc822; %s\r\n", hdr);
3385+ fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient);
3386+
3387+ if (orig_msgid != NULL)
3388+ fprintf(f, "Original-Message-ID: %s\r\n", orig_msgid);
3389+ fprintf(f, "Disposition: "
3390+ "automatic-action/MDN-sent-automatically; deleted\r\n");
3391+ fprintf(f, "\r\n");
3392+
3393+ /* original message's headers */
3394+ fprintf(f, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
3395+
3396+ if (mail_get_stream(mail, &hdr_size, NULL, &input) == 0) {
3397+ /* Note: If you add more headers, they need to be sorted.
3398+ We'll drop Content-Type because we're not including the message
3399+ body, and having a multipart Content-Type may confuse some
3400+ MIME parsers when they don't see the message boundaries. */
3401+ static const char *const exclude_headers[] = {
3402+ "Content-Type"
3403+ };
3404+
3405+ input = i_stream_create_header_filter(input,
3406+ HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR |
3407+ HEADER_FILTER_HIDE_BODY, exclude_headers,
3408+ N_ELEMENTS(exclude_headers),
3409+ null_header_filter_callback, NULL);
3410+
3411+ while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
3412+ if (fwrite(data, size, 1, f) == 0)
3413+ break;
3414+ i_stream_skip(input, size);
3415+ }
3416+ i_stream_unref(&input);
3417+
3418+ i_assert(ret != 0);
3419+ }
3420+
3421+ fprintf(f, "\r\n\r\n--%s--\r\n", boundary);
3422+ return smtp_client_close(smtp_client);
3423+}
3424+
3425+int mail_send_forward(struct mail *mail, const char *forwardto)
3426+{
3427+ static const char *hide_headers[] = {
3428+ "Return-Path"
3429+ };
3430+ struct istream *input;
3431+ struct smtp_client *smtp_client;
3432+ FILE *f;
3433+ const unsigned char *data;
3434+ const char *return_path;
3435+ size_t size;
3436+ int ret;
3437+
3438+ if (mail_get_stream(mail, NULL, NULL, &input) < 0)
3439+ return -1;
3440+
3441+ return_path = deliver_get_return_address(mail);
3442+ if (getenv("DEBUG") != NULL) {
3443+ i_info("Sending a forward to <%s> with return path <%s>",
3444+ forwardto, return_path);
3445+ }
3446+
3447+ smtp_client = smtp_client_open(forwardto, return_path, &f);
3448+
3449+ input = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE |
3450+ HEADER_FILTER_NO_CR, hide_headers,
3451+ N_ELEMENTS(hide_headers),
3452+ null_header_filter_callback, NULL);
3453+
3454+ while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
3455+ if (fwrite(data, size, 1, f) == 0)
3456+ break;
3457+ i_stream_skip(input, size);
3458+ }
3459+ i_stream_unref(&input);
3460+
3461+ return smtp_client_close(smtp_client);
3462+}
3463+
3464
3465=== removed file 'src/deliver/mail-send.c'
3466--- src/deliver/mail-send.c 2009-11-06 00:47:29 +0000
3467+++ src/deliver/mail-send.c 1970-01-01 00:00:00 +0000
3468@@ -1,208 +0,0 @@
3469-/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
3470-
3471-#include "lib.h"
3472-#include "ioloop.h"
3473-#include "hostpid.h"
3474-#include "istream.h"
3475-#include "str.h"
3476-#include "str-sanitize.h"
3477-#include "var-expand.h"
3478-#include "message-date.h"
3479-#include "message-size.h"
3480-#include "duplicate.h"
3481-#include "istream-header-filter.h"
3482-#include "smtp-client.h"
3483-#include "deliver.h"
3484-#include "mail-send.h"
3485-
3486-#include <stdlib.h>
3487-#include <sys/wait.h>
3488-
3489-int global_outgoing_count = 0;
3490-
3491-static const struct var_expand_table *
3492-get_var_expand_table(struct mail *mail, const char *reason,
3493- const char *recipient)
3494-{
3495- static struct var_expand_table static_tab[] = {
3496- { 'n', NULL, "crlf" },
3497- { 'r', NULL, "reason" },
3498- { 's', NULL, "subject" },
3499- { 't', NULL, "to" },
3500- { '\0', NULL, NULL }
3501- };
3502- struct var_expand_table *tab;
3503- const char *subject;
3504-
3505- tab = t_malloc(sizeof(static_tab));
3506- memcpy(tab, static_tab, sizeof(static_tab));
3507-
3508- tab[0].value = "\r\n";
3509- tab[1].value = reason;
3510- if (mail_get_first_header(mail, "Subject", &subject) <= 0)
3511- subject = "";
3512- tab[2].value = str_sanitize(subject, 80);
3513- tab[3].value = recipient;
3514-
3515- return tab;
3516-}
3517-
3518-int mail_send_rejection(struct mail *mail, const char *recipient,
3519- const char *reason)
3520-{
3521- struct istream *input;
3522- struct smtp_client *smtp_client;
3523- FILE *f;
3524- struct message_size hdr_size;
3525- const char *return_addr, *hdr;
3526- const unsigned char *data;
3527- const char *value, *msgid, *orig_msgid, *boundary;
3528- string_t *str;
3529- size_t size;
3530- int ret;
3531-
3532- if (mail_get_first_header(mail, "Auto-Submitted", &value) > 0 &&
3533- strcasecmp(value, "no") != 0) {
3534- i_info("msgid=%s: Auto-submitted message discarded: %s",
3535- orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
3536- str_sanitize(reason, 512));
3537- return 0;
3538- }
3539-
3540- if (mail_get_first_header(mail, "Message-ID", &orig_msgid) < 0)
3541- orig_msgid = NULL;
3542- return_addr = deliver_get_return_address(mail);
3543- if (return_addr == NULL) {
3544- i_info("msgid=%s: Return-Path missing, rejection reason: %s",
3545- orig_msgid == NULL ? "" : str_sanitize(orig_msgid, 80),
3546- str_sanitize(reason, 512));
3547- return 0;
3548- }
3549-
3550- if (getenv("DEBUG") != NULL) {
3551- i_info("Sending a rejection to %s: %s", recipient,
3552- str_sanitize(reason, 512));
3553- }
3554-
3555- smtp_client = smtp_client_open(return_addr, NULL, &f);
3556-
3557- msgid = deliver_get_new_message_id();
3558- boundary = t_strdup_printf("%s/%s", my_pid, deliver_set->hostname);
3559-
3560- fprintf(f, "Message-ID: %s\r\n", msgid);
3561- fprintf(f, "Date: %s\r\n", message_date_create(ioloop_time));
3562- fprintf(f, "From: Mail Delivery Subsystem <%s>\r\n",
3563- deliver_set->postmaster_address);
3564- fprintf(f, "To: <%s>\r\n", return_addr);
3565- fprintf(f, "MIME-Version: 1.0\r\n");
3566- fprintf(f, "Content-Type: "
3567- "multipart/report; report-type=disposition-notification;\r\n"
3568- "\tboundary=\"%s\"\r\n", boundary);
3569-
3570- str = t_str_new(256);
3571- var_expand(str, deliver_set->rejection_subject,
3572- get_var_expand_table(mail, reason, recipient));
3573- fprintf(f, "Subject: %s\r\n", str_c(str));
3574-
3575- fprintf(f, "Auto-Submitted: auto-replied (rejected)\r\n");
3576- fprintf(f, "Precedence: bulk\r\n");
3577- fprintf(f, "\r\nThis is a MIME-encapsulated message\r\n\r\n");
3578-
3579- /* human readable status report */
3580- fprintf(f, "--%s\r\n", boundary);
3581- fprintf(f, "Content-Type: text/plain; charset=utf-8\r\n");
3582- fprintf(f, "Content-Disposition: inline\r\n");
3583- fprintf(f, "Content-Transfer-Encoding: 8bit\r\n\r\n");
3584-
3585- str_truncate(str, 0);
3586- var_expand(str, deliver_set->rejection_reason,
3587- get_var_expand_table(mail, reason, recipient));
3588- fprintf(f, "%s\r\n", str_c(str));
3589-
3590- /* MDN status report */
3591- fprintf(f, "--%s\r\n"
3592- "Content-Type: message/disposition-notification\r\n\r\n",
3593- boundary);
3594- fprintf(f, "Reporting-UA: %s; Dovecot Mail Delivery Agent\r\n",
3595- deliver_set->hostname);
3596- if (mail_get_first_header(mail, "Original-Recipient", &hdr) > 0)
3597- fprintf(f, "Original-Recipient: rfc822; %s\r\n", hdr);
3598- fprintf(f, "Final-Recipient: rfc822; %s\r\n", recipient);
3599-
3600- if (orig_msgid != NULL)
3601- fprintf(f, "Original-Message-ID: %s\r\n", orig_msgid);
3602- fprintf(f, "Disposition: "
3603- "automatic-action/MDN-sent-automatically; deleted\r\n");
3604- fprintf(f, "\r\n");
3605-
3606- /* original message's headers */
3607- fprintf(f, "--%s\r\nContent-Type: message/rfc822\r\n\r\n", boundary);
3608-
3609- if (mail_get_stream(mail, &hdr_size, NULL, &input) == 0) {
3610- /* Note: If you add more headers, they need to be sorted.
3611- We'll drop Content-Type because we're not including the message
3612- body, and having a multipart Content-Type may confuse some
3613- MIME parsers when they don't see the message boundaries. */
3614- static const char *const exclude_headers[] = {
3615- "Content-Type"
3616- };
3617-
3618- input = i_stream_create_header_filter(input,
3619- HEADER_FILTER_EXCLUDE | HEADER_FILTER_NO_CR |
3620- HEADER_FILTER_HIDE_BODY, exclude_headers,
3621- N_ELEMENTS(exclude_headers),
3622- null_header_filter_callback, NULL);
3623-
3624- while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
3625- if (fwrite(data, size, 1, f) == 0)
3626- break;
3627- i_stream_skip(input, size);
3628- }
3629- i_stream_unref(&input);
3630-
3631- i_assert(ret != 0);
3632- }
3633-
3634- fprintf(f, "\r\n\r\n--%s--\r\n", boundary);
3635- return smtp_client_close(smtp_client);
3636-}
3637-
3638-int mail_send_forward(struct mail *mail, const char *forwardto)
3639-{
3640- static const char *hide_headers[] = {
3641- "Return-Path"
3642- };
3643- struct istream *input;
3644- struct smtp_client *smtp_client;
3645- FILE *f;
3646- const unsigned char *data;
3647- const char *return_path;
3648- size_t size;
3649- int ret;
3650-
3651- if (mail_get_stream(mail, NULL, NULL, &input) < 0)
3652- return -1;
3653-
3654- return_path = deliver_get_return_address(mail);
3655- if (getenv("DEBUG") != NULL) {
3656- i_info("Sending a forward to <%s> with return path <%s>",
3657- forwardto, return_path);
3658- }
3659-
3660- smtp_client = smtp_client_open(forwardto, return_path, &f);
3661-
3662- input = i_stream_create_header_filter(input, HEADER_FILTER_EXCLUDE |
3663- HEADER_FILTER_NO_CR, hide_headers,
3664- N_ELEMENTS(hide_headers),
3665- null_header_filter_callback, NULL);
3666-
3667- while ((ret = i_stream_read_data(input, &data, &size, 0)) > 0) {
3668- if (fwrite(data, size, 1, f) == 0)
3669- break;
3670- i_stream_skip(input, size);
3671- }
3672- i_stream_unref(&input);
3673-
3674- return smtp_client_close(smtp_client);
3675-}
3676-
3677
3678=== added file 'src/deliver/mail-send.h'
3679--- src/deliver/mail-send.h 1970-01-01 00:00:00 +0000
3680+++ src/deliver/mail-send.h 2010-02-13 00:05:29 +0000
3681@@ -0,0 +1,10 @@
3682+#ifndef MAIL_SEND_H
3683+#define MAIL_SEND_H
3684+
3685+struct mail;
3686+
3687+int mail_send_rejection(struct mail *mail, const char *recipient,
3688+ const char *reason);
3689+int mail_send_forward(struct mail *mail, const char *forwardto);
3690+
3691+#endif
3692
3693=== removed file 'src/deliver/mail-send.h'
3694--- src/deliver/mail-send.h 2009-11-06 00:47:29 +0000
3695+++ src/deliver/mail-send.h 1970-01-01 00:00:00 +0000
3696@@ -1,10 +0,0 @@
3697-#ifndef MAIL_SEND_H
3698-#define MAIL_SEND_H
3699-
3700-struct mail;
3701-
3702-int mail_send_rejection(struct mail *mail, const char *recipient,
3703- const char *reason);
3704-int mail_send_forward(struct mail *mail, const char *forwardto);
3705-
3706-#endif
3707
3708=== added file 'src/deliver/smtp-client.c'
3709--- src/deliver/smtp-client.c 1970-01-01 00:00:00 +0000
3710+++ src/deliver/smtp-client.c 2010-02-13 00:05:29 +0000
3711@@ -0,0 +1,114 @@
3712+/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
3713+
3714+#include "lib.h"
3715+#include "deliver.h"
3716+#include "smtp-client.h"
3717+
3718+#include <unistd.h>
3719+#include <sys/wait.h>
3720+
3721+struct smtp_client {
3722+ FILE *f;
3723+ pid_t pid;
3724+};
3725+
3726+static struct smtp_client *smtp_client_devnull(FILE **file_r)
3727+{
3728+ struct smtp_client *client;
3729+
3730+ client = i_new(struct smtp_client, 1);
3731+ client->f = *file_r = fopen("/dev/null", "w");
3732+ if (client->f == NULL)
3733+ i_fatal("fopen() failed: %m");
3734+ client->pid = (pid_t)-1;
3735+ return client;
3736+}
3737+
3738+static void ATTR_NORETURN
3739+smtp_client_run_sendmail(const char *destination,
3740+ const char *return_path, int fd)
3741+{
3742+ const char *argv[7], *sendmail_path;
3743+
3744+ /* deliver_set's contents may point to environment variables.
3745+ deliver_env_clean() cleans them up, so they have to be copied. */
3746+ sendmail_path = t_strdup(deliver_set->sendmail_path);
3747+
3748+ argv[0] = sendmail_path;
3749+ argv[1] = "-i"; /* ignore dots */
3750+ argv[2] = "-f";
3751+ argv[3] = return_path != NULL && *return_path != '\0' ?
3752+ return_path : "<>";
3753+ argv[4] = "--";
3754+ argv[5] = destination;
3755+ argv[6] = NULL;
3756+
3757+ if (dup2(fd, STDIN_FILENO) < 0)
3758+ i_fatal("dup2() failed: %m");
3759+
3760+ deliver_env_clean(TRUE);
3761+
3762+ (void)execv(sendmail_path, (void *)argv);
3763+ i_fatal("execv(%s) failed: %m", sendmail_path);
3764+}
3765+
3766+struct smtp_client *smtp_client_open(const char *destination,
3767+ const char *return_path, FILE **file_r)
3768+{
3769+ struct smtp_client *client;
3770+ int fd[2];
3771+ pid_t pid;
3772+
3773+ if (pipe(fd) < 0) {
3774+ i_error("pipe() failed: %m");
3775+ return smtp_client_devnull(file_r);
3776+ }
3777+
3778+ if ((pid = fork()) == (pid_t)-1) {
3779+ i_error("fork() failed: %m");
3780+ (void)close(fd[0]); (void)close(fd[1]);
3781+ return smtp_client_devnull(file_r);
3782+ }
3783+ if (pid == 0) {
3784+ /* child */
3785+ (void)close(fd[1]);
3786+ smtp_client_run_sendmail(destination, return_path, fd[0]);
3787+ }
3788+ (void)close(fd[0]);
3789+
3790+ client = i_new(struct smtp_client, 1);
3791+ client->f = *file_r = fdopen(fd[1], "w");
3792+ if (client->f == NULL)
3793+ i_fatal("fdopen() failed: %m");
3794+ return client;
3795+}
3796+
3797+int smtp_client_close(struct smtp_client *client)
3798+{
3799+ int ret = EX_TEMPFAIL, status;
3800+
3801+ fclose(client->f);
3802+ if (client->pid == (pid_t)-1) {
3803+ /* smtp_client_open() failed already */
3804+ } else if (waitpid(client->pid, &status, 0) < 0)
3805+ i_error("waitpid() failed: %m");
3806+ else if (WIFEXITED(status)) {
3807+ ret = WEXITSTATUS(status);
3808+ if (ret != 0) {
3809+ i_error("Sendmail process terminated abnormally, "
3810+ "exit status %d", ret);
3811+ }
3812+ } else if (WIFSIGNALED(status)) {
3813+ i_error("Sendmail process terminated abnormally, "
3814+ "signal %d", WTERMSIG(status));
3815+ } else if (WIFSTOPPED(status)) {
3816+ i_error("Sendmail process stopped, signal %d",
3817+ WSTOPSIG(status));
3818+ } else {
3819+ i_error("Sendmail process terminated abnormally, "
3820+ "return status %d", status);
3821+ }
3822+
3823+ i_free(client);
3824+ return ret;
3825+}
3826
3827=== removed file 'src/deliver/smtp-client.c'
3828--- src/deliver/smtp-client.c 2009-11-06 00:47:29 +0000
3829+++ src/deliver/smtp-client.c 1970-01-01 00:00:00 +0000
3830@@ -1,114 +0,0 @@
3831-/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
3832-
3833-#include "lib.h"
3834-#include "deliver.h"
3835-#include "smtp-client.h"
3836-
3837-#include <unistd.h>
3838-#include <sys/wait.h>
3839-
3840-struct smtp_client {
3841- FILE *f;
3842- pid_t pid;
3843-};
3844-
3845-static struct smtp_client *smtp_client_devnull(FILE **file_r)
3846-{
3847- struct smtp_client *client;
3848-
3849- client = i_new(struct smtp_client, 1);
3850- client->f = *file_r = fopen("/dev/null", "w");
3851- if (client->f == NULL)
3852- i_fatal("fopen() failed: %m");
3853- client->pid = (pid_t)-1;
3854- return client;
3855-}
3856-
3857-static void ATTR_NORETURN
3858-smtp_client_run_sendmail(const char *destination,
3859- const char *return_path, int fd)
3860-{
3861- const char *argv[7], *sendmail_path;
3862-
3863- /* deliver_set's contents may point to environment variables.
3864- deliver_env_clean() cleans them up, so they have to be copied. */
3865- sendmail_path = t_strdup(deliver_set->sendmail_path);
3866-
3867- argv[0] = sendmail_path;
3868- argv[1] = "-i"; /* ignore dots */
3869- argv[2] = "-f";
3870- argv[3] = return_path != NULL && *return_path != '\0' ?
3871- return_path : "<>";
3872- argv[4] = "--";
3873- argv[5] = destination;
3874- argv[6] = NULL;
3875-
3876- if (dup2(fd, STDIN_FILENO) < 0)
3877- i_fatal("dup2() failed: %m");
3878-
3879- deliver_env_clean(TRUE);
3880-
3881- (void)execv(sendmail_path, (void *)argv);
3882- i_fatal("execv(%s) failed: %m", sendmail_path);
3883-}
3884-
3885-struct smtp_client *smtp_client_open(const char *destination,
3886- const char *return_path, FILE **file_r)
3887-{
3888- struct smtp_client *client;
3889- int fd[2];
3890- pid_t pid;
3891-
3892- if (pipe(fd) < 0) {
3893- i_error("pipe() failed: %m");
3894- return smtp_client_devnull(file_r);
3895- }
3896-
3897- if ((pid = fork()) == (pid_t)-1) {
3898- i_error("fork() failed: %m");
3899- (void)close(fd[0]); (void)close(fd[1]);
3900- return smtp_client_devnull(file_r);
3901- }
3902- if (pid == 0) {
3903- /* child */
3904- (void)close(fd[1]);
3905- smtp_client_run_sendmail(destination, return_path, fd[0]);
3906- }
3907- (void)close(fd[0]);
3908-
3909- client = i_new(struct smtp_client, 1);
3910- client->f = *file_r = fdopen(fd[1], "w");
3911- if (client->f == NULL)
3912- i_fatal("fdopen() failed: %m");
3913- return client;
3914-}
3915-
3916-int smtp_client_close(struct smtp_client *client)
3917-{
3918- int ret = EX_TEMPFAIL, status;
3919-
3920- fclose(client->f);
3921- if (client->pid == (pid_t)-1) {
3922- /* smtp_client_open() failed already */
3923- } else if (waitpid(client->pid, &status, 0) < 0)
3924- i_error("waitpid() failed: %m");
3925- else if (WIFEXITED(status)) {
3926- ret = WEXITSTATUS(status);
3927- if (ret != 0) {
3928- i_error("Sendmail process terminated abnormally, "
3929- "exit status %d", ret);
3930- }
3931- } else if (WIFSIGNALED(status)) {
3932- i_error("Sendmail process terminated abnormally, "
3933- "signal %d", WTERMSIG(status));
3934- } else if (WIFSTOPPED(status)) {
3935- i_error("Sendmail process stopped, signal %d",
3936- WSTOPSIG(status));
3937- } else {
3938- i_error("Sendmail process terminated abnormally, "
3939- "return status %d", status);
3940- }
3941-
3942- i_free(client);
3943- return ret;
3944-}
3945
3946=== added file 'src/deliver/smtp-client.h'
3947--- src/deliver/smtp-client.h 1970-01-01 00:00:00 +0000
3948+++ src/deliver/smtp-client.h 2010-02-13 00:05:29 +0000
3949@@ -0,0 +1,11 @@
3950+#ifndef SMTP_CLIENT_H
3951+#define SMTP_CLIENT_H
3952+
3953+#include <stdio.h>
3954+
3955+struct smtp_client *smtp_client_open(const char *destination,
3956+ const char *return_path, FILE **file_r);
3957+/* Returns sysexits-compatible return value */
3958+int smtp_client_close(struct smtp_client *client);
3959+
3960+#endif
3961
3962=== removed file 'src/deliver/smtp-client.h'
3963--- src/deliver/smtp-client.h 2009-11-06 00:47:29 +0000
3964+++ src/deliver/smtp-client.h 1970-01-01 00:00:00 +0000
3965@@ -1,11 +0,0 @@
3966-#ifndef SMTP_CLIENT_H
3967-#define SMTP_CLIENT_H
3968-
3969-#include <stdio.h>
3970-
3971-struct smtp_client *smtp_client_open(const char *destination,
3972- const char *return_path, FILE **file_r);
3973-/* Returns sysexits-compatible return value */
3974-int smtp_client_close(struct smtp_client *client);
3975-
3976-#endif

Subscribers

People subscribed via source and target branches

to all changes: