summaryrefslogtreecommitdiffstats
path: root/src/lib-imap/imap-id.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib-imap/imap-id.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/src/lib-imap/imap-id.c b/src/lib-imap/imap-id.c
new file mode 100644
index 0000000..f873c57
--- /dev/null
+++ b/src/lib-imap/imap-id.c
@@ -0,0 +1,173 @@
+/* Copyright (c) 2008-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "str.h"
+#include "str-sanitize.h"
+#include "istream.h"
+#include "imap-parser.h"
+#include "imap-quote.h"
+#include "imap-id.h"
+#include "dovecot-version.h"
+
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>
+#endif
+
+#ifdef HAVE_UNAME
+static struct utsname utsname_result;
+static bool utsname_set = FALSE;
+
+static const char *imap_id_get_uname(const char *key)
+{
+ if (!utsname_set) {
+ utsname_set = TRUE;
+ if (uname(&utsname_result) < 0) {
+ i_error("uname() failed: %m");
+ i_zero(&utsname_result);
+ }
+ }
+
+ if (strcasecmp(key, "os") == 0)
+ return utsname_result.sysname;
+ if (strcasecmp(key, "os-version") == 0)
+ return utsname_result.release;
+ return NULL;
+}
+#endif
+
+static const char *imap_id_get_default(const char *key)
+{
+ if (strcasecmp(key, "name") == 0)
+ return PACKAGE_NAME;
+ if (strcasecmp(key, "version") == 0)
+ return PACKAGE_VERSION;
+ if (strcasecmp(key, "revision") == 0)
+ return DOVECOT_REVISION;
+ if (strcasecmp(key, "support-url") == 0)
+ return PACKAGE_WEBPAGE;
+ if (strcasecmp(key, "support-email") == 0)
+ return PACKAGE_BUGREPORT;
+#ifdef HAVE_UNAME
+ return imap_id_get_uname(key);
+#endif
+}
+
+static const char *
+imap_id_reply_generate_from_imap_args(const struct imap_arg *args)
+{
+ string_t *str;
+ const char *key, *value;
+
+ if (IMAP_ARG_IS_EOL(args))
+ return "NIL";
+
+ str = t_str_new(256);
+ str_append_c(str, '(');
+ for (; !IMAP_ARG_IS_EOL(args); args++) {
+ if (!imap_arg_get_astring(args, &key)) {
+ /* broken input */
+ if (IMAP_ARG_IS_EOL(&args[1]))
+ break;
+ args++;
+ } else {
+ /* key */
+ if (str_len(str) > 1)
+ str_append_c(str, ' ');
+ imap_append_quoted(str, key);
+ str_append_c(str, ' ');
+ /* value */
+ if (IMAP_ARG_IS_EOL(&args[1])) {
+ str_append(str, "NIL");
+ break;
+ }
+ args++;
+ if (!imap_arg_get_astring(args, &value))
+ value = NULL;
+ else {
+ if (strcmp(value, "*") == 0)
+ value = imap_id_get_default(key);
+ }
+ imap_append_nstring(str, value);
+ }
+ }
+ if (str_len(str) == 1) {
+ /* broken */
+ return "NIL";
+ }
+ str_append_c(str, ')');
+ return str_c(str);
+}
+
+const char *imap_id_reply_generate(const char *settings)
+{
+ struct istream *input;
+ struct imap_parser *parser;
+ const struct imap_arg *args;
+ const char *ret;
+
+ if (settings == NULL)
+ return "NIL";
+
+ input = i_stream_create_from_data(settings, strlen(settings));
+ (void)i_stream_read(input);
+
+ parser = imap_parser_create(input, NULL, SIZE_MAX);
+ if (imap_parser_finish_line(parser, 0, 0, &args) <= 0)
+ ret = "NIL";
+ else
+ ret = imap_id_reply_generate_from_imap_args(args);
+
+ imap_parser_unref(&parser);
+ i_stream_destroy(&input);
+ return ret;
+}
+
+void imap_id_log_reply_append(string_t *reply, const char *key,
+ const char *value)
+{
+ if (str_len(reply) > 0)
+ str_append(reply, ", ");
+ str_append(reply, str_sanitize(key, IMAP_ID_KEY_MAX_LEN));
+ str_append_c(reply, '=');
+ str_append(reply, value == NULL ? "NIL" : str_sanitize(value, 80));
+}
+
+const char *imap_id_args_get_log_reply(const struct imap_arg *args,
+ const char *settings)
+{
+ const char *const *keys, *key, *value;
+ string_t *reply;
+ bool log_all;
+
+ if (settings == NULL || *settings == '\0')
+ return NULL;
+ if (!imap_arg_get_list(args, &args))
+ return NULL;
+
+ log_all = strcmp(settings, "*") == 0;
+ reply = t_str_new(256);
+ keys = t_strsplit_spaces(settings, " ");
+ while (!IMAP_ARG_IS_EOL(&args[0]) &&
+ !IMAP_ARG_IS_EOL(&args[1])) {
+ if (!imap_arg_get_string(args, &key)) {
+ /* broken input */
+ args += 2;
+ continue;
+ }
+ args++;
+ if (strlen(key) > 30) {
+ /* broken: ID spec requires fields to be max. 30
+ octets */
+ args++;
+ continue;
+ }
+
+ if (log_all || str_array_icase_find(keys, key)) {
+ if (!imap_arg_get_nstring(args, &value))
+ value = "";
+ imap_id_log_reply_append(reply, key, value);
+ }
+ args++;
+ }
+ return str_len(reply) == 0 ? NULL : str_c(reply);
+}