1 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "str.h"
5 #include "istream.h"
6 #include "array.h"
7 #include "var-expand.h"
8 #include "dlua-script.h"
9 #include "dlua-script-private.h"
10 #include "mail-storage.h"
11 #include "mailbox-attribute.h"
12 #include "mail-storage-lua.h"
13 #include "mail-storage-lua-private.h"
14 #include "mail-user.h"
15 
16 /* lookup mailbox attribute */
lua_storage_mailbox_attribute_get(struct mailbox * box,const char * key,const char ** value_r,size_t * value_len_r,const char ** error_r)17 int lua_storage_mailbox_attribute_get(struct mailbox *box, const char *key,
18 				      const char **value_r, size_t *value_len_r,
19 				      const char **error_r)
20 {
21 	struct mail_attribute_value value;
22 	enum mail_attribute_type attr_type;
23 	int ret;
24 
25 	if (str_begins(key, "/private/")) {
26 		attr_type = MAIL_ATTRIBUTE_TYPE_PRIVATE;
27 		key += 9;
28 	} else if (str_begins(key, "/shared/")) {
29 		attr_type = MAIL_ATTRIBUTE_TYPE_SHARED;
30 		key += 8;
31 	} else {
32 		*error_r = "Invalid key prefix, must be /private/ or /shared/";
33 		return -1;
34 	}
35 
36 	/* get the attribute */
37 	if ((ret = mailbox_attribute_get_stream(box, attr_type, key, &value)) < 0) {
38 		*error_r = mailbox_get_last_error(box, NULL);
39 		return ret;
40 	} else if (ret == 0) {
41 		/* was not found */
42 		*value_r = NULL;
43 		*value_len_r = 0;
44 		return 0;
45 	}
46 
47 	if (value.value_stream != NULL) {
48 		string_t *str = t_str_new(128);
49 		const unsigned char *data;
50 		size_t siz;
51 		while((ret = i_stream_read_more(value.value_stream, &data, &siz))>0) {
52 			str_append_data(str, data, siz);
53 			i_stream_skip(value.value_stream, siz);
54 		}
55 		i_assert(ret != 0);
56 		if (ret == -1 && !value.value_stream->eof) {
57 			/* we could not read the stream */
58 			*error_r = i_stream_get_error(value.value_stream);
59 			ret = -1;
60 		} else {
61 			*value_r = str->data;
62 			*value_len_r = str->used;
63 			ret = 1;
64 		}
65 		i_stream_unref(&value.value_stream);
66 		return ret;
67 	}
68 
69 	*value_r = value.value;
70 	if (value.value != NULL)
71 		*value_len_r = strlen(value.value);
72 	else
73 		*value_len_r = 0;
74 	return 1;
75 }
76 
lua_storage_mailbox_attribute_set(struct mailbox * box,const char * key,const char * value,size_t value_len,const char ** error_r)77 int lua_storage_mailbox_attribute_set(struct mailbox *box, const char *key,
78 				      const char *value, size_t value_len,
79 				      const char **error_r)
80 {
81 	struct mail_attribute_value attr_value;
82 	enum mail_attribute_type attr_type;
83 	int ret;
84 
85 	i_assert(value != NULL || value_len == 0);
86 
87 	if (str_begins(key, "/private/")) {
88 		attr_type = MAIL_ATTRIBUTE_TYPE_PRIVATE;
89 		key += 9;
90 	} else if (str_begins(key, "/shared/")) {
91 		attr_type = MAIL_ATTRIBUTE_TYPE_SHARED;
92 		key += 8;
93 	} else {
94 		*error_r = "Invalid key prefix, must be /private/ or /shared/";
95 		return -1;
96 	}
97 
98 	struct mailbox_transaction_context *t =
99 		mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_NO_NOTIFY, __func__);
100 	i_zero(&attr_value);
101 
102 	if (value != NULL) {
103 		/* use stream API to allow NULs in data */
104 		attr_value.value_stream = i_stream_create_from_data(value, value_len);
105 	}
106 
107 	ret = mailbox_attribute_set(t, attr_type, key, &attr_value);
108 
109 	if (ret < 0) {
110 		*error_r = mailbox_get_last_error(box, NULL);
111 		mailbox_transaction_rollback(&t);
112 	} else if ((ret = mailbox_transaction_commit(&t)) < 0) {
113 		*error_r = mailbox_get_last_error(box, NULL);
114 	}
115 
116 	if (attr_value.value_stream != NULL)
117 		i_stream_unref(&attr_value.value_stream);
118 
119 	return ret;
120 }
121 
lua_storage_mailbox_attribute_list(struct mailbox * box,const char * prefix,ARRAY_TYPE (lua_storage_keyvalue)* items_r,const char ** error_r)122 int lua_storage_mailbox_attribute_list(struct mailbox *box, const char *prefix,
123 				       ARRAY_TYPE(lua_storage_keyvalue) *items_r,
124 				       const char **error_r)
125 {
126 	const char *key, *orig_prefix = prefix;
127 	enum mail_attribute_type attr_type;
128 	int ret;
129 
130 	if (str_begins(prefix, "/private/")) {
131 		attr_type = MAIL_ATTRIBUTE_TYPE_PRIVATE;
132 		prefix += 9;
133 	} else if (str_begins(prefix, "/shared/")) {
134 		attr_type = MAIL_ATTRIBUTE_TYPE_SHARED;
135 		prefix += 8;
136 	} else {
137 		*error_r = "Invalid key prefix, must be /private/ or /shared/";
138 		return -1;
139 	}
140 
141 	struct mailbox_attribute_iter *iter =
142 			mailbox_attribute_iter_init(box, attr_type, prefix);
143 
144 	ret = 0;
145 	*error_r = NULL;
146 	while((key = mailbox_attribute_iter_next(iter)) != NULL) {
147 		struct lua_storage_keyvalue *item = array_append_space(items_r);
148 		item->key = t_strdup_printf("%s%s", orig_prefix, key);
149 		if (lua_storage_mailbox_attribute_get(box, item->key, &item->value,
150 						      &item->value_len, error_r) < 0) {
151 			ret = -1;
152 			break;
153 		}
154 	}
155 
156 	if (mailbox_attribute_iter_deinit(&iter) < 0 || ret == -1) {
157 		if (*error_r == NULL)
158 			*error_r = mailbox_get_last_error(box, NULL);
159 		return -1;
160 	}
161 
162 	return 0;
163 }
164