+ if (p->address[0] == '|')
+ {
+ type = US"pipe";
+ GET_OPTION("system_filter_pipe_transport");
+ tpname = system_filter_pipe_transport;
+ address_pipe = p->address;
+ }
+ else if (p->address[0] == '>')
+ {
+ type = US"reply";
+ GET_OPTION("system_filter_reply_transport");
+ tpname = system_filter_reply_transport;
+ }
+ else
+ {
+ if (p->address[Ustrlen(p->address)-1] == '/')
+ {
+ type = US"directory";
+ GET_OPTION("system_filter_directory_transport");
+ tpname = system_filter_directory_transport;
+ }
+ else
+ {
+ type = US"file";
+ GET_OPTION("system_filter_file_transport");
+ tpname = system_filter_file_transport;
+ }
+ address_file = p->address;
+ }
+
+ /* Now find the actual transport, first expanding the name. We have
+ set address_file or address_pipe above. */
+
+ if (tpname)
+ {
+ uschar *tmp = expand_string(tpname);
+ address_file = address_pipe = NULL;
+ if (!tmp)
+ p->message = string_sprintf("failed to expand \"%s\" as a "
+ "system filter transport name", tpname);
+ if (is_tainted(tmp))
+ p->message = string_sprintf("attempt to used tainted value '%s' for"
+ "transport '%s' as a system filter", tmp, tpname);
+ tpname = tmp;
+ }
+ else
+ p->message = string_sprintf("system_filter_%s_transport is unset",
+ type);
+
+ if (tpname)
+ {
+ transport_instance *tp;
+ for (tp = transports; tp; tp = tp->next)
+ if (Ustrcmp(tp->name, tpname) == 0)
+ {
+ p->transport = tp;
+ break;
+ }
+ if (!tp)
+ p->message = string_sprintf("failed to find \"%s\" transport "
+ "for system filter delivery", tpname);
+ }
+
+ /* If we couldn't set up a transport, defer the delivery, putting the
+ error on the panic log as well as the main log. */
+
+ if (!p->transport)
+ {
+ address_item * badp = p;
+ p = p->next;
+ if (!addr_last) addr_new = p; else addr_last->next = p;
+ badp->local_part = badp->address; /* Needed for log line */
+ post_process_one(badp, DEFER, LOG_MAIN|LOG_PANIC, EXIM_DTYPE_ROUTER, 0);
+ continue;
+ }
+ } /* End of pfr handling */
+
+ /* Either a non-pfr delivery, or we found a transport */
+
+ DEBUG(D_deliver|D_filter)
+ debug_printf("system filter added %s\n", p->address);
+
+ addr_last = p;
+ p = p->next;
+ } /* Loop through all addr_new addresses */
+ }
+ }
+
+
+/* Scan the recipients list, and for every one that is not in the non-
+recipients tree, add an addr item to the chain of new addresses. If the pno
+value is non-negative, we must set the onetime parent from it. This which
+points to the relevant entry in the recipients list.
+
+This processing can be altered by the setting of the process_recipients
+variable, which is changed if recipients are to be ignored, failed, or
+deferred. This can happen as a result of system filter activity, or if the -Mg
+option is used to fail all of them.
+
+Duplicate addresses are handled later by a different tree structure; we can't
+just extend the non-recipients tree, because that will be re-written to the
+spool if the message is deferred, and in any case there are casing
+complications for local addresses. */
+
+if (process_recipients != RECIP_IGNORE)
+ for (i = 0; i < recipients_count; i++)
+ if (!tree_search(tree_nonrecipients, recipients_list[i].address))
+ {
+ recipient_item * r = recipients_list + i;
+ address_item * new = deliver_make_addr(r->address, FALSE);
+
+ new->prop.errors_address = r->errors_to;
+#ifdef SUPPORT_I18N
+ if ((new->prop.utf8_msg = message_smtputf8))
+ {
+ new->prop.utf8_downcvt = message_utf8_downconvert == 1;
+ new->prop.utf8_downcvt_maybe = message_utf8_downconvert == -1;
+ DEBUG(D_deliver) debug_printf("utf8, downconvert %s\n",
+ new->prop.utf8_downcvt ? "yes"
+ : new->prop.utf8_downcvt_maybe ? "ifneeded"
+ : "no");
+ }
+#endif