+ /* Make a stdio stream out of it. */
+
+ if (!(message_log = fdopen(fd, "a")))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC, "Couldn't fdopen message log %s: %s",
+ fname, strerror(errno));
+ return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */
+ }
+ }
+
+
+/* If asked to give up on a message, log who did it, and set the action for all
+the addresses. */
+
+if (give_up)
+ {
+ struct passwd *pw = getpwuid(real_uid);
+ log_write(0, LOG_MAIN, "cancelled by %s",
+ pw ? US pw->pw_name : string_sprintf("uid %ld", (long int)real_uid));
+ process_recipients = RECIP_FAIL;
+ }
+
+/* Otherwise, if there are too many Received: headers, fail all recipients. */
+
+else if (received_count > received_headers_max)
+ process_recipients = RECIP_FAIL_LOOP;
+
+/* Otherwise, if a system-wide, address-independent message filter is
+specified, run it now, except in the case when we are failing all recipients as
+a result of timeout_frozen_after. If the system filter yields "delivered", then
+ignore the true recipients of the message. Failure of the filter file is
+logged, and the delivery attempt fails. */
+
+else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
+ {
+ int rc;
+ int filtertype;
+ ugid_block ugid;
+ redirect_block redirect;
+
+ if (system_filter_uid_set)
+ {
+ ugid.uid = system_filter_uid;
+ ugid.gid = system_filter_gid;
+ ugid.uid_set = ugid.gid_set = TRUE;
+ }
+ else
+ ugid.uid_set = ugid.gid_set = FALSE;
+
+ return_path = sender_address;
+ f.enable_dollar_recipients = TRUE; /* Permit $recipients in system filter */
+ f.system_filtering = TRUE;
+
+ /* Any error in the filter file causes a delivery to be abandoned. */
+
+ GET_OPTION("system_filter");
+ redirect.string = system_filter;
+ redirect.isfile = TRUE;
+ redirect.check_owner = redirect.check_group = FALSE;
+ redirect.owners = NULL;
+ redirect.owngroups = NULL;
+ redirect.pw = NULL;
+ redirect.modemask = 0;
+
+ DEBUG(D_deliver|D_filter) debug_printf("running system filter\n");
+
+ rc = rda_interpret(
+ &redirect, /* Where the data is */
+ RDO_DEFER | /* Turn on all the enabling options */
+ RDO_FAIL | /* Leave off all the disabling options */
+ RDO_FILTER |
+ RDO_FREEZE |
+ RDO_REALLOG |
+ RDO_REWRITE,
+ NULL, /* No :include: restriction (not used in filter) */
+ NULL, /* No sieve info (not sieve!) */
+ &ugid, /* uid/gid data */
+ &addr_new, /* Where to hang generated addresses */
+ &filter_message, /* Where to put error message */
+ NULL, /* Don't skip syntax errors */
+ &filtertype, /* Will always be set to FILTER_EXIM for this call */
+ US"system filter"); /* For error messages */
+
+ DEBUG(D_deliver|D_filter) debug_printf("system filter returned %d\n", rc);
+
+ if (rc == FF_ERROR || rc == FF_NONEXIST)
+ {
+ (void)close(deliver_datafile);
+ deliver_datafile = -1;
+ log_write(0, LOG_MAIN|LOG_PANIC, "Error in system filter: %s",
+ string_printing(filter_message));
+ return continue_closedown(); /* yields DELIVER_NOT_ATTEMPTED */
+ }
+
+ /* Reset things. If the filter message is an empty string, which can happen
+ for a filter "fail" or "freeze" command with no text, reset it to NULL. */
+
+ f.system_filtering = FALSE;
+ f.enable_dollar_recipients = FALSE;
+ if (filter_message && filter_message[0] == 0) filter_message = NULL;
+
+ /* Save the values of the system filter variables so that user filters
+ can use them. */
+
+ memcpy(filter_sn, filter_n, sizeof(filter_sn));
+
+ /* The filter can request that delivery of the original addresses be
+ deferred. */
+
+ if (rc == FF_DEFER)
+ {
+ process_recipients = RECIP_DEFER;
+ deliver_msglog("Delivery deferred by system filter\n");
+ log_write(0, LOG_MAIN, "Delivery deferred by system filter");
+ }
+
+ /* The filter can request that a message be frozen, but this does not
+ take place if the message has been manually thawed. In that case, we must
+ unset "delivered", which is forced by the "freeze" command to make -bF
+ work properly. */
+
+ else if (rc == FF_FREEZE && !f.deliver_manual_thaw)
+ {
+ f.deliver_freeze = TRUE;
+ deliver_frozen_at = time(NULL);
+ process_recipients = RECIP_DEFER;
+ frozen_info = string_sprintf(" by the system filter%s%s",
+ filter_message ? US": " : US"",
+ filter_message ? filter_message : US"");
+ }
+
+ /* The filter can request that a message be failed. The error message may be
+ quite long - it is sent back to the sender in the bounce - but we don't want
+ to fill up the log with repetitions of it. If it starts with << then the text
+ between << and >> is written to the log, with the rest left for the bounce
+ message. */
+
+ else if (rc == FF_FAIL)
+ {
+ uschar *colon = US"";
+ uschar *logmsg = US"";
+ int loglen = 0;
+
+ process_recipients = RECIP_FAIL_FILTER;
+
+ if (filter_message)