manager, since a better test was implemented recently in
the trivial-rewrite server. Files: *qmgr/qmgr_message.c.
+20030126
+
+ Update: maildir filename algorithm updated according to
+ today's version of http://cr.yp.to/proto/maildir.html.
+
+20030127
+
+ Cleanup: use separate error messages for separate problems
+ with computing the list of SASL authentication mechanisms.
+ File: smtpd/smtpd_sasl_glue.c.
+
+20030130
+
+ Bugfix: allow $name in default time values. File:
+ global/mail_conf_time.c.
+
+20030219
+
+ Bugfix: the local pickup daemon skipped unterminated records,
+ since they happened to have the same record type code as
+ content filtering instructions. Victor Duchovni. Files:
+ global/rec_type.h, pickup/pickup.c.
+
+ Portability: Postfix could block, and thus not enforce
+ command execution time limits, while delivering mail to
+ command. File: global/pipe_command.c.
+
+ Bugfix: command execution time limits were not enforced
+ because the child process killing code in pipe_command()
+ was running with the wrong privileges. Problem reported by
+ Ben Rosengart, Panix. File: global/pipe_command.c.
+
+ Bugfix: duplicate recipient filtering in the cleanup server
+ did not eliminate virtual expansion duplicates with the
+ same original recipient. File: cleanup/cleanup_out_recipient.c.
+
Open problems:
Low: after successful delivery, per-queue window += 1/window,
all names or addresses of local recipients. A recipient address is
local when the address domain matches $mydestination or $inet_interfaces.
+The right-hand side of the lookup tables is conveniently ignored.
+In the left-hand side, specify a bare username, an @domain.tld
+wild-card, or specify a user@domain.tld address.
+
If the local_recipient_maps parameter value is non-empty, then the
SMTP server will reject for an unknown local recipient mail with
"User unknown in local recipient table".
date. Snapshots change only the release date, unless they include
the same bugfixes as a patch release.
+Incompatible changes with Postfix version 2.0.4 (released 20030219)
+===================================================================
+
+The maildir file naming algorithm has changed in accordance with
+an updated version of http://cr.yp.to/proto/maildir.html. The name
+is now TIME.VdevIinum.HOST
+
+Incompatible changes with Postfix version 2.0.3 (released 20030124)
+===================================================================
+
+The maildir file naming algorithm has changed. Pending a usable
+version of http://cr.yp.to/proto/maildir.html, the name is now
+TIME.DEV_INUM.HOST.
+
Incompatible changes with Postfix version 2.0.1 (released 20030112)
===================================================================
# about content filters is in the Postfix FIL-
# TER_README file.
#
-# Note: this action currently affects all recipients
-# of the message.
+# Note: this action overrides the main.cf con-
+# tent_filter setting, and currently affects all
+# recipients of the message.
#
# restriction...
# Apply the named UCE restriction(s) (permit, reject,
# reject_unauth_destination, and so on).
#
# REGULAR EXPRESSION TABLES
-# This section describes how the table lookups change when
+# This section describes how the table lookups change when
# the table is given in the form of regular expressions. For
-# a description of regular expression lookup table syntax,
+# a description of regular expression lookup table syntax,
# see regexp_table(5) or pcre_table(5).
#
-# Each pattern is a regular expression that is applied to
+# Each pattern is a regular expression that is applied to
# the entire string being looked up. Depending on the appli-
-# cation, that string is an entire client hostname, an
+# cation, that string is an entire client hostname, an
# entire client IP address, or an entire mail address. Thus,
# no parent domain or parent network search is done,
-# user@domain mail addresses are not broken up into their
+# user@domain mail addresses are not broken up into their
# user@ and domain constituent parts, nor is user+foo broken
# up into user and foo.
#
-# Patterns are applied in the order as specified in the
-# table, until a pattern is found that matches the search
+# Patterns are applied in the order as specified in the
+# table, until a pattern is found that matches the search
# string.
#
-# Actions are the same as with indexed file lookups, with
-# the additional feature that parenthesized substrings from
+# Actions are the same as with indexed file lookups, with
+# the additional feature that parenthesized substrings from
# the pattern can be interpolated as $1, $2 and so on.
#
# BUGS
-# The table format does not understand quoting conventions.
+# The table format does not understand quoting conventions.
#
# SEE ALSO
# postmap(1) create mapping table
# regexp_table(5) format of POSIX regular expression tables
#
# LICENSE
-# The Secure Mailer license must be distributed with this
+# The Secure Mailer license must be distributed with this
# software.
#
# AUTHOR(S)
# to access the passwd file via the proxymap service, in order to
# overcome chroot restrictions. The alternative, having a copy of
# the system passwd file in the chroot jail is just not practical.
+#
+# The right-hand side of the lookup tables is conveniently ignored.
+# In the left-hand side, specify a bare username, an @domain.tld
+# wild-card, or specify a user@domain.tld address.
#
#local_recipient_maps = unix:passwd.byname $alias_maps
#local_recipient_maps = proxy:unix:passwd.byname $alias_maps
#
# If this parameter is defined, then the SMTP server will reject
# mail for unknown relay users. This feature is off by default.
+#
+# The right-hand side of the lookup tables is conveniently ignored.
+# In the left-hand side, specify an @domain.tld wild-card, or specify
+# a user@domain.tld address.
#
#relay_recipient_maps = hash:/etc/postfix/relay_recipients
# and after the filter, with header/body
# checks turned off in the second cleanup
# server. More information about content filters
-# is in the Postfix FILTER_README file.
+# is in the Postfix FILTER_README file. This feature
+# overrides the main.cf content_filter setting.
#
# Substitution of sub-strings from the matched expression is
# possible using the conventional perl syntax. The macros in the
# and after the filter, with header/body
# checks turned off in the second cleanup
# server. More information about content filters
-# is in the Postfix FILTER_README file.
+# is in the Postfix FILTER_README file. This feature
+# overrides the main.cf content_filter setting.
#
# Substitution of sub-strings from the matched expression is
# possible using the conventional perl syntax. The macros in the
# After the message is queued, send the entire message through
# a content filter. This requires different cleanup servers
# before and after the filter, with header/body checks turned
-# off in the second cleanup server.
+# off in the second cleanup server. This overrides the main.cf
+# content filter setting.
# Skip over base 64 encoded blocks. This saves lots of CPU cycles.
# Expressions by Liviu Daia. Amended by Victor Duchovni.
# After the message is queued, send the entire message through
# a content filter. This requires different cleanup servers
# before and after the filter, with header/body checks turned
-# off in the second cleanup server.
+# off in the second cleanup server. This overrides the main.cf
+# content filter setting.
/^Subject: Make Money Fast/ REJECT
/^To: friend@public.com/ REJECT
# - You use the "luser_relay", "mailbox_transport", or "fallback_transport"
# feature of the Postfix local delivery agent (see sample-local.cf).
#
+# Details are described in the LOCAL_RECIPIENT_README file.
+#
# Beware: if the Postfix SMTP server runs chrooted, you probably have
# to access the passwd file via the proxymap service, in order to
# overcome chroot restrictions. The alternative, having a copy of
# the system passwd file in the chroot jail is just not practical.
#
+# The right-hand side of the lookup tables is conveniently ignored.
+# In the left-hand side, specify a bare username, an @domain.tld
+# wild-card, or specify a user@domain.tld address.
+#
#local_recipient_maps =
#local_recipient_maps = unix:passwd.byname $alias_maps
local_recipient_maps = proxy:unix:passwd.byname $alias_maps
#
# If this parameter is defined, then the SMTP server will reject
# mail for unknown relay users. This feature is off by default.
+#
+# The right-hand side of the lookup tables is conveniently ignored.
+# In the left-hand side, specify an @domain.tld wild-card, or specify
+# a user@domain.tld address.
#
#relay_recipient_maps = hash:/etc/postfix/relay_recipients
# Discard the message if the result is DISCARD text...
# Hold the message in the queue if the result is HOLD text...
# Release mail "on hold" with the postsuper(1) command.
+# Filter the message if the result is FILTER transport:nexthop.
# Permit the SMTP client if the result is OK or all numerical.
# reject_rbl_client domain.tld: reject if the reversed client IP address
# is listed in an A record under domain.tld.
# Discard the message if the result is DISCARD text...
# Hold the message in the queue if the result is HOLD text...
# Release mail "on hold" with the postsuper(1) command.
+# Filter the message if the result is FILTER transport:nexthop.
# Permit the HELO command if the result is OK or all numerical.
# reject: reject the request. Place this at the end of a restriction.
# permit: permit the request. Place this at the end of a restriction.
# Discard the message if the result is DISCARD text...
# Hold the message in the queue if the result is HOLD text...
# Release mail "on hold" with the postsuper(1) command.
+# Filter the message if the result is FILTER transport:nexthop.
# Permit the sender if the result is OK or all numerical.
# reject_sender_login_mismatch: reject if $smtpd_sender_login_maps specifies
# a MAIL FROM address owner, but the client is not (SASL) logged in as
# Discard the message if the result is DISCARD text...
# Hold the message in the queue if the result is HOLD text...
# Release mail "on hold" with the postsuper(1) command.
+# Filter the message if the result is FILTER transport:nexthop.
# Permit the recipient if the result is OK or all numerical.
# reject_non_fqdn_recipient: reject recipient address that is not in FQDN form
# reject: reject the request. Place this at the end of a restriction.
about content filters is in the Postfix FIL-
TER_README file.
- Note: this action currently affects all recipients
- of the message.
+ Note: this action overrides the <b>main.cf</b> <b>con-</b>
+ <b>tent</b><i>_</i><b>filter</b> setting, and currently affects all
+ recipients of the message.
<i>restriction...</i>
Apply the named UCE restriction(s) (<b>permit</b>, <b>reject</b>,
<b>reject</b><i>_</i><b>unauth</b><i>_</i><b>destination</b>, and so on).
<b>REGULAR</b> <b>EXPRESSION</b> <b>TABLES</b>
- This section describes how the table lookups change when
+ This section describes how the table lookups change when
the table is given in the form of regular expressions. For
- a description of regular expression lookup table syntax,
+ a description of regular expression lookup table syntax,
see <a href="regexp_table.5.html"><b>regexp</b><i>_</i><b>table</b>(5)</a> or <a href="pcre_table.5.html"><b>pcre</b><i>_</i><b>table</b>(5)</a>.
- Each pattern is a regular expression that is applied to
+ Each pattern is a regular expression that is applied to
the entire string being looked up. Depending on the appli-
- cation, that string is an entire client hostname, an
+ cation, that string is an entire client hostname, an
entire client IP address, or an entire mail address. Thus,
no parent domain or parent network search is done,
- <i>user@domain</i> mail addresses are not broken up into their
+ <i>user@domain</i> mail addresses are not broken up into their
<i>user@</i> and <i>domain</i> constituent parts, nor is <i>user+foo</i> broken
up into <i>user</i> and <i>foo</i>.
- Patterns are applied in the order as specified in the
- table, until a pattern is found that matches the search
+ Patterns are applied in the order as specified in the
+ table, until a pattern is found that matches the search
string.
- Actions are the same as with indexed file lookups, with
- the additional feature that parenthesized substrings from
+ Actions are the same as with indexed file lookups, with
+ the additional feature that parenthesized substrings from
the pattern can be interpolated as <b>$1</b>, <b>$2</b> and so on.
<b>BUGS</b>
- The table format does not understand quoting conventions.
+ The table format does not understand quoting conventions.
<b>SEE</b> <b>ALSO</b>
<a href="postmap.1.html">postmap(1)</a> create mapping table
<a href="regexp_table.5.html">regexp_table(5)</a> format of POSIX regular expression tables
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
a content filter. More information about content filters
is in the Postfix FILTER_README file.
.sp
-Note: this action currently affects all recipients of the message.
+Note: this action overrides the \fBmain.cf content_filter\fR setting,
+and currently affects all recipients of the message.
.IP \fIrestriction...\fR
Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
\fBreject_unauth_destination\fR, and so on).
# a content filter. More information about content filters
# is in the Postfix FILTER_README file.
# .sp
-# Note: this action currently affects all recipients of the message.
+# Note: this action overrides the \fBmain.cf content_filter\fR setting,
+# and currently affects all recipients of the message.
# .IP \fIrestriction...\fR
# Apply the named UCE restriction(s) (\fBpermit\fR, \fBreject\fR,
# \fBreject_unauth_destination\fR, and so on).
char **cpp;
/*
- * Apply the duplicate recipient filter before virtual expansion, so that
- * we can distinguish between different addresses that map onto the same
- * mailbox. The recipient will use our original recipient message header
- * to figure things out.
+ * Distinguish between different original recipient addresses that map
+ * onto the same mailbox. The recipient will use our original recipient
+ * message header to figure things out.
*/
- if (been_here_fixed(state->dups, recip) != 0)
- return;
-
if (cleanup_virt_alias_maps == 0) {
- cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
- cleanup_out_string(state, REC_TYPE_RCPT, recip);
- state->rcpt_count++;
+ if (been_here(state->dups, "%s\n%s", orcpt, recip) == 0) {
+ cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
+ cleanup_out_string(state, REC_TYPE_RCPT, recip);
+ state->rcpt_count++;
+ }
} else {
argv = cleanup_map1n_internal(state, recip, cleanup_virt_alias_maps,
cleanup_ext_prop_mask & EXT_PROP_VIRTUAL);
for (cpp = argv->argv; *cpp; cpp++) {
- cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
- cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
- state->rcpt_count++;
+ if (been_here(state->dups, "%s\n%s", orcpt, *cpp) == 0) {
+ cleanup_out_string(state, REC_TYPE_ORCP, orcpt);
+ cleanup_out_string(state, REC_TYPE_RCPT, *cpp);
+ state->rcpt_count++;
+ }
}
argv_free(argv);
}
pipe_command.o: ../../include/iostuff.h
pipe_command.o: ../../include/timed_wait.h
pipe_command.o: ../../include/set_ugid.h
+pipe_command.o: ../../include/set_eugid.h
pipe_command.o: ../../include/argv.h
pipe_command.o: mail_params.h
pipe_command.o: mail_copy.h
{
const char *cp;
- for (cp = defval; /* void */ ; cp++) {
+ for (cp = mail_conf_eval(defval); /* void */ ; cp++) {
if (*cp == 0)
msg_panic("parameter %s: missing time unit in default value: %s",
name, defval);
* Patches change the patchlevel and the release date. Snapshots change the
* release date only, unless they include the same bugfix as a patch release.
*/
-#define MAIL_RELEASE_DATE "20030124"
+#define MAIL_RELEASE_DATE "20030219"
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "2.0.3"
+#define DEF_MAIL_VERSION "2.0.4"
extern char *var_mail_version;
/*
#include <iostuff.h>
#include <timed_wait.h>
#include <set_ugid.h>
+#include <set_eugid.h>
#include <argv.h>
/* Global library. */
}
}
+/* kill_command - terminate command forcibly */
+
+static void kill_command(pid_t pid, int sig, uid_t kill_uid, gid_t kill_gid)
+{
+ pid_t saved_euid = geteuid();
+ gid_t saved_egid = getegid();
+
+ /*
+ * Switch privileges to that of the child process. Terminate the child
+ * and its offspring.
+ */
+ set_eugid(kill_uid, kill_gid);
+ if (kill(-pid, sig) < 0 && kill(pid, sig) < 0)
+ msg_warn("cannot kill process (group) %lu: %m",
+ (unsigned long) pid);
+ set_eugid(saved_euid, saved_egid);
+}
+
/* pipe_command_wait_or_kill - wait for command with time limit, or kill it */
-static int pipe_command_wait_or_kill(pid_t pid, WAIT_STATUS_T *statusp, int sig)
+static int pipe_command_wait_or_kill(pid_t pid, WAIT_STATUS_T *statusp, int sig,
+ uid_t kill_uid, gid_t kill_gid)
{
int maxtime = (pipe_command_timeout == 0) ? pipe_command_maxtime : 1;
char *myname = "pipe_command_wait_or_kill";
msg_info("%s: time limit exceeded", myname);
pipe_command_timeout = 1;
}
- kill(-pid, sig);
+ kill_command(pid, sig, kill_uid, kill_gid);
n = waitpid(pid, statusp, 0);
}
return (n);
* truncated without too much loss. I could even argue that truncating
* the amount of diagnostic output is a good thing to do, but I won't go
* that far.
+ *
+ * Turn on non-blocking writes to the child process so that we can enforce
+ * timeouts after partial writes.
*/
if (pipe(cmd_in_pipe) < 0 || pipe(cmd_out_pipe) < 0)
msg_fatal("%s: pipe: %m", myname);
non_blocking(cmd_out_pipe[1], NON_BLOCKING);
+ non_blocking(cmd_in_pipe[1], NON_BLOCKING);
/*
* Spawn off a child process and irrevocably change privilege to the
* not just the child process but also its offspring.
*/
if (pipe_command_timeout)
- (void) kill(-pid, SIGKILL);
- if (pipe_command_wait_or_kill(pid, &wait_status, SIGKILL) < 0)
+ kill_command(pid, SIGKILL, args.uid, args.gid);
+ if (pipe_command_wait_or_kill(pid, &wait_status, SIGKILL,
+ args.uid, args.gid) < 0)
msg_fatal("wait: %m");
if (pipe_command_timeout) {
vstring_sprintf(why, "Command time limit exceeded: \"%s\"%s%s",
* this is "postfix internal" information. However, the pickup server has to
* allow for the presence of A records in the extracted segment, because it
* can be requested to re-process already queued mail with `postsuper -r'.
+ *
+ * Note: REC_TYPE_FILT and REC_TYPE_CONT are encoded with the same 'L'
+ * constant, and it is too late to change that now.
*/
#define REC_TYPE_ENVELOPE "MCTFILSDROWVA"
#define REC_TYPE_CONTENT "XLN"
-#define REC_TYPE_EXTRACT "EDROPreAFI"
+#define REC_TYPE_EXTRACT "EDROPreAFIL"
/*
* The record at the beginning of the envelope segment specifies the message
* the file to new/ we use the device number and inode number. I do not
* care if this breaks on a remote AFS file system, because people should
* know better.
+ *
+ * On January 26, 2003, http://cr.yp.to/proto/maildir.html said:
+ *
+ * A unique name has three pieces, separated by dots. On the left is the
+ * result of time() or the second counter from gettimeofday(). On the
+ * right is the result of gethostname(). (To deal with invalid host
+ * names, replace / with \057 and : with \072.) In the middle is a
+ * delivery identifier, discussed below.
+ *
+ * [...]
+ *
+ * Modern delivery identifiers are created by concatenating enough of the
+ * following strings to guarantee uniqueness:
+ *
+ * [...]
+ *
+ * In, where n is (in hexadecimal) the UNIX inode number of this file.
+ * Unfortunately, inode numbers aren't always available through NFS.
+ *
+ * Vn, where n is (in hexadecimal) the UNIX device number of this file.
+ * Unfortunately, device numbers aren't always available through NFS.
+ * (Device numbers are also not helpful with the standard UNIX
+ * filesystem: a maildir has to be within a single UNIX device for link()
+ * and rename() to work.)
+ *
+ * [...]
+ *
+ * Pn, where n is (in decimal) the process ID.
+ *
+ * [...]
*/
#define STR vstring_str
set_eugid(usr_attr.uid, usr_attr.gid);
- vstring_sprintf(buf, "%lu.%d.%s",
+ vstring_sprintf(buf, "%lu.P%d.%s",
(unsigned long) starttime, var_pid, get_hostname());
tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
newfile = 0;
} else if (fstat(vstream_fileno(dst), &st) < 0) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
- vstring_sprintf(buf, "%lu.%lu_%lu.%s",
+ vstring_sprintf(buf, "%lu.V%lxI%lx.%s",
(unsigned long) starttime, (unsigned long) st.st_dev,
(unsigned long) st.st_ino, get_hostname());
newfile = concatenate(newdir, STR(buf), (char *) 0);
if (type == REC_TYPE_INSP)
/* Use current content inspection settings instead. */
continue;
- if (type == REC_TYPE_FILT)
+
+ /*
+ * XXX Workaround: REC_TYPE_FILT (used in envelopes) == REC_TYPE_CONT
+ * (used in message content).
+ */
+ if (type == REC_TYPE_FILT && *expected != REC_TYPE_CONTENT[0])
/* Use current content filter settings instead. */
continue;
else {
char *var_local_rcpt_maps;
char *var_virt_alias_maps;
char *var_virt_alias_doms;
-char *var_virt_mbox_maps;
-char *var_virt_mbox_doms;
+char *var_virt_mailbox_maps;
+char *var_virt_mailbox_doms;
char *var_relay_rcpt_maps;
char *var_relay_domains;
char *var_canonical_maps;
char *var_send_canon_maps;
char *var_rcpt_canon_maps;
-char *var_relocatedmaps;
+char *var_relocated_maps;
char *var_transport_maps;
char *var_proxy_read_maps;
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
- VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mbox_maps, 0, 0,
- VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mbox_doms, 0, 0,
+ VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
+ VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms, 0, 0,
VAR_RELAY_RCPT_MAPS, DEF_RELAY_RCPT_MAPS, &var_relay_rcpt_maps, 0, 0,
VAR_RELAY_DOMAINS, DEF_RELAY_DOMAINS, &var_relay_domains, 0, 0,
VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
- VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocatedmaps, 0, 0,
+ VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
VAR_PROXY_READ_MAPS, DEF_PROXY_READ_MAPS, &var_proxy_read_maps, 0, 0,
0,
*/
if (STREQUAL(value, "FILTER", cmd_len)) {
if (*cmd_text == 0) {
- msg_warn("access map %s entry %s has FILTER entry without value",
+ msg_warn("access map %s entry \"%s\" has FILTER entry without value",
table, datum);
return (SMTPD_CHECK_DUNNO);
} else if (strchr(cmd_text, ':') == 0) {
- msg_warn("access map %s entry %s requires transport:destination",
+ msg_warn("access map %s entry \"%s\" requires transport:destination",
table, datum);
return (SMTPD_CHECK_DUNNO);
} else {
"", " ", "",
&state->sasl_mechanism_list,
IGNORE_MECHANISM_LEN,
- &sasl_mechanism_count) != SASL_OK
- || sasl_mechanism_count <= 0)
+ &sasl_mechanism_count) != SASL_OK)
+ msg_fatal("cannot lookup SASL authentication mechanisms");
+ if (sasl_mechanism_count <= 0)
msg_fatal("no SASL authentication mechanisms");
}
dict_open.o: htable.h
dict_pcre.o: dict_pcre.c
dict_pcre.o: sys_defs.h
+dict_pcre.o: mymalloc.h
+dict_pcre.o: msg.h
+dict_pcre.o: safe.h
+dict_pcre.o: vstream.h
+dict_pcre.o: vbuf.h
+dict_pcre.o: vstring.h
+dict_pcre.o: stringops.h
+dict_pcre.o: readlline.h
+dict_pcre.o: dict.h
+dict_pcre.o: argv.h
+dict_pcre.o: dict_pcre.h
+dict_pcre.o: mac_parse.h
dict_regexp.o: dict_regexp.c
dict_regexp.o: sys_defs.h
dict_regexp.o: mymalloc.h
* the file to new/ we use the device number and inode number. I do not
* care if this breaks on a remote AFS file system, because people should
* know better.
+ *
+ * On January 26, 2003, http://cr.yp.to/proto/maildir.html said:
+ *
+ * A unique name has three pieces, separated by dots. On the left is the
+ * result of time() or the second counter from gettimeofday(). On the
+ * right is the result of gethostname(). (To deal with invalid host
+ * names, replace / with \057 and : with \072.) In the middle is a
+ * delivery identifier, discussed below.
+ *
+ * [...]
+ *
+ * Modern delivery identifiers are created by concatenating enough of the
+ * following strings to guarantee uniqueness:
+ *
+ * [...]
+ *
+ * In, where n is (in hexadecimal) the UNIX inode number of this file.
+ * Unfortunately, inode numbers aren't always available through NFS.
+ *
+ * Vn, where n is (in hexadecimal) the UNIX device number of this file.
+ * Unfortunately, device numbers aren't always available through NFS.
+ * (Device numbers are also not helpful with the standard UNIX
+ * filesystem: a maildir has to be within a single UNIX device for link()
+ * and rename() to work.)
+ *
+ * [...]
+ *
+ * Pn, where n is (in decimal) the process ID.
+ *
+ * [...]
*/
#define STR vstring_str
set_eugid(usr_attr.uid, usr_attr.gid);
- vstring_sprintf(buf, "%lu.%d.%s",
+ vstring_sprintf(buf, "%lu.P%d.%s",
(unsigned long) starttime, var_pid, get_hostname());
tmpfile = concatenate(tmpdir, STR(buf), (char *) 0);
newfile = 0;
} else if (fstat(vstream_fileno(dst), &st) < 0) {
vstring_sprintf(why, "create %s: %m", tmpfile);
} else {
- vstring_sprintf(buf, "%lu.%lu_%lu.%s",
+ vstring_sprintf(buf, "%lu.V%lxI%lx.%s",
(unsigned long) starttime, (unsigned long) st.st_dev,
(unsigned long) st.st_ino, get_hostname());
newfile = concatenate(newdir, STR(buf), (char *) 0);