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