1 /* Copyright (c) 2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 #include "ioloop.h"
6 #include "str.h"
7 #include "hash.h"
8 #include "dlua-script.h"
9 #include "dlua-script-private.h"
10 
11 #include "mail-storage.h"
12 #include "mail-user.h"
13 #include "mail-lua-plugin.h"
14 #include "mail-storage-lua.h"
15 
16 #include "push-notification-plugin.h"
17 #include "push-notification-drivers.h"
18 #include "push-notification-events.h"
19 #include "push-notification-event-message-common.h"
20 #include "push-notification-txn-mbox.h"
21 #include "push-notification-txn-msg.h"
22 
23 #include "push-notification-event-flagsclear.h"
24 #include "push-notification-event-flagsset.h"
25 #include "push-notification-event-mailboxcreate.h"
26 #include "push-notification-event-mailboxdelete.h"
27 #include "push-notification-event-mailboxrename.h"
28 #include "push-notification-event-mailboxsubscribe.h"
29 #include "push-notification-event-mailboxunsubscribe.h"
30 #include "push-notification-event-messageappend.h"
31 #include "push-notification-event-message-common.h"
32 #include "push-notification-event-messageexpunge.h"
33 #include "push-notification-event-messagenew.h"
34 #include "push-notification-event-messageread.h"
35 #include "push-notification-event-messagetrash.h"
36 
37 #define DLUA_LOG_USERENV_KEY "push_notification_lua_script_file"
38 
39 #define DLUA_FN_BEGIN_TXN "dovecot_lua_notify_begin_txn"
40 #define DLUA_FN_EVENT_PREFIX "dovecot_lua_notify_event"
41 #define DLUA_FN_END_TXN "dovecot_lua_notify_end_txn"
42 
43 #define DLUA_CALL_FINISHED "push_notification_lua_call_finished"
44 
45 struct dlua_push_notification_context {
46 	struct dlua_script *script;
47 	struct event *event;
48 	bool debug;
49 
50 	struct push_notification_event_messagenew_config config_mn;
51 	struct push_notification_event_messageappend_config config_ma;
52 	struct push_notification_event_flagsclear_config config_fc;
53 	struct push_notification_event_flagsset_config config_fs;
54 };
55 
56 struct dlua_push_notification_txn_context {
57 	int tx_ref;
58 };
59 
60 #define DLUA_DEFAULT_EVENTS (\
61 	PUSH_NOTIFICATION_MESSAGE_HDR_FROM | \
62 	PUSH_NOTIFICATION_MESSAGE_HDR_TO | \
63 	PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT | \
64 	PUSH_NOTIFICATION_MESSAGE_HDR_DATE | \
65 	PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET | \
66 	PUSH_NOTIFICATION_MESSAGE_FLAGS | \
67 	PUSH_NOTIFICATION_MESSAGE_KEYWORDS | \
68 	PUSH_NOTIFICATION_MESSAGE_HDR_MESSAGE_ID)
69 
70 static const char *push_notification_driver_lua_to_fn(const char *evname);
71 
72 static int
push_notification_driver_lua_init(struct push_notification_driver_config * config,struct mail_user * user,pool_t pool,void ** context,const char ** error_r)73 push_notification_driver_lua_init(
74 	struct push_notification_driver_config *config, struct mail_user *user,
75 	pool_t pool, void **context, const char **error_r)
76 {
77 	struct dlua_push_notification_context *ctx;
78 	const char *tmp, *file;
79 	struct event *event = event_create(user->event);
80 	event_add_category(event, push_notification_get_event_category());
81 	event_set_append_log_prefix(event, "lua: ");
82 
83 	if ((tmp = mail_user_plugin_getenv(user, DLUA_LOG_USERENV_KEY)) == NULL)
84 		tmp = hash_table_lookup(config->config, (const char *)"file");
85 
86 	if (tmp == NULL) {
87 		struct dlua_script *script;
88 		/* If there is a script loaded, use the same context */
89 		if (mail_lua_plugin_get_script(user, &script)) {
90 			dlua_script_ref(script);
91 			ctx = p_new(
92 				pool, struct dlua_push_notification_context, 1);
93 			ctx->script = script;
94 			ctx->event = event;
95 			*context = ctx;
96 			return 0;
97 		}
98 
99 		event_unref(&event);
100 		*error_r = "No file in config and no "
101 			   DLUA_LOG_USERENV_KEY " set";
102 		return -1;
103 	}
104 	file = tmp;
105 
106 	ctx = p_new(pool, struct dlua_push_notification_context, 1);
107 	ctx->event = event;
108 
109 	e_debug(ctx->event, "Loading %s", file);
110 
111 	if (dlua_script_create_file(file, &ctx->script, event, error_r) < 0) {
112 		/* There is a T_POP after this, which will break errors */
113 		event_unref(&event);
114 		*error_r = p_strdup(pool, *error_r);
115 		return -1;
116 	}
117 
118 	/* Register dovecot helpers */
119 	dlua_dovecot_register(ctx->script);
120 	dlua_register_mail_storage(ctx->script);
121 
122 	e_debug(ctx->event, "Calling script_init");
123 
124 	/* Initialize script */
125 	if (dlua_script_init(ctx->script, error_r) < 0) {
126 		*error_r = p_strdup(pool, *error_r);
127 		event_unref(&event);
128 		dlua_script_unref(&ctx->script);
129 		return -1;
130 	}
131 
132 	*context = ctx;
133 	return 0;
134 }
135 
136 static bool
push_notification_driver_lua_init_events(struct push_notification_driver_txn * dtxn)137 push_notification_driver_lua_init_events(
138 	struct push_notification_driver_txn *dtxn)
139 {
140 	struct dlua_push_notification_context *ctx = dtxn->duser->context;
141 	const struct push_notification_event *event;
142 	ctx->config_mn.flags = DLUA_DEFAULT_EVENTS;
143 	ctx->config_ma.flags = DLUA_DEFAULT_EVENTS;
144 	ctx->config_fc.store_old = TRUE;
145 	bool found_one = FALSE;
146 
147 	/* Register *all* events that are present in Lua */
148 	array_foreach_elem(push_notification_get_events(), event) {
149 		const char *name = event->name;
150 		const char *fn = push_notification_driver_lua_to_fn(name);
151 		if (!dlua_script_has_function(ctx->script, fn))
152 			continue;
153 
154 		found_one = TRUE;
155 
156 		e_debug(ctx->event, "Found %s, handling %s event", fn, name);
157 
158 		if (strcmp(name, "MessageNew") == 0) {
159 			push_notification_event_init(dtxn, name,
160 						     &ctx->config_mn);
161 		} else if (strcmp(name, "MessageAppend") == 0) {
162 			push_notification_event_init(dtxn, name,
163 						     &ctx->config_ma);
164 		} else if (strcmp(name, "FlagsSet") == 0) {
165 			push_notification_event_init(dtxn, name,
166 						     &ctx->config_fs);
167 		} else if (strcmp(name, "FlagsClear") == 0) {
168 			push_notification_event_init(dtxn, name,
169 						     &ctx->config_fc);
170 		} else if (event->init.default_config != NULL) {
171 			void *config = event->init.default_config();
172 			push_notification_event_init(dtxn, name, config);
173 		} else {
174 			push_notification_event_init(dtxn, name, NULL);
175 		}
176 	}
177 
178 	return found_one;
179 }
180 
181 static bool
push_notification_driver_lua_begin_txn(struct push_notification_driver_txn * dtxn)182 push_notification_driver_lua_begin_txn(
183 	struct push_notification_driver_txn *dtxn)
184 {
185 	struct mail_user *user = dtxn->ptxn->muser;
186 	struct dlua_push_notification_context *ctx = dtxn->duser->context;
187 	struct event *event = event_create(ctx->event);
188 	const char *error;
189 
190 	event_set_name(event, DLUA_CALL_FINISHED);
191 	event_add_str(event, "function_name", DLUA_FN_BEGIN_TXN);
192 
193 	if (!dlua_script_has_function(ctx->script, DLUA_FN_BEGIN_TXN)) {
194 		event_add_str(event, "error",
195 			      "Missing function " DLUA_FN_BEGIN_TXN);
196 		e_error(event, "Missing function " DLUA_FN_BEGIN_TXN);
197 		event_unref(&event);
198 		return FALSE;
199 	}
200 
201 	if (!push_notification_driver_lua_init_events(dtxn)) {
202 		e_debug(event, "No event handlers found in script");
203 		event_unref(&event);
204 		return FALSE;
205 	}
206 
207 	e_debug(ctx->event, "Calling " DLUA_FN_BEGIN_TXN "(%s)",
208 		user->username);
209 
210 	/* Push mail user as argument */
211 	dlua_push_mail_user(ctx->script->L, user);
212 	if (dlua_pcall(ctx->script->L, DLUA_FN_BEGIN_TXN, 1, 1, &error) < 0) {
213 		event_add_str(event, "error", error);
214 		e_error(event, "%s", error);
215 		return FALSE;
216 	}
217 
218 	e_debug(event, "Called " DLUA_FN_BEGIN_TXN);
219 	event_unref(&event);
220 
221 	/* Store the result */
222 	struct dlua_push_notification_txn_context *tctx =
223 		p_new(dtxn->ptxn->pool,
224 		      struct dlua_push_notification_txn_context, 1);
225 
226 	tctx->tx_ref = luaL_ref(ctx->script->L, LUA_REGISTRYINDEX);
227 	dtxn->context = tctx;
228 	mail_user_ref(user);
229 
230 	return TRUE;
231 }
232 
233 /* This function only works here, it converts MessageType to event_message_type
234  */
push_notification_driver_lua_to_fn(const char * evname)235 static const char *push_notification_driver_lua_to_fn(const char *evname)
236 {
237 	/* Camelcase to event_event_name (most events have two underscores) */
238 	string_t *fn = t_str_new(strlen(evname) +
239 				 strlen(DLUA_FN_EVENT_PREFIX) + 2);
240 	str_append(fn, DLUA_FN_EVENT_PREFIX);
241 
242 	for(; *evname != '\0'; evname++) {
243 		if (*evname >= 'A' && *evname <= 'Z') {
244 			str_append_c(fn, '_');
245 			str_append_c(fn, (*evname) - 'A' + 'a');
246 		} else {
247 			str_append_c(fn, *evname);
248 		}
249 	}
250 
251 	return str_c(fn);
252 }
253 
254 /* Pushes lua list of flags */
dlua_push_flags(struct dlua_script * script,enum mail_flags flags)255 static void dlua_push_flags(struct dlua_script *script, enum mail_flags flags)
256 {
257 	lua_newtable(script->L);
258 	int idx = 1;
259 
260 	if ((flags & MAIL_ANSWERED) != 0) {
261 		lua_pushliteral(script->L, "\\Answered");
262 		lua_rawseti(script->L, -2, idx++);
263 	}
264 	if ((flags & MAIL_FLAGGED) != 0) {
265 		lua_pushliteral(script->L, "\\Flagged");
266 		lua_rawseti(script->L, -2, idx++);
267 	}
268 	if ((flags & MAIL_DELETED) != 0) {
269 		lua_pushliteral(script->L, "\\Deleted");
270 		lua_rawseti(script->L, -2, idx++);
271 	}
272 	if ((flags & MAIL_SEEN) != 0) {
273 		lua_pushliteral(script->L, "\\Seen");
274 		lua_rawseti(script->L, -2, idx++);
275 	}
276 	if ((flags & MAIL_DRAFT) != 0) {
277 		lua_pushliteral(script->L, "\\Draft");
278 		lua_rawseti(script->L, -2, idx++);
279 	}
280 	if ((flags & MAIL_RECENT) != 0) {
281 		lua_pushliteral(script->L, "\\Recent");
282 		lua_rawseti(script->L, -2, idx++);
283 	}
284 }
285 
286 static void
dlua_push_keywords(struct dlua_script * script,const char * const * keywords,unsigned int count)287 dlua_push_keywords(struct dlua_script *script, const char *const *keywords,
288 		  unsigned int count)
289 {
290 	lua_newtable(script->L);
291 	if (keywords == NULL)
292 		return;
293 	for (unsigned int idx = 0; idx < count; idx++) {
294 		lua_pushstring(script->L, keywords[idx]);
295 		lua_rawseti(script->L, -2, idx+1);
296 	}
297 }
298 
299 static void
push_notification_lua_push_flagsclear(const struct push_notification_txn_event * event,struct dlua_script * script)300 push_notification_lua_push_flagsclear(
301 	const struct push_notification_txn_event *event,
302 	struct dlua_script *script)
303 {
304 	/* Push cleared flags */
305 	unsigned int size = 0;
306 	struct push_notification_event_flagsclear_data *data = event->data;
307 
308 	dlua_push_flags(script, data->flags_clear);
309 	lua_setfield(script->L, -2, "flags");
310 	dlua_push_flags(script, data->flags_old);
311 	lua_setfield(script->L, -2, "flags_old");
312 
313 	if (array_is_created(&data->keywords_clear)) {
314 		const char *const *kw = array_get(&data->keywords_clear, &size);
315 		dlua_push_keywords(script, kw, size);
316 		lua_setfield(script->L, -2, "keywords");
317 	}
318 
319 	if (array_is_created(&data->keywords_old)) {
320 		const char *const *kw = array_get(&data->keywords_old, &size);
321 		dlua_push_keywords(script, kw, size);
322 		lua_setfield(script->L, -2, "keywords_old");
323 	}
324 }
325 
326 static void
push_notification_lua_push_flagsset(const struct push_notification_txn_event * event,struct dlua_script * script)327 push_notification_lua_push_flagsset(
328 	const struct push_notification_txn_event *event,
329 	struct dlua_script *script)
330 {
331 	/* push set flags */
332 	unsigned int size = 0;
333 	struct push_notification_event_flagsset_data *data = event->data;
334 
335 	dlua_push_flags(script, data->flags_set);
336 	lua_setfield(script->L, -2, "flags");
337 
338 	if (array_is_created(&data->keywords_set)) {
339 		const char *const *kw = array_get(&data->keywords_set, &size);
340 		dlua_push_keywords(script, kw, size);
341 		lua_setfield(script->L, -2, "keywords");
342 	}
343 }
344 
345 static void
push_notification_lua_push_mailboxrename(const struct push_notification_txn_event * event,struct dlua_script * script)346 push_notification_lua_push_mailboxrename(
347 	const struct push_notification_txn_event *event,
348 	struct dlua_script *script)
349 {
350 	struct push_notification_event_mailboxrename_data *data = event->data;
351 
352 	lua_pushstring(script->L, data->old_mbox);
353 	lua_setfield(script->L, -2, "mailbox_old");
354 }
355 
356 #define push_notification_lua_push_string(L, value) \
357 	lua_pushstring((L), (value) == NULL ? "" : (value))
358 
359 static void
push_notification_lua_push_message_ext(const struct push_notification_message_ext * ext,struct dlua_script * script)360 push_notification_lua_push_message_ext(
361 	const struct push_notification_message_ext *ext,
362 	struct dlua_script *script)
363 {
364 	push_notification_lua_push_string(script->L, ext->from_address);
365 	lua_setfield(script->L, -2, "from_address");
366 	push_notification_lua_push_string(script->L, ext->from_display_name_utf8);
367 	lua_setfield(script->L, -2, "from_display_name");
368 
369 	push_notification_lua_push_string(script->L, ext->to_address);
370 	lua_setfield(script->L, -2, "to_address");
371 	push_notification_lua_push_string(script->L, ext->to_display_name_utf8);
372 	lua_setfield(script->L, -2, "to_display_name");
373 
374 	lua_pushstring(script->L, ext->subject_utf8);
375 	lua_setfield(script->L, -2, "subject");
376 }
377 
378 static void
push_notification_lua_push_messageappend(const struct push_notification_txn_event * event,struct dlua_script * script)379 push_notification_lua_push_messageappend(
380 	const struct push_notification_txn_event *event,
381 	struct dlua_script *script)
382 {
383 	struct push_notification_event_messageappend_data *data = event->data;
384 
385 	lua_pushnumber(script->L, data->date);
386 	lua_setfield(script->L, -2, "date");
387 
388 	lua_pushnumber(script->L, data->date_tz);
389 	lua_setfield(script->L, -2, "tz");
390 
391 	push_notification_lua_push_string(script->L, data->from);
392 	lua_setfield(script->L, -2, "from");
393 
394 	push_notification_lua_push_string(script->L, data->to);
395 	lua_setfield(script->L, -2, "to");
396 
397 	lua_pushstring(script->L, data->snippet);
398 	lua_setfield(script->L, -2, "snippet");
399 
400 	dlua_push_flags(script, data->flags);
401 	lua_setfield(script->L, -2, "flags");
402 
403 	dlua_push_keywords(script, data->keywords,
404 			  str_array_length(data->keywords));
405 	lua_setfield(script->L, -2, "keywords");
406 
407 	lua_pushstring(script->L, data->message_id);
408 	lua_setfield(script->L, -2, "message_id");
409 
410 	push_notification_lua_push_message_ext(&data->ext, script);
411 }
412 
413 static void
push_notification_lua_push_messagenew(const struct push_notification_txn_event * event,struct dlua_script * script)414 push_notification_lua_push_messagenew(
415 	const struct push_notification_txn_event *event,
416 	struct dlua_script *script)
417 {
418 	struct push_notification_event_messagenew_data *data = event->data;
419 
420 	lua_pushnumber(script->L, data->date);
421 	lua_setfield(script->L, -2, "date");
422 
423 	lua_pushnumber(script->L, data->date_tz);
424 	lua_setfield(script->L, -2, "tz");
425 
426 	push_notification_lua_push_string(script->L, data->from);
427 	lua_setfield(script->L, -2, "from");
428 
429 	push_notification_lua_push_string(script->L, data->to);
430 	lua_setfield(script->L, -2, "to");
431 
432 	lua_pushstring(script->L, data->snippet);
433 	lua_setfield(script->L, -2, "snippet");
434 
435 	dlua_push_flags(script, data->flags);
436 	lua_setfield(script->L, -2, "flags");
437 
438 	dlua_push_keywords(script, data->keywords,
439 			  str_array_length(data->keywords));
440 	lua_setfield(script->L, -2, "keywords");
441 
442 	lua_pushstring(script->L, data->message_id);
443 	lua_setfield(script->L, -2, "message_id");
444 
445 	push_notification_lua_push_message_ext(&data->ext, script);
446 }
447 
448 /* Events that need special treatment */
449 static struct push_notification_event_to_lua {
450 	const char *event_name;
451 	void (*push)(const struct push_notification_txn_event *event,
452 		     struct dlua_script *script);
453 } event_to_push_table[] = {
454 	{
455 		.event_name = "FlagsClear",
456 		.push = push_notification_lua_push_flagsclear
457 	},
458 	{
459 		.event_name = "FlagsSet",
460 		.push = push_notification_lua_push_flagsset
461 	},
462 	{
463 		.event_name = "MailboxRename",
464 		.push = push_notification_lua_push_mailboxrename
465 	},
466 	{
467 		.event_name = "MessageAppend",
468 		.push = push_notification_lua_push_messageappend
469 	},
470 	{
471 		.event_name = "MessageNew",
472 		.push = push_notification_lua_push_messagenew
473 	},
474 };
475 
476 static void
push_notification_driver_lua_push_event(const struct push_notification_txn_event * event,struct dlua_push_notification_context * ctx)477 push_notification_driver_lua_push_event(
478 	const struct push_notification_txn_event *event,
479 	struct dlua_push_notification_context *ctx)
480 {
481 	struct dlua_script *script = ctx->script;
482 	const char *name = event->event->event->name;
483 
484 	/* Create a table */
485 	lua_newtable(script->L);
486 
487 	/* Event name */
488 	lua_pushstring(script->L, name);
489 	lua_setfield(script->L, -2, "name");
490 
491 	for(size_t i = 0; i < N_ELEMENTS(event_to_push_table); i++)
492 		if (strcmp(event_to_push_table[i].event_name, name) == 0)
493 			event_to_push_table[i].push(event, script);
494 }
495 
496 static void
push_notification_driver_lua_call(struct dlua_push_notification_context * ctx,struct dlua_push_notification_txn_context * tctx,const struct push_notification_txn_event * event,const struct push_notification_txn_mbox * mbox,struct push_notification_txn_msg * msg)497 push_notification_driver_lua_call(
498 	struct dlua_push_notification_context *ctx,
499 	struct dlua_push_notification_txn_context *tctx,
500 	const struct push_notification_txn_event *event,
501 	const struct push_notification_txn_mbox *mbox,
502 	struct push_notification_txn_msg *msg)
503 {
504 	const char *error;
505 	const char *fn =
506 		push_notification_driver_lua_to_fn(event->event->event->name);
507 	struct event *e = event_create(ctx->event);
508 	event_set_name(e, DLUA_CALL_FINISHED);
509 	event_add_str(e, "event_name", event->event->event->name);
510 	event_add_str(e, "function_name", fn);
511 
512 	/* Push context */
513 	lua_rawgeti(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
514 
515 	/* Push event + common fields */
516 	push_notification_driver_lua_push_event(event, ctx);
517 
518 	if (mbox != NULL) {
519 		lua_pushstring(ctx->script->L, mbox->mailbox);
520 		lua_setfield(ctx->script->L, -2, "mailbox");
521 		e_debug(ctx->event,
522 			"Calling %s(ctx, event[name=%s,mailbox=%s])",
523 			fn, event->event->event->name, mbox->mailbox);
524 		event_add_str(e, "mailbox", mbox->mailbox);
525 	} else if (msg != NULL) {
526 		lua_pushstring(ctx->script->L, msg->mailbox);
527 		lua_setfield(ctx->script->L, -2, "mailbox");
528 		lua_pushnumber(ctx->script->L, msg->uid);
529 		lua_setfield(ctx->script->L, -2, "uid");
530 		lua_pushnumber(ctx->script->L, msg->uid_validity);
531 		lua_setfield(ctx->script->L, -2, "uid_validity");
532 		e_debug(ctx->event,
533 			"Calling %s(ctx, event[name=%s,mailbox=%s,uid=%u])",
534 			fn, event->event->event->name, msg->mailbox, msg->uid);
535 		event_add_str(e, "mailbox", msg->mailbox);
536 		event_add_int(e, "uid", msg->uid);
537 	} else
538 		i_unreached();
539 
540 	/* Perform call */
541 	if (dlua_pcall(ctx->script->L, fn, 2, 0, &error) < 0) {
542 		event_add_str(e, "error", error);
543 		e_error(e, "%s", error);
544 	} else {
545 		e_debug(e, "Called %s", fn);
546 	}
547 	event_unref(&e);
548 }
549 
550 static void
push_notification_driver_lua_process_mbox(struct push_notification_driver_txn * dtxn,struct push_notification_txn_mbox * mbox)551 push_notification_driver_lua_process_mbox(
552 	struct push_notification_driver_txn *dtxn,
553 	struct push_notification_txn_mbox *mbox)
554 {
555 	struct push_notification_txn_event *event;
556 	struct dlua_push_notification_context *ctx = dtxn->duser->context;
557 	struct dlua_push_notification_txn_context *tctx = dtxn->context;
558 
559 	if (array_is_created(&mbox->eventdata)) {
560 		array_foreach_elem(&mbox->eventdata, event) {
561 			push_notification_driver_lua_call(ctx, tctx,
562 							  event, mbox, NULL);
563 		}
564 	}
565 }
566 
567 static void
push_notification_driver_lua_process_msg(struct push_notification_driver_txn * dtxn,struct push_notification_txn_msg * msg)568 push_notification_driver_lua_process_msg(
569 	struct push_notification_driver_txn *dtxn,
570 	struct push_notification_txn_msg *msg)
571 {
572 	struct push_notification_txn_event *event;
573 	struct dlua_push_notification_context *ctx = dtxn->duser->context;
574 	struct dlua_push_notification_txn_context *tctx = dtxn->context;
575 
576 	if (array_is_created(&msg->eventdata)) {
577 		array_foreach_elem(&msg->eventdata, event) {
578 			push_notification_driver_lua_call(ctx, tctx,
579 							  event, NULL, msg);
580 		}
581 	}
582 }
583 
584 static void
push_notification_driver_lua_end_txn(struct push_notification_driver_txn * dtxn,bool success)585 push_notification_driver_lua_end_txn(struct push_notification_driver_txn *dtxn,
586 				     bool success)
587 {
588 	/* Call end txn */
589 	const char *error;
590 	struct dlua_push_notification_context *ctx = dtxn->duser->context;
591 	struct dlua_push_notification_txn_context *tctx = dtxn->context;
592 	struct mail_user *user = dtxn->ptxn->muser;
593 	struct event *event = event_create(ctx->event);
594 	event_set_name(event, DLUA_CALL_FINISHED);
595 	event_add_str(event, "function_name", DLUA_FN_END_TXN);
596 
597 	if (!dlua_script_has_function(ctx->script, DLUA_FN_END_TXN)) {
598 		e_error(event, "Missing function " DLUA_FN_END_TXN);
599 	} else {
600 		e_debug(ctx->event, "Calling " DLUA_FN_END_TXN);
601 		lua_rawgeti(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
602 		lua_pushboolean(ctx->script->L, success);
603 		if (dlua_pcall(ctx->script->L, DLUA_FN_END_TXN, 2, 0, &error) < 0) {
604 			event_add_str(event, "error", error);
605 			e_error(event, "%s", error);
606 		} else {
607 			e_debug(event, "Called " DLUA_FN_END_TXN);
608 		}
609 	}
610 
611 	event_unref(&event);
612 	/* Release context */
613 	luaL_unref(ctx->script->L, LUA_REGISTRYINDEX, tctx->tx_ref);
614 	/* Call gc here */
615 	(void)lua_gc(ctx->script->L, LUA_GCCOLLECT, 1);
616 	mail_user_unref(&user);
617 }
618 
619 static void
push_notification_driver_lua_deinit(struct push_notification_driver_user * duser)620 push_notification_driver_lua_deinit(struct push_notification_driver_user *duser)
621 {
622 	/* Call lua deinit */
623 	struct dlua_push_notification_context *ctx = duser->context;
624 	dlua_script_unref(&ctx->script);
625 	event_unref(&ctx->event);
626 }
627 
push_notification_driver_lua_cleanup(void)628 static void push_notification_driver_lua_cleanup(void)
629 {
630 	/* noop */
631 }
632 
633 /* Driver definition */
634 
635 struct push_notification_driver push_notification_driver_lua = {
636 	.name = "lua",
637 	.v = {
638 		.init = push_notification_driver_lua_init,
639 		.begin_txn = push_notification_driver_lua_begin_txn,
640 		.process_mbox = push_notification_driver_lua_process_mbox,
641 		.process_msg = push_notification_driver_lua_process_msg,
642 		.end_txn = push_notification_driver_lua_end_txn,
643 		.deinit = push_notification_driver_lua_deinit,
644 		.cleanup = push_notification_driver_lua_cleanup,
645 	},
646 };
647 
648 void push_notification_lua_plugin_init(struct module *module);
649 void push_notification_lua_plugin_deinit(void);
650 
push_notification_lua_plugin_init(struct module * module ATTR_UNUSED)651 void push_notification_lua_plugin_init(struct module *module ATTR_UNUSED)
652 {
653 	push_notification_driver_register(&push_notification_driver_lua);
654 }
655 
push_notification_lua_plugin_deinit(void)656 void push_notification_lua_plugin_deinit(void)
657 {
658 	push_notification_driver_unregister(&push_notification_driver_lua);
659 }
660 
661 const char *push_notification_lua_plugin_version = DOVECOT_ABI_VERSION;
662 const char *push_notification_lua_plugin_dependencies[] =
663 	{ "push_notification", "mail_lua", NULL};
664