1 /* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
2
3 #include "test-lib.h"
4 #include "str.h"
5 #include "array.h"
6 #include "test-common.h"
7 #include "smtp-common.h"
8 #include "smtp-address.h"
9 #include "smtp-params.h"
10
11 static const char *test_extensions[] = { "FROP", "FRUP", NULL };
12
13 static struct smtp_address test_address1 =
14 { .localpart = NULL, .domain = NULL };
15 static struct smtp_address test_address2 =
16 { .localpart = "user+detail", .domain = NULL };
17 static struct smtp_address test_address3 =
18 { .localpart = "e=mc2", .domain = "example.com" };
19
20 static struct smtp_param test_params1[] = {
21 { .keyword = "FROP", .value = "friep" }
22 };
23 static struct smtp_param test_params2[] = {
24 { .keyword = "FROP", .value = "friep" },
25 { .keyword = "FRUP", .value = "frml" }
26 };
27
28 static struct buffer test_params_buffer1 = {
29 .data = (void*)&test_params1,
30 .used = sizeof(test_params1)
31 };
32 static struct buffer test_params_buffer2 = {
33 .data = (void*)&test_params2,
34 .used = sizeof(test_params2)
35 };
36
37 /* Valid mail params tests */
38
39 struct valid_mail_params_parse_test {
40 const char *input, *output;
41
42 enum smtp_capability caps;
43 const char *const *extensions;
44 const char *const *body_extensions;
45
46 struct smtp_params_mail params;
47 };
48
49 static const struct valid_mail_params_parse_test
50 valid_mail_params_parse_tests[] = {
51 /* AUTH */
52 {
53 .input = "AUTH=<>",
54 .caps = SMTP_CAPABILITY_AUTH,
55 .params = {
56 .auth = &test_address1
57 }
58 },
59 {
60 .input = "AUTH=user+2Bdetail",
61 .caps = SMTP_CAPABILITY_AUTH,
62 .params = {
63 .auth = &test_address2
64 }
65 },
66 {
67 .input = "AUTH=e+3Dmc2@example.com",
68 .caps = SMTP_CAPABILITY_AUTH,
69 .params = {
70 .auth = &test_address3
71 }
72 },
73 /* BODY */
74 {
75 .input = "",
76 .caps = SMTP_CAPABILITY_8BITMIME,
77 .params = {
78 .body = {
79 .type = SMTP_PARAM_MAIL_BODY_TYPE_UNSPECIFIED,
80 }
81 }
82 },
83 {
84 .input = "BODY=7BIT",
85 .caps = SMTP_CAPABILITY_8BITMIME,
86 .params = {
87 .body = {
88 .type = SMTP_PARAM_MAIL_BODY_TYPE_7BIT,
89 }
90 }
91 },
92 {
93 .input = "BODY=8BITMIME",
94 .caps = SMTP_CAPABILITY_8BITMIME,
95 .params = {
96 .body = {
97 .type = SMTP_PARAM_MAIL_BODY_TYPE_8BITMIME,
98 }
99 }
100 },
101 {
102 .input = "BODY=BINARYMIME",
103 .caps = SMTP_CAPABILITY_8BITMIME |
104 SMTP_CAPABILITY_BINARYMIME |
105 SMTP_CAPABILITY_CHUNKING,
106 .params = {
107 .body = {
108 .type = SMTP_PARAM_MAIL_BODY_TYPE_BINARYMIME,
109 }
110 }
111 },
112 {
113 .input = "BODY=FROP",
114 .caps = SMTP_CAPABILITY_8BITMIME |
115 SMTP_CAPABILITY_BINARYMIME |
116 SMTP_CAPABILITY_CHUNKING,
117 .body_extensions = test_extensions,
118 .params = {
119 .body = {
120 .type = SMTP_PARAM_MAIL_BODY_TYPE_EXTENSION,
121 .ext = "FROP"
122 }
123 }
124 },
125 /* ENVID */
126 {
127 .input = "",
128 .caps = SMTP_CAPABILITY_DSN,
129 .params = {
130 .envid = NULL,
131 }
132 },
133 {
134 .input = "ENVID=",
135 .caps = SMTP_CAPABILITY_DSN,
136 .params = {
137 .envid = "",
138 }
139 },
140 {
141 .input = "ENVID=AABBCCDD",
142 .caps = SMTP_CAPABILITY_DSN,
143 .params = {
144 .envid = "AABBCCDD",
145 }
146 },
147 {
148 .input = "ENVID=AA+2BBB+3DCC+2BDD",
149 .caps = SMTP_CAPABILITY_DSN,
150 .params = {
151 .envid = "AA+BB=CC+DD",
152 }
153 },
154 /* RET */
155 {
156 .input = "",
157 .caps = SMTP_CAPABILITY_DSN,
158 .params = {
159 .ret = SMTP_PARAM_MAIL_RET_UNSPECIFIED,
160 }
161 },
162 {
163 .input = "RET=HDRS",
164 .caps = SMTP_CAPABILITY_DSN,
165 .params = {
166 .ret = SMTP_PARAM_MAIL_RET_HDRS,
167 }
168 },
169 {
170 .input = "RET=FULL",
171 .caps = SMTP_CAPABILITY_DSN,
172 .params = {
173 .ret = SMTP_PARAM_MAIL_RET_FULL,
174 }
175 },
176 /* SIZE */
177 {
178 .input = "",
179 .caps = SMTP_CAPABILITY_SIZE,
180 .params = {
181 .size = 0
182 }
183 },
184 {
185 .input = "SIZE=267914296",
186 .caps = SMTP_CAPABILITY_SIZE,
187 .params = {
188 .size = 267914296
189 }
190 },
191 /* <extensions> */
192 {
193 .input = "FROP=friep",
194 .caps = SMTP_CAPABILITY_SIZE,
195 .extensions = test_extensions,
196 .params = {
197 .extra_params = {
198 .arr = {
199 .buffer = &test_params_buffer1,
200 .element_size = sizeof(struct smtp_param)
201 }
202 }
203 }
204 },
205 {
206 .input = "FROP=friep FRUP=frml",
207 .extensions = test_extensions,
208 .params = {
209 .extra_params = {
210 .arr = {
211 .buffer = &test_params_buffer2,
212 .element_size = sizeof(struct smtp_param)
213 }
214 }
215 }
216 }
217 };
218
219 unsigned int valid_mail_params_parse_test_count =
220 N_ELEMENTS(valid_mail_params_parse_tests);
221
222 static void
test_smtp_mail_params_auth(const struct smtp_params_mail * test,const struct smtp_params_mail * parsed)223 test_smtp_mail_params_auth(const struct smtp_params_mail *test,
224 const struct smtp_params_mail *parsed)
225 {
226 if (parsed->auth->localpart == NULL ||
227 test->auth->localpart == NULL) {
228 test_out(t_strdup_printf("params.auth->localpart = %s",
229 parsed->auth->localpart),
230 (parsed->auth->localpart == test->auth->localpart));
231 } else {
232 test_out(t_strdup_printf("params.auth->localpart = \"%s\"",
233 parsed->auth->localpart),
234 strcmp(parsed->auth->localpart,
235 test->auth->localpart) == 0);
236 }
237 if (parsed->auth->domain == NULL ||
238 test->auth->domain == NULL) {
239 test_out(t_strdup_printf("params.auth->domain = %s",
240 parsed->auth->domain),
241 (parsed->auth->domain == test->auth->domain));
242 } else {
243 test_out(t_strdup_printf("params.auth->domain = \"%s\"",
244 parsed->auth->domain),
245 strcmp(parsed->auth->domain,
246 test->auth->domain) == 0);
247 }
248 }
249
250 static void
test_smtp_mail_params_body(const struct smtp_params_mail * test,const struct smtp_params_mail * parsed)251 test_smtp_mail_params_body(const struct smtp_params_mail *test,
252 const struct smtp_params_mail *parsed)
253 {
254 const char *type_name = NULL;
255
256 switch (parsed->body.type) {
257 case SMTP_PARAM_MAIL_BODY_TYPE_UNSPECIFIED:
258 type_name = "<UNSPECIFIED>";
259 break;
260 case SMTP_PARAM_MAIL_BODY_TYPE_7BIT:
261 type_name = "7BIT";
262 break;
263 case SMTP_PARAM_MAIL_BODY_TYPE_8BITMIME:
264 type_name = "8BITMIME";
265 break;
266 case SMTP_PARAM_MAIL_BODY_TYPE_BINARYMIME:
267 type_name = "BINARYMIME";
268 break;
269 case SMTP_PARAM_MAIL_BODY_TYPE_EXTENSION:
270 type_name = parsed->body.ext;
271 break;
272 default:
273 i_unreached();
274 }
275
276 test_out(t_strdup_printf("params.body.type = %s", type_name),
277 (parsed->body.type == test->body.type &&
278 (parsed->body.type != SMTP_PARAM_MAIL_BODY_TYPE_EXTENSION ||
279 (parsed->body.ext != NULL &&
280 strcmp(parsed->body.ext, test->body.ext) == 0))));
281 }
282
283 static void
test_smtp_mail_params_envid(const struct smtp_params_mail * test,const struct smtp_params_mail * parsed)284 test_smtp_mail_params_envid(const struct smtp_params_mail *test,
285 const struct smtp_params_mail *parsed)
286 {
287 if (parsed->envid == NULL || test->envid == NULL) {
288 test_out(t_strdup_printf("params.auth->localpart = %s",
289 parsed->envid),
290 (parsed->envid == test->envid));
291 } else {
292 test_out(t_strdup_printf("params.auth->localpart = \"%s\"",
293 parsed->envid),
294 strcmp(parsed->envid, test->envid) == 0);
295 }
296 }
297
298 static void
test_smtp_mail_params_ret(const struct smtp_params_mail * test,const struct smtp_params_mail * parsed)299 test_smtp_mail_params_ret(const struct smtp_params_mail *test,
300 const struct smtp_params_mail *parsed)
301 {
302 const char *ret_name = NULL;
303
304 switch (parsed->ret) {
305 case SMTP_PARAM_MAIL_RET_UNSPECIFIED:
306 ret_name = "<UNSPECIFIED>";
307 break;
308 case SMTP_PARAM_MAIL_RET_HDRS:
309 ret_name = "HDRS";
310 break;
311 case SMTP_PARAM_MAIL_RET_FULL:
312 ret_name = "FULL";
313 break;
314 default:
315 i_unreached();
316 }
317
318 test_out(t_strdup_printf("params.ret = %s", ret_name),
319 parsed->ret == test->ret);
320 }
321
322 static void
test_smtp_mail_params_size(const struct smtp_params_mail * test,const struct smtp_params_mail * parsed)323 test_smtp_mail_params_size(const struct smtp_params_mail *test,
324 const struct smtp_params_mail *parsed)
325 {
326 test_out(t_strdup_printf("params.size = %"PRIuUOFF_T, parsed->size),
327 parsed->size == test->size);
328 }
329
330 static void
test_smtp_mail_params_extensions(const struct smtp_params_mail * test,const struct smtp_params_mail * parsed)331 test_smtp_mail_params_extensions(const struct smtp_params_mail *test,
332 const struct smtp_params_mail *parsed)
333 {
334 const struct smtp_param *tparam, *pparam;
335 unsigned int i;
336
337 if (!array_is_created(&test->extra_params) ||
338 array_count(&test->extra_params) == 0) {
339 test_out(t_strdup_printf("params.extra_params.count = %u",
340 (!array_is_created(&parsed->extra_params) ?
341 0 : array_count(&parsed->extra_params))),
342 (!array_is_created(&parsed->extra_params) ||
343 array_count(&parsed->extra_params) == 0));
344 return;
345 }
346
347 if (!array_is_created(&parsed->extra_params) ||
348 array_count(&parsed->extra_params) == 0) {
349 test_out("params.extra_params.count = 0", FALSE);
350 return;
351 }
352
353 if (array_count(&test->extra_params) !=
354 array_count(&parsed->extra_params)) {
355 test_out(t_strdup_printf("params.extra_params.count = %u",
356 (!array_is_created(&parsed->extra_params) ?
357 0 : array_count(&parsed->extra_params))), FALSE);
358 return;
359 }
360
361 for (i = 0; i < array_count(&test->extra_params); i++) {
362 tparam = array_idx(&test->extra_params, i);
363 pparam = array_idx(&parsed->extra_params, i);
364
365 test_out(t_strdup_printf("params.extra_params[%u] = [\"%s\"=\"%s\"]",
366 i, pparam->keyword, pparam->value),
367 strcmp(pparam->keyword, tparam->keyword) == 0 &&
368 ((pparam->value == NULL && tparam->value == NULL) ||
369 (pparam->value != NULL && tparam->value != NULL &&
370 strcmp(pparam->value, tparam->value) == 0)));
371 }
372 }
373
test_smtp_mail_params_parse_valid(void)374 static void test_smtp_mail_params_parse_valid(void)
375 {
376 unsigned int i;
377
378 for (i = 0; i < valid_mail_params_parse_test_count; i++) T_BEGIN {
379 const struct valid_mail_params_parse_test *test;
380 struct smtp_params_mail params;
381 enum smtp_param_parse_error error_code;
382 const char *error = NULL, *output;
383 int ret;
384
385 test = &valid_mail_params_parse_tests[i];
386 ret = smtp_params_mail_parse(pool_datastack_create(),
387 test->input, test->caps, test->extensions,
388 test->body_extensions, ¶ms, &error_code, &error);
389
390 test_begin(t_strdup_printf("smtp mail params valid [%d]", i));
391 test_out_reason(t_strdup_printf("parse(\"%s\")", test->input),
392 ret >= 0, error);
393
394 if (ret >= 0) {
395 string_t *encoded;
396
397 /* AUTH */
398 if ((test->caps & SMTP_CAPABILITY_AUTH) != 0)
399 test_smtp_mail_params_auth(&test->params, ¶ms);
400 /* BODY */
401 if ((test->caps & SMTP_CAPABILITY_8BITMIME) != 0 ||
402 (test->caps & SMTP_CAPABILITY_BINARYMIME) != 0)
403 test_smtp_mail_params_body(&test->params, ¶ms);
404 /* ENVID */
405 if ((test->caps & SMTP_CAPABILITY_DSN) != 0)
406 test_smtp_mail_params_envid(&test->params, ¶ms);
407 /* RET */
408 if ((test->caps & SMTP_CAPABILITY_DSN) != 0)
409 test_smtp_mail_params_ret(&test->params, ¶ms);
410 /* SIZE */
411 if ((test->caps & SMTP_CAPABILITY_SIZE) != 0)
412 test_smtp_mail_params_size(&test->params, ¶ms);
413 /* <extensions> */
414 if (test->extensions != NULL)
415 test_smtp_mail_params_extensions(&test->params, ¶ms);
416
417 encoded = t_str_new(256);
418 smtp_params_mail_write(encoded, test->caps,
419 test->extensions, ¶ms);
420
421 output = (test->output == NULL ? test->input : test->output);
422 test_out(t_strdup_printf("encode() = \"%s\"",
423 str_c(encoded)),
424 strcmp(str_c(encoded), output) == 0);
425 }
426 test_end();
427 } T_END;
428 }
429
430 /* Invalid mail params tests */
431
432 struct invalid_mail_params_parse_test {
433 const char *input;
434
435 enum smtp_capability caps;
436 const char *const *extensions;
437 };
438
439 static const struct invalid_mail_params_parse_test
440 invalid_mail_params_parse_tests[] = {
441 /* AUTH */
442 {
443 .input = "AUTH=<>",
444 },
445 {
446 .input = "AUTH=++",
447 .caps = SMTP_CAPABILITY_AUTH
448 },
449 /* BODY */
450 {
451 .input = "BODY=8BITMIME",
452 },
453 {
454 .input = "BODY=BINARYMIME",
455 },
456 {
457 .input = "BODY=BINARYMIME",
458 .caps = SMTP_CAPABILITY_BINARYMIME
459 },
460 {
461 .input = "BODY=FROP",
462 .caps = SMTP_CAPABILITY_8BITMIME
463 },
464 /* ENVID */
465 {
466 .input = "ENVID=AABBCC",
467 },
468 {
469 .input = "ENVID=++",
470 .caps = SMTP_CAPABILITY_DSN
471 },
472 /* RET */
473 {
474 .input = "RET=FULL",
475 },
476 {
477 .input = "RET=HDR",
478 },
479 {
480 .input = "RET=FROP",
481 .caps = SMTP_CAPABILITY_DSN
482 },
483 /* SIZE */
484 {
485 .input = "SIZE=13",
486 },
487 {
488 .input = "SIZE=ABC",
489 .caps = SMTP_CAPABILITY_SIZE
490 }
491 };
492
493 unsigned int invalid_mail_params_parse_test_count =
494 N_ELEMENTS(invalid_mail_params_parse_tests);
495
test_smtp_mail_params_parse_invalid(void)496 static void test_smtp_mail_params_parse_invalid(void)
497 {
498 unsigned int i;
499
500 for (i = 0; i < invalid_mail_params_parse_test_count; i++) T_BEGIN {
501 const struct invalid_mail_params_parse_test *test;
502 struct smtp_params_mail params;
503 enum smtp_param_parse_error error_code;
504 const char *error = NULL;
505 int ret;
506
507 test = &invalid_mail_params_parse_tests[i];
508 ret = smtp_params_mail_parse(pool_datastack_create(),
509 test->input, test->caps,
510 test->extensions, NULL,
511 ¶ms, &error_code, &error);
512
513 test_begin(t_strdup_printf("smtp mail params invalid [%d]", i));
514 test_out_reason(t_strdup_printf("parse(\"%s\")", test->input),
515 ret < 0, error);
516 test_end();
517 } T_END;
518 }
519
520 /* Valid rcpt params tests */
521
522 struct valid_rcpt_params_parse_test {
523 const char *input, *output;
524
525 enum smtp_param_rcpt_parse_flags flags;
526 enum smtp_capability caps;
527 const char *const *extensions;
528
529 struct smtp_params_rcpt params;
530 };
531
532 static const struct valid_rcpt_params_parse_test
533 valid_rcpt_params_parse_tests[] = {
534 /* ORCPT */
535 {
536 .input = "ORCPT=rfc822;e+3Dmc2@example.com",
537 .caps = SMTP_CAPABILITY_DSN,
538 .params = {
539 .orcpt = {
540 .addr = &test_address3
541 }
542 }
543 },
544 {
545 .input = "ORCPT=rfc822;<e+3Dmc2@example.com>",
546 .output = "ORCPT=rfc822;e+3Dmc2@example.com",
547 .caps = SMTP_CAPABILITY_DSN,
548 .params = {
549 .orcpt = {
550 .addr = &test_address3
551 }
552 }
553 },
554 {
555 .input = "ORCPT=rfc822;user+2Bdetail",
556 .flags = SMTP_PARAM_RCPT_FLAG_ORCPT_ALLOW_LOCALPART,
557 .caps = SMTP_CAPABILITY_DSN,
558 .params = {
559 .orcpt = {
560 .addr = &test_address2
561 }
562 }
563 },
564 {
565 .input = "ORCPT=rfc822;<user+2Bdetail>",
566 .output = "ORCPT=rfc822;user+2Bdetail",
567 .flags = SMTP_PARAM_RCPT_FLAG_ORCPT_ALLOW_LOCALPART,
568 .caps = SMTP_CAPABILITY_DSN,
569 .params = {
570 .orcpt = {
571 .addr = &test_address2
572 }
573 }
574 },
575 /* NOTIFY */
576 {
577 .input = "",
578 .caps = SMTP_CAPABILITY_DSN,
579 .params = {
580 .notify = SMTP_PARAM_RCPT_NOTIFY_UNSPECIFIED,
581 }
582 },
583 {
584 .input = "NOTIFY=SUCCESS",
585 .caps = SMTP_CAPABILITY_DSN,
586 .params = {
587 .notify = SMTP_PARAM_RCPT_NOTIFY_SUCCESS,
588 }
589 },
590 {
591 .input = "NOTIFY=FAILURE",
592 .caps = SMTP_CAPABILITY_DSN,
593 .params = {
594 .notify = SMTP_PARAM_RCPT_NOTIFY_FAILURE,
595 }
596 },
597 {
598 .input = "NOTIFY=DELAY",
599 .caps = SMTP_CAPABILITY_DSN,
600 .params = {
601 .notify = SMTP_PARAM_RCPT_NOTIFY_DELAY,
602 }
603 },
604 {
605 .input = "NOTIFY=NEVER",
606 .caps = SMTP_CAPABILITY_DSN,
607 .params = {
608 .notify = SMTP_PARAM_RCPT_NOTIFY_NEVER,
609 }
610 },
611 {
612 .input = "NOTIFY=SUCCESS,FAILURE,DELAY",
613 .caps = SMTP_CAPABILITY_DSN,
614 .params = {
615 .notify = SMTP_PARAM_RCPT_NOTIFY_SUCCESS |
616 SMTP_PARAM_RCPT_NOTIFY_FAILURE |
617 SMTP_PARAM_RCPT_NOTIFY_DELAY,
618 }
619 },
620 /* <extensions> */
621 {
622 .input = "FROP=friep",
623 .caps = SMTP_CAPABILITY_SIZE,
624 .extensions = test_extensions,
625 .params = {
626 .extra_params = {
627 .arr = {
628 .buffer = &test_params_buffer1,
629 .element_size = sizeof(struct smtp_param)
630 }
631 }
632 }
633 },
634 {
635 .input = "FROP=friep FRUP=frml",
636 .extensions = test_extensions,
637 .params = {
638 .extra_params = {
639 .arr = {
640 .buffer = &test_params_buffer2,
641 .element_size = sizeof(struct smtp_param)
642 }
643 }
644 }
645 }
646 };
647
648 unsigned int valid_rcpt_params_parse_test_count =
649 N_ELEMENTS(valid_rcpt_params_parse_tests);
650
651 static void
test_smtp_rcpt_params_orcpt(const struct smtp_params_rcpt * test,const struct smtp_params_rcpt * parsed)652 test_smtp_rcpt_params_orcpt(const struct smtp_params_rcpt *test,
653 const struct smtp_params_rcpt *parsed)
654 {
655 if (parsed->orcpt.addr == NULL) {
656 test_out("params.orcpt.addr = NULL",
657 test->orcpt.addr == NULL);
658 return;
659 }
660
661 if (parsed->orcpt.addr->localpart == NULL ||
662 test->orcpt.addr->localpart == NULL) {
663 test_out(t_strdup_printf("params.orcpt.addr->localpart = %s",
664 parsed->orcpt.addr->localpart),
665 (parsed->orcpt.addr->localpart ==
666 test->orcpt.addr->localpart));
667 } else {
668 test_out(t_strdup_printf("params.orcpt.addr->localpart = \"%s\"",
669 parsed->orcpt.addr->localpart),
670 strcmp(parsed->orcpt.addr->localpart,
671 test->orcpt.addr->localpart) == 0);
672 }
673 if (parsed->orcpt.addr->domain == NULL ||
674 test->orcpt.addr->domain == NULL) {
675 test_out(t_strdup_printf("params.orcpt.addr->domain = %s",
676 parsed->orcpt.addr->domain),
677 (parsed->orcpt.addr->domain ==
678 test->orcpt.addr->domain));
679 } else {
680 test_out(t_strdup_printf("params.orcpt.addr->domain = \"%s\"",
681 parsed->orcpt.addr->domain),
682 strcmp(parsed->orcpt.addr->domain,
683 test->orcpt.addr->domain) == 0);
684 }
685 }
686
687
688 static void
test_smtp_rcpt_params_notify(const struct smtp_params_rcpt * test,const struct smtp_params_rcpt * parsed)689 test_smtp_rcpt_params_notify(const struct smtp_params_rcpt *test,
690 const struct smtp_params_rcpt *parsed)
691 {
692 string_t *notify_name;
693
694 notify_name = t_str_new(64);
695 if (parsed->notify == 0) {
696 str_append(notify_name, "<UNSPECIFIED>");
697 } else if ((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_NEVER) != 0) {
698 i_assert((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_SUCCESS) == 0);
699 i_assert((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_FAILURE) == 0);
700 i_assert((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_DELAY) == 0);
701 str_append(notify_name, "NEVER");
702 } else {
703 if ((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_SUCCESS) != 0)
704 str_append(notify_name, "SUCCESS");
705 if ((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_FAILURE) != 0) {
706 if (str_len(notify_name) > 0)
707 str_append_c(notify_name, ',');
708 str_append(notify_name, "FAILURE");
709 }
710 if ((parsed->notify & SMTP_PARAM_RCPT_NOTIFY_DELAY) != 0) {
711 if (str_len(notify_name) > 0)
712 str_append_c(notify_name, ',');
713 str_append(notify_name, "DELAY");
714 }
715 }
716
717 test_out(t_strdup_printf("params.notify = %s", str_c(notify_name)),
718 parsed->notify == test->notify);
719 }
720
721 static void
test_smtp_rcpt_params_extensions(const struct smtp_params_rcpt * test,const struct smtp_params_rcpt * parsed)722 test_smtp_rcpt_params_extensions(const struct smtp_params_rcpt *test,
723 const struct smtp_params_rcpt *parsed)
724 {
725 const struct smtp_param *tparam, *pparam;
726 unsigned int i;
727
728 if (!array_is_created(&test->extra_params) ||
729 array_count(&test->extra_params) == 0) {
730 test_out(t_strdup_printf("params.extra_params.count = %u",
731 (!array_is_created(&parsed->extra_params) ?
732 0 : array_count(&parsed->extra_params))),
733 (!array_is_created(&parsed->extra_params) ||
734 array_count(&parsed->extra_params) == 0));
735 return;
736 }
737
738 if (!array_is_created(&parsed->extra_params) ||
739 array_count(&parsed->extra_params) == 0) {
740 test_out("params.extra_params.count = 0", FALSE);
741 return;
742 }
743
744 if (array_count(&test->extra_params) !=
745 array_count(&parsed->extra_params)) {
746 test_out(t_strdup_printf("params.extra_params.count = %u",
747 (!array_is_created(&parsed->extra_params) ? 0 :
748 array_count(&parsed->extra_params))), FALSE);
749 return;
750 }
751
752 for (i = 0; i < array_count(&test->extra_params); i++) {
753 tparam = array_idx(&test->extra_params, i);
754 pparam = array_idx(&parsed->extra_params, i);
755
756 test_out(t_strdup_printf("params.extra_params[%u] = [\"%s\"=\"%s\"]",
757 i, pparam->keyword, pparam->value),
758 strcmp(pparam->keyword, tparam->keyword) == 0 &&
759 ((pparam->value == NULL && tparam->value == NULL) ||
760 (pparam->value != NULL && tparam->value != NULL &&
761 strcmp(pparam->value, tparam->value) == 0)));
762 }
763 }
764
test_smtp_rcpt_params_parse_valid(void)765 static void test_smtp_rcpt_params_parse_valid(void)
766 {
767 unsigned int i;
768
769 for (i = 0; i < valid_rcpt_params_parse_test_count; i++) T_BEGIN {
770 const struct valid_rcpt_params_parse_test *test;
771 struct smtp_params_rcpt params;
772 enum smtp_param_parse_error error_code;
773 const char *error = NULL, *output;
774 int ret;
775
776 test = &valid_rcpt_params_parse_tests[i];
777 ret = smtp_params_rcpt_parse(pool_datastack_create(),
778 test->input, test->flags,
779 test->caps, test->extensions,
780 ¶ms, &error_code, &error);
781
782 test_begin(t_strdup_printf("smtp rcpt params valid [%d]", i));
783 test_out_reason(t_strdup_printf("parse(\"%s\")",
784 test->input), ret >= 0, error);
785
786 if (ret >= 0) {
787 string_t *encoded;
788
789 /* ORCPT */
790 if ((test->caps & SMTP_CAPABILITY_DSN) != 0)
791 test_smtp_rcpt_params_orcpt(&test->params, ¶ms);
792 /* NOTIFY */
793 if ((test->caps & SMTP_CAPABILITY_DSN) != 0)
794 test_smtp_rcpt_params_notify(&test->params, ¶ms);
795 /* <extensions> */
796 if (test->extensions != NULL)
797 test_smtp_rcpt_params_extensions(&test->params, ¶ms);
798
799 encoded = t_str_new(256);
800 smtp_params_rcpt_write(encoded, test->caps,
801 test->extensions, ¶ms);
802
803 output = (test->output == NULL ? test->input : test->output);
804 test_out(t_strdup_printf("encode() = \"%s\"",
805 str_c(encoded)),
806 strcmp(str_c(encoded), output) == 0);
807 }
808 test_end();
809 } T_END;
810 }
811
812 /* Invalid rcpt params tests */
813
814 struct invalid_rcpt_params_parse_test {
815 const char *input;
816
817 enum smtp_param_rcpt_parse_flags flags;
818 enum smtp_capability caps;
819 const char *const *extensions;
820 };
821
822 static const struct invalid_rcpt_params_parse_test
823 invalid_rcpt_params_parse_tests[] = {
824 /* DSN */
825 {
826 .input = "ORCPT=rfc822;frop@example.com",
827 },
828 {
829 .input = "ORCPT=rfc822;<>",
830 .caps = SMTP_CAPABILITY_DSN
831 },
832 {
833 .input = "ORCPT=rfc822;",
834 .caps = SMTP_CAPABILITY_DSN
835 },
836 {
837 .input = "ORCPT=++",
838 .caps = SMTP_CAPABILITY_DSN
839 },
840 {
841 .input = "ORCPT=rfc822;++",
842 .caps = SMTP_CAPABILITY_DSN
843 },
844 {
845 .input = "NOTIFY=SUCCESS",
846 },
847 {
848 .input = "NOTIFY=FROP",
849 .caps = SMTP_CAPABILITY_DSN
850 },
851 {
852 .input = "NOTIFY=NEVER,SUCCESS",
853 .caps = SMTP_CAPABILITY_DSN
854 }
855 };
856
857 unsigned int invalid_rcpt_params_parse_test_count =
858 N_ELEMENTS(invalid_rcpt_params_parse_tests);
859
test_smtp_rcpt_params_parse_invalid(void)860 static void test_smtp_rcpt_params_parse_invalid(void)
861 {
862 unsigned int i;
863
864 for (i = 0; i < invalid_rcpt_params_parse_test_count; i++) T_BEGIN {
865 const struct invalid_rcpt_params_parse_test *test;
866 struct smtp_params_rcpt params;
867 enum smtp_param_parse_error error_code;
868 const char *error = NULL;
869 int ret;
870
871 test = &invalid_rcpt_params_parse_tests[i];
872 ret = smtp_params_rcpt_parse(pool_datastack_create(),
873 test->input, test->flags,
874 test->caps, test->extensions,
875 ¶ms, &error_code, &error);
876
877 test_begin(t_strdup_printf("smtp rcpt params invalid [%d]", i));
878 test_out_reason(t_strdup_printf("parse(\"%s\")", test->input),
879 ret < 0, error);
880 test_end();
881 } T_END;
882 }
883
main(void)884 int main(void)
885 {
886 static void (*test_functions[])(void) = {
887 test_smtp_mail_params_parse_valid,
888 test_smtp_mail_params_parse_invalid,
889 test_smtp_rcpt_params_parse_valid,
890 test_smtp_rcpt_params_parse_invalid,
891 NULL
892 };
893 return test_run(test_functions);
894 }
895