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