/* products derived from this software without specific prior written */
/* permission. */
/* */
-/* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND */
-/* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE */
-/* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
-/* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS */
-/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */
-/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF */
-/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS */
-/* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN */
-/* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) */
-/* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF */
-/* THE POSSIBILITY OF SUCH DAMAGE. */
+/* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS */
+/* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
+/* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
+/* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY */
+/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
+/* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS */
+/* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) */
+/* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, */
+/* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN */
+/* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE */
+/* POSSIBILITY OF SUCH DAMAGE. */
+/* */
+/* Copyright (c) 2006-2008 the Authors */
+/* see AUTHORS and source files for details */
/******************************************************************************/
/*
#include "query.h"
#include "policy_tokens.h"
+#include "str.h"
+
+const static_str_t smtp_state_names[SMTP_count] = {
+ { "CONNECT", 7 },
+ { "HELO", 4 },
+ { "MAIL", 4 },
+ { "RCPT", 4 },
+ { "DATA", 4 },
+ { "END-OF-MESSAGE", 14 },
+ { "VRFY", 4 },
+ { "ETRN", 4 },
+};
+
+static const static_str_t static_ESMTP = { "ESMTP", 5 };
+static const static_str_t static_SMTP = { "SMTP", 4 };
bool query_parse(query_t *query, char *p)
{
vtk = policy_tokenize(v, vlen);
switch (policy_tokenize(k, klen)) {
-#define CASE(up, low) case PTK_##up: query->low = v; v[vlen] = '\0'; break;
+#define CASE(up, low) case PTK_##up: query->low.str = v; query->low.len = vlen; v[vlen] = '\0'; break;
CASE(HELO_NAME, helo_name);
CASE(QUEUE_ID, queue_id);
CASE(RECIPIENT_COUNT, recipient_count);
#undef CASE
case PTK_SENDER:
- query->sender = v;
+ query->sender.str = v;
+ query->sender.len = vlen;
v[vlen] = '\0';
- query->sender_domain = memchr(query->sender, '@', vlen);
- if (query->sender_domain != NULL) {
- ++query->sender_domain;
+ query->sender_domain.str = memchr(query->sender.str, '@', vlen);
+ if (query->sender_domain.str != NULL) {
+ ++query->sender_domain.str;
+ query->sender_domain.len = query->sender.len
+ - (query->sender_domain.str - query->sender.str);
}
break;
case PTK_RECIPIENT:
- query->recipient = v;
+ query->recipient.str = v;
+ query->recipient.len = vlen;
v[vlen] = '\0';
- query->recipient_domain = memchr(query->recipient, '@', vlen);
- if (query->recipient_domain != NULL) {
- ++query->recipient_domain;
+ query->recipient_domain.str = memchr(query->recipient.str, '@', vlen);
+ if (query->recipient_domain.str != NULL) {
+ ++query->recipient_domain.str;
+ query->recipient_domain.len = query->recipient.len
+ - (query->recipient_domain.str - query->recipient.str);
+
}
break;
#undef PARSE_CHECK
}
-const char *query_field_for_id(const query_t *query, postlicyd_token id)
+const static_str_t *query_field_for_id(const query_t *query, postlicyd_token id)
{
switch (id) {
#define CASE(Up, Low) \
- case PTK_ ## Up: return query->Low;
+ case PTK_ ## Up: return &query->Low;
CASE(HELO_NAME, helo_name)
CASE(QUEUE_ID, queue_id)
CASE(SENDER, sender)
CASE(ETRN_DOMAIN, etrn_domain)
CASE(STRESS, stress)
#undef CASE
+ case PTK_PROTOCOL_NAME:
+ return query->esmtp ? &static_ESMTP : &static_SMTP;
+
+ case PTK_PROTOCOL_STATE:
+ return &smtp_state_names[query->state];
+
default: return NULL;
}
}
-const char *query_field_for_name(const query_t *query, const char *name)
+const static_str_t *query_field_for_name(const query_t *query, const char *name)
{
postlicyd_token id = policy_tokenize(name, strlen(name));
+ if (id == PTK_UNKNOWN) {
+ warn("unknown query field %s", name);
+ return NULL;
+ }
return query_field_for_id(query, id);
}
+ssize_t query_format(char *dest, size_t len, const char *fmt, const query_t *query)
+{
+ size_t written = 0;
+ size_t pos = 0;
+
+#define WRITE(Src, Len) \
+ do { \
+ size_t __len = (Len); \
+ if (written < len) { \
+ size_t __to_write = MIN(len - written - 1, __len); \
+ memcpy(dest + written, (Src), __to_write); \
+ written += __to_write; \
+ } \
+ pos += __len; \
+ } while (0)
+ while (*fmt != '\0') {
+ const char *next_format = strchr(fmt, '$');
+ while (next_format != NULL && next_format[1] != '{') {
+ next_format = strchr(next_format + 1, '$');
+ }
+ if (next_format == NULL) {
+ next_format = fmt + m_strlen(fmt);
+ }
+ WRITE(fmt, next_format - fmt);
+ fmt = next_format;
+ if (*fmt != '\0') {
+ fmt += 2;
+ next_format = strchr(fmt, '}');
+ if (next_format == NULL) {
+ return -1;
+ }
+
+ postlicyd_token tok = policy_tokenize(fmt, next_format - fmt);
+ if (tok == PTK_UNKNOWN) {
+ warn("unknown field name \"%.*s\"", (int)(next_format - fmt), fmt);
+ }
+ const static_str_t *field = query == NULL ? NULL
+ : query_field_for_id(query, tok);
+ if (field == NULL) {
+ WRITE("(null)", 6);
+ } else {
+ WRITE(field->str, field->len);
+ }
+ fmt = next_format + 1;
+ }
+ }
+
+ if (written > 0 && len > 0) {
+ dest[written] = '\0';
+ }
+ return pos;
+}
+
+bool query_format_buffer(buffer_t *buf, const char *fmt, const query_t *query)
+{
+ buffer_ensure(buf, m_strlen(fmt) + 64);
+
+ ssize_t size = array_free_space(*buf);
+ ssize_t format_size = query_format(array_end(*buf),
+ size, fmt, query);
+ if (format_size == -1) {
+ return false;
+ } else if (format_size > size) {
+ buffer_ensure(buf, format_size + 1);
+ query_format(array_end(*buf),
+ array_free_space(*buf),
+ fmt, query);
+ array_len(*buf) += format_size;
+ } else {
+ array_len(*buf) += format_size;
+ }
+ return true;
+}