/*++ /* NAME /* dsn_util 3 /* SUMMARY /* DSN status parsing routines /* SYNOPSIS /* #include /* /* #define DSN_SIZE ... /* /* typedef struct { ... } DSN_BUF; /* /* typedef struct { /* .in +4 /* DSN_STAT dsn; /* RFC 3463 status */ /* const char *text; /* Free text */ /* .in -4 /* } DSN_SPLIT; /* /* DSN_SPLIT *dsn_split(dp, def_dsn, text) /* DSN_SPLIT *dp; /* const char *def_dsn; /* const char *text; /* /* char *dsn_prepend(def_dsn, text) /* const char *def_dsn; /* const char *text; /* /* size_t dsn_valid(text) /* const char *text; /* /* void DSN_UPDATE(dsn_buf, dsn, len) /* DSN_BUF dsn_buf; /* const char *dsn; /* size_t len; /* /* const char *DSN_CODE(dsn_buf) /* DSN_BUF dsn_buf; /* /* char *DSN_CLASS(dsn_buf) /* DSN_BUF dsn_buf; /* DESCRIPTION /* The functions in this module manipulate pairs of RFC 3463 /* status codes and descriptive free text. /* /* dsn_split() splits text into an RFC 3463 status code and /* descriptive free text. When the text does not start with /* a status code, the specified default status code is used /* instead. Whitespace before the optional status code or /* text is skipped. dsn_split() returns a copy of the RFC /* 3463 status code, and returns a pointer to (not copy of) /* the remainder of the text. The result value is the first /* argument. /* /* dsn_prepend() prepends the specified default RFC 3463 status /* code to the specified text if no status code is present in /* the text. This function produces the same result as calling /* concatenate() with the results from dsn_split(). The result /* should be passed to myfree(). Whitespace before the optional /* status code or text is skipped. /* /* dsn_valid() returns the length of the RFC 3463 status code /* at the beginning of text, or zero. It does not skip initial /* whitespace. /* /* Arguments: /* .IP def_dsn /* Null-terminated default RFC 3463 status code that will be /* used when the free text does not start with one. /* .IP dp /* Pointer to storage for copy of DSN status code, and for /* pointer to free text. /* .IP dsn /* Null-terminated RFC 3463 status code. /* .IP text /* Null-terminated free text. /* SEE ALSO /* msg(3) diagnostics interface /* DIAGNOSTICS /* Panic: invalid default DSN code. /* 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 /*--*/ /* System library. */ #include #include #include #include /* Utility library. */ #include #include #include #include /* Global library. */ #include /* dsn_valid - check RFC 3463 enhanced status code, return length or zero */ size_t dsn_valid(const char *text) { const unsigned char *cp = (unsigned char *) text; size_t len; /* First portion is one digit followed by dot. */ if ((cp[0] != '2' && cp[0] != '4' && cp[0] != '5') || cp[1] != '.') return (0); /* Second portion is 1-3 digits followed by dot. */ cp += 2; if ((len = strspn((char *) cp, "0123456789")) < 1 || len > DSN_DIGS2 || cp[len] != '.') return (0); /* Last portion is 1-3 digits followed by end-of-string or whitespace. */ cp += len + 1; if ((len = strspn((char *) cp, "0123456789")) < 1 || len > DSN_DIGS3 || (cp[len] != 0 && !ISSPACE(cp[len]))) return (0); return (((char *) cp - text) + len); } /* dsn_split - split text into DSN and text */ DSN_SPLIT *dsn_split(DSN_SPLIT *dp, const char *def_dsn, const char *text) { const char *myname = "dsn_split"; const char *cp = text; size_t len; /* * Look for an optional RFC 3463 enhanced status code. * * XXX If we want to enforce that the first digit of the status code in the * text matches the default status code, then pipe_command() needs to be * changed. It currently auto-detects the reply code without knowing in * advance if the result will start with '4' or '5'. */ while (ISSPACE(*cp)) cp++; if ((len = dsn_valid(cp)) > 0) { strncpy(dp->dsn.data, cp, len); dp->dsn.data[len] = 0; cp += len + 1; } else if ((len = dsn_valid(def_dsn)) > 0) { strncpy(dp->dsn.data, def_dsn, len); dp->dsn.data[len] = 0; } else { msg_panic("%s: bad default status \"%s\"", myname, def_dsn); } /* * The remainder is free text. */ while (ISSPACE(*cp)) cp++; dp->text = cp; return (dp); } /* dsn_prepend - prepend optional status to text, result on heap */ char *dsn_prepend(const char *def_dsn, const char *text) { DSN_SPLIT dp; dsn_split(&dp, def_dsn, text); return (concatenate(DSN_STATUS(dp.dsn), " ", dp.text, (char *) 0)); }