93 #define STR vstring_str
101 const char *myname =
"smtp_reply_footer";
106 ssize_t dsn_offs = -1;
108 ssize_t reply_code_offs = -1;
109 ssize_t reply_patch_undo_len;
110 int mac_expand_error = 0;
112 char *saved_template;
118 msg_panic(
"%s: bad start: %ld", myname, (
long) start);
127 for (cp =
STR(buffer) + start, end = cp + strlen(cp);;) {
129 || (cp[3] !=
' ' && cp[3] !=
'-'))
131 reply_code_offs = cp -
STR(buffer);
132 if ((next = strstr(cp,
"\r\n")) == 0) {
142 if (reply_code_offs < 0)
160 dsn_offs = reply_code_offs + 4;
163 saved_template =
mystrdup(
template);
164 for (cp = saved_template, end = cp + strlen(cp);;) {
165 if ((next = strstr(cp,
"\\n")) != 0) {
170 if (cp == saved_template && strncmp(cp,
"\\c", 2) == 0) {
190 if (mac_expand_error)
199 if (mac_expand_error) {
202 }
else if (line_added > 0) {
203 STR(buffer)[reply_code_offs + 3] =
'-';
208 return (mac_expand_error ? -2 : 0);
223 const char *orig_reply;
224 const char *
template;
227 const char *expected_reply;
230 #define NO_FILTER ((char *) 0)
231 #define NO_TEMPLATE "NO_TEMPLATE"
233 #define BAD_SMTP (-1)
234 #define BAD_MACRO (-2)
236 static const struct test_case test_cases[] = {
237 {
"missing reply",
"", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
238 {
"long smtp_code",
"1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
239 {
"short smtp_code",
"12 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
240 {
"good+bad smtp_code",
"321 foo\r\n1234 foo", NO_TEMPLATE, NO_FILTER, BAD_SMTP, 0},
241 {
"1-line no dsn",
"550 Foo",
"\\c footer", NO_FILTER, NO_ERROR,
"550 Foo footer"},
242 {
"1-line no dsn",
"550 Foo",
"Bar", NO_FILTER, NO_ERROR,
"550-Foo\r\n550 Bar"},
243 {
"2-line no dsn",
"550-Foo\r\n550 Bar",
"Baz", NO_FILTER, NO_ERROR,
"550-Foo\r\n550-Bar\r\n550 Baz"},
244 {
"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"},
245 {
"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"},
246 {
"bad macro",
"220 myhostname",
"\\c ${whatever", NO_FILTER, BAD_MACRO, 0},
247 {
"bad macroCRLF",
"220 myhostname\r\n",
"\\c ${whatever", NO_FILTER, BAD_MACRO, 0},
248 {
"good macro",
"220 myhostname",
"\\c $whatever", NO_FILTER, NO_ERROR,
"220 myhostname DUMMY"},
249 {
"good macroCRLF",
"220 myhostname\r\n",
"\\c $whatever", NO_FILTER, NO_ERROR,
"220 myhostname DUMMY\r\n"},
253 static const char *lookup(
const char *name,
int unused_mode,
void *context)
258 int main(
int argc,
char **argv)
260 const struct test_case *tp;
267 for (tp = test_cases; tp->title != 0; tp++) {
271 if (status != tp->expected_status) {
272 msg_warn(
"test \"%s\": status %d, expected %d",
273 tp->title, status, tp->expected_status);
274 }
else if (status < 0 && strcmp(
STR(buf), tp->orig_reply) != 0) {
275 msg_warn(
"test \"%s\": result \"%s\", expected \"%s\"",
276 tp->title,
STR(buf), tp->orig_reply);
277 }
else if (status == 0 && strcmp(
STR(buf), tp->expected_reply) != 0) {
278 msg_warn(
"test \"%s\": result \"%s\", expected \"%s\"",
279 tp->title,
STR(buf), tp->expected_reply);
281 msg_info(
"test \"%s\": pass", tp->title);
size_t dsn_valid(const char *text)
char * mystrdup(const char *str)
int mac_expand(VSTRING *result, const char *pattern, int flags, const char *filter, MAC_EXP_LOOKUP_FN lookup, void *context)
NORETURN msg_panic(const char *fmt,...)
int main(int argc, char **argv)
VSTRING * vstring_strncat(VSTRING *vp, const char *src, ssize_t len)
VSTRING * vstring_truncate(VSTRING *vp, ssize_t len)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
#define VSTRING_TERMINATE(vp)
const char *(* MAC_EXP_LOOKUP_FN)(const char *, int, void *)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
#define VSTRING_SPACE(vp, len)
VSTRING * vstring_free(VSTRING *vp)
void msg_vstream_init(const char *name, VSTREAM *vp)
#define MAC_EXP_FLAG_APPEND
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
void msg_info(const char *fmt,...)