Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/global/   (Postfix Mailserver Version 3.11©)  Datei vom 9.3.2016 mit Größe 8 kB image not shown  

Quelle  smtp_reply_footer.c

  Sprache: C
 

/*++
/* NAME
/* smtp_reply_footer 3
/* SUMMARY
/* SMTP reply footer text support
/* SYNOPSIS
/* #include <smtp_reply_footer.h>
/*
/* int smtp_reply_footer(buffer, start, template, filter,
/* lookup, context)
/* VSTRING *buffer;
/* ssize_t start;
/* const char *template;
/* const char *filter;
/* const char *(*lookup) (const char *name, void *context);
/* void *context;
/* DESCRIPTION
/* smtp_reply_footer() expands a reply template, and appends
/* the result to an existing reply text.
/*
/* Arguments:
/* .IP buffer
/* Result buffer. This should contain a properly formatted
/* one-line or multi-line SMTP reply, with or without the final
/* <CR><LF>. The reply code and optional enhanced status code
/* will be replicated in the footer text.  One space character
/* after the SMTP reply code is replaced by '-'. If the existing
/* reply ends in <CR><LF>, the result text will also end in
/* <CR><LF>.
/* .IP start
/* The beginning of the SMTP reply that the footer will be
/* appended to. This supports applications that buffer up
/* multiple responses in one buffer.
/* .IP template
/* Template text, with optional $name attributes that will be
/* expanded. The two-character sequence "\n" is replaced by a
/* line break followed by a copy of the original SMTP reply
/* code and optional enhanced status code.
/* The two-character sequence "\c" at the start of the template
/* suppresses the line break between the reply text and the
/* template text.
/* .IP filter
/* The set of characters that are allowed in attribute expansion.
/* .IP lookup
/* Attribute name/value lookup function. The result value must
/* be a null for a name that is not found, otherwise a pointer
/* to null-terminated string.
/* .IP context
/* Call-back context for the lookup function.
/* SEE ALSO
/* mac_expand(3) macro expansion
/* DIAGNOSTICS
/* smtp_reply_footer() returns 0 upon success, -1 if the existing
/* reply text is malformed, -2 in the case of a template macro
/* parsing error (an undefined macro value is not an error).
/*
/* Fatal errors: memory allocation problem.
/* 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
/*--*/


/* System library. */

#include <sys_defs.h>
#include <string.h>
#include <ctype.h>

/* Utility library. */

#include <msg.h>
#include <mymalloc.h>
#include <vstring.h>

/* Global library. */

#include <dsn_util.h>
#include <smtp_reply_footer.h>

/* SLMs. */

#define STR vstring_str

int     smtp_reply_footer(VSTRING *buffer, ssize_t start,
             const char *template,
             const char *filter,
             MAC_EXP_LOOKUP_FN lookup,
             void *context)
{
    const char *myname = "smtp_reply_footer";
    char   *cp;
    char   *next;
    char   *end;
    ssize_t dsn_len;   /* last status code length */
    ssize_t dsn_offs = -1;  /* last status code offset */
    int     crlf_at_end = 0;
    ssize_t reply_code_offs = -1/* last SMTP reply code offset */
    ssize_t reply_patch_undo_len; /* length without final CRLF */
    int     mac_expand_error = 0;
    int     line_added;
    char   *saved_template;

    /*
     * Sanity check.
     */

    if (start < 0 || start > VSTRING_LEN(buffer))
 msg_panic("%s: bad start: %ld", myname, (long) start);
    if (*template == 0)
 msg_panic("%s: empty template", myname);

    /*
     * Scan the original response without making changes. If the response is
     * not what we expect, report an error. Otherwise, remember the offset of
     * the last SMTP reply code.
     */

    for (cp = STR(buffer) + start, end = cp + strlen(cp);;) {
 if (!ISDIGIT(cp[0]) || !ISDIGIT(cp[1]) || !ISDIGIT(cp[2])
     || (cp[3] != ' ' && cp[3] != '-'))
     return (-1);
 reply_code_offs = cp - STR(buffer);
 if ((next = strstr(cp, "\r\n")) == 0) {
     next = end;
     break;
 }
 cp = next + 2;
 if (cp == end) {
     crlf_at_end = 1;
     break;
 }
    }
    if (reply_code_offs < 0)
 return (-1);

    /*
     * Truncate text after the first null, and truncate the trailing CRLF.
     */

    if (next < vstring_end(buffer))
 vstring_truncate(buffer, next - STR(buffer));
    reply_patch_undo_len = VSTRING_LEN(buffer);

    /*
     * Append the footer text one line at a time. Caution: before we append
     * parts from the buffer to itself, we must extend the buffer first,
     * otherwise we would have a dangling pointer "read" bug.
     * 
     * XXX mac_expand() has no template length argument, so we must
     * null-terminate the template in the middle.
     */

    dsn_offs = reply_code_offs + 4;
    dsn_len = dsn_valid(STR(buffer) + dsn_offs);
    line_added = 0;
    saved_template = mystrdup(template);
    for (cp = saved_template, end = cp + strlen(cp);;) {
 if ((next = strstr(cp, "\\n")) != 0) {
     *next = 0;
 } else {
     next = end;
 }
 if (cp == saved_template && strncmp(cp, "\\c"2) == 0) {
     /* Handle \c at start of template. */
     cp += 2;
 } else {
     /* Append a clone of the SMTP reply code. */
     vstring_strcat(buffer, "\r\n");
     VSTRING_SPACE(buffer, 3);
     vstring_strncat(buffer, STR(buffer) + reply_code_offs, 3);
     vstring_strcat(buffer, next != end ? "-" : " ");
     /* Append a clone of the optional enhanced status code. */
     if (dsn_len > 0) {
  VSTRING_SPACE(buffer, dsn_len);
  vstring_strncat(buffer, STR(buffer) + dsn_offs, dsn_len);
  vstring_strcat(buffer, " ");
     }
     line_added = 1;
 }
 /* Append one line of footer text. */
 mac_expand_error = (mac_expand(buffer, cp, MAC_EXP_FLAG_APPEND, filter,
           lookup, context) & MAC_PARSE_ERROR);
 if (mac_expand_error)
     break;
 if (next < end) {
     cp = next + 2;
 } else
     break;
    }
    myfree(saved_template);
    /* Discard appended text after error, or finalize the result. */
    if (mac_expand_error) {
 vstring_truncate(buffer, reply_patch_undo_len);
 VSTRING_TERMINATE(buffer);
    } else if (line_added > 0) {
 STR(buffer)[reply_code_offs + 3] = '-';
    }
    /* Restore CRLF at end. */
    if (crlf_at_end)
 vstring_strcat(buffer, "\r\n");
    return (mac_expand_error ? -2 : 0);
}

#ifdef TEST

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <msg.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <msg_vstream.h>

struct test_case {
    const char *title;
    const char *orig_reply;
    const char *template;
    const char *filter;
    int     expected_status;
    const char *expected_reply;
};

#define NO_FILTER ((char *) 0)
#define NO_TEMPLATE "NO_TEMPLATE"
#define NO_ERROR (0)
#define BAD_SMTP (-1)
#define BAD_MACRO (-2)

static const struct test_case test_cases[] = {
    {"missing reply""", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
    {"long smtp_code""1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
    {"short smtp_code""12 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
    {"good+bad smtp_code""321 foo\r\n1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
    {"1-line no dsn""550 Foo""\\c footer", NO_FILTER, NO_ERROR, "550 Foo footer"},
    {"1-line no dsn""550 Foo""Bar", NO_FILTER, NO_ERROR, "550-Foo\r\n550 Bar"},
    {"2-line no dsn""550-Foo\r\n550 Bar""Baz", NO_FILTER, NO_ERROR, "550-Foo\r\n550-Bar\r\n550 Baz"},
    {"1-line with dsn""550 5.1.1 Foo""Bar", NO_FILTER, NO_ERROR, "550-5.1.1 Foo\r\n550 5.1.1 Bar"},
    {"2-line with dsn""550-5.1.1 Foo\r\n450 4.1.1 Bar""Baz", NO_FILTER, NO_ERROR, "550-5.1.1 Foo\r\n450-4.1.1 Bar\r\n450 4.1.1 Baz"},
    {"bad macro""220 myhostname""\\c ${whatever", NO_FILTER, BAD_MACRO, 0},
    {"bad macroCRLF""220 myhostname\r\n""\\c ${whatever", NO_FILTER, BAD_MACRO, 0},
    {"good macro""220 myhostname""\\c $whatever", NO_FILTER, NO_ERROR, "220 myhostname DUMMY"},
    {"good macroCRLF""220 myhostname\r\n""\\c $whatever", NO_FILTER, NO_ERROR, "220 myhostname DUMMY\r\n"},
    0,
};

static const char *lookup(const char *name, int unused_mode, void *context)
{
    return "DUMMY";
}

int     main(int argc, char **argv)
{
    const struct test_case *tp;
    int     status;
    VSTRING *buf = vstring_alloc(10);
    void   *context = 0;

    msg_vstream_init(argv[0], VSTREAM_ERR);

    for (tp = test_cases; tp->title != 0; tp++) {
 vstring_strcpy(buf, tp->orig_reply);
 status = smtp_reply_footer(buf, 0, tp->template, tp->filter,
       lookup, context);
 if (status != tp->expected_status) {
     msg_warn("test \"%s\": status %d, expected %d",
       tp->title, status, tp->expected_status);
 } else if (status < 0 && strcmp(STR(buf), tp->orig_reply) != 0) {
     msg_warn("test \"%s\": result \"%s\", expected \"%s\"",
       tp->title, STR(buf), tp->orig_reply);
 } else if (status == 0 && strcmp(STR(buf), tp->expected_reply) != 0) {
     msg_warn("test \"%s\": result \"%s\", expected \"%s\"",
       tp->title, STR(buf), tp->expected_reply);
 } else {
     msg_info("test \"%s\": pass", tp->title);
 }
    }
    vstring_free(buf);
    exit(0);
}

#endif

Messung V0.5 in Prozent
C=89 H=98 G=93

¤ 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.