/* * Queue some data into the input buffer */ static ssize_t mta_queue_data(struct mta_session *s) { char *ln; size_t len, q; q = iobuf_queued(&s->iobuf); while (iobuf_queued(&s->iobuf) < MTA_HIWAT) { if ((ln = fgetln(s->datafp, &len)) == NULL) break; if (ln[len - 1] == '\n') ln[len - 1] = '\0'; iobuf_xfqueue(&s->iobuf, "mta_queue_data", "%s%s\r\n", *ln == '.' ? "." : "", ln); } if (ferror(s->datafp)) { mta_flush_task(s, IMSG_DELIVERY_TEMPFAIL, "Error reading content file", 0, 0); return (-1); } if (feof(s->datafp)) { fclose(s->datafp); s->datafp = NULL; } return (iobuf_queued(&s->iobuf) - q); }
/* * Queue some data into the input buffer */ static ssize_t mta_queue_data(struct mta_session *s) { char *ln; size_t len, q; q = iobuf_queued(&s->iobuf); while (iobuf_queued(&s->iobuf) < MTA_HIWAT) { if ((ln = fgetln(s->datafp, &len)) == NULL) break; if (ln[len - 1] == '\n') ln[len - 1] = '\0'; iobuf_xfqueue(&s->iobuf, "mta_queue_data", "%s%s\r\n", *ln == '.' ? "." : "", ln); } if (ferror(s->datafp)) { mta_status(s, 1, "460 Error reading content file"); return (-1); } if (feof(s->datafp)) { fclose(s->datafp); s->datafp = NULL; } if (s->is_reading) { s->is_reading = 0; io_set_write(&s->io); } return (iobuf_queued(&s->iobuf) - q); }
static void mta_send(struct mta_session *s, char *fmt, ...) { va_list ap; char *p; int len; va_start(ap, fmt); if ((len = vasprintf(&p, fmt, ap)) == -1) fatal("mta: vasprintf"); va_end(ap); log_trace(TRACE_MTA, "mta: %p: >>> %s", s, p); iobuf_xfqueue(&s->iobuf, "mta_send", "%s\r\n", p); free(p); }
void session_respond(struct session *s, char *fmt, ...) { va_list ap; int n, delay; char buf[SMTP_LINE_MAX]; va_start(ap, fmt); n = vsnprintf(buf, sizeof buf, fmt, ap); va_end(ap); if (n == -1 || n >= SMTP_LINE_MAX) fatal("session_respond: line too long"); if (n < 4) fatal("session_respond: response too short"); log_trace(TRACE_SMTP, "smtp: %p: >>> %s", s, buf); iobuf_xfqueue(&s->s_iobuf, "session_respond", "%s\r\n", buf); /* * Log failures. Might be annoying in the long term, but it is a good * development aid for now. */ switch (buf[0]) { case '5': case '4': log_info("%08x: from=<%s@%s>, relay=%s [%s], stat=LocalError (%.*s)", evpid_to_msgid(s->s_msg.id), s->s_msg.sender.user, s->s_msg.sender.domain, s->s_hostname, ss_to_text(&s->s_ss), n, buf); break; } /* Detect multi-line response. */ switch (buf[3]) { case '-': return; case ' ': break; default: fatalx("session_respond: invalid response"); } /* * Deal with request flooding; avoid letting response rate keep up * with incoming request rate. */ s->s_nresp[s->s_state]++; if (s->s_state == S_RCPT) delay = 0; else if ((n = s->s_nresp[s->s_state] - FAST_RESPONSES) > 0) delay = MIN(1 << (n - 1), MAX_RESPONSE_DELAY); else delay = 0; if (delay > 0) { struct timeval tv = { delay, 0 }; io_pause(&s->s_io, IO_PAUSE_OUT); stat_increment("smtp.delays", 1); /* in case session_respond is called multiple times */ evtimer_del(&s->s_ev); evtimer_set(&s->s_ev, session_respond_delayed, s); evtimer_add(&s->s_ev, &tv); } }