From 6e1288472fcc877a17277e10a2e1f23f64b66a55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilja=20Karta=C5=A1ov?= Date: Mon, 8 Apr 2019 22:19:28 +0200 Subject: [PATCH] Add mod's interface and mod-feedback prototype --- mods/interface.c | 74 ++++++++++++++ mods/interface.h | 90 +++++++++++++++++ mods/mod-feedback.c | 234 ++++++++++++++++++++++++++++++++++++++++++++ mods/mod-feedback.h | 64 ++++++++++++ 4 files changed, 462 insertions(+) create mode 100644 mods/interface.c create mode 100644 mods/interface.h create mode 100644 mods/mod-feedback.c create mode 100644 mods/mod-feedback.h diff --git a/mods/interface.c b/mods/interface.c new file mode 100644 index 0000000..677c879 --- /dev/null +++ b/mods/interface.c @@ -0,0 +1,74 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file interface.c + * @author Ilja Kartašov + * @brief Interface source file for AISL SDK modules + * + * @see https://lowenware.com/ + */ + +#include "interface.h" + + +aisl_mod_ctx_t +aisl_mod_ctx_new(aislx_mod_t mod) +{ + aisl_mod_ctx_t ctx; + + if ((ctx = calloc(1, mod->ctx_size)) != NULL) + { + ctx->mod = mod; + } + + return ctx; +} + + +void +aislx_mod_ctx_free(aislx_mod_ctx_t ctx) +{ + free(ctx); +} + + +aisl_status_t +aislx_mod_on_event(aislx_mod_t mod, aisl_evt_t const evt) +{ + switch(evt->code) + { + case AISL_EVENT_STREAM_OPEN: + { + aisl_evt_stream_open_t so_evt = (aisl_evt_stream_open_t)evt; + if ( strncmp(so_evt->path, mod->end_point, mod->ep_length) != 0) + return AISL_IDLE; + + break; + } + + case AISL_EVENT_STREAM_HEADER: + case AISL_EVENT_STREAM_INPUT: + case AISL_EVENT_STREAM_REQUEST: + case AISL_EVENT_STREAM_OUTPUT: + case AISL_EVENT_STREAM_CLOSE: + { + aislx_mod_ctx_t ctx = aisl_get_context((aisl_stream_t)evt->source); + + if (!ctx) + return AISL_SUCCESS; + + if (ctx->mod == mod) + break; + } + + default: + return AISL_IDLE; + } + + return mod->on_event(mod, evt); +} diff --git a/mods/interface.h b/mods/interface.h new file mode 100644 index 0000000..82a012f --- /dev/null +++ b/mods/interface.h @@ -0,0 +1,90 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file interface.h + * @author Ilja Kartašov + * @brief Interface header file for AISL SDK modules + * + * @see https://lowenware.com/aisl/ + */ + +#ifndef AISL_SDK_MODS_INTERFACE_H_1AEFECA5_9341_431B_8194_EA0C2E76B5EA +#define AISL_SDK_MODS_INTERFACE_H_1AEFECA5_9341_431B_8194_EA0C2E76B5EA + +#include + + +#define AISLX_MOD_INIT(MOD, END_POINT) \ + do { \ + ((aislx_mod_t) mod)->end_point = END_POINT; \ + ((aislx_mod_t) mod)->ep_length = strlen(END_POINT); \ + ((aislx_mod_t) mod)->on_stream_event = MOD##_on_event; \ + ((aislx_mod_t) mod)->ctx_size = sizeof(struct context); \ + } while(0) \ + + +/** @brief AISL mod structure pointer + */ +typedef struct aislx_mod * aislx_mod_t; + + +/** @brief Pointer to AISL stream event observer + */ +typedef aisl_status_t +(* aislx_mod_observer_t)(aislx_mode * aislx_mod_t, aisl_evt_t const evt); + + +/** @brief Root level AISL mod's structure + */ +struct aislx_mod +{ + const char * end_point; /**< Root mod's URL or NULL */ + aislx_mod_observer_t on_event; /**< Mod's stream event observer */ + size_t ctx_size; /**< Mod's context size */ + uint8_t ep_length; /**< Mod's context size */ +}; + + +/** @brief Root level ASIL mod's context structure + */ +struct aislx_mod_ctx +{ + aislx_mod_t mod; /**< Mod's pointer */ +}; + +/** @brief Root level ASIL mod's context structure pointer + */ +typedef struct aislx_mod_ctx * aislx_mod_ctx_t; + + +/** @brief Allocates zeroed #aislx_mod_t context + * @param mod an instance of #aislx_mod_t + * @return pointer to newly allocated #aisl_mox_ctx_t + */ +aisl_mod_ctx_t +aisl_mod_ctx_new(aislx_mod_t mod); + + +/** @brief Frees previosly allocated #aislx_mod_ctx_t + * @param ctx an instance of mod's context structure + * */ +void +aislx_mod_ctx_free(aislx_mod_ctx_t ctx); + + +/** @brief Wrapper function that calles mod's observer + * @param mod an instance of #aislx_mod_t + * @param evt an AISL stream event + * @return AISL_SUCCESS if event handled, AISL_IDLE if event not handled or an + * error code + */ +aisl_status_t +aislx_mod_on_event(aislx_mod_t mod, aisl_evt_t const evt); + + +#endif /* !AISL_SDK_MODS_INTERFACE_H */ diff --git a/mods/mod-feedback.c b/mods/mod-feedback.c new file mode 100644 index 0000000..5723447 --- /dev/null +++ b/mods/mod-feedback.c @@ -0,0 +1,234 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file mod-feedback.c + * @author Ilja Kartašov + * @brief AISL feedback module source file + * + * @see https://lowenware.com/aisl/ + */ +#include +#include +#include +#include +#include "mod-feedback.h" + + +struct context +{ + struct aislx_mod_ctx root; + struct aislx_query_stream qs; + struct aislx_mail mail; + + char * email; + char * message; +}; + +typedef struct context * context_t; + + +static void +context_free(context_t ctx) +{ + aislx_query_stream_release(&ctx->qs); + aislx_mail_release(&ctx->mail); + + if (ctx->email) + free(ctx->email); + + if (ctx->message) + free(ctx->message); + + aislx_mod_ctx_free(ctx); +} + + +static int +on_input_var( const char * key, int k_len, + const char * val, int v_len, + void * p_ctx ) +{ + context_t ctx = (context_t) p_ctx; + aislx_mod_feedback_t mod = (aislx_mod_feedback_t)((aislx_mod_ctx_t)ctx)->mod; + + if (!ctx->email && k_len == mod->name_email_length) + { + if (strncmp(key, mod->name_email, k_len)==0) + return cstuff_strncpy(&ctx->email, val, v_len); + } + + if (!ctx->message && k_len == mod->name_message_length) + { + if (strncmp(key, mod->name_message, k_len)==0) + return cstuff_strncpy(&ctx->message, val, v_len); + } + + return 0; +} + + +static aisl_status_t +on_stream_open(aislx_mod_feedback_t mod, aisl_evt_stream_open_t const evt) +{ + context_t ctx; + aisl_stream_t s = (aisl_stream_t) (evt->evt.source); + + if (!(ctx = (context_t)aislx_mod_ctx_new(mod))) + goto e_malloc; + + ctx->mail.from = mod->mail_from; + ctx->mail.subject = mod->mail_subject; + ctx->mail.smtp_server = mod->smtp_server; + ctx->mail.smtp_user = mod->smtp_user; + ctx->mail.smtp_password = mod->smtp_password; + ctx->mail.smtp_port = mod->smtp_port; + + if(aislx_query_stream_init(&ctx->qs, on_input_var, NULL, (void*)ctx) != 0) + goto release; + + aisl_set_context(s, ctx); + + return AISL_SUCCESS; + +release: + context_free(ctx); + +e_malloc: + return AISL_MALLOC_ERROR; +} + + +static aisl_status_t +on_stream_header(aislx_mod_feedback_t mod, aisl_evt_stream_header_t const evt) +{ + return AISL_SUCCESS; +} + + +static aisl_status_t +on_stream_input(aislx_mod_feedback_t mod, aisl_evt_stream_input_t const evt) +{ + context_t ctx = aisl_get_context((aisl_stream_t)evt->evt.source); + + aislx_query_stream_feed(ctx->qs, evt->data, evt->size); + + return AISL_SUCCESS; +} + + +static aisl_status_t +on_stream_request(aislx_mod_feedback_t mod, aisl_evt_t const evt) +{ + context_t ctx = aisl_get_context((aisl_stream_t)evt->evt.source); + aisl_stream_t s = (aisl_stream_t)evt->source; + + /* finalize input */ + aislx_query_stream_flush(ctx->qs); + + /* verify input */ + if (!ctx->email || !ctx->message || aislx_validate_email(ctx->email) != 0) + aislx_quick_response(s, AISL_HTTP_BAD_REQUEST); + + ctx->mail.to = ctx->email; + ctx->mail.message = ctx->message; + + /* create thread */ + if (aislx_mail_send(&ctx->mail) != AISL_SUCCESS) + aislx_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR); + + aisl_set_output_event(s, true); /**< enable output event */ + + return AISL_SUCCESS; +} + + +static aisl_status_t +on_stream_output(aislx_mod_feedback_t mod, aisl_evt_t const evt) +{ + context_t ctx = aisl_get_context((aisl_stream_t)evt->evt.source); + + aisl_http_response_t rc = AISL_HTTP_OK; + + switch (aislx_mail_get_status(&ctx->mail)) + { + case AISL_SUCCESS: break; + case AISL_IDLE: return AISL_SUCCESS; + + default: + rc = AISL_HTTP_INTERNAL_SERVER_ERROR; + } + + aislx_quick_response((aisl_stream_t)evt->source, rc); + + return AISL_SUCCESS; +} + + +static aisl_status_t +on_stream_close(aislx_mod_feedback_t mod, aisl_evt_t const evt) +{ + context_free((context_t)aisl_get_context((aisl_stream_t)evt->evt.source)); + return AISL_SUCCESS; +} + + +static aisl_status_t +aislx_mod_feedback_on_event(aislx_mod_feedback_t mod, aisl_evt_t const evt) +{ + switch(evt->code) + { + case AISL_EVENT_STREAM_OPEN: + return on_stream_open(mod, (aisl_evt_stream_open_t)evt); + + case AISL_EVENT_STREAM_HEADER: + return on_stream_header(mod, (aisl_evt_stream_header_t)evt); + + case AISL_EVENT_STREAM_INPUT: + return on_stream_input(mod, (aisl_evt_stream_input_t)evt); + + case AISL_EVENT_STREAM_REQUEST: + return on_stream_request(mod, evt); + + case AISL_EVENT_STREAM_OUTPUT: + return on_stream_output(mod, evt); + + case AISL_EVENT_STREAM_CLOSE: + return on_stream_close(mod, evt); + + default: + return AISL_IDLE; + } +} + + +aisl_status_t +aislx_mod_feedback_init(aislx_mod_feedback_t mod, aislx_mod_feedback_cfg_t cfg) +{ + AISLX_MOD_INIT(aislx_mod_feedback, cfg->end_point); + + mod->mail_subject = cfg->mail_subject; + mod->mail_from = cfg->mail_from; + mod->name_email = cfg->name_email; + mod->name_message = cfg->name_message; + mod->smtp_server = cfg->smtp_server; + mod->smtp_user = cfg->smtp_user; + mod->smtp_password = cfg->smtp_password; + mod->smtp_port = cfg->smtp_port; + + mod->name_email_length = strlen(cfg->name_email); + mod->name_message_length = strlen(cfg->name_message); + + return AISL_SUCCESS; +} + + +void +aislx_mod_feedback_release(aislx_mod_feedback_t mod) +{ + +} diff --git a/mods/mod-feedback.h b/mods/mod-feedback.h new file mode 100644 index 0000000..111e1a5 --- /dev/null +++ b/mods/mod-feedback.h @@ -0,0 +1,64 @@ +/****************************************************************************** + * + * Copyright (c) 2017-2019 by Löwenware Ltd + * Please, refer LICENSE file for legal information + * + ******************************************************************************/ + +/** + * @file mod-feedback.h + * @author Ilja Kartašov + * @brief AISL feedback module header file + * + * @see https://lowenware.com/aisl/ + */ + +#ifndef AISLX_MOD_FEEDBACK_H_6CC516E4_A7F2_4A9D_B467_75DCF6F58108 +#define AISLX_MOD_FEEDBACK_H_6CC516E4_A7F2_4A9D_B467_75DCF6F58108 + +#include + + +struct aislx_mod_feedback_cfg +{ + const char * end_point; + const char * mail_subject; + const char * mail_from; + const char * name_email; + const char * name_message; + const char * smtp_server; + const char * smtp_user; + const char * smtp_password; + uint16_t smtp_port; + +}; + +struct aislx_mod_feedback +{ + struct aislx_mod root; + + const char * mail_subject; + const char * mail_from; + const char * name_email; + const char * name_message; + const char * smtp_server; + const char * smtp_user; + const char * smtp_password; + uint16_t smtp_port; + + uint16_t name_email_length; + uint16_t name_message_length; +}; + + +typedef struct aislx_mod_feedback * aislx_mod_feedback_t; + + +aisl_status_t +aislx_mod_feedback_init(aislx_mod_feedback_t mod, aislx_mod_feedback_cfg_t cfg); + + +void +aislx_mod_feedback_release(aislx_mod_feedback_t mod); + +#endif /* !AISLX_MOD_FEEDBACK_H */