forked from extern/alertik
Rework string manipulation & minor improvements on webhook events
This commit is contained in:
parent
db437fb6e3
commit
11079f41c1
2
Makefile
2
Makefile
@ -8,7 +8,7 @@ CFLAGS += -Wall -Wextra
|
||||
LDLIBS += -pthread -lcurl
|
||||
STRIP = strip
|
||||
VERSION = v0.1
|
||||
OBJS = alertik.o events.o env_events.o notifiers.o log.o syslog.o
|
||||
OBJS = alertik.o events.o env_events.o notifiers.o log.o syslog.o str.o
|
||||
|
||||
ifeq ($(LOG_FILE),yes)
|
||||
CFLAGS += -DUSE_FILE_AS_LOG
|
||||
|
99
env_events.c
99
env_events.c
@ -15,6 +15,7 @@
|
||||
#include "env_events.h"
|
||||
#include "alertik.h"
|
||||
#include "notifiers.h"
|
||||
#include "str.h"
|
||||
|
||||
/*
|
||||
* Environment events
|
||||
@ -105,30 +106,10 @@ get_event_idx(int ev_num, char *str, const char *const *str_list, int size)
|
||||
panic("String parameter (%s) invalid for %s\n", env, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends a character to the destination buffer if there is space.
|
||||
*
|
||||
* @param dst Pointer to the destination buffer.
|
||||
* @param dst_end End of the destination buffer.
|
||||
* @param c Character to append.
|
||||
*
|
||||
* @return Returns 1 if the character was appended, 0 otherwise.
|
||||
*/
|
||||
static int append_dst(char **dst, const char *dst_end, char c) {
|
||||
char *d = *dst;
|
||||
if (d < dst_end) {
|
||||
*d = c;
|
||||
*dst = ++d;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handles match replacement in the event mask message.
|
||||
*
|
||||
* @param dst Pointer to the destination buffer.
|
||||
* @param dst_e End of the destination buffer.
|
||||
* @param notif_message Pointer to the append buffer.
|
||||
* @param c_msk Pointer to the current position in the mask message.
|
||||
* @param e_msk End of the mask message.
|
||||
* @param pmatch Array of regex matches.
|
||||
@ -138,7 +119,7 @@ static int append_dst(char **dst, const char *dst_end, char c) {
|
||||
* @return Returns 1 if the replacement was handled, 0 otherwise.
|
||||
*/
|
||||
static int handle_match_replacement(
|
||||
char **dst, char *dst_e,
|
||||
struct str_ab *notif_message,
|
||||
const char **c_msk, const char *e_msk,
|
||||
regmatch_t *pmatch,
|
||||
struct env_event *env,
|
||||
@ -172,10 +153,8 @@ static int handle_match_replacement(
|
||||
off = pmatch[match].rm_so;
|
||||
len = pmatch[match].rm_eo - off;
|
||||
|
||||
for (regoff_t i = 0; i < len; i++) {
|
||||
if ( !append_dst(dst, dst_e, log_ev->msg[off + i]) )
|
||||
return 0;
|
||||
}
|
||||
if (ab_append_str(notif_message, log_ev->msg + off, len) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -192,22 +171,19 @@ static int handle_match_replacement(
|
||||
*
|
||||
* @return Returns the pointer to the end of the masked message.
|
||||
*/
|
||||
static char*
|
||||
static int
|
||||
create_masked_message(struct env_event *env, regmatch_t *pmatch,
|
||||
struct log_event *log_ev, char *buf, size_t buf_size)
|
||||
struct log_event *log_ev, struct str_ab *notif_message)
|
||||
{
|
||||
char *dst, *dst_e;
|
||||
const char *c_msk, *e_msk;
|
||||
const char *c_msk, *e_msk;
|
||||
|
||||
c_msk = env->ev_mask_msg;
|
||||
e_msk = c_msk + strlen(c_msk);
|
||||
dst = buf;
|
||||
dst_e = dst + buf_size;
|
||||
|
||||
for (; *c_msk != '\0'; c_msk++)
|
||||
{
|
||||
if (*c_msk != '@') {
|
||||
if (!append_dst(&dst, dst_e, *c_msk))
|
||||
if (ab_append_chr(notif_message, *c_msk) < 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
@ -220,7 +196,7 @@ create_masked_message(struct env_event *env, regmatch_t *pmatch,
|
||||
* If next is also '@',escape it.
|
||||
*/
|
||||
if (c_msk[1] == '@') {
|
||||
if (!append_dst(&dst, dst_e, *c_msk))
|
||||
if (ab_append_chr(notif_message, *c_msk) < 0)
|
||||
break;
|
||||
else {
|
||||
c_msk++;
|
||||
@ -240,14 +216,16 @@ create_masked_message(struct env_event *env, regmatch_t *pmatch,
|
||||
else
|
||||
{
|
||||
c_msk++;
|
||||
if (!handle_match_replacement(&dst, dst_e, &c_msk, e_msk,
|
||||
if (!handle_match_replacement(notif_message, &c_msk, e_msk,
|
||||
pmatch, env, log_ev))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
|
||||
/* If we could parse the entire mask. */
|
||||
return (*c_msk == '\0');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -262,10 +240,10 @@ static int handle_regex(struct log_event *ev, int idx_env)
|
||||
{
|
||||
char time_str[32] = {0};
|
||||
regmatch_t pmatch[MAX_MATCHES] = {0};
|
||||
char notification_message[2048] = {0};
|
||||
struct str_ab notif_message;
|
||||
|
||||
int ret;
|
||||
int notif_idx;
|
||||
char *notif_p;
|
||||
struct env_event *env_ev;
|
||||
|
||||
env_ev = &env_events[idx_env];
|
||||
@ -280,34 +258,35 @@ static int handle_regex(struct log_event *ev, int idx_env)
|
||||
log_msg("> amnt sub expr: %zu\n", env_ev->regex.re_nsub);
|
||||
log_msg("> notifier : %s\n", notifiers_str[notif_idx]);
|
||||
|
||||
notif_p = notification_message;
|
||||
ab_init(¬if_message);
|
||||
|
||||
/* Check if there are any subexpressions, if not, just format
|
||||
* the message.
|
||||
*/
|
||||
if (env_ev->regex.re_nsub) {
|
||||
notif_p = create_masked_message(env_ev, pmatch, ev,
|
||||
notification_message, sizeof(notification_message) - 1);
|
||||
if (!create_masked_message(env_ev, pmatch, ev, ¬if_message)) {
|
||||
log_msg("Unable to create masked message!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
notif_p,
|
||||
(notification_message + sizeof(notification_message)) - notif_p,
|
||||
", at: %s",
|
||||
get_formatted_time(ev->timestamp, time_str)
|
||||
);
|
||||
if (ab_append_fmt(¬if_message, ", at: %s",
|
||||
get_formatted_time(ev->timestamp, time_str)))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
snprintf(
|
||||
notification_message,
|
||||
sizeof(notification_message) - 1,
|
||||
ret = ab_append_fmt(¬if_message,
|
||||
"%s, at: %s",
|
||||
env_ev->ev_mask_msg,
|
||||
get_formatted_time(ev->timestamp, time_str)
|
||||
);
|
||||
get_formatted_time(ev->timestamp, time_str));
|
||||
|
||||
if (ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (notifiers[notif_idx].send_notification(notification_message) < 0) {
|
||||
if (notifiers[notif_idx].send_notification(notif_message.buff) < 0) {
|
||||
log_msg("unable to send the notification through %s\n",
|
||||
notifiers_str[notif_idx]);
|
||||
}
|
||||
@ -325,10 +304,11 @@ static int handle_regex(struct log_event *ev, int idx_env)
|
||||
*/
|
||||
static int handle_substr(struct log_event *ev, int idx_env)
|
||||
{
|
||||
int ret;
|
||||
int notif_idx;
|
||||
char time_str[32] = {0};
|
||||
struct env_event *env_ev;
|
||||
char notification_message[2048] = {0};
|
||||
struct str_ab notif_message;
|
||||
|
||||
env_ev = &env_events[idx_env];
|
||||
notif_idx = env_ev->ev_notifier_idx;
|
||||
@ -340,16 +320,19 @@ static int handle_substr(struct log_event *ev, int idx_env)
|
||||
log_msg("> type: substr, match: (%s), notifier: %s\n",
|
||||
env_ev->ev_match_str, notifiers_str[notif_idx]);
|
||||
|
||||
ab_init(¬if_message);
|
||||
|
||||
/* Format the message. */
|
||||
snprintf(
|
||||
notification_message,
|
||||
sizeof notification_message - 1,
|
||||
ret = ab_append_fmt(¬if_message,
|
||||
"%s, at: %s",
|
||||
env_ev->ev_mask_msg,
|
||||
get_formatted_time(ev->timestamp, time_str)
|
||||
);
|
||||
|
||||
if (notifiers[notif_idx].send_notification(notification_message) < 0) {
|
||||
if (ret)
|
||||
return 0;
|
||||
|
||||
if (notifiers[notif_idx].send_notification(notif_message.buff) < 0) {
|
||||
log_msg("unable to send the notification through %s\n",
|
||||
notifiers_str[notif_idx]);
|
||||
}
|
||||
|
15
events.c
15
events.c
@ -12,6 +12,7 @@
|
||||
#include "alertik.h"
|
||||
#include "notifiers.h"
|
||||
#include "log.h"
|
||||
#include "str.h"
|
||||
|
||||
/*
|
||||
* Static events
|
||||
@ -252,18 +253,19 @@ static void handle_wifi_login_attempts(struct log_event *ev, int idx_env)
|
||||
char time_str[32] = {0};
|
||||
char mac_addr[32] = {0};
|
||||
char wifi_iface[32] = {0};
|
||||
char notification_message[2048] = {0};
|
||||
struct str_ab notif_message;
|
||||
int notif_idx;
|
||||
int ret;
|
||||
|
||||
log_msg("> Login attempt detected!\n");
|
||||
|
||||
if (parse_login_attempt_msg(ev->msg, wifi_iface, mac_addr) < 0)
|
||||
return;
|
||||
|
||||
ab_init(¬if_message);
|
||||
|
||||
/* Send our notification. */
|
||||
snprintf(
|
||||
notification_message,
|
||||
sizeof notification_message - 1,
|
||||
ret = ab_append_fmt(¬if_message,
|
||||
"There is someone trying to connect "
|
||||
"to your WiFi: %s, with the mac-address: %s, at:%s",
|
||||
wifi_iface,
|
||||
@ -271,10 +273,13 @@ static void handle_wifi_login_attempts(struct log_event *ev, int idx_env)
|
||||
get_formatted_time(ev->timestamp, time_str)
|
||||
);
|
||||
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
log_msg("> Retrieved info, MAC: (%s), Interface: (%s)\n", mac_addr, wifi_iface);
|
||||
|
||||
notif_idx = static_events[idx_env].ev_notifier_idx;
|
||||
if (notifiers[notif_idx].send_notification(notification_message) < 0) {
|
||||
if (notifiers[notif_idx].send_notification(notif_message.buff) < 0) {
|
||||
log_msg("unable to send the notification!\n");
|
||||
return;
|
||||
}
|
||||
|
84
notifiers.c
84
notifiers.c
@ -11,6 +11,7 @@
|
||||
#include "log.h"
|
||||
#include "notifiers.h"
|
||||
#include "alertik.h"
|
||||
#include "str.h"
|
||||
|
||||
/*
|
||||
* Notification handling/notifiers
|
||||
@ -69,7 +70,12 @@ static int setopts_get_curl(CURL *hnd, const char *url)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Cleanup all resources used by libcurl, including the handler,
|
||||
* curl_slist and escape'd chars.
|
||||
*
|
||||
* @param hnd curl handler
|
||||
* @param escape Escape string if any (leave NULL if there's none).
|
||||
* @param slist String list if any (leave NULL if there's none).
|
||||
*/
|
||||
static void do_curl_cleanup(CURL *hnd, char *escape, struct curl_slist *slist)
|
||||
{
|
||||
@ -80,19 +86,33 @@ static void do_curl_cleanup(CURL *hnd, char *escape, struct curl_slist *slist)
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Finally sends a curl request, check its return code
|
||||
* and then cleanup the resources allocated.
|
||||
*
|
||||
* @param hnd curl handler
|
||||
* @param escape Escape string if any (leave NULL if there's none).
|
||||
* @param slist String list if any (leave NULL if there's none).
|
||||
*
|
||||
* @return Returns CURLE_OK if success, !CURLE_OK if error.
|
||||
*/
|
||||
static CURLcode do_curl(CURL *hnd, char *escape, struct curl_slist *slist)
|
||||
{
|
||||
CURLcode ret_curl = !CURLE_OK;
|
||||
long response_code = 0;
|
||||
CURLcode ret_curl = !CURLE_OK;
|
||||
|
||||
#ifndef DISABLE_NOTIFICATIONS
|
||||
ret_curl = curl_easy_perform(hnd);
|
||||
if (ret_curl != CURLE_OK) {
|
||||
log_msg("> Unable to send request!\n");
|
||||
goto error;
|
||||
} else {
|
||||
log_msg("> Done!\n");
|
||||
}
|
||||
else {
|
||||
curl_easy_getinfo(hnd, CURLINFO_RESPONSE_CODE, &response_code);
|
||||
log_msg("> Done!\n", response_code);
|
||||
if (response_code != 200) {
|
||||
log_msg("(Info: Response code != 200 (%ld), your message might "
|
||||
"not be correctly sent!)\n", response_code);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -143,36 +163,48 @@ static int setopts_post_json_curl(CURL *hnd, const char *url,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends a generic webhook POST request with JSON payload in the
|
||||
* format {"text": "text here"}.
|
||||
*
|
||||
* @param url Target webhook URL.
|
||||
* @param text Text to be sent in the json payload.
|
||||
*
|
||||
* @return Returns CURLE_OK if success, 1 if error.
|
||||
*/
|
||||
static int send_generic_webhook(const char *url, const char *text)
|
||||
{
|
||||
CURL *hnd = NULL;
|
||||
struct curl_slist *s = NULL;
|
||||
char payload_data[4096] = {0};
|
||||
struct str_ab payload_data;
|
||||
const char *t;
|
||||
|
||||
if (!(hnd = curl_easy_init())) {
|
||||
log_msg("Failed to initialize libcurl!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
payload_data,
|
||||
sizeof payload_data - 1,
|
||||
"{\"text\":\"%s\"}",
|
||||
text
|
||||
);
|
||||
ab_init(&payload_data);
|
||||
ab_append_str(&payload_data, "{\"text\":\"", 9);
|
||||
|
||||
/* Append the payload data text while escaping double
|
||||
* quotes.
|
||||
*/
|
||||
for (t = text; *t != '\0'; t++) {
|
||||
if (*t != '"') {
|
||||
if (ab_append_chr(&payload_data, *t) < 0)
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
if (ab_append_str(&payload_data, "\\\"", 2) < 0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
TODO:
|
||||
- escape "" in the payload, otherwise it will silently
|
||||
escape from the {"text": }
|
||||
- think about the return code from the request and
|
||||
emmit some message if not 200
|
||||
#endif
|
||||
/* End the string. */
|
||||
if (ab_append_str(&payload_data, "\"}", 2) < 0)
|
||||
return 1;
|
||||
|
||||
if (setopts_post_json_curl(hnd, url, payload_data, &s))
|
||||
if (setopts_post_json_curl(hnd, url, payload_data.buff, &s))
|
||||
return 1;
|
||||
|
||||
log_msg("> Sending notification!\n");
|
||||
@ -209,9 +241,10 @@ void setup_telegram(void)
|
||||
|
||||
static int send_telegram_notification(const char *msg)
|
||||
{
|
||||
char full_request_url[4096] = {0};
|
||||
struct str_ab full_request_url;
|
||||
char *escaped_msg = NULL;
|
||||
CURL *hnd = NULL;
|
||||
int ret;
|
||||
|
||||
if (!(hnd = curl_easy_init())) {
|
||||
log_msg("Failed to initialize libcurl!\n");
|
||||
@ -224,13 +257,16 @@ static int send_telegram_notification(const char *msg)
|
||||
do_curl_cleanup(hnd, escaped_msg, NULL);
|
||||
}
|
||||
|
||||
snprintf(
|
||||
full_request_url,
|
||||
sizeof full_request_url - 1,
|
||||
ab_init(&full_request_url);
|
||||
|
||||
ret = ab_append_fmt(&full_request_url,
|
||||
"https://api.telegram.org/bot%s/sendMessage?chat_id=%s&text=%s",
|
||||
telegram_bot_token, telegram_chat_id, escaped_msg);
|
||||
|
||||
setopts_get_curl(hnd, full_request_url);
|
||||
if (ret)
|
||||
return -1;
|
||||
|
||||
setopts_get_curl(hnd, full_request_url.buff);
|
||||
log_msg("> Sending notification!\n");
|
||||
return do_curl(hnd, escaped_msg, NULL);
|
||||
}
|
||||
@ -250,7 +286,7 @@ void setup_slack(void)
|
||||
|
||||
slack_webhook_url = getenv("SLACK_WEBHOOK_URL");
|
||||
if (!slack_webhook_url) {
|
||||
panic("Unable to find env vars for, please check if you have set\n"
|
||||
panic("Unable to find env vars for Slack, please check if you have set "
|
||||
"the SLACK_WEBHOOK_URL!!\n");
|
||||
}
|
||||
setup = 1;
|
||||
|
244
str.c
Normal file
244
str.c
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Alertik: a tiny 'syslog' server & notification tool for Mikrotik routers.
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*/
|
||||
|
||||
/*
|
||||
* String/append buffer implementation based on Aqua:
|
||||
* https://gist.github.com/Theldus/09ed2205aa5ba15cdf4571b71cd1c8fc
|
||||
*/
|
||||
|
||||
#include "str.h"
|
||||
#include "log.h"
|
||||
|
||||
/* Malloc is only used if AB_USE_MALLOC is defined. */
|
||||
#ifdef AB_USE_MALLOC
|
||||
#if defined(AB_CALLOC) && defined(AB_REALLOC) && defined(AB_FREE)
|
||||
# define AB_USE_STDLIB
|
||||
#elif !defined(AB_CALLOC) && !defined(AB_REALLOC) && !defined(AB_FREE)
|
||||
# define AB_USE_STDLIB
|
||||
#else
|
||||
#error "For custom memory allocators, you should define all three routines!"
|
||||
#error "Please define: AB_CALLOC, AB_REALLOC and AB_FREE!"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AB_CALLOC
|
||||
#define AB_CALLOC(nmemb,sz) calloc((nmemb),(sz))
|
||||
#define AB_REALLOC(p,newsz) realloc((p),(newsz))
|
||||
#define AB_FREE(p) free((p))
|
||||
#endif
|
||||
|
||||
#ifdef AB_USE_STDLIB
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* ========================================================================= */
|
||||
/* BUFFER ROUTINES */
|
||||
/* ========================================================================= */
|
||||
|
||||
#ifdef AB_USE_MALLOC
|
||||
/**
|
||||
* @brief Rounds up to the next power of two.
|
||||
*
|
||||
* @param target Target number to be rounded.
|
||||
*
|
||||
* @return Returns the next power of two.
|
||||
*/
|
||||
static size_t next_power(size_t target)
|
||||
{
|
||||
target--;
|
||||
target |= target >> 1;
|
||||
target |= target >> 2;
|
||||
target |= target >> 4;
|
||||
target |= target >> 8;
|
||||
target |= target >> 16;
|
||||
target++;
|
||||
return (target);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Checks if the new size fits in the append buffer, if not,
|
||||
* reallocates the buffer size by @p incr bytes.
|
||||
*
|
||||
* If the macro AB_USE_MALLOC is not defined (default), this only
|
||||
* checks if the new size fits the buffer.
|
||||
*
|
||||
* @param sh Aqua highlight context.
|
||||
* @param incr Size (in bytes) to be incremented.
|
||||
*
|
||||
* @return Returns 0 if success, -1 otherwise.
|
||||
*
|
||||
* @note The new size is the next power of two, that is capable
|
||||
* to hold the required buffer size.
|
||||
*/
|
||||
static int increase_buff(struct str_ab *sh, size_t incr)
|
||||
{
|
||||
#ifndef AB_USE_MALLOC
|
||||
if (sh->pos + incr >= MAX_LINE) {
|
||||
log_msg("(increase buffer) Unable to fit appended message!\n");
|
||||
log_msg("(static storage) incr: %zu, buff_len: %zu, pos: %zu\n",
|
||||
incr, sh->pos, sh->buff_len);
|
||||
return (-1);
|
||||
}
|
||||
#else
|
||||
char *new;
|
||||
size_t new_size;
|
||||
if (sh->pos + incr >= sh->buff_len)
|
||||
{
|
||||
new_size = next_power(sh->buff_len + incr);
|
||||
new = AB_REALLOC(sh->buff, new_size);
|
||||
if (new == NULL)
|
||||
{
|
||||
AB_FREE(sh->buff);
|
||||
sh->buff = NULL;
|
||||
|
||||
log_msg("(increase buffer) Unable to fit appended message!\n");
|
||||
log_msg("(realloc storage) incr: %zu, buff_len: %zu, pos: %zu\n",
|
||||
incr, sh->pos, sh->buff_len);
|
||||
return (-1);
|
||||
}
|
||||
sh->buff_len = new_size;
|
||||
sh->buff = new;
|
||||
}
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initializes the append buffer context.
|
||||
*
|
||||
* @param ab Append buffer structure.
|
||||
*
|
||||
* @return Returns 0 if success, -1 otherwise.
|
||||
*/
|
||||
int ab_init(struct str_ab *ab)
|
||||
{
|
||||
if (!ab)
|
||||
return (-1);
|
||||
|
||||
memset(ab, 0, sizeof(*ab));
|
||||
|
||||
#ifndef AB_USE_MALLOC
|
||||
ab->buff_len = MAX_LINE;
|
||||
#else
|
||||
ab->buff = AB_CALLOC(MAX_LINE, 1);
|
||||
if (!ab->buff)
|
||||
return (-1);
|
||||
ab->buff_len = MAX_LINE;
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Append a given char @p c into the buffer.
|
||||
*
|
||||
* @param sh Aqua highlight context.
|
||||
* @param c Char to be appended.
|
||||
*
|
||||
* @return Returns 0 if success, -1 otherwise.
|
||||
*/
|
||||
int ab_append_chr(struct str_ab *sh, char c)
|
||||
{
|
||||
if (increase_buff(sh, 2) < 0)
|
||||
return (-1);
|
||||
|
||||
sh->buff[sh->pos + 0] = c;
|
||||
sh->buff[sh->pos + 1] = '\0';
|
||||
sh->pos++;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends a given string pointed by @p s of size @p len
|
||||
* into the current buffer.
|
||||
*
|
||||
* If @p len is 0, the string is assumed to be null-terminated
|
||||
* and its length is obtained.
|
||||
*
|
||||
* @param ab Append buffer context.
|
||||
* @param s String to be append into the buffer.
|
||||
* @param len String size, if 0, it's length is obtained.
|
||||
*
|
||||
* @return Returns 0 if success, -1 otherwise.
|
||||
*/
|
||||
int ab_append_str(struct str_ab *ab, const char *s, size_t len)
|
||||
{
|
||||
if (!len)
|
||||
len = strlen(s);
|
||||
|
||||
if (increase_buff(ab, len + 1) < 0)
|
||||
return (-1);
|
||||
|
||||
memcpy(ab->buff + ab->pos, s, len);
|
||||
ab->pos += len;
|
||||
ab->buff[ab->pos] = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Appends a given formatted string pointed by @p fmt.
|
||||
*
|
||||
* @param ab Append buffer context.
|
||||
* @param fmt Formatted string to be appended.
|
||||
*
|
||||
* @return Returns 0 if success, -1 otherwise.
|
||||
*/
|
||||
int ab_append_fmt(struct str_ab *ab, const char *fmt, ...)
|
||||
{
|
||||
int str_len, ab_len, orig_ab_pos;
|
||||
char *buff_st;
|
||||
va_list ap;
|
||||
|
||||
buff_st = ab->buff + ab->pos;
|
||||
ab_len = ab->buff_len - ab->pos;
|
||||
|
||||
va_start(ap, fmt);
|
||||
str_len = vsnprintf(buff_st, ab_len, fmt, ap);
|
||||
if (str_len < 0) {
|
||||
log_msg("Unable to fit appended message!\n");
|
||||
return (-1);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
/* If it fits, just happily returns. */
|
||||
if (str_len + 1 <= ab_len) {
|
||||
ab->pos += str_len;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Otherwise, adjust current pos and try to increase buffer. */
|
||||
else {
|
||||
orig_ab_pos = ab->pos;
|
||||
|
||||
/* temporarily advance our buffer
|
||||
* to trick our increase buffer. */
|
||||
ab->pos = ab->buff_len;
|
||||
|
||||
if (increase_buff(ab, (str_len + 1) - ab_len))
|
||||
return (-1);
|
||||
|
||||
ab->pos = orig_ab_pos;
|
||||
}
|
||||
|
||||
buff_st = ab->buff + ab->pos;
|
||||
ab_len = ab->buff_len - ab->pos;
|
||||
|
||||
va_start(ap, fmt);
|
||||
str_len = vsnprintf(buff_st, ab_len, fmt, ap);
|
||||
if (str_len < 0 || (str_len + 1) > ab_len) {
|
||||
log_msg("Unable to fit appended message!\n");
|
||||
return (-1);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
ab->pos += str_len;
|
||||
return (0);
|
||||
}
|
39
str.h
Normal file
39
str.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Alertik: a tiny 'syslog' server & notification tool for Mikrotik routers.
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*/
|
||||
|
||||
#ifndef STR_H
|
||||
#define STR_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/*
|
||||
* Enable to disable malloc support and enable dinamically
|
||||
* allocated buffer.
|
||||
*/
|
||||
#if 0
|
||||
#define AB_USE_MALLOC
|
||||
#endif
|
||||
|
||||
/* Maximum highlighted line len, when built without malloc. */
|
||||
#define MAX_LINE 4096
|
||||
|
||||
/* Append buffer. */
|
||||
struct str_ab
|
||||
{
|
||||
#ifndef AB_USE_MALLOC
|
||||
char buff[MAX_LINE + 1];
|
||||
#else
|
||||
char *buff;
|
||||
#endif
|
||||
size_t buff_len;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
extern int ab_init(struct str_ab *ab);
|
||||
extern int ab_append_chr(struct str_ab *sh, char c);
|
||||
extern int ab_append_str(struct str_ab *ab, const char *s, size_t len);
|
||||
extern int ab_append_fmt(struct str_ab *ab, const char *fmt, ...);
|
||||
|
||||
#endif /* STR_H. */
|
Loading…
Reference in New Issue
Block a user