From: Stephan Bosch Date: Sun, 1 Dec 2019 10:24:04 +0000 (+0100) Subject: plugins: push-notification: Reformat push-notification-driver-ox.c. X-Git-Tag: 2.3.10~92 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=59438a21177adc1b410070d7c00213be01cef087;p=thirdparty%2Fdovecot%2Fcore.git plugins: push-notification: Reformat push-notification-driver-ox.c. --- diff --git a/src/plugins/push-notification/push-notification-driver-ox.c b/src/plugins/push-notification/push-notification-driver-ox.c index 48d509e660..ec540950b3 100644 --- a/src/plugins/push-notification/push-notification-driver-ox.c +++ b/src/plugins/push-notification/push-notification-driver-ox.c @@ -21,7 +21,8 @@ #include "push-notification-txn-msg.h" #define OX_METADATA_KEY \ - MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER "vendor/vendor.dovecot/http-notify" + MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER \ + "vendor/vendor.dovecot/http-notify" /* Default values. */ static const char *const default_events[] = { "MessageNew", NULL }; @@ -32,414 +33,439 @@ static const char *const default_mboxes[] = { "INBOX", NULL }; /* This is data that is shared by all plugin users. */ struct push_notification_driver_ox_global { - struct http_client *http_client; - int refcount; + struct http_client *http_client; + int refcount; }; static struct push_notification_driver_ox_global *ox_global = NULL; /* This is data specific to an OX driver. */ struct push_notification_driver_ox_config { - struct http_url *http_url; - struct event *event; - unsigned int cached_ox_metadata_lifetime_secs; - bool use_unsafe_username; - unsigned int http_max_retries; - unsigned int http_timeout_msecs; - - char *cached_ox_metadata; - time_t cached_ox_metadata_timestamp; + struct http_url *http_url; + struct event *event; + unsigned int cached_ox_metadata_lifetime_secs; + bool use_unsafe_username; + unsigned int http_max_retries; + unsigned int http_timeout_msecs; + + char *cached_ox_metadata; + time_t cached_ox_metadata_timestamp; }; /* This is data specific to an OX driver transaction. */ struct push_notification_driver_ox_txn { - const char *unsafe_user; + const char *unsafe_user; }; static void -push_notification_driver_ox_init_global(struct mail_user *user, +push_notification_driver_ox_init_global( + struct mail_user *user, struct push_notification_driver_ox_config *config) { - struct http_client_settings http_set; - struct ssl_iostream_settings ssl_set; - - if (ox_global->http_client == NULL) { - /* this is going to use the first user's settings, but these are - unlikely to change between users so it shouldn't matter much. */ - i_zero(&http_set); - http_set.debug = user->mail_debug; - http_set.max_attempts = config->http_max_retries+1; - http_set.request_timeout_msecs = config->http_timeout_msecs; - http_set.event_parent = user->event; - i_zero(&ssl_set); - mail_user_init_ssl_client_settings(user, &ssl_set); - http_set.ssl = &ssl_set; - - ox_global->http_client = http_client_init(&http_set); - } + struct http_client_settings http_set; + struct ssl_iostream_settings ssl_set; + + if (ox_global->http_client == NULL) { + /* This is going to use the first user's settings, but these are + unlikely to change between users so it shouldn't matter much. + */ + i_zero(&http_set); + http_set.debug = user->mail_debug; + http_set.max_attempts = config->http_max_retries+1; + http_set.request_timeout_msecs = config->http_timeout_msecs; + http_set.event_parent = user->event; + i_zero(&ssl_set); + mail_user_init_ssl_client_settings(user, &ssl_set); + http_set.ssl = &ssl_set; + + ox_global->http_client = http_client_init(&http_set); + } } static int push_notification_driver_ox_init(struct push_notification_driver_config *config, - struct mail_user *user, pool_t pool, - void **context, const char **error_r) + struct mail_user *user, pool_t pool, + void **context, const char **error_r) { - struct push_notification_driver_ox_config *dconfig; - const char *error, *tmp; - - /* Valid config keys: cache_lifetime, url */ - tmp = hash_table_lookup(config->config, (const char *)"url"); - if (tmp == NULL) { - *error_r = "Driver requires the url parameter"; - return -1; - } - - dconfig = p_new(pool, struct push_notification_driver_ox_config, 1); - dconfig->event = event_create(user->event); - event_add_category(dconfig->event, &event_category_push_notification); - event_set_append_log_prefix(dconfig->event, "push-notification-ox: "); - - if (http_url_parse(tmp, NULL, HTTP_URL_ALLOW_USERINFO_PART, pool, - &dconfig->http_url, &error) < 0) { - event_unref(&dconfig->event); - *error_r = t_strdup_printf("Failed to parse OX REST URL %s: %s", - tmp, error); - return -1; - } - dconfig->use_unsafe_username = - hash_table_lookup(config->config, (const char *)"user_from_metadata") != NULL; - - e_debug(dconfig->event, "Using URL %s", tmp); - - tmp = hash_table_lookup(config->config, (const char *)"cache_lifetime"); - if (tmp == NULL) - dconfig->cached_ox_metadata_lifetime_secs = DEFAULT_CACHE_LIFETIME_SECS; - else if (settings_get_time(tmp, &dconfig->cached_ox_metadata_lifetime_secs, &error) < 0) { - event_unref(&dconfig->event); - *error_r = t_strdup_printf("Failed to parse OX cache_lifetime %s: %s", - tmp, error); - return -1; - } - - tmp = hash_table_lookup(config->config, (const char *)"max_retries"); - if ((tmp == NULL) || - (str_to_uint(tmp, &dconfig->http_max_retries) < 0)) { - dconfig->http_max_retries = DEFAULT_RETRY_COUNT; - } - tmp = hash_table_lookup(config->config, (const char *)"timeout_msecs"); - if ((tmp == NULL) || - (str_to_uint(tmp, &dconfig->http_timeout_msecs) < 0)) { - dconfig->http_timeout_msecs = DEFAULT_TIMEOUT_MSECS; - } - - e_debug(dconfig->event, "Using cache lifetime: %u", - dconfig->cached_ox_metadata_lifetime_secs); - - if (ox_global == NULL) { - ox_global = i_new(struct push_notification_driver_ox_global, 1); - ox_global->refcount = 0; - } - - ++ox_global->refcount; - *context = dconfig; - - return 0; + struct push_notification_driver_ox_config *dconfig; + const char *error, *tmp; + + /* Valid config keys: cache_lifetime, url */ + tmp = hash_table_lookup(config->config, (const char *)"url"); + if (tmp == NULL) { + *error_r = "Driver requires the url parameter"; + return -1; + } + + dconfig = p_new(pool, struct push_notification_driver_ox_config, 1); + dconfig->event = event_create(user->event); + event_add_category(dconfig->event, &event_category_push_notification); + event_set_append_log_prefix(dconfig->event, "push-notification-ox: "); + + if (http_url_parse(tmp, NULL, HTTP_URL_ALLOW_USERINFO_PART, pool, + &dconfig->http_url, &error) < 0) { + event_unref(&dconfig->event); + *error_r = t_strdup_printf("Failed to parse OX REST URL %s: %s", + tmp, error); + return -1; + } + dconfig->use_unsafe_username = + hash_table_lookup(config->config, + (const char *)"user_from_metadata") != NULL; + + e_debug(dconfig->event, "Using URL %s", tmp); + + tmp = hash_table_lookup(config->config, (const char *)"cache_lifetime"); + if (tmp == NULL) { + dconfig->cached_ox_metadata_lifetime_secs = + DEFAULT_CACHE_LIFETIME_SECS; + } else if (settings_get_time( + tmp, &dconfig->cached_ox_metadata_lifetime_secs, &error) < 0) { + event_unref(&dconfig->event); + *error_r = t_strdup_printf( + "Failed to parse OX cache_lifetime %s: %s", tmp, error); + return -1; + } + + tmp = hash_table_lookup(config->config, (const char *)"max_retries"); + if ((tmp == NULL) || + (str_to_uint(tmp, &dconfig->http_max_retries) < 0)) { + dconfig->http_max_retries = DEFAULT_RETRY_COUNT; + } + tmp = hash_table_lookup(config->config, (const char *)"timeout_msecs"); + if ((tmp == NULL) || + (str_to_uint(tmp, &dconfig->http_timeout_msecs) < 0)) { + dconfig->http_timeout_msecs = DEFAULT_TIMEOUT_MSECS; + } + + e_debug(dconfig->event, "Using cache lifetime: %u", + dconfig->cached_ox_metadata_lifetime_secs); + + if (ox_global == NULL) { + ox_global = i_new(struct push_notification_driver_ox_global, 1); + ox_global->refcount = 0; + } + + ++ox_global->refcount; + *context = dconfig; + + return 0; } -static const char *push_notification_driver_ox_get_metadata -(struct push_notification_driver_txn *dtxn) +static const char * +push_notification_driver_ox_get_metadata( + struct push_notification_driver_txn *dtxn) { - struct push_notification_driver_ox_config *dconfig = dtxn->duser->context; - struct mail_attribute_value attr; - struct mailbox *inbox; - struct mail_namespace *ns; - bool success = FALSE, use_existing_txn = FALSE; - int ret; - - if ((dconfig->cached_ox_metadata != NULL) && - ((dconfig->cached_ox_metadata_timestamp + - (time_t)dconfig->cached_ox_metadata_lifetime_secs) > ioloop_time)) { - return dconfig->cached_ox_metadata; - } - - /* Get canonical INBOX, where private server-level metadata is stored. - * See imap/cmd-getmetadata.c */ - if ((dtxn->ptxn->t != NULL) && dtxn->ptxn->mbox->inbox_user) { - inbox = dtxn->ptxn->mbox; - use_existing_txn = TRUE; - } else { - ns = mail_namespace_find_inbox(dtxn->ptxn->muser->namespaces); - inbox = mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY); - } - - ret = mailbox_attribute_get(inbox, MAIL_ATTRIBUTE_TYPE_PRIVATE, - OX_METADATA_KEY, &attr); - if (ret < 0) { - e_error(dconfig->event, "Skipped because unable to get attribute: %s", - mailbox_get_last_internal_error(inbox, NULL)); - } else if (ret == 0) { - e_debug(dconfig->event, - "Skipped because not active (/private/"OX_METADATA_KEY" METADATA not set)"); - } else { - success = TRUE; - } - - if (!use_existing_txn) { - mailbox_free(&inbox); - } - if (!success) - return NULL; - - i_free(dconfig->cached_ox_metadata); - dconfig->cached_ox_metadata = i_strdup(attr.value); - dconfig->cached_ox_metadata_timestamp = ioloop_time; - - return dconfig->cached_ox_metadata; + struct push_notification_driver_ox_config *dconfig = + dtxn->duser->context; + struct mail_attribute_value attr; + struct mailbox *inbox; + struct mail_namespace *ns; + bool success = FALSE, use_existing_txn = FALSE; + int ret; + + if ((dconfig->cached_ox_metadata != NULL) && + ((dconfig->cached_ox_metadata_timestamp + + (time_t)dconfig->cached_ox_metadata_lifetime_secs) > + ioloop_time)) { + return dconfig->cached_ox_metadata; + } + + /* Get canonical INBOX, where private server-level metadata is stored. + * See imap/cmd-getmetadata.c */ + if ((dtxn->ptxn->t != NULL) && dtxn->ptxn->mbox->inbox_user) { + inbox = dtxn->ptxn->mbox; + use_existing_txn = TRUE; + } else { + ns = mail_namespace_find_inbox(dtxn->ptxn->muser->namespaces); + inbox = mailbox_alloc(ns->list, "INBOX", MAILBOX_FLAG_READONLY); + } + + ret = mailbox_attribute_get(inbox, MAIL_ATTRIBUTE_TYPE_PRIVATE, + OX_METADATA_KEY, &attr); + if (ret < 0) { + e_error(dconfig->event, + "Skipped because unable to get attribute: %s", + mailbox_get_last_internal_error(inbox, NULL)); + } else if (ret == 0) { + e_debug(dconfig->event, + "Skipped because not active " + "(/private/"OX_METADATA_KEY" METADATA not set)"); + } else { + success = TRUE; + } + + if (!use_existing_txn) + mailbox_free(&inbox); + if (!success) + return NULL; + + i_free(dconfig->cached_ox_metadata); + dconfig->cached_ox_metadata = i_strdup(attr.value); + dconfig->cached_ox_metadata_timestamp = ioloop_time; + + return dconfig->cached_ox_metadata; } -static bool push_notification_driver_ox_begin_txn -(struct push_notification_driver_txn *dtxn) +static bool +push_notification_driver_ox_begin_txn(struct push_notification_driver_txn *dtxn) { - const char *const *args; - struct push_notification_event_messagenew_config *config; - const char *key, *mbox_curr, *md_value, *value; - bool mbox_found = FALSE; - struct push_notification_driver_ox_txn *txn; - struct push_notification_driver_ox_config *dconfig = dtxn->duser->context; - - md_value = push_notification_driver_ox_get_metadata(dtxn); - if (md_value == NULL) { - return FALSE; - } - - /* Unused keys: events, expire, folder */ - /* TODO: To be implemented later(?) */ - const char *const *events = default_events; - time_t expire = INT_MAX; - const char *const *mboxes = default_mboxes; - - if (expire < ioloop_time) { - e_debug(dconfig->event, "Skipped due to expiration (%ld < %ld)", - (long)expire, (long)ioloop_time); - return FALSE; - } - - mbox_curr = mailbox_get_vname(dtxn->ptxn->mbox); - for (; *mboxes != NULL; mboxes++) { - if (strcmp(mbox_curr, *mboxes) == 0) { - mbox_found = TRUE; - break; - } - } - - if (mbox_found == FALSE) { - e_debug(dconfig->event, "Skipped because %s is not a watched mailbox", - mbox_curr); - return FALSE; - } - - txn = p_new(dtxn->ptxn->pool, struct push_notification_driver_ox_txn, 1); - - /* Valid keys: user */ - args = t_strsplit_tabescaped(md_value); - for (; *args != NULL; args++) { - key = *args; - - value = strchr(key, '='); - if (value != NULL) { - key = t_strdup_until(key, value++); - if (strcmp(key, "user") == 0) { - txn->unsafe_user = p_strdup(dtxn->ptxn->pool, value); - } - } - } - - if (txn->unsafe_user == NULL) { - e_error(dconfig->event, "No user provided in config"); - return FALSE; - } - - e_debug(dconfig->event, "User (%s)", txn->unsafe_user); - - for (; *events != NULL; events++) { - if (strcmp(*events, "MessageNew") == 0) { - config = p_new(dtxn->ptxn->pool, - struct push_notification_event_messagenew_config, 1); - config->flags = PUSH_NOTIFICATION_MESSAGE_HDR_FROM | - PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT | - PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET; - push_notification_event_init(dtxn, "MessageNew", config); - e_debug(dconfig->event, "Handling MessageNew event"); - } - } - - dtxn->context = txn; - - return TRUE; + const char *const *args; + struct push_notification_event_messagenew_config *config; + const char *key, *mbox_curr, *md_value, *value; + bool mbox_found = FALSE; + struct push_notification_driver_ox_txn *txn; + struct push_notification_driver_ox_config *dconfig = + dtxn->duser->context; + + md_value = push_notification_driver_ox_get_metadata(dtxn); + if (md_value == NULL) + return FALSE; + + /* Unused keys: events, expire, folder */ + /* TODO: To be implemented later(?) */ + const char *const *events = default_events; + time_t expire = INT_MAX; + const char *const *mboxes = default_mboxes; + + if (expire < ioloop_time) { + e_debug(dconfig->event, "Skipped due to expiration (%ld < %ld)", + (long)expire, (long)ioloop_time); + return FALSE; + } + + mbox_curr = mailbox_get_vname(dtxn->ptxn->mbox); + for (; *mboxes != NULL; mboxes++) { + if (strcmp(mbox_curr, *mboxes) == 0) { + mbox_found = TRUE; + break; + } + } + + if (mbox_found == FALSE) { + e_debug(dconfig->event, + "Skipped because %s is not a watched mailbox", + mbox_curr); + return FALSE; + } + + txn = p_new(dtxn->ptxn->pool, + struct push_notification_driver_ox_txn, 1); + + /* Valid keys: user */ + args = t_strsplit_tabescaped(md_value); + for (; *args != NULL; args++) { + key = *args; + + value = strchr(key, '='); + if (value != NULL) { + key = t_strdup_until(key, value++); + if (strcmp(key, "user") == 0) { + txn->unsafe_user = + p_strdup(dtxn->ptxn->pool, value); + } + } + } + + if (txn->unsafe_user == NULL) { + e_error(dconfig->event, "No user provided in config"); + return FALSE; + } + + e_debug(dconfig->event, "User (%s)", txn->unsafe_user); + + for (; *events != NULL; events++) { + if (strcmp(*events, "MessageNew") == 0) { + config = p_new( + dtxn->ptxn->pool, + struct push_notification_event_messagenew_config, 1); + config->flags = PUSH_NOTIFICATION_MESSAGE_HDR_FROM | + PUSH_NOTIFICATION_MESSAGE_HDR_SUBJECT | + PUSH_NOTIFICATION_MESSAGE_BODY_SNIPPET; + push_notification_event_init( + dtxn, "MessageNew", config); + e_debug(dconfig->event, "Handling MessageNew event"); + } + } + + dtxn->context = txn; + + return TRUE; } -static void push_notification_driver_ox_http_callback -(const struct http_response *response, struct push_notification_driver_ox_config *dconfig) +static void +push_notification_driver_ox_http_callback( + const struct http_response *response, + struct push_notification_driver_ox_config *dconfig) { - switch (response->status / 100) { - case 2: - // Success. - e_debug(dconfig->event, "Notification sent successfully: %s", - http_response_get_message(response)); - break; - - default: - // Error. - e_error(dconfig->event, "Error when sending notification: %s", - http_response_get_message(response)); - break; - } + switch (response->status / 100) { + case 2: + // Success. + e_debug(dconfig->event, "Notification sent successfully: %s", + http_response_get_message(response)); + break; + + default: + // Error. + e_error(dconfig->event, "Error when sending notification: %s", + http_response_get_message(response)); + break; + } } /* Callback needed for i_stream_add_destroy_callback() in - * push_notification_driver_ox_process_msg. */ + push_notification_driver_ox_process_msg. */ static void str_free_i(string_t *str) { - str_free(&str); + str_free(&str); } -static int push_notification_driver_ox_get_mailbox_status -(struct push_notification_driver_txn *dtxn, - struct mailbox_status *r_box_status) +static int +push_notification_driver_ox_get_mailbox_status( + struct push_notification_driver_txn *dtxn, + struct mailbox_status *r_box_status) { - struct push_notification_driver_ox_config *dconfig = dtxn->duser->context; - /* The already opened mailbox. We cannot use or sync it, because we are within a save transaction. */ - struct mailbox *mbox = dtxn->ptxn->mbox; - struct mailbox *box; - int ret; - - /* open and sync new instance of the same mailbox to get most recent status */ - box = mailbox_alloc(mailbox_get_namespace(mbox)->list, mailbox_get_name(mbox), MAILBOX_FLAG_READONLY); - if (mailbox_sync(box, 0) < 0) { - e_error(dconfig->event, "mailbox_sync(%s) failed: %s", mailbox_get_vname(mbox), mailbox_get_last_internal_error(box, NULL)); - ret = -1; - } else { - /* only 'unseen' is needed at the moment */ - mailbox_get_open_status(box, STATUS_UNSEEN, r_box_status); - e_debug(dconfig->event, "Got status of mailbox '%s': (unseen: %u)", - mailbox_get_vname(box), r_box_status->unseen); - ret = 0; - } - - mailbox_free(&box); - return ret; + struct push_notification_driver_ox_config *dconfig = + dtxn->duser->context; + /* The already opened mailbox. We cannot use or sync it, because we are + within a save transaction. */ + struct mailbox *mbox = dtxn->ptxn->mbox; + struct mailbox *box; + int ret; + + /* Open and sync new instance of the same mailbox to get most recent + status */ + box = mailbox_alloc(mailbox_get_namespace(mbox)->list, + mailbox_get_name(mbox), MAILBOX_FLAG_READONLY); + if (mailbox_sync(box, 0) < 0) { + e_error(dconfig->event, "mailbox_sync(%s) failed: %s", + mailbox_get_vname(mbox), + mailbox_get_last_internal_error(box, NULL)); + ret = -1; + } else { + /* only 'unseen' is needed at the moment */ + mailbox_get_open_status(box, STATUS_UNSEEN, r_box_status); + e_debug(dconfig->event, + "Got status of mailbox '%s': (unseen: %u)", + mailbox_get_vname(box), r_box_status->unseen); + ret = 0; + } + + mailbox_free(&box); + return ret; } -static void push_notification_driver_ox_process_msg -(struct push_notification_driver_txn *dtxn, - struct push_notification_txn_msg *msg) +static void +push_notification_driver_ox_process_msg( + struct push_notification_driver_txn *dtxn, + struct push_notification_txn_msg *msg) { - struct push_notification_driver_ox_config *dconfig = - (struct push_notification_driver_ox_config *)dtxn->duser->context; - struct http_client_request *http_req; - struct push_notification_event_messagenew_data *messagenew; - struct istream *payload; - string_t *str; - struct push_notification_driver_ox_txn *txn = - (struct push_notification_driver_ox_txn *)dtxn->context; - struct mail_user *user = dtxn->ptxn->muser; - struct mailbox_status box_status; - bool status_success = TRUE; - - if (push_notification_driver_ox_get_mailbox_status(dtxn, &box_status) < 0) { - status_success = FALSE; - } - - messagenew = push_notification_txn_msg_get_eventdata(msg, "MessageNew"); - if (messagenew == NULL) { - return; - } - - push_notification_driver_ox_init_global(user, dconfig); - - http_req = http_client_request_url(ox_global->http_client, "PUT", - dconfig->http_url, - push_notification_driver_ox_http_callback, - dconfig); - http_client_request_set_event(http_req, dconfig->event); - http_client_request_add_header(http_req, "Content-Type", - "application/json; charset=utf-8"); - - str = str_new(default_pool, 256); - str_append(str, "{\"user\":\""); - json_append_escaped(str, dconfig->use_unsafe_username ? - txn->unsafe_user : user->username); - str_append(str, "\",\"event\":\"messageNew\",\"folder\":\""); - json_append_escaped(str, msg->mailbox); - str_printfa(str, "\",\"imap-uidvalidity\":%u,\"imap-uid\":%u", - msg->uid_validity, msg->uid); - if (messagenew->from != NULL) { - str_append(str, ",\"from\":\""); - json_append_escaped(str, messagenew->from); - str_append(str, "\""); - } - if (messagenew->subject != NULL) { - str_append(str, ",\"subject\":\""); - json_append_escaped(str, messagenew->subject); - str_append(str, "\""); - } - if (messagenew->snippet != NULL) { - str_append(str, ",\"snippet\":\""); - json_append_escaped(str, messagenew->snippet); - str_append(str, "\""); - } - if (status_success) { - str_printfa(str, ",\"unseen\":%u", box_status.unseen); - } - str_append(str, "}"); - - e_debug(dconfig->event, "Sending notification: %s", str_c(str)); - - payload = i_stream_create_from_data(str_data(str), str_len(str)); - i_stream_add_destroy_callback(payload, str_free_i, str); - http_client_request_set_payload(http_req, payload, FALSE); - - http_client_request_submit(http_req); - i_stream_unref(&payload); + struct push_notification_driver_ox_config *dconfig = + (struct push_notification_driver_ox_config *) + dtxn->duser->context; + struct http_client_request *http_req; + struct push_notification_event_messagenew_data *messagenew; + struct istream *payload; + string_t *str; + struct push_notification_driver_ox_txn *txn = + (struct push_notification_driver_ox_txn *)dtxn->context; + struct mail_user *user = dtxn->ptxn->muser; + struct mailbox_status box_status; + bool status_success = TRUE; + + if (push_notification_driver_ox_get_mailbox_status( + dtxn, &box_status) < 0) { + status_success = FALSE; + } + + messagenew = push_notification_txn_msg_get_eventdata(msg, "MessageNew"); + if (messagenew == NULL) + return; + + push_notification_driver_ox_init_global(user, dconfig); + + http_req = http_client_request_url( + ox_global->http_client, "PUT", dconfig->http_url, + push_notification_driver_ox_http_callback, dconfig); + http_client_request_set_event(http_req, dconfig->event); + http_client_request_add_header(http_req, "Content-Type", + "application/json; charset=utf-8"); + + str = str_new(default_pool, 256); + str_append(str, "{\"user\":\""); + json_append_escaped(str, dconfig->use_unsafe_username ? + txn->unsafe_user : user->username); + str_append(str, "\",\"event\":\"messageNew\",\"folder\":\""); + json_append_escaped(str, msg->mailbox); + str_printfa(str, "\",\"imap-uidvalidity\":%u,\"imap-uid\":%u", + msg->uid_validity, msg->uid); + if (messagenew->from != NULL) { + str_append(str, ",\"from\":\""); + json_append_escaped(str, messagenew->from); + str_append(str, "\""); + } + if (messagenew->subject != NULL) { + str_append(str, ",\"subject\":\""); + json_append_escaped(str, messagenew->subject); + str_append(str, "\""); + } + if (messagenew->snippet != NULL) { + str_append(str, ",\"snippet\":\""); + json_append_escaped(str, messagenew->snippet); + str_append(str, "\""); + } + if (status_success) { + str_printfa(str, ",\"unseen\":%u", box_status.unseen); + } + str_append(str, "}"); + + e_debug(dconfig->event, "Sending notification: %s", str_c(str)); + + payload = i_stream_create_from_data(str_data(str), str_len(str)); + i_stream_add_destroy_callback(payload, str_free_i, str); + http_client_request_set_payload(http_req, payload, FALSE); + + http_client_request_submit(http_req); + i_stream_unref(&payload); } -static void push_notification_driver_ox_deinit -(struct push_notification_driver_user *duser ATTR_UNUSED) +static void +push_notification_driver_ox_deinit( + struct push_notification_driver_user *duser ATTR_UNUSED) { - struct push_notification_driver_ox_config *dconfig = duser->context; - - i_free(dconfig->cached_ox_metadata); - if (ox_global != NULL) { - if (ox_global->http_client != NULL) - http_client_wait(ox_global->http_client); - i_assert(ox_global->refcount > 0); - --ox_global->refcount; - } - event_unref(&dconfig->event); + struct push_notification_driver_ox_config *dconfig = duser->context; + + i_free(dconfig->cached_ox_metadata); + if (ox_global != NULL) { + if (ox_global->http_client != NULL) + http_client_wait(ox_global->http_client); + i_assert(ox_global->refcount > 0); + --ox_global->refcount; + } + event_unref(&dconfig->event); } static void push_notification_driver_ox_cleanup(void) { - if ((ox_global != NULL) && (ox_global->refcount <= 0)) { - if (ox_global->http_client != NULL) { - http_client_deinit(&ox_global->http_client); - } - i_free_and_null(ox_global); - } + if ((ox_global != NULL) && (ox_global->refcount <= 0)) { + if (ox_global->http_client != NULL) { + http_client_deinit(&ox_global->http_client); + } + i_free_and_null(ox_global); + } } - /* Driver definition */ extern struct push_notification_driver push_notification_driver_ox; struct push_notification_driver push_notification_driver_ox = { - .name = "ox", - .v = { - .init = push_notification_driver_ox_init, - .begin_txn = push_notification_driver_ox_begin_txn, - .process_msg = push_notification_driver_ox_process_msg, - .deinit = push_notification_driver_ox_deinit, - .cleanup = push_notification_driver_ox_cleanup - } + .name = "ox", + .v = { + .init = push_notification_driver_ox_init, + .begin_txn = push_notification_driver_ox_begin_txn, + .process_msg = push_notification_driver_ox_process_msg, + .deinit = push_notification_driver_ox_deinit, + .cleanup = push_notification_driver_ox_cleanup, + }, };