Merge lp:~ubuntu-branches/ubuntu/lucid/dovecot/lucid-201002122358 into lp:ubuntu/lucid/dovecot
- Lucid (10.04)
- lucid-201002122358
- Merge into lucid
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 |
Related bugs: |
Commit message
Description of the change
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-mountpoin t.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
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 |
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.