Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  bounce_notify_util.c

  Sprache: C
 

/*++
/* NAME
/* bounce_notify_util 3
/* SUMMARY
/* send non-delivery report to sender, server side
/* SYNOPSIS
/* #include "bounce_service.h"
/*
/* typedef struct {
/* .in +4
/* /* All private members... */

/* .in -4
/* } BOUNCE_INFO;
/*
/* BOUNCE_INFO *bounce_mail_init(service, queue_name, queue_id, encoding,
/* sendopts, dsn_envid, template)
/* const char *service;
/* const char *queue_name;
/* const char *queue_id;
/* const char *encoding;
/* int sendopts;
/* const char *dsn_envid;
/* const BOUNCE_TEMPLATE *template;
/*
/* BOUNCE_INFO *bounce_mail_one_init(queue_name, queue_id, encoding,
/* sendopts, dsn_envid, dsn_notify,
/* rcpt_buf, dsn_buf, template)
/* const char *queue_name;
/* const char *queue_id;
/* const char *encoding;
/* int sendopts;
/* int dsn_notify;
/* const char *dsn_envid;
/* RCPT_BUF *rcpt_buf;
/* DSN_BUF *dsn_buf;
/* const BOUNCE_TEMPLATE *template;
/*
/* void bounce_mail_free(bounce_info)
/* BOUNCE_INFO *bounce_info;
/*
/* int bounce_header(fp, bounce_info, recipient, postmaster_copy)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/* const char *recipient;
/* int postmaster_copy;
/*
/* int bounce_boilerplate(fp, bounce_info)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/*
/* int     bounce_recipient_log(fp, bounce_info)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/*
/* int     bounce_diagnostic_log(fp, bounce_info, notify_filter)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/* int notify_filter;
/*
/* int     bounce_header_dsn(fp, bounce_info)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/*
/* int     bounce_recipient_dsn(fp, bounce_info)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/*
/* int     bounce_diagnostic_dsn(fp, bounce_info, notify_filter)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/* int notify_filter;
/*
/* int bounce_original(fp, bounce_info, headers_only)
/* VSTREAM *fp;
/* BOUNCE_INFO *bounce_info;
/* int headers_only;
/*
/* void bounce_delrcpt(bounce_info)
/* BOUNCE_INFO *bounce_info;
/*
/* void bounce_delrcpt_one(bounce_info)
/* BOUNCE_INFO *bounce_info;
/* DESCRIPTION
/* This module implements the grunt work of sending a non-delivery
/* notification. A bounce is sent in a form that satisfies RFC 1894
/* (delivery status notifications).
/*
/* bounce_mail_init() bundles up its argument and attempts to
/* open the corresponding logfile and message file. A BOUNCE_INFO
/* structure contains all the necessary information about an
/* undeliverable message.
/*
/* bounce_mail_one_init() provides the same function for only
/* one recipient that is not read from bounce logfile.
/*
/* bounce_mail_free() releases memory allocated by bounce_mail_init()
/* and closes any files opened by bounce_mail_init().
/*
/* bounce_header() produces a standard mail header with the specified
/* recipient and starts a text/plain message segment for the
/* human-readable problem description. postmaster_copy is either
/* POSTMASTER_COPY or NO_POSTMASTER_COPY.
/*
/* bounce_boilerplate() produces the standard "sorry" text that
/* creates the illusion that mail systems are civilized.
/*
/* bounce_recipient_log() sends a human-readable representation of
/* logfile information for one recipient, with the recipient address
/* and with the text why the recipient was undeliverable.
/*
/* bounce_diagnostic_log() sends a human-readable representation of
/* logfile information for all undeliverable recipients. The
/* notify_filter specifies what recipient status records should be
/* reported: DSN_NOTIFY_SUCCESS, DSN_NOTIFY_FAILURE, DSN_NOTIFY_DELAY.
/* In the absence of DSN NOTIFY information all records are reported.
/* The result value is -1 in case of error, the number of reported
/* recipients in case of success.
/*
/* bounce_header_dsn() starts a message/delivery-status message
/* segment and sends the machine-readable information that identifies
/* the reporting MTA.
/*
/* bounce_recipient_dsn() sends a machine-readable representation of
/* logfile information for one recipient, with the recipient address
/* and with the text why the recipient was undeliverable.
/*
/* bounce_diagnostic_dsn() sends a machine-readable representation of
/* logfile information for all undeliverable recipients. The
/* notify_filter specifies what recipient status records should be
/* reported: DSN_NOTIFY_SUCCESS, DSN_NOTIFY_FAILURE, DSN_NOTIFY_DELAY.
/* In the absence of DSN NOTIFY information all records are reported.
/* The result value is -1 in case of error, the number of reported
/* recipients in case of success.
/*
/* bounce_original() starts a message/rfc822 or text/rfc822-headers
/* message segment and sends the original message, either full
/* (DSN_RET_FULL) or message headers only (DSN_RET_HDRS).
/*
/* bounce_delrcpt() deletes recipients in the logfile from the original
/* queue file.
/*
/* bounce_delrcpt_one() deletes one recipient from the original
/* queue file.
/* DIAGNOSTICS
/* Fatal error: error opening existing file.
/* BUGS
/* SEE ALSO
/* bounce(3) basic bounce service client interface
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*
/* Wietse Venema
/* porcupine.org
/*--*/


/* System library. */

#include <sys_defs.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>   /* sscanf() */
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>

#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <events.h>
#include <vstring.h>
#include <vstream.h>
#include <line_wrap.h>
#include <stringops.h>
#include <myflock.h>

/* Global library. */

#include <mail_queue.h>
#include <quote_822_local.h>
#include <mail_params.h>
#include <is_header.h>
#include <record.h>
#include <rec_type.h>
#include <post_mail.h>
#include <mail_addr.h>
#include <mail_error.h>
#include <bounce_log.h>
#include <mail_date.h>
#include <mail_proto.h>
#include <lex_822.h>
#include <deliver_completed.h>
#include <dsn_mask.h>
#include <smtputf8.h>
#include <header_opts.h>

/* Application-specific. */

#include "bounce_service.h"

#define STR vstring_str
#define LEN VSTRING_LEN

/* bounce_mail_alloc - initialize */

static BOUNCE_INFO *bounce_mail_alloc(const char *service,
                  const char *queue_name,
                  const char *queue_id,
                  const char *encoding,
                  int sendopts,
                  const char *dsn_envid,
                  RCPT_BUF *rcpt_buf,
                  DSN_BUF *dsn_buf,
                  BOUNCE_TEMPLATE *template,
                  BOUNCE_LOG *log_handle)
{
    BOUNCE_INFO *bounce_info;
    int     rec_type;
    int     skip_message_segment = 0;

    /*
     * Bundle up a bunch of parameters and initialize information that will
     * be discovered on the fly.
     * 
     * XXX Instead of overriding the returned-message MIME encoding, separate
     * the returned-message MIME encoding from the (boiler plate, delivery
     * status) MIME encoding.
     */

    bounce_info = (BOUNCE_INFO *) mymalloc(sizeof(*bounce_info));
    bounce_info->service = service;
    bounce_info->queue_name = queue_name;
    bounce_info->queue_id = queue_id;
    bounce_info->sendopts = sendopts;
    /* Fix 20140708: override MIME encoding: addresses may be 8bit. */
    /* Fix 20140718: override MIME encoding: 8bit $myhostname expansion. */
    if (var_smtputf8_enable /* was: bounce_info->smtputf8 */ ) {
 bounce_info->mime_encoding = "8bit";
    } else if (strcmp(encoding, MAIL_ATTR_ENC_8BIT) == 0) {
 bounce_info->mime_encoding = "8bit";
    } else if (strcmp(encoding, MAIL_ATTR_ENC_7BIT) == 0) {
 bounce_info->mime_encoding = "7bit";
    } else {
 if (strcmp(encoding, MAIL_ATTR_ENC_NONE) != 0)
     msg_warn("%s: unknown encoding: %.200s",
       bounce_info->queue_id, encoding);
 bounce_info->mime_encoding = 0;
    }
    if (dsn_envid && *dsn_envid)
 bounce_info->dsn_envid = dsn_envid;
    else
 bounce_info->dsn_envid = 0;
    bounce_info->template = template;
    bounce_info->buf = vstring_alloc(100);
    bounce_info->sender = vstring_alloc(100);
    bounce_info->arrival_time = 0;
    bounce_info->orig_offs = 0;
    bounce_info->message_size = 0;
    bounce_info->orig_msgid = vstring_alloc(100);
    bounce_info->rcpt_buf = rcpt_buf;
    bounce_info->dsn_buf = dsn_buf;
    bounce_info->log_handle = log_handle;

    /*
     * RFC 1894: diagnostic-type is an RFC 822 atom. We use X-$mail_name and
     * must ensure it is valid.
     */

    bounce_info->mail_name = mystrdup(var_mail_name);
    translit(bounce_info->mail_name, " \t\r\n()<>@,;:\\\".[]",
      "-----------------");

    /*
     * Compute a supposedly unique boundary string. This assumes that a queue
     * ID and a hostname contain acceptable characters for a boundary string,
     * but the assumption is not verified.
     */

    vstring_sprintf(bounce_info->buf, "%s.%lu/%s",
      queue_id, (unsigned long) event_time(), var_myhostname);
    bounce_info->mime_boundary = mystrdup(STR(bounce_info->buf));

    /*
     * If the original message cannot be found, do not raise a run-time
     * error. There is nothing we can do about the error, and all we are
     * doing is to inform the sender of a delivery problem. Bouncing a
     * message does not have to be a perfect job. But if the system IS
     * running out of resources, raise a fatal run-time error and force a
     * backoff.
     */

    if ((bounce_info->orig_fp = mail_queue_open(queue_name, queue_id,
      O_RDWR, 0)) == 0
 && errno != ENOENT)
 msg_fatal("open %s %s: %m", service, queue_id);

    /*
     * Get time/size/sender information from the original message envelope
     * records. If the envelope is corrupted just send whatever we can
     * (remember this is a best effort, it does not have to be perfect).
     * 
     * Lock the file for shared use, so that queue manager leaves it alone after
     * restarting.
     */

#define DELIVER_LOCK_MODE (MYFLOCK_OP_SHARED | MYFLOCK_OP_NOWAIT)

    if (bounce_info->orig_fp != 0) {
 if (myflock(vstream_fileno(bounce_info->orig_fp), INTERNAL_LOCK,
      DELIVER_LOCK_MODE) < 0)
     msg_fatal("cannot get shared lock on %s: %m",
        VSTREAM_PATH(bounce_info->orig_fp));
 while ((rec_type =
  rec_get(bounce_info->orig_fp, bounce_info->buf, 0)) > 0) {

     /*
      * Postfix version dependent: data offset in SIZE record.
     */

     if (rec_type == REC_TYPE_SIZE) {
  if (bounce_info->message_size == 0)
      sscanf(STR(bounce_info->buf), "%ld %ld",
      &bounce_info->message_size,
      &bounce_info->orig_offs);
  if (bounce_info->message_size < 0)
      bounce_info->message_size = 0;
  if (bounce_info->orig_offs < 0)
      bounce_info->orig_offs = 0;
     }

     /*
      * Information for the Arrival-Date: attribute.
     */

     else if (rec_type == REC_TYPE_TIME) {
  if (bounce_info->arrival_time == 0
      && (bounce_info->arrival_time = atol(STR(bounce_info->buf))) < 0)
      bounce_info->arrival_time = 0;
     }

     /*
      * Information for the X-Postfix-Sender: attribute.
     */

     else if (rec_type == REC_TYPE_FROM) {
  quote_822_local_flags(bounce_info->sender,
          VSTRING_LEN(bounce_info->buf) ?
          STR(bounce_info->buf) :
          mail_addr_mail_daemon(),
          QUOTE_FLAG_8BITCLEAN);
     }

     /*
      * Backwards compatibility: no data offset in SIZE record.
     */

     else if (rec_type == REC_TYPE_MESG) {
  /* XXX Future: sender+recipient after message content. */
  if (VSTRING_LEN(bounce_info->sender) == 0)
      msg_warn("%s: no sender before message content record",
        bounce_info->queue_id);
  bounce_info->orig_offs = vstream_ftell(bounce_info->orig_fp);
  skip_message_segment = 1;
     }

     /*
      * Extract Message-ID from extracted segment, for use in threaded
      * bounces.
     */

     else if (rec_type == REC_TYPE_ATTR && var_threaded_bounce) {
  char   *cp = STR(bounce_info->buf);
  ssize_t len = sizeof(MAIL_ATTR_MESSAGE_ID);
  char   *err;

  if (strncmp(cp, MAIL_ATTR_MESSAGE_ID "=", len) == 0) {
      cp += len;
      if ((err = extpar(&cp, "<>", EXTPAR_FLAG_NONE)) != 0) {
   msg_warn("%s: malformed Message-ID attribute: %s",
     bounce_info->queue_id, err);
   myfree(err);
      } else {
   vstring_sprintf(bounce_info->orig_msgid, "<%s>", cp);
      }
  }
     }

     /*
      * Are we done yet?
     */

     if (bounce_info->orig_offs > 0
  && bounce_info->arrival_time > 0
  && VSTRING_LEN(bounce_info->sender) > 0
  && (var_threaded_bounce == 0
      || VSTRING_LEN(bounce_info->orig_msgid) > 0)) {
  break;
     }

     /*
      * Skip over (the remainder of) the message segment. If that
      * fails, degrade.
     */

     if (skip_message_segment) {
  if (vstream_fseek(bounce_info->orig_fp,
      bounce_info->orig_offs +
      bounce_info->message_size,
      SEEK_SET) < 0)
       /* void */ ;
  skip_message_segment = 0;
     }
 }
    }
    return (bounce_info);
}

/* bounce_mail_init - initialize */

BOUNCE_INFO *bounce_mail_init(const char *service,
                 const char *queue_name,
                 const char *queue_id,
                 const char *encoding,
                 int sendopts,
                 const char *dsn_envid,
                 BOUNCE_TEMPLATE *template)
{
    BOUNCE_INFO *bounce_info;
    BOUNCE_LOG *log_handle;
    RCPT_BUF *rcpt_buf;
    DSN_BUF *dsn_buf;

    /*
     * Initialize the bounce_info structure. If the bounce log cannot be
     * found, do not raise a fatal run-time error. There is nothing we can do
     * about the error, and all we are doing is to inform the sender of a
     * delivery problem, Bouncing a message does not have to be a perfect
     * job. But if the system IS running out of resources, raise a fatal
     * run-time error and force a backoff.
     */

    if ((log_handle = bounce_log_open(service, queue_id, O_RDONLY, 0)) == 0) {
 if (errno != ENOENT)
     msg_fatal("open %s %s: %m", service, queue_id);
 rcpt_buf = 0;
 dsn_buf = 0;
    } else {
 rcpt_buf = rcpb_create();
 dsn_buf = dsb_create();
    }
    bounce_info = bounce_mail_alloc(service, queue_name, queue_id, encoding,
        sendopts, dsn_envid, rcpt_buf, dsn_buf,
        template, log_handle);
    return (bounce_info);
}

/* bounce_mail_one_init - initialize */

BOUNCE_INFO *bounce_mail_one_init(const char *queue_name,
              const char *queue_id,
              const char *encoding,
              int sendopts,
              const char *dsn_envid,
              RCPT_BUF *rcpt_buf,
              DSN_BUF *dsn_buf,
              BOUNCE_TEMPLATE *template)
{
    BOUNCE_INFO *bounce_info;

    /*
     * Initialize the bounce_info structure for just one recipient.
     */

    bounce_info = bounce_mail_alloc("none", queue_name, queue_id, encoding,
        sendopts, dsn_envid, rcpt_buf, dsn_buf,
        template, (BOUNCE_LOG *) 0);
    return (bounce_info);
}

/* bounce_mail_free - undo bounce_mail_init */

void    bounce_mail_free(BOUNCE_INFO *bounce_info)
{
    if (bounce_info->log_handle) {
 if (bounce_log_close(bounce_info->log_handle))
     msg_warn("%s: read bounce log %s: %m",
       bounce_info->queue_id, bounce_info->queue_id);
 vstring_free(bounce_info->orig_msgid);
 rcpb_free(bounce_info->rcpt_buf);
 dsb_free(bounce_info->dsn_buf);
    }
    if (bounce_info->orig_fp && vstream_fclose(bounce_info->orig_fp))
 msg_warn("%s: read message file %s %s: %m",
   bounce_info->queue_id, bounce_info->queue_name,
   bounce_info->queue_id);
    vstring_free(bounce_info->buf);
    vstring_free(bounce_info->sender);
    myfree(bounce_info->mail_name);
    myfree((void *) bounce_info->mime_boundary);
    myfree((void *) bounce_info);
}

/* bounce_header - generate bounce message header */

int     bounce_header(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
                const char *dest, int postmaster_copy)
{
    BOUNCE_TEMPLATE *template = bounce_info->template;

    /*
     * Print a minimal bounce header. The cleanup service will add other
     * headers and will make all addresses fully qualified.
     */

#define STREQ(a, b) (strcasecmp((a), (b)) == 0)
#define STRNE(a, b) (strcasecmp((a), (b)) != 0)

    /*
     * Generic headers.
     */

    bounce_template_headers(post_mail_fprintf, bounce, template,
       STR(quote_822_local(bounce_info->buf, dest)),
       postmaster_copy);

    /*
     * References and Reply-To header that references the original message-id
     * for better threading in MUAs.
     */

    if (VSTRING_LEN(bounce_info->orig_msgid) > 0) {
 post_mail_fprintf(bounce, "References: %s", STR(bounce_info->orig_msgid));
 post_mail_fprintf(bounce, "In-Reply-To: %s", STR(bounce_info->orig_msgid));
    }

    /*
     * Trade confidentiality against availability. See also up-stream code in
     * edit_notification_properties().
     */

    if (var_tls_required_enable
 && (bounce_info->sendopts & SOPT_REQUIRETLS_HEADER) != 0)
 post_mail_fprintf(bounce, "TLS-Required: no");

    /*
     * Auto-Submitted header, as per RFC 3834.
     */

    post_mail_fprintf(bounce, "Auto-Submitted: %s", postmaster_copy ?
        "auto-generated" : "auto-replied");

    /*
     * MIME header. Use 8bit encoding when either the bounced message or the
     * template requires it.
     */

    post_mail_fprintf(bounce, "MIME-Version: 1.0");
    post_mail_fprintf(bounce, "Content-Type: %s; report-type=%s;",
        "multipart/report""delivery-status");
    post_mail_fprintf(bounce, "\tboundary=\"%s\"", bounce_info->mime_boundary);
    if (bounce_info->mime_encoding)
 post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
       STREQ(bounce_info->mime_encoding, MAIL_ATTR_ENC_7BIT) ?
     bounce_template_encoding(template) :
     bounce_info->mime_encoding);
    post_mail_fputs(bounce, "");
    post_mail_fputs(bounce, "This is a MIME-encapsulated message.");

    /*
     * MIME header.
     */

#define NOT_US_ASCII(tp) \
 STRNE(bounce_template_charset(template), "us-ascii")

#define NOT_7BIT_MIME(bp) \
 (bp->mime_encoding && STRNE(bp->mime_encoding, MAIL_ATTR_ENC_7BIT))

    post_mail_fputs(bounce, "");
    post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
    post_mail_fprintf(bounce, "Content-Description: %s""Notification");
    /* Fix 20140718: UTF-8 address or $myhostname expansion. */
    post_mail_fprintf(bounce, "Content-Type: %s; charset=%s",
        "text/plain", NOT_US_ASCII(template) ?
        bounce_template_charset(template) :
        NOT_7BIT_MIME(bounce_info) ?
        "utf-8" : "us-ascii");
    /* Fix 20140709: addresses may be 8bit. */
    if (NOT_7BIT_MIME(bounce_info))
 post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
     bounce_info->mime_encoding);
    post_mail_fputs(bounce, "");

    return (vstream_ferror(bounce));
}

/* bounce_boilerplate - generate boiler-plate text */

int     bounce_boilerplate(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{

    /*
     * Print the boiler-plate text.
     */

    bounce_template_expand(post_mail_fputs, bounce, bounce_info->template);
    return (vstream_ferror(bounce));
}

/* bounce_print - line_wrap callback */

static void bounce_print(const char *str, int len, int indent, void *context)
{
    VSTREAM *bounce = (VSTREAM *) context;

    post_mail_fprintf(bounce, "%*s%.*s", indent, "", len, str);
}

/* bounce_print_wrap - print and wrap a line */

static void bounce_print_wrap(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
                 const char *format,...)
{
    va_list ap;

#define LENGTH 79
#define INDENT 4

    va_start(ap, format);
    vstring_vsprintf(bounce_info->buf, format, ap);
    va_end(ap);
    line_wrap(STR(bounce_info->buf), LENGTH, INDENT,
       bounce_print, (void *) bounce);
}

/* bounce_recipient_log - send one bounce log report entry */

int     bounce_recipient_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
    RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;
    DSN    *dsn = &bounce_info->dsn_buf->dsn;

    /*
     * Mask control and non-ASCII characters (done in bounce_log_read()),
     * wrap long lines and prepend one blank, so this data can safely be
     * piped into other programs. Sort of like TCP Wrapper's safe_finger
     * program.
     */

#define NON_NULL_EMPTY(s) ((s) && *(s))

    post_mail_fputs(bounce, "");
    if (NON_NULL_EMPTY(rcpt->orig_addr)) {
 bounce_print_wrap(bounce, bounce_info, "<%s> (expanded from <%s>): %s",
     rcpt->address, rcpt->orig_addr, dsn->reason);
    } else {
 bounce_print_wrap(bounce, bounce_info, "<%s>: %s",
     rcpt->address, dsn->reason);
    }
    return (vstream_ferror(bounce));
}

/* bounce_diagnostic_log - send bounce log report */

int     bounce_diagnostic_log(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
                 int notify_filter)
{
    RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;
    int     count = 0;

    /*
     * Append a human-readable copy of the delivery error log. We're doing a
     * best effort, so there is no point raising a fatal run-time error in
     * case of a logfile read error.
     * 
     * XXX DSN If the logfile with failed recipients is unavailable, pretend
     * that we found something anyway, so that this notification will not be
     * canceled.
     */

    if (bounce_info->log_handle == 0
 || bounce_log_rewind(bounce_info->log_handle)) {
 if (IS_FAILURE_TEMPLATE(bounce_info->template)) {
     post_mail_fputs(bounce, "");
     post_mail_fputs(bounce, "\t--- Delivery report unavailable ---");
     count = 1;    /* XXX don't abort */
 }
    } else {
 while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf,
          bounce_info->dsn_buf) != 0) {
     if (rcpt->dsn_notify == 0  /* compat */
  || (rcpt->dsn_notify & notify_filter)) {
  count++;
  if (bounce_recipient_log(bounce, bounce_info) != 0)
      break;
     }
 }
    }
    return (vstream_ferror(bounce) ? -1 : count);
}

/* bounce_header_dsn - send per-MTA bounce DSN records */

int     bounce_header_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{

    /*
     * MIME header.
     */

    post_mail_fputs(bounce, "");
    post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
    post_mail_fprintf(bounce, "Content-Description: %s",
        "Delivery report");
    /* Generate *global* only if the original requested SMTPUTF8 support. */
    post_mail_fprintf(bounce, "Content-Type: message/%sdelivery-status",
        (bounce_info->sendopts & SMTPUTF8_FLAG_REQUESTED) ?
        "global-" : "");
    /* Fix 20140709: addresses may be 8bit. */
    if (NOT_7BIT_MIME(bounce_info)
    /* BC Fix 20170610: prevent MIME downgrade of message/delivery-status. */
 && (bounce_info->sendopts & SMTPUTF8_FLAG_REQUESTED))
 post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
     bounce_info->mime_encoding);

    /*
     * According to RFC 1894: The body of a message/delivery-status consists
     * of one or more "fields" formatted according to the ABNF of RFC 822
     * header "fields" (see [6]).  The per-message fields appear first,
     * followed by a blank line.
     */

    post_mail_fputs(bounce, "");
    post_mail_fprintf(bounce, "Reporting-MTA: dns; %s", var_myhostname);
#if 0
    post_mail_fprintf(bounce, "Received-From-MTA: dns; %s""whatever");
#endif
    if (NON_NULL_EMPTY(bounce_info->dsn_envid)) {
 post_mail_fprintf(bounce, "Original-Envelope-Id: %s",
     bounce_info->dsn_envid);
    }
    post_mail_fprintf(bounce, "X-%s-Queue-ID: %s",
        bounce_info->mail_name, bounce_info->queue_id);

#define IS_UTF8_ADDRESS(str) \
 ((str)[0] != 0 && !allascii(str) && valid_utf8_stringz(str))

    /* Fix 20140708: use "utf-8" or "rfc822" as appropriate. */
    if (VSTRING_LEN(bounce_info->sender) > 0)
 post_mail_fprintf(bounce, "X-%s-Sender: %s; %s",
     bounce_info->mail_name,
     (bounce_info->sendopts & SMTPUTF8_FLAG_ALL)
     && IS_UTF8_ADDRESS(STR(bounce_info->sender)) ?
     "utf-8" : "rfc822", STR(bounce_info->sender));
    if (bounce_info->arrival_time > 0)
 post_mail_fprintf(bounce, "Arrival-Date: %s",
     mail_date(bounce_info->arrival_time));
    return (vstream_ferror(bounce));
}

/* bounce_recipient_dsn - send per-recipient DSN records */

int     bounce_recipient_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info)
{
    RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;
    DSN    *dsn = &bounce_info->dsn_buf->dsn;

    post_mail_fputs(bounce, "");
    /* Fix 20140708: Don't send "utf-8" type with non-UTF8 address. */
    post_mail_fprintf(bounce, "Final-Recipient: %s; %s",
        (bounce_info->sendopts & SMTPUTF8_FLAG_ALL)
        && IS_UTF8_ADDRESS(rcpt->address) ?
        "utf-8" : "rfc822", rcpt->address);

    /*
     * XXX DSN
     * 
     * RFC 3464 section 6.3.d: "If no ORCPT parameter was provided for this
     * recipient, the Original-Recipient field MUST NOT appear."
     * 
     * This is inconsistent with section 5.2.1.d: "If no ORCPT parameter was
     * present in the RCPT command when the message was received, an ORCPT
     * parameter MAY be added to the RCPT command when the message is
     * relayed.". Postfix adds an ORCPT parameter under these conditions.
     * 
     * Therefore, all down-stream MTAs will send DSNs with Original-Recipient
     * field containing this same ORCPT value. When a down-stream MTA can use
     * that information in their DSNs, it makes no sense that an up-stream
     * MTA can't use that same information in its own DSNs.
     * 
     * Postfix always reports an Original-Recipient field, because it is more
     * more useful and more consistent.
     */

    if (NON_NULL_EMPTY(rcpt->dsn_orcpt)) {
 post_mail_fprintf(bounce, "Original-Recipient: %s", rcpt->dsn_orcpt);
    } else if (NON_NULL_EMPTY(rcpt->orig_addr)) {
 /* Fix 20140708: Don't send "utf-8" type with non-UTF8 address. */
 post_mail_fprintf(bounce, "Original-Recipient: %s; %s",
     (bounce_info->sendopts & SMTPUTF8_FLAG_ALL)
     && IS_UTF8_ADDRESS(rcpt->orig_addr) ?
     "utf-8" : "rfc822", rcpt->orig_addr);
    }
    post_mail_fprintf(bounce, "Action: %s",
        IS_FAILURE_TEMPLATE(bounce_info->template) ?
        "failed" : dsn->action);
    post_mail_fprintf(bounce, "Status: %s", dsn->status);
    if (NON_NULL_EMPTY(dsn->mtype) && NON_NULL_EMPTY(dsn->mname))
 bounce_print_wrap(bounce, bounce_info, "Remote-MTA: %s; %s",
     dsn->mtype, dsn->mname);
    if (NON_NULL_EMPTY(dsn->dtype) && NON_NULL_EMPTY(dsn->dtext))
 bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: %s; %s",
     dsn->dtype, dsn->dtext);
    else
 bounce_print_wrap(bounce, bounce_info, "Diagnostic-Code: X-%s; %s",
     bounce_info->mail_name, dsn->reason);
#if 0
    if (dsn->time > 0)
 post_mail_fprintf(bounce, "Last-Attempt-Date: %s",
     mail_date(dsn->time));
#endif
    if (IS_DELAY_TEMPLATE(bounce_info->template))
 post_mail_fprintf(bounce, "Will-Retry-Until: %s",
   mail_date(bounce_info->arrival_time + var_max_queue_time));
    return (vstream_ferror(bounce));
}

/* bounce_diagnostic_dsn - send bounce log report, machine readable form */

int     bounce_diagnostic_dsn(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
                 int notify_filter)
{
    RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;
    int     count = 0;

    /*
     * Append a machine-readable copy of the delivery error log. We're doing
     * a best effort, so there is no point raising a fatal run-time error in
     * case of a logfile read error.
     * 
     * XXX DSN If the logfile with failed recipients is unavailable, pretend
     * that we found something anyway, so that this notification will not be
     * canceled.
     */

    if (bounce_info->log_handle == 0
 || bounce_log_rewind(bounce_info->log_handle)) {
 if (IS_FAILURE_TEMPLATE(bounce_info->template))
     count = 1;    /* XXX don't abort */
    } else {
 while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf,
          bounce_info->dsn_buf) != 0) {
     if (rcpt->dsn_notify == 0  /* compat */
  || (rcpt->dsn_notify & notify_filter)) {
  count++;
  if (bounce_recipient_dsn(bounce, bounce_info) != 0)
      break;
     }
 }
    }
    return (vstream_ferror(bounce) ? -1 : count);
}

/* bounce_original - send a copy of the original to the victim */

int     bounce_original(VSTREAM *bounce, BOUNCE_INFO *bounce_info,
           int headers_only)
{
    int     status = 0;
    int     rec_type = 0;

    /*
     * When truncating a large message, don't damage the MIME structure: send
     * the message headers only.
     */

    if (var_bounce_limit > 0
 && bounce_info->orig_fp
 && (bounce_info->message_size <= 0
     || bounce_info->message_size > var_bounce_limit))
 headers_only = DSN_RET_HDRS;

    /*
     * MIME headers.
     */

#define IS_UNDELIVERED_TEMPLATE(template) \
        (IS_FAILURE_TEMPLATE(template) || IS_DELAY_TEMPLATE(template))

    post_mail_fputs(bounce, "");
    post_mail_fprintf(bounce, "--%s", bounce_info->mime_boundary);
    post_mail_fprintf(bounce, "Content-Description: %s%s",
        IS_UNDELIVERED_TEMPLATE(bounce_info->template) ?
        "Undelivered " : "",
        headers_only == DSN_RET_HDRS ?
        "Message Headers" : "Message");
    /* Generate *global* only if the original requested SMTPUTF8 support. */
    if (bounce_info->sendopts & SMTPUTF8_FLAG_REQUESTED)
 post_mail_fprintf(bounce, "Content-Type: message/%s",
     headers_only == DSN_RET_HDRS ?
     "global-headers" : "global");
    else
 post_mail_fprintf(bounce, "Content-Type: %s",
     headers_only == DSN_RET_HDRS ?
     "text/rfc822-headers" : "message/rfc822");
    if (NOT_7BIT_MIME(bounce_info))
 post_mail_fprintf(bounce, "Content-Transfer-Encoding: %s",
     bounce_info->mime_encoding);
    post_mail_fputs(bounce, "");

    /*
     * Send place holder if original is unavailable.
     */

    if (bounce_info->orig_offs == 0 || vstream_fseek(bounce_info->orig_fp,
        bounce_info->orig_offs, SEEK_SET) < 0) {
 post_mail_fputs(bounce, "\t--- Undelivered message unavailable ---");
 return (vstream_ferror(bounce));
    }

    /*
     * XXX The cleanup server removes Return-Path: headers. This should be
     * done only with mail that enters via a non-SMTP channel, but changing
     * this now could break other software. Removing Return-Path: could break
     * digital signatures, though this is unlikely. In any case,
     * header_checks are more effective when the Return-Path: header is
     * present, so we prepend one to the bounce message.
     */

    post_mail_fprintf(bounce, "Return-Path: <%s>", STR(bounce_info->sender));

    /*
     * Copy the original message contents. We're doing raw record output here
     * so that we don't throw away binary transparency yet.
     */

#define IS_HEADER(s) (IS_SPACE_TAB(*(s)) || is_header(s))

    while (status == 0 && (rec_type = rec_get(bounce_info->orig_fp, bounce_info->buf, 0)) > 0) {
 if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
     break;
 if (headers_only == DSN_RET_HDRS
     && !IS_HEADER(vstring_str(bounce_info->buf)))
     break;
 status = (REC_PUT_BUF(bounce, rec_type, bounce_info->buf) != rec_type);
    }

    /*
     * Final MIME headers. These require -- at the end of the boundary
     * string.
     * 
     * XXX This should be a separate bounce_terminate() entry so we can be
     * assured that the terminator will always be sent.
     */

    post_mail_fputs(bounce, "");
    post_mail_fprintf(bounce, "--%s--", bounce_info->mime_boundary);

    return (status);
}

/* bounce_delrcpt - delete recipients from original queue file */

void    bounce_delrcpt(BOUNCE_INFO *bounce_info)
{
    RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;

    if (bounce_info->orig_fp != 0
 && bounce_info->log_handle != 0
 && bounce_log_rewind(bounce_info->log_handle) == 0)
 while (bounce_log_read(bounce_info->log_handle, bounce_info->rcpt_buf,
          bounce_info->dsn_buf) != 0)
     if (rcpt->offset > 0)
  deliver_completed(bounce_info->orig_fp, rcpt->offset);
}

/* bounce_delrcpt_one - delete one recipient from original queue file */

void    bounce_delrcpt_one(BOUNCE_INFO *bounce_info)
{
    RECIPIENT *rcpt = &bounce_info->rcpt_buf->rcpt;

    if (bounce_info->orig_fp != 0 && rcpt->offset > 0)
 deliver_completed(bounce_info->orig_fp, rcpt->offset);
}

Messung V0.5 in Prozent
C=77 H=96 G=86

¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=738142