"Fossies" - the Fresh Open Source Software Archive

Member "dovecot-2.3.8/src/plugins/push-notification/push-notification-plugin.c" (8 Oct 2019, 13024 Bytes) of package /linux/misc/dovecot-2.3.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "push-notification-plugin.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.3.7.2_vs_2.3.8.

    1 /* Copyright (c) 2015-2018 Dovecot authors, see the included COPYING file */
    2 
    3 #include "lib.h"
    4 #include "array.h"
    5 #include "ioloop.h"
    6 #include "mail-namespace.h"
    7 #include "mail-storage.h"
    8 #include "mail-storage-private.h"
    9 #include "notify-plugin.h"
   10 #include "str.h"
   11 
   12 #include "push-notification-drivers.h"
   13 #include "push-notification-events.h"
   14 #include "push-notification-events-rfc5423.h"
   15 #include "push-notification-plugin.h"
   16 #include "push-notification-triggers.h"
   17 #include "push-notification-txn-mbox.h"
   18 #include "push-notification-txn-msg.h"
   19 
   20 
   21 #define PUSH_NOTIFICATION_CONFIG "push_notification_driver"
   22 #define PUSH_NOTIFICATION_CONFIG_OLD "push_notification_backend"
   23 #define PUSH_NOTIFICATION_EVENT_FINISHED "push_notification_finished"
   24 
   25 #define PUSH_NOTIFICATION_USER_CONTEXT(obj) \
   26         MODULE_CONTEXT_REQUIRE(obj, push_notification_user_module)
   27 static MODULE_CONTEXT_DEFINE_INIT(push_notification_user_module,
   28                                   &mail_user_module_register);
   29 static struct ioloop *main_ioloop;
   30 
   31 struct event_category event_category_push_notification = {
   32     .name = "push_notification",
   33 };
   34 
   35 struct event_category *push_notification_get_event_category(void)
   36 {
   37     return &event_category_push_notification;
   38 }
   39 
   40 struct push_notification_event *
   41 push_notification_get_event_messagenew(void)
   42 {
   43     return &push_notification_event_messagenew;
   44 }
   45 
   46 static void
   47 push_notification_transaction_init(struct push_notification_txn *ptxn)
   48 {
   49     struct push_notification_driver_txn *dtxn;
   50     struct push_notification_driver_user **duser;
   51     struct mail_storage *storage;
   52 
   53     if (ptxn->initialized) {
   54         return;
   55     }
   56 
   57     ptxn->initialized = TRUE;
   58 
   59     storage = mailbox_get_storage(ptxn->mbox);
   60     if (storage->user->autocreated &&
   61         (strcmp(storage->name, "raw") == 0)) {
   62         /* no notifications for autocreated raw users */
   63         return;
   64     }
   65 
   66     array_foreach_modifiable(&ptxn->puser->driverlist->drivers, duser) {
   67         dtxn = p_new(ptxn->pool, struct push_notification_driver_txn, 1);
   68         dtxn->duser = *duser;
   69         dtxn->ptxn = ptxn;
   70 
   71         if ((dtxn->duser->driver->v.begin_txn == NULL) ||
   72             dtxn->duser->driver->v.begin_txn(dtxn)) {
   73             array_push_back(&ptxn->drivers, &dtxn);
   74         }
   75     }
   76 }
   77 
   78 static struct push_notification_txn *
   79 push_notification_transaction_create(struct mailbox *box,
   80                                      struct mailbox_transaction_context *t)
   81 {
   82     pool_t pool;
   83     struct push_notification_txn *ptxn;
   84     struct mail_storage *storage;
   85 
   86     pool = pool_alloconly_create("push notification transaction", 2048);
   87 
   88     ptxn = p_new(pool, struct push_notification_txn, 1);
   89     ptxn->mbox = box;
   90     storage = mailbox_get_storage(box);
   91     ptxn->muser = mail_storage_get_user(storage);
   92     ptxn->pool = pool;
   93     ptxn->puser = PUSH_NOTIFICATION_USER_CONTEXT(ptxn->muser);
   94     ptxn->t = t;
   95     ptxn->trigger = PUSH_NOTIFICATION_EVENT_TRIGGER_NONE;
   96     ptxn->event = event_create(ptxn->muser->event);
   97     event_add_category(ptxn->event, &event_category_push_notification);
   98     event_set_append_log_prefix(ptxn->event, "push-notification: ");
   99     p_array_init(&ptxn->drivers, pool, 4);
  100 
  101     return ptxn;
  102 }
  103 
  104 static void push_notification_transaction_end
  105 (struct push_notification_txn *ptxn, bool success)
  106 {
  107     struct push_notification_driver_txn **dtxn;
  108 
  109     if (ptxn->initialized) {
  110         array_foreach_modifiable(&ptxn->drivers, dtxn) {
  111             if ((*dtxn)->duser->driver->v.end_txn != NULL) {
  112                 (*dtxn)->duser->driver->v.end_txn(*dtxn, success);
  113             }
  114         }
  115     }
  116 
  117     struct event_passthrough *e = event_create_passthrough(ptxn->event)->
  118         set_name(PUSH_NOTIFICATION_EVENT_FINISHED);
  119     /* emit event */
  120     e_debug(e->event(), "Push notification transaction completed");
  121     event_unref(&ptxn->event);
  122     pool_unref(&ptxn->pool);
  123 }
  124 
  125 static void push_notification_transaction_commit
  126 (void *txn, struct mail_transaction_commit_changes *changes)
  127 {
  128     struct push_notification_txn *ptxn = (struct push_notification_txn *)txn;
  129     struct ioloop *prev_ioloop = current_ioloop;
  130 
  131     /* Make sure we're not in just any random ioloop, which could get
  132        destroyed soon. This way the push-notification drivers can do async
  133        operations that finish in the main ioloop. */
  134     io_loop_set_current(main_ioloop);
  135     if (changes == NULL) {
  136         push_notification_txn_mbox_end(ptxn);
  137     } else {
  138         push_notification_txn_msg_end(ptxn, changes);
  139     }
  140 
  141     push_notification_transaction_end(ptxn, TRUE);
  142     io_loop_set_current(prev_ioloop);
  143 }
  144 
  145 static void push_notification_mailbox_create(struct mailbox *box)
  146 {
  147     struct push_notification_txn *ptxn;
  148 
  149     ptxn = push_notification_transaction_create(box, NULL);
  150     push_notification_transaction_init(ptxn);
  151     push_notification_trigger_mbox_create(ptxn, box, NULL);
  152     push_notification_transaction_commit(ptxn, NULL);
  153 }
  154 
  155 static void push_notification_mailbox_delete(void *txn ATTR_UNUSED,
  156                                              struct mailbox *box)
  157 {
  158     struct push_notification_txn *ptxn;
  159 
  160     ptxn = push_notification_transaction_create(box, NULL);
  161     push_notification_transaction_init(ptxn);
  162     push_notification_trigger_mbox_delete(ptxn, box, NULL);
  163     push_notification_transaction_commit(ptxn, NULL);
  164 }
  165 
  166 static void push_notification_mailbox_rename(struct mailbox *src,
  167                                              struct mailbox *dest)
  168 {
  169     struct push_notification_txn *ptxn;
  170 
  171     ptxn = push_notification_transaction_create(dest, NULL);
  172     push_notification_transaction_init(ptxn);
  173     push_notification_trigger_mbox_rename(ptxn, src, dest, NULL);
  174     push_notification_transaction_commit(ptxn, NULL);
  175 }
  176 
  177 static void push_notification_mailbox_subscribe(struct mailbox *box,
  178                                                 bool subscribed)
  179 {
  180     struct push_notification_txn *ptxn;
  181 
  182     ptxn = push_notification_transaction_create(box, NULL);
  183     push_notification_transaction_init(ptxn);
  184     push_notification_trigger_mbox_subscribe(ptxn, box, subscribed, NULL);
  185     push_notification_transaction_commit(ptxn, NULL);
  186 }
  187 
  188 static void push_notification_mail_save(void *txn, struct mail *mail)
  189 {
  190     struct push_notification_txn *ptxn = txn;
  191 
  192     push_notification_transaction_init(ptxn);
  193 
  194     /* POST_SESSION means MTA delivery. */
  195     if ((mail->box->flags & MAILBOX_FLAG_POST_SESSION) != 0) {
  196         push_notification_trigger_msg_save_new(ptxn, mail, NULL);
  197     } else {
  198         push_notification_trigger_msg_save_append(ptxn, mail, NULL);
  199     }
  200 }
  201 
  202 static void push_notification_mail_copy(void *txn,
  203                                         struct mail *src ATTR_UNUSED,
  204                                         struct mail *dest)
  205 {
  206     push_notification_mail_save(txn, dest);
  207 }
  208 
  209 static void push_notification_mail_expunge(void *txn, struct mail *mail)
  210 {
  211     struct push_notification_txn *ptxn = txn;
  212 
  213     push_notification_transaction_init(ptxn);
  214     push_notification_trigger_msg_save_expunge(txn, mail, NULL);
  215 }
  216 
  217 static void
  218 push_notification_mail_update_flags(void *txn, struct mail *mail,
  219                                     enum mail_flags old_flags)
  220 {
  221     struct push_notification_txn *ptxn = txn;
  222 
  223     push_notification_transaction_init(ptxn);
  224     push_notification_trigger_msg_flag_change(txn, mail, NULL, old_flags);
  225 }
  226 
  227 static void
  228 push_notification_mail_update_keywords(void *txn, struct mail *mail,
  229                                        const char *const *old_keywords)
  230 {
  231     struct push_notification_txn *ptxn = txn;
  232 
  233     push_notification_transaction_init(ptxn);
  234     push_notification_trigger_msg_keyword_change(txn, mail, NULL, old_keywords);
  235 }
  236 
  237 static void *
  238 push_notification_transaction_begin(struct mailbox_transaction_context *t)
  239 {
  240     return push_notification_transaction_create(mailbox_transaction_get_mailbox(t), t);
  241 }
  242 
  243 static void push_notification_transaction_rollback(void *txn)
  244 {
  245     struct push_notification_txn *ptxn = txn;
  246 
  247     push_notification_transaction_end(ptxn, FALSE);
  248 }
  249 
  250 static void
  251 push_notification_config_init(const char *config_name,
  252                               struct mail_user *user,
  253                               struct push_notification_driver_list *dlist)
  254 {
  255     struct push_notification_driver_user *duser;
  256     const char *env;
  257     unsigned int i;
  258     string_t *root_name;
  259 
  260     root_name = t_str_new(32);
  261     str_append(root_name, config_name);
  262 
  263     for (i = 2;; i++) {
  264         env = mail_user_plugin_getenv(user, str_c(root_name));
  265         if ((env == NULL) || (*env == '\0')) {
  266             break;
  267         }
  268 
  269         if (push_notification_driver_init(user, env, user->pool, &duser) < 0) {
  270             break;
  271         }
  272 
  273         // Add driver.
  274         array_push_back(&dlist->drivers, &duser);
  275 
  276         str_truncate(root_name, strlen(config_name));
  277         str_printfa(root_name, "%d", i);
  278     }
  279 }
  280 
  281 static struct push_notification_driver_list *
  282 push_notification_driver_list_init(struct mail_user *user)
  283 {
  284     struct push_notification_driver_list *dlist;
  285 
  286     dlist = p_new(user->pool, struct push_notification_driver_list, 1);
  287     p_array_init(&dlist->drivers, user->pool, 4);
  288 
  289     push_notification_config_init(PUSH_NOTIFICATION_CONFIG, user, dlist);
  290 
  291     if (array_is_empty(&dlist->drivers)) {
  292         /* Support old configuration (it was available at time initial OX
  293          * driver was first released). */
  294         push_notification_config_init(PUSH_NOTIFICATION_CONFIG_OLD, user,
  295                                       dlist);
  296     }
  297     return dlist;
  298 }
  299 
  300 static void push_notification_user_deinit(struct mail_user *user)
  301 {
  302     struct push_notification_user *puser = PUSH_NOTIFICATION_USER_CONTEXT(user);
  303     struct push_notification_driver_list *dlist = puser->driverlist;
  304     struct push_notification_driver_user **duser;
  305     struct ioloop *prev_ioloop = current_ioloop;
  306 
  307     /* Make sure we're in the main ioloop, so if the deinit/cleanup moves any
  308        I/Os or timeouts they won't get moved to some temporary ioloop. */
  309     io_loop_set_current(main_ioloop);
  310 
  311     array_foreach_modifiable(&dlist->drivers, duser) {
  312         if ((*duser)->driver->v.deinit != NULL) {
  313             (*duser)->driver->v.deinit(*duser);
  314         }
  315 
  316         if ((*duser)->driver->v.cleanup != NULL) {
  317             (*duser)->driver->v.cleanup();
  318         }
  319     }
  320     io_loop_set_current(prev_ioloop);
  321 
  322     puser->module_ctx.super.deinit(user);
  323 }
  324 
  325 static void push_notification_user_created(struct mail_user *user)
  326 {
  327     struct mail_user_vfuncs *v = user->vlast;
  328     struct push_notification_user *puser;
  329 
  330     puser = p_new(user->pool, struct push_notification_user, 1);
  331     puser->module_ctx.super = *v;
  332     user->vlast = &puser->module_ctx.super;
  333     v->deinit = push_notification_user_deinit;
  334     puser->driverlist = push_notification_driver_list_init(user);
  335 
  336     MODULE_CONTEXT_SET(user, push_notification_user_module, puser);
  337 }
  338 
  339 
  340 /* Plugin interface. */
  341 
  342 const char *push_notification_plugin_version = DOVECOT_ABI_VERSION;
  343 const char *push_notification_plugin_dependencies[] = { "notify", NULL };
  344 
  345 extern struct push_notification_driver push_notification_driver_dlog;
  346 extern struct push_notification_driver push_notification_driver_ox;
  347 
  348 static struct notify_context *push_notification_ctx;
  349 
  350 static const struct notify_vfuncs push_notification_vfuncs = {
  351     /* Mailbox Events */
  352     .mailbox_create = push_notification_mailbox_create,
  353     .mailbox_delete_commit = push_notification_mailbox_delete,
  354     .mailbox_rename = push_notification_mailbox_rename,
  355     .mailbox_set_subscribed = push_notification_mailbox_subscribe,
  356 
  357     /* Mail Events */
  358     .mail_copy = push_notification_mail_copy,
  359     .mail_save = push_notification_mail_save,
  360     .mail_expunge = push_notification_mail_expunge,
  361     .mail_update_flags = push_notification_mail_update_flags,
  362     .mail_update_keywords = push_notification_mail_update_keywords,
  363     .mail_transaction_begin = push_notification_transaction_begin,
  364     .mail_transaction_commit = push_notification_transaction_commit,
  365     .mail_transaction_rollback = push_notification_transaction_rollback
  366 };
  367 
  368 static struct mail_storage_hooks push_notification_storage_hooks = {
  369     .mail_user_created = push_notification_user_created
  370 };
  371 
  372 void push_notification_plugin_init(struct module *module)
  373 {
  374     push_notification_ctx = notify_register(&push_notification_vfuncs);
  375     mail_storage_hooks_add(module, &push_notification_storage_hooks);
  376 
  377     push_notification_driver_register(&push_notification_driver_dlog);
  378     push_notification_driver_register(&push_notification_driver_ox);
  379 
  380     push_notification_event_register_rfc5423_events();
  381     main_ioloop = current_ioloop;
  382     i_assert(main_ioloop != NULL);
  383 }
  384 
  385 void push_notification_plugin_deinit(void)
  386 {
  387     push_notification_driver_unregister(&push_notification_driver_dlog);
  388     push_notification_driver_unregister(&push_notification_driver_ox);
  389 
  390     push_notification_event_unregister_rfc5423_events();
  391     mail_storage_hooks_remove(&push_notification_storage_hooks);
  392     notify_unregister(push_notification_ctx);
  393 }