bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch#include "lib.h"
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch#include "array.h"
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch#include "str.h"
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch#include "strfuncs.h"
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch#include "smtp-reply.h"
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschvoid smtp_reply_init(struct smtp_reply *reply, unsigned int status,
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char *text)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char **text_lines = t_new(const char *, 2);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch text_lines[0] = text;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch text_lines[1] = NULL;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch i_zero(reply);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch reply->status = status;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch reply->text_lines = text_lines;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschvoid smtp_reply_printf(struct smtp_reply *reply, unsigned int status,
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char *format, ...)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch va_list args;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch va_start(args, format);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch smtp_reply_init(reply, status, t_strdup_vprintf(format, args));
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch va_end(args);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschconst char *
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschsmtp_reply_get_enh_code(const struct smtp_reply *reply)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (reply->enhanced_code.x < 2)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch return NULL;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (reply->enhanced_code.x >= 6)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch return NULL;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch return t_strdup_printf("%u.%u.%u",
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch reply->enhanced_code.x, reply->enhanced_code.y, reply->enhanced_code.z);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschvoid
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschsmtp_reply_write(string_t *out, const struct smtp_reply *reply)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char *prefix, *enh_code;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char *const *lines;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch i_assert(reply->status < 560);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch i_assert(reply->enhanced_code.x < 6);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch prefix = t_strdup_printf("%03u", reply->status);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch enh_code = smtp_reply_get_enh_code(reply);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (reply->text_lines == NULL || *reply->text_lines == NULL) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, prefix);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (enh_code != NULL) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append_c(out, ' ');
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, enh_code);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, " \r\n");
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch return;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch lines = reply->text_lines;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch while (*lines != NULL) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, prefix);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (*(lines+1) == NULL)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append_c(out, ' ');
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch else
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append_c(out, '-');
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (enh_code != NULL) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, enh_code);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append_c(out, ' ');
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, *lines);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(out, "\r\n");
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch lines++;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Boschvoid smtp_reply_write_one_line(string_t *out, const struct smtp_reply *reply)
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch{
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch const char *enh_code = smtp_reply_get_enh_code(reply);
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch const char *const *lines;
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch i_assert(reply->status < 560);
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch i_assert(reply->enhanced_code.x < 6);
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch str_printfa(out, "%03u", reply->status);
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch if (enh_code != NULL) {
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch str_append_c(out, ' ');
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch str_append(out, enh_code);
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch }
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch lines = reply->text_lines;
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch while (*lines != NULL) {
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch str_append_c(out, ' ');
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch str_append(out, *lines);
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch lines++;
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch }
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch}
57b18ecb6fdfa9f8503fc00a6869763e6ffcecb2Stephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschconst char *smtp_reply_log(const struct smtp_reply *reply)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char *const *lines;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch string_t *msg = t_str_new(256);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (smtp_reply_is_remote(reply)) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const char *enh_code = smtp_reply_get_enh_code(reply);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_printfa(msg, "%03u", reply->status);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (enh_code != NULL) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append_c(msg, ' ');
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(msg, enh_code);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch lines = reply->text_lines;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch while (*lines != NULL) {
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch if (str_len(msg) > 0)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append_c(msg, ' ');
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch str_append(msg, *lines);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch lines++;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch }
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch return str_c(msg);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschvoid smtp_reply_copy(pool_t pool, struct smtp_reply *dst,
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const struct smtp_reply *src)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch *dst = *src;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch dst->text_lines = p_strarray_dup(pool, src->text_lines);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Boschstruct smtp_reply *smtp_reply_clone(pool_t pool,
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch const struct smtp_reply *src)
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch{
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch struct smtp_reply *dst;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch dst = p_new(pool, struct smtp_reply, 1);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch smtp_reply_copy(pool, dst, src);
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch return dst;
a8433392e8a5ddfe8a125716f62b2a4dc8f1f01eStephan Bosch}