Compare commits
12
Commits
db758cd938
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6347444494 | ||
|
|
f43bb30065 | ||
|
|
e00ffe6f70 | ||
|
|
b9e247b88f | ||
|
|
45b4f6bee0 | ||
|
|
c9c9bbbff6 | ||
|
|
cbdf7b2523 | ||
|
|
08e771eaa0 | ||
|
|
e623c0dce1 | ||
|
|
e3e84a0441 | ||
|
|
dc52c20098 | ||
|
|
6fba6f42a0 |
-101
@@ -1,101 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
|
||||||
* Please, refer LICENSE file for legal information
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file log.c
|
|
||||||
* @author Ilja Kartašov <ik@lowenware.com>
|
|
||||||
* @brief cStuff log module source file
|
|
||||||
*
|
|
||||||
* @see https://lowenware.com/
|
|
||||||
*/
|
|
||||||
#include <time.h>
|
|
||||||
#include "log.h"
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
cstuff_log_init(cstuff_log_t self, uint8_t level)
|
|
||||||
{
|
|
||||||
self->target = stderr;
|
|
||||||
self->level = level;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
cstuff_log_release(cstuff_log_t self)
|
|
||||||
{
|
|
||||||
if (self->target != stderr)
|
|
||||||
fclose(self->target);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
cstuff_retcode_t
|
|
||||||
cstuff_log_set_file(cstuff_log_t self, const char * filename)
|
|
||||||
{
|
|
||||||
FILE * fp;
|
|
||||||
|
|
||||||
|
|
||||||
if ( !(fp = fopen(filename, "a")) )
|
|
||||||
return CSTUFF_SYSCALL_ERROR;
|
|
||||||
|
|
||||||
self->target = fp;
|
|
||||||
return CSTUFF_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_log_printf(cstuff_log_t self, uint8_t level, const char * format, ...)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
va_list vl;
|
|
||||||
|
|
||||||
va_start(vl, format);
|
|
||||||
result = cstuff_log_vprintf(self, level, format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_log_vprintf(cstuff_log_t self,
|
|
||||||
uint8_t level,
|
|
||||||
const char * format,
|
|
||||||
va_list vl)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
|
|
||||||
if (self->level & level)
|
|
||||||
{
|
|
||||||
FILE * f = self->target;
|
|
||||||
char * label;
|
|
||||||
time_t rawtime;
|
|
||||||
char strtime[32+1];
|
|
||||||
struct tm timeinfo;
|
|
||||||
|
|
||||||
time (&rawtime);
|
|
||||||
localtime_r (&rawtime, &timeinfo);
|
|
||||||
strftime (strtime, 32, "%F %T", &timeinfo);
|
|
||||||
|
|
||||||
switch (level)
|
|
||||||
{
|
|
||||||
case CSTUFF_LOG_ERROR : label = "!!"; break;
|
|
||||||
case CSTUFF_LOG_ALERT : label = "~!"; break;
|
|
||||||
case CSTUFF_LOG_DEBUG : label = "**"; break;
|
|
||||||
default : label = "--";
|
|
||||||
}
|
|
||||||
|
|
||||||
result = fprintf(f, "%s %s ", strtime, label);
|
|
||||||
result += vfprintf(f, format, vl);
|
|
||||||
fputc('\n', f);
|
|
||||||
result++;
|
|
||||||
fflush(f);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
result = 0;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
|
||||||
* Please, refer LICENSE file for legal information
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file log.h
|
|
||||||
* @author Ilja Kartašov <ik@lowenware.com>
|
|
||||||
* @brief cStuff log module header file
|
|
||||||
*
|
|
||||||
* @see https://lowenware.com/cStuff/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CSTUFF_LOG_H_557ADEFE_2BE8_4B9B_A894_F08FF64008EF
|
|
||||||
#define CSTUFF_LOG_H_557ADEFE_2BE8_4B9B_A894_F08FF64008EF
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "retcode.h"
|
|
||||||
|
|
||||||
#define CSTUFF_LOG_OFF (0)
|
|
||||||
#define CSTUFF_LOG_ERROR (1<<0)
|
|
||||||
#define CSTUFF_LOG_ALERT (1<<1)
|
|
||||||
#define CSTUFF_LOG_STATE (1<<2)
|
|
||||||
#define CSTUFF_LOG_DEBUG (1<<3)
|
|
||||||
#define CSTUFF_LOG_ALL (0xFF)
|
|
||||||
|
|
||||||
struct cstuff_log
|
|
||||||
{
|
|
||||||
FILE * target;
|
|
||||||
uint8_t level;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct cstuff_log * cstuff_log_t;
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
cstuff_log_init(cstuff_log_t self, uint8_t level);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
cstuff_log_release(cstuff_log_t self);
|
|
||||||
|
|
||||||
|
|
||||||
cstuff_retcode_t
|
|
||||||
cstuff_log_set_file(cstuff_log_t self, const char * filename);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_log_printf(cstuff_log_t self, uint8_t level, const char * format, ...);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_log_vprintf( cstuff_log_t self,
|
|
||||||
uint8_t level,
|
|
||||||
const char * format,
|
|
||||||
va_list vl );
|
|
||||||
|
|
||||||
#endif /* !CSTUFF_LOG_H */
|
|
||||||
-103
@@ -1,103 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
|
||||||
* Please, refer LICENSE file for legal information
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file string.c
|
|
||||||
* @author Ilja Kartašov <ik@lowenware.com>
|
|
||||||
* @brief cStuff string module implementation
|
|
||||||
*
|
|
||||||
* @see https://lowenware.com/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "string.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_strcpy(char **out, const char *in)
|
|
||||||
{
|
|
||||||
return cstuff_strncpy(out, in, strlen(in));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_strncpy(char **out, const char *in, int len)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if (!(s = malloc( len + 1 )))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
strncpy(s, in, len);
|
|
||||||
s[len]=0;
|
|
||||||
|
|
||||||
*out = s;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_strset(char **out, const char *in)
|
|
||||||
{
|
|
||||||
return cstuff_strnset(out, in, strlen(in));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_strnset(char **out, const char *in, int len)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
if (!(s = realloc(*out, len+1)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
strncpy(s, in, len);
|
|
||||||
s[len] = 0;
|
|
||||||
|
|
||||||
*out = s;
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_sprintf(char **out, const char *format, ...)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
va_list vl;
|
|
||||||
|
|
||||||
va_start(vl, format);
|
|
||||||
result = cstuff_vsprintf(out, format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_vsprintf(char **out, const char *format, va_list args)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
va_list vc;
|
|
||||||
char tmp, *s;
|
|
||||||
|
|
||||||
va_copy(vc, args);
|
|
||||||
result = vsnprintf(&tmp, 1, format, vc);
|
|
||||||
va_end(vc);
|
|
||||||
|
|
||||||
if (!(s = malloc(result + 1)))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
result = vsnprintf(s, result+1, format, args);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Copyright (c) 2017-2019 by Löwenware Ltd
|
|
||||||
* Please, refer LICENSE file for legal information
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file string.h
|
|
||||||
* @author Ilja Kartašov <ik@lowenware.com>
|
|
||||||
* @brief String module declarations
|
|
||||||
*
|
|
||||||
* @see https://lowenware.com/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef CSTUFF_STRING_H_938B242C_B750_40E9_8B67_A69F2F37EB87
|
|
||||||
#define CSTUFF_STRING_H_938B242C_B750_40E9_8B67_A69F2F37EB87
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include "retcode.h"
|
|
||||||
|
|
||||||
|
|
||||||
/** @brief Copies in string to newly allocated out buffer
|
|
||||||
* @param out a pointer to an address where new pointer must be stored
|
|
||||||
* @param in an input string
|
|
||||||
* @return length of string or -1 if out of memory
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
cstuff_strcpy(char **out, const char *in);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_strncpy(char **out, const char *in, int len);
|
|
||||||
|
|
||||||
|
|
||||||
/** @brief Overwrites content of out buffer with in string using realloc
|
|
||||||
* @param out a pointer to an address where new string must be stored
|
|
||||||
* @param in an input string
|
|
||||||
* @return length of string or -1 if out of memory
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
cstuff_strset(char **out, const char *in);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_strnset(char **out, const char *in, int len);
|
|
||||||
|
|
||||||
|
|
||||||
/** @brief Allocates memory and prints a formatted string into it
|
|
||||||
* @param out a pointer to an address where new string must be stored
|
|
||||||
* @param format a format for string (see manual for stdlib sprintf)
|
|
||||||
* @return length of string or -1 if out of memory
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
cstuff_sprintf(char **out, const char *format, ...);
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
cstuff_vsprintf(char **out, const char *format, va_list args);
|
|
||||||
|
|
||||||
#endif /* !CSTUFF_STRING_H */
|
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file crypt.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include "crypt.h"
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_crypt__read_key_file(const char *key_file, unsigned char *key,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
AislStatus result = AISL_SYSCALL_ERROR;
|
||||||
|
int i;
|
||||||
|
FILE *f;
|
||||||
|
char buff[2*(AX_CRYPT_KEY_SIZE + AX_CRYPT_SALT_SIZE) + 1], char hex[2 + 1],
|
||||||
|
*ptr = buff, *ep = NULL;
|
||||||
|
|
||||||
|
if (!(f = fopen(key_file))) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fread(buff, 1, sizeof (buff), f) != sizeof (buff)) {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
hex[2] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_SALT_SIZE; i++) {
|
||||||
|
memcpy(hex, ptr, 2);
|
||||||
|
salt[i] = strtol(hex, &ep, 16);
|
||||||
|
if (ep != &hex[2]) {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*(ptr++) != '$') {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_KEY_SIZE; i++) {
|
||||||
|
memcpy(hex, ptr, 2);
|
||||||
|
key[i] = strtol(hex, &ep, 16);
|
||||||
|
if (ep != &hex[2]) {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = AISL_SUCCESS;
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
e_input:
|
||||||
|
result = AISL_INPUT_ERROR;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_crypt__write_key_file(const char *key_file, unsigned char *key,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
AislStatus result = AISL_SYSCALL_ERROR;
|
||||||
|
int i;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (!(f = fopen(key_file))) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_SALT_SIZE; i++) {
|
||||||
|
if (fprintf(f, "%02x", salt[i] & 0xFF) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fputc('$', f) == EOF) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < AX_CRYPT_KEY_SIZE; i++) {
|
||||||
|
if (fprintf(f, "%02x", key[i] & 0xFF) < 0) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = AISL_SUCCESS;
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(f);
|
||||||
|
chmod(key_file, S_IRUSR);
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_crypt_init(AxSession crypt, const char *key_file)
|
||||||
|
{
|
||||||
|
AislStatus result;
|
||||||
|
unsigned char key[AX_CRYPT_KEY_SIZE], salt[AX_CRYPT_SALT_SIZE],
|
||||||
|
evp_key[AX_CRYPT_KEY_SIZE], iv[AX_CRYPT_KEY_SIZE];
|
||||||
|
|
||||||
|
if (cstuff_file_exists(key_file)) {
|
||||||
|
result = ax_crypt__read_key_file(key_file, key, salt);
|
||||||
|
} else {
|
||||||
|
RAND_bytes(key, sizeof (key));
|
||||||
|
RAND_bytes(salt, sizeof (salt));
|
||||||
|
result = ax_crypt__write_key_file(key_file, key, salt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != AISL_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), salt, key, sizeof (key), 5,
|
||||||
|
key, iv)) {
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((crypt->e_ctx = EVP_CIPHER_CTX_new())) {
|
||||||
|
EVP_CIPHER_CTX_init(crypt->e_ctx);
|
||||||
|
EVP_EncryptInit_ex(crypt->e_ctx, EVP_aes_256_cbc(), NULL, key, iv);
|
||||||
|
if ((crypt->d_ctx = EVP_CIPHER_CTX_new())) {
|
||||||
|
EVP_CIPHER_CTX_init(crypt->d_ctx);
|
||||||
|
EVP_DecryptInit_ex(crypt->d_ctx, EVP_aes_256_cbc(), NULL, key, iv);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
EVP_CIPHER_CTX_free(crypt->e_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_crypt_release(AxSession crypt)
|
||||||
|
{
|
||||||
|
if (crypt->e_ctx) {
|
||||||
|
EVP_CIPHER_CTX_free(crypt->e_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crypt->d_ctx) {
|
||||||
|
EVP_CIPHER_CTX_free(crypt->d_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_write(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = in_len, l;
|
||||||
|
unsigned char *out;
|
||||||
|
EVP_CIPHER_CTX *e_ctx = crypt->e_ctx;
|
||||||
|
|
||||||
|
if (!(out = calloc(result + EVP_MAX_BLOCK_LENGTH, sizeof (char)))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_EncryptInit_ex(e_ctx, NULL, NULL, NULL, NULL);
|
||||||
|
EVP_EncryptUpdate(e_ctx, out, &result, (const unsigned char *)input, in_len);
|
||||||
|
EVP_EncryptFinal_ex(e_ctx, &out[result], &l);
|
||||||
|
*p_out = (char *)out;
|
||||||
|
return result + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_read(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = in_len, l;
|
||||||
|
unsigned char *out;
|
||||||
|
EVP_CIPHER_CTX *d_ctx = crypt->d_ctx;
|
||||||
|
|
||||||
|
if (!(out = malloc(in_len + EVP_MAX_BLOCK_LENGTH))) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_DecryptInit_ex(d_ctx, NULL, NULL, NULL, NULL);
|
||||||
|
EVP_DecryptUpdate(d_ctx, out, &result, input, in_len);
|
||||||
|
EVP_DecryptFinal_ex(d_ctx, &out[result], &l);
|
||||||
|
|
||||||
|
*p_out = (char *)out;
|
||||||
|
return result + l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_encode(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
BIO *bio, *b64;
|
||||||
|
BUF_MEM *bptr;
|
||||||
|
unsigned char *out, *cipher;
|
||||||
|
|
||||||
|
if ((in_len = ax_crypt_write(crypt, &cipher, input, in_len)) != -1) {
|
||||||
|
if ((b64 = BIO_new( BIO_f_base64()))) {
|
||||||
|
if ((bio = BIO_new( BIO_s_mem()))) {
|
||||||
|
if ((b64 = BIO_push(b64, bio))) {
|
||||||
|
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
BIO_write(b64, cipher, in_len);
|
||||||
|
BIO_flush(b64);
|
||||||
|
BIO_get_mem_ptr(b64, &bptr);
|
||||||
|
result = bptr->length;
|
||||||
|
if ((out = malloc(result + 1))) {
|
||||||
|
memcpy(out, bptr->data, result);
|
||||||
|
out[result] = '\0';
|
||||||
|
*p_out = (char *)out;
|
||||||
|
} else {
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BIO_free_all(b64);
|
||||||
|
}
|
||||||
|
free(cipher);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_crypt_decode(AxSession crypt, char **p_out, const char *input, int in_len)
|
||||||
|
{
|
||||||
|
int result = -1;
|
||||||
|
BIO *bio, *b64;
|
||||||
|
BUF_MEM *bptr;
|
||||||
|
unsigned char *out, *cipher;
|
||||||
|
|
||||||
|
if ((cipher = malloc(in_len * sizeof (unsigned char)))) {
|
||||||
|
if ((bio = BIO_new_mem_buf((void*)input, in_len))) {
|
||||||
|
if ((b64 = BIO_new(BIO_f_base64()))) {
|
||||||
|
if ((bio = BIO_push(b64, bio))) {
|
||||||
|
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
in_len = BIO_read(bio, cipher, in_len);
|
||||||
|
result = ax_crypt_read(crypt, p_out, cipher, in_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BIO_free_all(bio);
|
||||||
|
}
|
||||||
|
free(cipher);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file crypt.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_CRYPT_H_F18E0303_66D9_4793_A902_230BA0A0A46F
|
||||||
|
#define AX_CRYPT_H_F18E0303_66D9_4793_A902_230BA0A0A46F
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <aisl/aisl.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#define AX_CRYPT_KEY_SIZE 32
|
||||||
|
#define AX_CRYPT_SALT_SIZE 8
|
||||||
|
|
||||||
|
struct ax_crypt {
|
||||||
|
EVP_CIPHER_CTX *e_ctx;
|
||||||
|
EVP_CIPHER_CTX *d_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ax_crypt * AxCrypt;
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_crypt_init(AxSession crypt, const char *key_file);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_crypt_release(AxSession crypt);
|
||||||
|
|
||||||
|
|
||||||
|
/* encrypt */
|
||||||
|
int
|
||||||
|
ax_crypt_write(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* decrypt */
|
||||||
|
int
|
||||||
|
ax_crypt_read(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* encrypt and convert to BASE64 */
|
||||||
|
int
|
||||||
|
ax_crypt_encode(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
|
||||||
|
/* decrypt from BASE64 */
|
||||||
|
int
|
||||||
|
ax_crypt_decode(AxSession crypt, char **out, const char *input, int in_len);
|
||||||
|
|
||||||
|
#endif /* !AX_CRYPT_H */
|
||||||
@@ -0,0 +1,465 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file html.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <cStuff/string.h>
|
||||||
|
|
||||||
|
#include "html.h"
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
ax_html_escape(char *src, uint32_t len)
|
||||||
|
{
|
||||||
|
uint32_t extra = 0;
|
||||||
|
char *ptr = src;
|
||||||
|
char ch, *result;
|
||||||
|
|
||||||
|
while ((ch = *ptr) != 0) {
|
||||||
|
switch (ch) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
case '\n':
|
||||||
|
extra++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result = calloc(len + extra + 1, sizeof (char))) != NULL) {
|
||||||
|
if (extra) {
|
||||||
|
ptr = result;
|
||||||
|
while (len--) {
|
||||||
|
switch (*src) {
|
||||||
|
case '"':
|
||||||
|
case '\\':
|
||||||
|
*(ptr++) = '\\';
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
*(ptr++) = '\\';
|
||||||
|
*(ptr++) = 'n';
|
||||||
|
case '\r': /* go through */
|
||||||
|
src++;
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!(*(ptr++) = *(src++)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strncpy(result, src, len);
|
||||||
|
result[len] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct ax_html *
|
||||||
|
ax_html_append_new(CStuffList list, const struct ax_html *src)
|
||||||
|
{
|
||||||
|
struct ax_html *result;
|
||||||
|
|
||||||
|
if ((result = malloc(sizeof (*result))) != NULL) {
|
||||||
|
result->type = src->type;
|
||||||
|
result->offset = src->offset;
|
||||||
|
result->size = src->size;
|
||||||
|
if ((result->data = ax_html_escape(src->data, src->size)) != NULL) {
|
||||||
|
if (cstuff_list_append(list, result) != -1) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
free(result->data);
|
||||||
|
}
|
||||||
|
free(result);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_html_check_chars(char *begin, char *end)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
while (begin < end) {
|
||||||
|
char c = *begin;
|
||||||
|
if (c == '-') {
|
||||||
|
c = (*begin = '_');
|
||||||
|
}
|
||||||
|
if (isalnum(c) || c == '_') {
|
||||||
|
result++;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_html_read_line(CStuffList list, char *line)
|
||||||
|
{
|
||||||
|
const char input_open[] = "${",
|
||||||
|
input_close[] = "}",
|
||||||
|
block_open[] = "<!--@",
|
||||||
|
block_close[] = "-->";
|
||||||
|
|
||||||
|
struct ax_html node;
|
||||||
|
size_t offset;
|
||||||
|
char *cur;
|
||||||
|
|
||||||
|
offset = strspn(line, "\t ");
|
||||||
|
cur = &line[offset];
|
||||||
|
|
||||||
|
while (*cur) {
|
||||||
|
char *p1, *p2, *p;
|
||||||
|
uint16_t type = AX_HTML_PLAIN;
|
||||||
|
uint32_t close_len = 0;
|
||||||
|
|
||||||
|
p1 = strstr(cur, input_open);
|
||||||
|
p2 = strstr(cur, block_open);
|
||||||
|
|
||||||
|
if (p1 && (!p2 || p2 > p1)) {
|
||||||
|
p = &p1[sizeof (input_open) - 1];
|
||||||
|
if ((p2 = strstr(p, input_close)) && ax_html_check_chars(p, p2)) {
|
||||||
|
type = AX_HTML_INPUT;
|
||||||
|
close_len = sizeof (input_close) - 1;
|
||||||
|
}
|
||||||
|
} else if (p2 && (!p1 || p1 > p2)) {
|
||||||
|
p1 = p2;
|
||||||
|
p = &p1[sizeof (block_open) - 1];
|
||||||
|
if ((p2 = strstr(p, block_close)) && ax_html_check_chars(p, p2)) {
|
||||||
|
type = AX_HTML_BLOCK;
|
||||||
|
close_len = sizeof (block_close) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type != AX_HTML_PLAIN) {
|
||||||
|
if (p1 != cur) {
|
||||||
|
node.type = AX_HTML_PLAIN;
|
||||||
|
node.offset = offset;
|
||||||
|
node.size = (uint32_t)(p1 - cur);
|
||||||
|
node.data = cur;
|
||||||
|
offset = 0;
|
||||||
|
if (ax_html_append_new(list, &node) == NULL) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.type = type;
|
||||||
|
node.offset = offset;
|
||||||
|
node.size = (uint32_t)(p2 - p);
|
||||||
|
node.data = p;
|
||||||
|
offset = 0;
|
||||||
|
if (ax_html_append_new(list, &node) == NULL) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
cur = p2 + close_len;
|
||||||
|
if (type == AX_HTML_BLOCK) {
|
||||||
|
size_t lfcr = strspn(cur, "\r\n");
|
||||||
|
if (lfcr) {
|
||||||
|
cur += lfcr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
node.type = type;
|
||||||
|
node.offset = offset;
|
||||||
|
node.size = strlen(cur);
|
||||||
|
node.data = cur;
|
||||||
|
if (ax_html_append_new(list, &node) == NULL) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
cur = &cur[node.size];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_import(CStuffList list, const char *html_file)
|
||||||
|
{
|
||||||
|
FILE *f = NULL;
|
||||||
|
size_t sz = 256;
|
||||||
|
char *line;
|
||||||
|
ssize_t rs;
|
||||||
|
AislStatus result = AISL_SUCCESS;
|
||||||
|
|
||||||
|
if (!(line = malloc(sz)))
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
if (!(f = fopen(html_file, "r")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
while ((rs = getdelim(&line, &sz, '\n', f)) != -1) {
|
||||||
|
if ((result = ax_html_read_line(list, line)) != AISL_SUCCESS) {
|
||||||
|
goto finally;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(errno) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENOMEM:
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto e_syscall;
|
||||||
|
}
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_malloc:
|
||||||
|
result = AISL_MALLOC_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_syscall:
|
||||||
|
result = AISL_SYSCALL_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if (line)
|
||||||
|
free(line);
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_export(CStuffList list, const struct ax_html_options *opts)
|
||||||
|
{
|
||||||
|
AislStatus result = AISL_SUCCESS;
|
||||||
|
FILE *out = NULL;
|
||||||
|
int i, l;
|
||||||
|
char *c_prefix = NULL, *u_prefix = NULL, *f = NULL;
|
||||||
|
const char *ofst = opts->offset;
|
||||||
|
|
||||||
|
/* Cammel case prefix */
|
||||||
|
if (cstuff_strcpy(&c_prefix, opts->name) == -1)
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
*c_prefix = toupper(*c_prefix);
|
||||||
|
|
||||||
|
/* Upper case prefix */
|
||||||
|
if ((i = cstuff_strcpy(&u_prefix, opts->name)) == -1)
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
while (i--) {
|
||||||
|
u_prefix[i] = toupper(u_prefix[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* header file */
|
||||||
|
if ((l = cstuff_sprintf(&f, "%s/%s.h", opts->path, opts->name)) == -1)
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
if (!(out = fopen(f, "w")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
fprintf(out, "#ifndef %s_H_AISL_COMPOSED\n", u_prefix);
|
||||||
|
fprintf(out, "#define %s_H_AISL_COMPOSED\n\n", u_prefix);
|
||||||
|
fprintf(out, "#include <aisl/aisl.h>\n");
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
fprintf(out, "#include <cStuff/list.h>\n");
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
fprintf(out, "#define %s_put(STREAM, BLOCK, CB, CTX) ", opts->name);
|
||||||
|
fprintf(out, "%s_put_##BLOCK##(STREAM, CB, CTX)\n\n", opts->name);
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
fprintf(out, "typedef int\n(*%sCallback)(AislStream s, const char *input, "
|
||||||
|
"void *ctx);\n\n", c_prefix);
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
fprintf(out, "int\n%s_put(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx, const char *block);\n\n", opts->name, c_prefix);
|
||||||
|
fprintf(out, "int\n%s_set(CStuffList list);\n\n", opts->name);
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
struct ax_html *html = list->items[i];
|
||||||
|
|
||||||
|
if (html->type == AX_HTML_BLOCK) {
|
||||||
|
fprintf(out, "int\n%s_put_%s(AislStream s, %sCallback callback, void *ctx);\n\n",
|
||||||
|
opts->name, html->data, c_prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "#endif\n");
|
||||||
|
fprintf(out, "\n\n");
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
/* source file */
|
||||||
|
f[l-1] = 'c';
|
||||||
|
|
||||||
|
if (!(out = fopen(f, "w")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
fprintf(out, "#include <stdint.h>\n");
|
||||||
|
fprintf(out, "#include \"%s.h\"\n\n", opts->name);
|
||||||
|
fprintf(out, "#define %s_PLAIN %d\n", u_prefix, AX_HTML_PLAIN);
|
||||||
|
fprintf(out, "#define %s_BLOCK %d\n", u_prefix, AX_HTML_BLOCK);
|
||||||
|
fprintf(out, "#define %s_INPUT %d\n\n", u_prefix, AX_HTML_INPUT);
|
||||||
|
fprintf(out, "struct %s {\n", opts->name);
|
||||||
|
fprintf(out, "%suint16_t type;\n", ofst);
|
||||||
|
fprintf(out, "%suint16_t offset;\n", ofst);
|
||||||
|
fprintf(out, "%suint32_t size;\n", ofst);
|
||||||
|
fprintf(out, "%sconst char *code;\n", ofst);
|
||||||
|
fprintf(out, "};\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "static struct %s *m_%s = NULL;\n\n", opts->name, opts->name);
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "static const struct %s m_%s[] = {\n", opts->name, opts->name);
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
struct ax_html *html = list->items[i];
|
||||||
|
uint32_t offset, size = html->size;
|
||||||
|
|
||||||
|
if (opts->minimize) {
|
||||||
|
offset = 0;
|
||||||
|
if (html->type == AX_HTML_PLAIN) {
|
||||||
|
int l = strlen(html->data);
|
||||||
|
|
||||||
|
if (!(l < 2) && !strcmp(&html->data[l - 2], "\\n")) {
|
||||||
|
size--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
offset = html->offset & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(out, "%s{%u, %u, %u, \"%s\"},\n", ofst, html->type, offset,
|
||||||
|
size, html->data);
|
||||||
|
}
|
||||||
|
fprintf(out, "%s{0, 0, 0, NULL}\n};\n\n", ofst);
|
||||||
|
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
|
||||||
|
fprintf(out, "static int\nput_from(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx, uint32_t from)\n{\n", c_prefix);
|
||||||
|
fprintf(out, "%sint result = 0, r;\n", ofst);
|
||||||
|
fprintf(out, "%swhile (m_%s[from]->data) {\n", ofst, opts->name);
|
||||||
|
fprintf(out, "%s%sswitch (m_%s[from]->type) {\n", ofst, ofst,
|
||||||
|
opts->name);
|
||||||
|
fprintf(out, "%s%scase %s_PLAIN:\n", ofst, ofst, u_prefix);
|
||||||
|
fprintf(out, "%s%s%sr = aisl_write(s, m_%s[from]->data, m_%s[from]->size);\n",
|
||||||
|
ofst, ofst, ofst, opts->name, opts->name);
|
||||||
|
fprintf(out, "%s%s%sbreak;\n", ofst, ofst, ofst);
|
||||||
|
|
||||||
|
fprintf(out, "%s%scase %s_INPUT:\n", ofst, ofst, u_prefix);
|
||||||
|
fprintf(out, "%s%s%sr = callback(s, m_%s[from]->data, ctx);\n",
|
||||||
|
ofst, ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s%s%sbreak;\n", ofst, ofst, ofst);
|
||||||
|
fprintf(out, "%s%scase %s_BLOCK:\n", ofst, ofst, u_prefix);
|
||||||
|
fprintf(out, "%s%s%sreturn result;\n", ofst, ofst, ofst);
|
||||||
|
fprintf(out, "%s%sdefault:\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%s%sreturn -1;\n", ofst, ofst, ofst);
|
||||||
|
fprintf(out, "%s%s}\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sif (r == -1) return r;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sresult += r;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sfrom++;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%sreturn result;\n}\n\n", ofst);
|
||||||
|
|
||||||
|
fprintf(out, "#ifdef DEVEL\n\n");
|
||||||
|
fprintf(out, "int\n%s_put(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx, const char *block)\n{\n", opts->name, c_prefix);
|
||||||
|
fprintf(out, "%sint i = 0;\n", ofst);
|
||||||
|
fprintf(out, "%swhile (m_%s[i]->data) {\n", ofst, opts->name);
|
||||||
|
fprintf(out, "%s%sif (m_%s[i]->type == %s_BLOCK && "
|
||||||
|
"!strcmp(m_%s[i]->data, block)) {\n", ofst, ofst, opts->name, u_prefix,
|
||||||
|
opts->name);
|
||||||
|
fprintf(out, "%s%s%sreturn put_from(s, callback, ctx, i + 1);\n", ofst, ofst,
|
||||||
|
ofst);
|
||||||
|
fprintf(out, "%s%s}\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%sreturn 0;\n}\n\n", ofst);
|
||||||
|
|
||||||
|
fprintf(out, "int\n%s_set(CStuffList list)\n{\n", opts->name);
|
||||||
|
fprintf(out, "%sint i;\n", ofst);
|
||||||
|
fprintf(out, "%sif (m_%s) {\n", ofst, opts->name);
|
||||||
|
fprintf(out, "%s%si = 0;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%swhile (m_%s[i].data) {\n", ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s%s%sfree(m_%s[i].data);\n", ofst, ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s%s}\n", ofst, ofst);
|
||||||
|
fprintf(out, "%s%sfree(m_%s);\n", ofst, ofst, opts->name);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%sif (!(m_%s = malloc(list->length * sizeof (*m_%s))))\n", ofst,
|
||||||
|
opts->name, opts->name);
|
||||||
|
fprintf(out, "%s%sreturn -1;\n", ofst, ofst);
|
||||||
|
fprintf(out, "%sfor (i = 0; i < list->length; i++) {\n", ofst);
|
||||||
|
fprintf(out, "%s%smemcpy(&m_%s[i], list->items[i], sizeof (*m_%s));\n", ofst,
|
||||||
|
ofst, opts->name, opts->name);
|
||||||
|
fprintf(out, "%s}\n", ofst);
|
||||||
|
fprintf(out, "%smemset(&m_%s[i], 0, sizeof (m_%s[i]));\n", ofst, opts->name,
|
||||||
|
opts->name);
|
||||||
|
fprintf(out, "%sreturn i;\n", ofst);
|
||||||
|
fprintf(out, "}\n\n");
|
||||||
|
|
||||||
|
|
||||||
|
fprintf(out, "#else\n\n");
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
struct ax_html *html = list->items[i];
|
||||||
|
if (html->type == AX_HTML_BLOCK) {
|
||||||
|
fprintf(out, "int\n%s_put_%s(AislStream s, %sCallback callback, "
|
||||||
|
"void *ctx)\n", opts->name, html->data, c_prefix);
|
||||||
|
fprintf(out, "{\n");
|
||||||
|
fprintf(out, "%sreturn put_from(s, callback, ctx, %u);\n", ofst, i + 1);
|
||||||
|
fprintf(out, "}\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(out, "#endif\n\n");
|
||||||
|
|
||||||
|
fclose(out);
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_syscall:
|
||||||
|
result = AISL_SYSCALL_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_malloc:
|
||||||
|
result = AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
if (c_prefix)
|
||||||
|
free(c_prefix);
|
||||||
|
|
||||||
|
if (u_prefix)
|
||||||
|
free(u_prefix);
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
free(f);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_html_free(struct ax_html *html)
|
||||||
|
{
|
||||||
|
if (html->data) {
|
||||||
|
free(html->data);
|
||||||
|
}
|
||||||
|
free(html);
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file template.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_HTML_H_92C08532_E423_4CE4_A44C_27CF864A2C60
|
||||||
|
#define AX_HTML_H_92C08532_E423_4CE4_A44C_27CF864A2C60
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <aisl/aisl.h>
|
||||||
|
#include <cStuff/list.h>
|
||||||
|
|
||||||
|
#define AX_HTML_NULL 0
|
||||||
|
#define AX_HTML_PLAIN 1
|
||||||
|
#define AX_HTML_BLOCK 2
|
||||||
|
#define AX_HTML_INPUT 3
|
||||||
|
|
||||||
|
struct ax_html {
|
||||||
|
uint16_t type;
|
||||||
|
uint16_t offset;
|
||||||
|
uint32_t size;
|
||||||
|
char *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ax_html_options {
|
||||||
|
const char *offset;
|
||||||
|
const char *path;
|
||||||
|
const char *name;
|
||||||
|
bool minimize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_import(CStuffList list, const char *html_file);
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_html_export(CStuffList list, const struct ax_html_options *opts);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_html_free(struct ax_html *html);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !HTML_H */
|
||||||
@@ -6,23 +6,19 @@
|
|||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file retcode.h
|
* @file log.c
|
||||||
* @author Ilja Kartašov <ik@lowenware.com>
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
* @brief cStuff return codes
|
* @brief
|
||||||
*
|
*
|
||||||
* @see https://lowenware.com/
|
* @see https://lowenware.com/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CSTUFF_RETCODE_H_CBA3C16B_88D6_49F4_966D_DBDA727583FE
|
#include "log.h"
|
||||||
#define CSTUFF_RETCODE_H_CBA3C16B_88D6_49F4_966D_DBDA727583FE
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
CSTUFF_MALLOC_ERROR = -2
|
|
||||||
, CSTUFF_SYSCALL_ERROR = -1
|
|
||||||
, CSTUFF_SUCCESS = 0
|
|
||||||
, CSTUFF_IDLE = 1
|
|
||||||
|
|
||||||
} cstuff_retcode_t;
|
|
||||||
|
|
||||||
#endif /* !CSTUFF_RETCODE_H */
|
#if AX_LOG_ENABLED == 1
|
||||||
|
|
||||||
|
struct cstuff_log axLog;
|
||||||
|
|
||||||
|
#endif /* AX_LOG_ENABLED == 1 */
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file log.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief Log macro wrapper header-only module
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LOG_H_97A757CA_02E8_4D9C_BE42_29A930928F49
|
||||||
|
#define LOG_H_97A757CA_02E8_4D9C_BE42_29A930928F49
|
||||||
|
|
||||||
|
#include <cStuff/log.h>
|
||||||
|
|
||||||
|
#ifndef AX_LOG_ENABLED
|
||||||
|
#define AX_LOG_ENABLED 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if AX_LOG_ENABLED == 1
|
||||||
|
|
||||||
|
extern struct cstuff_log axLog;
|
||||||
|
|
||||||
|
#define AX_LOG_INIT(LEVEL) cstuff_log_init(&axLog, LEVEL)
|
||||||
|
#define AX_LOG_RELEASE() cstuff_log_release(&axLog)
|
||||||
|
|
||||||
|
#define AX_LOG_DEBUG(...) cstuff_log_printf(&axLog, CSTUFF_LOG_DEBUG, __VA_ARGS__)
|
||||||
|
#define AX_LOG_STATE(...) cstuff_log_printf(&axLog, CSTUFF_LOG_STATE, __VA_ARGS__)
|
||||||
|
#define AX_LOG_ALERT(...) cstuff_log_printf(&axLog, CSTUFF_LOG_ALERT, __VA_ARGS__)
|
||||||
|
#define AX_LOG_ERROR(...) cstuff_log_printf(&axLog, CSTUFF_LOG_ERROR, __VA_ARGS__)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define AX_LOG_DECLARE()
|
||||||
|
#define AX_LOG_INIT(TARGET)
|
||||||
|
#define AX_LOG_RELEASE()
|
||||||
|
|
||||||
|
#define AX_LOG_DEBUG(...)
|
||||||
|
#define AX_LOG_STATE(...)
|
||||||
|
#define AX_LOG_ALERT(...)
|
||||||
|
#define AX_LOG_ERROR(...)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* !LOG_H */
|
||||||
+28
-16
@@ -17,6 +17,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cStuff/string.h>
|
#include <cStuff/string.h>
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
#include <components/log.h>
|
||||||
#include "mail.h"
|
#include "mail.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ payload_free(struct payload *payload)
|
|||||||
|
|
||||||
|
|
||||||
static struct payload *
|
static struct payload *
|
||||||
payload_new(aislx_mail_t mail, const char *server)
|
payload_new(AxMail mail, struct ax_mail_smtp *smtp)
|
||||||
{
|
{
|
||||||
size_t total;
|
size_t total;
|
||||||
struct payload *payload;
|
struct payload *payload;
|
||||||
@@ -130,6 +131,7 @@ payload_new(aislx_mail_t mail, const char *server)
|
|||||||
if (!(payload = calloc(1, sizeof(struct payload))))
|
if (!(payload = calloc(1, sizeof(struct payload))))
|
||||||
goto except;
|
goto except;
|
||||||
|
|
||||||
|
|
||||||
payload__get_now(payload->now, sizeof(payload->now));
|
payload__get_now(payload->now, sizeof(payload->now));
|
||||||
|
|
||||||
if (cstuff_strcpy(&payload->to, mail->to) == -1)
|
if (cstuff_strcpy(&payload->to, mail->to) == -1)
|
||||||
@@ -138,10 +140,21 @@ payload_new(aislx_mail_t mail, const char *server)
|
|||||||
if (cstuff_strcpy(&payload->from, mail->from) == -1)
|
if (cstuff_strcpy(&payload->from, mail->from) == -1)
|
||||||
goto e_cleanup;
|
goto e_cleanup;
|
||||||
|
|
||||||
if ( !(payload->msg_id = payload__get_id(mail->msg_id, server)) )
|
if (cstuff_strcpy(&payload->smtp_user, smtp->user) == -1)
|
||||||
goto e_cleanup;
|
goto e_cleanup;
|
||||||
|
|
||||||
total = cstuff_sprintf( &payload->data, AISLX_MAIL_FORMAT
|
if (cstuff_strcpy(&payload->smtp_pass, smtp->pass) == -1)
|
||||||
|
goto e_cleanup;
|
||||||
|
|
||||||
|
if ( !(payload->msg_id = payload__get_id(mail->msg_id, smtp->host)) )
|
||||||
|
goto e_cleanup;
|
||||||
|
|
||||||
|
if (cstuff_sprintf(&payload->smtp_url, "smtps://%s:%d/", smtp->host,
|
||||||
|
smtp->port & 0xFFFF) == -1) {
|
||||||
|
goto e_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
total = cstuff_sprintf( &payload->data, AX_MAIL_FORMAT
|
||||||
, payload->now
|
, payload->now
|
||||||
, payload->to
|
, payload->to
|
||||||
, payload->from
|
, payload->from
|
||||||
@@ -166,10 +179,10 @@ except:
|
|||||||
|
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
aislx_mail_execute(void *p_ctx)
|
ax_mail_execute(void *p_ctx)
|
||||||
{
|
{
|
||||||
struct payload * payload = (struct payload *)p_ctx;
|
struct payload * payload = (struct payload *)p_ctx;
|
||||||
aisl_status_t status = AISL_MALLOC_ERROR;
|
AislStatus status = AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
CURL *curl;
|
CURL *curl;
|
||||||
struct curl_slist *rcpts;
|
struct curl_slist *rcpts;
|
||||||
@@ -180,6 +193,7 @@ aislx_mail_execute(void *p_ctx)
|
|||||||
curl_easy_setopt(curl, CURLOPT_URL, payload->smtp_url);
|
curl_easy_setopt(curl, CURLOPT_URL, payload->smtp_url);
|
||||||
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long) CURLUSESSL_ALL);
|
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long) CURLUSESSL_ALL);
|
||||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_feed);
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_feed);
|
||||||
curl_easy_setopt(curl, CURLOPT_READDATA, payload);
|
curl_easy_setopt(curl, CURLOPT_READDATA, payload);
|
||||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||||
@@ -190,6 +204,8 @@ aislx_mail_execute(void *p_ctx)
|
|||||||
if ((rcpts = curl_slist_append(NULL, payload->to)) != NULL) {
|
if ((rcpts = curl_slist_append(NULL, payload->to)) != NULL) {
|
||||||
CURLcode res;
|
CURLcode res;
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpts);
|
||||||
|
|
||||||
if ((res = curl_easy_perform(curl)) != CURLE_OK) {
|
if ((res = curl_easy_perform(curl)) != CURLE_OK) {
|
||||||
fprintf(stderr, "curl_easy_perform() failed: %s\n"
|
fprintf(stderr, "curl_easy_perform() failed: %s\n"
|
||||||
, curl_easy_strerror(res));
|
, curl_easy_strerror(res));
|
||||||
@@ -206,20 +222,16 @@ aislx_mail_execute(void *p_ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_mail_send( aislx_mail_t mail,
|
ax_mail_send(AxMail mail, struct ax_mail_smtp *smtp, int flags)
|
||||||
const char *smtp_server,
|
|
||||||
const char *smtp_user,
|
|
||||||
const char *smtp_pass,
|
|
||||||
int flags )
|
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct payload *payload;
|
struct payload *payload;
|
||||||
|
|
||||||
if (!(payload = payload_new(mail, smtp_server)))
|
if (!(payload = payload_new(mail, smtp)))
|
||||||
return AISL_MALLOC_ERROR;
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
rc = pthread_create(&mail->thread, NULL, aislx_mail_execute, (void*)payload);
|
rc = pthread_create(&mail->thread, NULL, ax_mail_execute, (void*)payload);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
payload_free(payload);
|
payload_free(payload);
|
||||||
return AISL_SYSCALL_ERROR;
|
return AISL_SYSCALL_ERROR;
|
||||||
@@ -228,8 +240,8 @@ aislx_mail_send( aislx_mail_t mail,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_mail_get_status(aislx_mail_t mail)
|
ax_mail_get_status(AxMail mail)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
void * retval;
|
void * retval;
|
||||||
@@ -237,7 +249,7 @@ aislx_mail_get_status(aislx_mail_t mail)
|
|||||||
rc = pthread_tryjoin_np(mail->thread, &retval);
|
rc = pthread_tryjoin_np(mail->thread, &retval);
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
rc = (aisl_status_t)retval;
|
rc = (AislStatus)retval;
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
return AISL_IDLE;
|
return AISL_IDLE;
|
||||||
|
|||||||
+19
-16
@@ -13,8 +13,8 @@
|
|||||||
* @see https://lowenware.com/aisl/
|
* @see https://lowenware.com/aisl/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_MAIL_H_2738BEC4_CF82_4D77_A41F_0E2615848194
|
#ifndef MAIL_H_2738BEC4_CF82_4D77_A41F_0E2615848194
|
||||||
#define AISLX_MAIL_H_2738BEC4_CF82_4D77_A41F_0E2615848194
|
#define MAIL_H_2738BEC4_CF82_4D77_A41F_0E2615848194
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
#include <uuid/uuid.h>
|
#include <uuid/uuid.h>
|
||||||
|
|
||||||
|
|
||||||
#ifndef AISLX_MAIL_FORMAT
|
#ifndef AX_MAIL_FORMAT
|
||||||
|
|
||||||
#define AISLX_MAIL_FORMAT \
|
#define AX_MAIL_FORMAT \
|
||||||
"Date: %s\r\n" \
|
"Date: %s\r\n" \
|
||||||
"To: %s\r\n" \
|
"To: %s\r\n" \
|
||||||
"From: %s\r\n" \
|
"From: %s\r\n" \
|
||||||
@@ -37,8 +37,7 @@
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct aislx_mail
|
struct ax_mail {
|
||||||
{
|
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
const char *to;
|
const char *to;
|
||||||
const char *reply_to;
|
const char *reply_to;
|
||||||
@@ -48,19 +47,23 @@ struct aislx_mail
|
|||||||
uuid_t msg_id;
|
uuid_t msg_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct aislx_mail * aislx_mail_t;
|
typedef struct ax_mail * AxMail;
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
struct ax_mail_smtp {
|
||||||
aislx_mail_send( aislx_mail_t mail,
|
const char *user;
|
||||||
const char *smtp_server,
|
const char *pass;
|
||||||
const char *smtp_user,
|
const char *host;
|
||||||
const char *smtp_pass,
|
uint16_t port;
|
||||||
int flags );
|
};
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_mail_get_status(aislx_mail_t mail);
|
ax_mail_send(AxMail mail, struct ax_mail_smtp *smtp, int flags);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !AISLX_MAIL_H */
|
AislStatus
|
||||||
|
ax_mail_get_status(AxMail mail);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !MAIL_H */
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file passwd.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <cStuff/file.h>
|
||||||
|
#include "passwd.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_passwd_ctx {
|
||||||
|
struct ax_passwd *items;
|
||||||
|
int count;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_passwd_hex2bytes(const char *hex, char *out, int max_len)
|
||||||
|
{
|
||||||
|
char s_byte[] = {'\0', '\0', '\0'}, *e_ptr = NULL;
|
||||||
|
for (i = 0; i < max_len; i++) {
|
||||||
|
if (!(*ptr)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
memcpy(s_byte, hex, 2);
|
||||||
|
*out = strtol(s_byte, &e_ptr, 16) & 0xFF;
|
||||||
|
if (e_ptr != &s_byte[2]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (!(*ptr)) ? true : flase;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_hash(struct ax_passwd *entry, char *hash, int length)
|
||||||
|
{
|
||||||
|
char *ptr, *saveptr = NULL, *out, c;
|
||||||
|
int token = 0, i, cnt;
|
||||||
|
|
||||||
|
while ((ptr = strtok(hash, "$", &saveptr)) != NULL) {
|
||||||
|
switch (token++) {
|
||||||
|
case 0:
|
||||||
|
if (!(*ptr)) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
if (!(strcmp(ptr, "1"))) {
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
if (ax_passwd_hex2bytes(ptr, entry->salt, sizeof (entry->salt))) {
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
if (ax_passwd_hex2bytes(ptr, entry->hash, sizeof (entry->hash))) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_line(char *line, ssize_t len, void *p_ctx)
|
||||||
|
{
|
||||||
|
int token = 0;
|
||||||
|
struct ax_passwd_ctx *ctx = (struct ax_passwd_ctx *)p_ctx;
|
||||||
|
struct ax_passwd entry = {0};
|
||||||
|
char *ptr, *saveptr = NULL;
|
||||||
|
|
||||||
|
while ((ptr = strtok(line, ":", &saveptr)) != NULL) {
|
||||||
|
switch (token++) {
|
||||||
|
case 0:
|
||||||
|
if (!cstuff_strncpy(&entry.name, ptr, (int)(saveptr - line))) {
|
||||||
|
line = NULL;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
return CSTUFF_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
entry.uid = strtol(ptr, NULL, 10);
|
||||||
|
continue;
|
||||||
|
case 2:
|
||||||
|
entry.gid = strtol(ptr, NULL, 10);
|
||||||
|
continue;
|
||||||
|
case 3:
|
||||||
|
return ax_passwd_get_hash(&entry, ptr, (int)(saveptr - line));
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_import(struct ax_passwd **p_out, const char *file)
|
||||||
|
{
|
||||||
|
struct ax_passwd_ctx ctx = {NULL, 0};
|
||||||
|
|
||||||
|
if (!cstuff_file_get_lines(file, ax_passwd_get_line, (void *)&ctx)) {
|
||||||
|
*p_out = ctx->items;
|
||||||
|
return ctx->count;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_export(const struct ax_passwd *in, int size, const char *file)
|
||||||
|
{
|
||||||
|
int result = -1, i, j = 0;
|
||||||
|
char *swap, hash[2 * (sizeof (in->salt) + sizeof (in->hash)) + 2];
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof (in->salt); i++) {
|
||||||
|
sprintf(&hash[j], "%02x", in->salt[i] & 0xFF);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
hash[j++] = '$';
|
||||||
|
for (i = 0; i < sizeof (in->hash); i++) {
|
||||||
|
sprintf(&hash[j], "%02x", in->hash[i] & 0xFF);
|
||||||
|
j += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cstuff_printf(&swap, "%s.swap", file)) {
|
||||||
|
if ((f = fopen(swap, "w")) != NULL) {
|
||||||
|
result = 0;
|
||||||
|
while (size--) {
|
||||||
|
if (fprintf(f, "%s:%"PRIu32":%"PRIu32":$1$%s:\n", in->name, in->uid,
|
||||||
|
in->gid, hash) < 0) {
|
||||||
|
result = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
in++;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
if (!result) {
|
||||||
|
if (cstuff_file_move(swap, file) != CSTUFF_SUCCESS)
|
||||||
|
result = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(swap);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_passwd_get_salted(unsigned char **out, const char *password,
|
||||||
|
unsigned char *salt)
|
||||||
|
{
|
||||||
|
int l = strlen(password), result = l + AX_PASSWD_SALT_SIZE;
|
||||||
|
unsigned char *salted;
|
||||||
|
|
||||||
|
if ((salted = malloc(result)) != NULL) {
|
||||||
|
strcpy(salted, password);
|
||||||
|
memcpy(&salted[l], salt, AX_PASSWD_SALT_SIZE);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_verify(const struct ax_passwd *passwd, const char *password)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned char *sltpass, hash[AX_PASSWD_HASH_SIZE];
|
||||||
|
int l;
|
||||||
|
|
||||||
|
if ((l = ax_passwd_get_salted(&sltpass, password, passwd->salt)) != -1) {
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, sltpass, l);
|
||||||
|
SHA1_Final(hash, &ctx);
|
||||||
|
free(sltpass);
|
||||||
|
return (!memcmp(passwd->hash, hash, sizeof (hash))) ? 0 : 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_set_hash(struct ax_passwd *out, const char *password)
|
||||||
|
{
|
||||||
|
SHA1_CTX ctx;
|
||||||
|
unsigned char *sltpass;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
RAND_bytes(out->salt, (sizeof (out->salt)));
|
||||||
|
|
||||||
|
if ((l = ax_passwd_get_salted(&sltpass, password, out->salt)) != -1) {
|
||||||
|
SHA1_Init(&ctx);
|
||||||
|
SHA1_Update(&ctx, sltpass, l);
|
||||||
|
SHA1_Final(out->hash, &ctx);
|
||||||
|
free(sltpass);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_free(struct ax_passwd **p_out, int size)
|
||||||
|
{
|
||||||
|
struct ax_passwd *p = *p_out;
|
||||||
|
|
||||||
|
while (size--) {
|
||||||
|
if (p->name)
|
||||||
|
free(p->name);
|
||||||
|
if (p->hash)
|
||||||
|
free(p->hash);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
free(*p_out);
|
||||||
|
*p_out = NULL;
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file passwd.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA
|
||||||
|
#define AX_PASSWD_H_0DE6E254_27E2_4DEF_A88A_4EE84D5C00DA
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#define AX_PASSWD_TOKENS 4
|
||||||
|
#define AX_PASSWD_SALT_SIZE 16
|
||||||
|
#define AX_PASSWD_HASH_SIZE SHA1_DIGEST_LENGTH
|
||||||
|
|
||||||
|
struct ax_passwd {
|
||||||
|
uint32_t uid;
|
||||||
|
uint32_t gid;
|
||||||
|
char *name;
|
||||||
|
char salt[AX_PASSWD_SALT_SIZE];
|
||||||
|
char hash[AX_PASSWD_HASH_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_passwd * AxPasswd;
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_import(struct ax_passwd **p_out, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_export(const struct ax_passwd *in, int size, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_verify(const struct ax_passwd *passwd, const char *password);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_set_hash(struct ax_passwd *out, const char *password);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_passwd_free(struct ax_passwd **p_out, int size);
|
||||||
|
|
||||||
|
#endif /* !AX_PASSWD_H */
|
||||||
+38
-16
@@ -16,20 +16,18 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "log.h"
|
||||||
#include "query.h"
|
#include "query.h"
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_query_init( aislx_query_t query,
|
ax_query_init(AxQuery query, size_t total, AxQueryHandler on_var, void *p_ctx)
|
||||||
size_t total,
|
|
||||||
aislx_query_on_var on_var,
|
|
||||||
void * p_ctx )
|
|
||||||
{
|
{
|
||||||
query->on_var = on_var;
|
query->on_var = on_var;
|
||||||
query->p_ctx = p_ctx;
|
query->p_ctx = p_ctx;
|
||||||
query->data = NULL;
|
query->data = NULL;
|
||||||
query->size = 0;
|
query->size = 0;
|
||||||
query->total = 0;
|
query->total = total;
|
||||||
query->separator = 0;
|
query->separator = 0;
|
||||||
|
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
@@ -37,7 +35,7 @@ aislx_query_init( aislx_query_t query,
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
aislx_query_release(aislx_query_t query)
|
ax_query_release(AxQuery query)
|
||||||
{
|
{
|
||||||
if (query->data)
|
if (query->data)
|
||||||
free(query->data);
|
free(query->data);
|
||||||
@@ -45,9 +43,9 @@ aislx_query_release(aislx_query_t query)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
aislx_query_notify(const char * key, uint32_t k_len,
|
ax_query_notify(const char *key, uint32_t k_len,
|
||||||
const char * val, uint32_t v_len,
|
const char *val, uint32_t v_len,
|
||||||
aislx_query_t query)
|
AxQuery query)
|
||||||
{
|
{
|
||||||
if (query->on_var) {
|
if (query->on_var) {
|
||||||
if (query->on_var(key, k_len, val, v_len, query->p_ctx) != 0)
|
if (query->on_var(key, k_len, val, v_len, query->p_ctx) != 0)
|
||||||
@@ -57,7 +55,7 @@ aislx_query_notify(const char * key, uint32_t k_len,
|
|||||||
|
|
||||||
|
|
||||||
static int32_t
|
static int32_t
|
||||||
aislx_query_process(aislx_query_t query, const char * data, int32_t length)
|
ax_query_process(AxQuery query, const char *data, int32_t length)
|
||||||
{
|
{
|
||||||
const char *i = data,
|
const char *i = data,
|
||||||
*key = data,
|
*key = data,
|
||||||
@@ -86,7 +84,7 @@ aislx_query_process(aislx_query_t query, const char * data, int32_t length)
|
|||||||
query->separator = c;
|
query->separator = c;
|
||||||
|
|
||||||
if (query->separator == c) {
|
if (query->separator == c) {
|
||||||
aislx_query_notify(key, k_len, val, i-val, query);
|
ax_query_notify(key, k_len, val, i-val, query);
|
||||||
/* reset parser */
|
/* reset parser */
|
||||||
key = (c == ';') ? i+2 : i+1;
|
key = (c == ';') ? i+2 : i+1;
|
||||||
k_len = 0;
|
k_len = 0;
|
||||||
@@ -98,7 +96,7 @@ aislx_query_process(aislx_query_t query, const char * data, int32_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (query->total == result) {
|
if (query->total == result) {
|
||||||
aislx_query_notify(key, k_len, val, i-val, query);
|
ax_query_notify(key, k_len, val, i-val, query);
|
||||||
} else {
|
} else {
|
||||||
result = (key > i) ? i - data : key - data;
|
result = (key > i) ? i - data : key - data;
|
||||||
}
|
}
|
||||||
@@ -109,8 +107,8 @@ aislx_query_process(aislx_query_t query, const char * data, int32_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_query_feed(aislx_query_t query, const char *data, int32_t length)
|
ax_query_feed(AxQuery query, const char *data, int32_t length)
|
||||||
{
|
{
|
||||||
size_t processed;
|
size_t processed;
|
||||||
const char *source;
|
const char *source;
|
||||||
@@ -128,7 +126,7 @@ aislx_query_feed(aislx_query_t query, const char *data, int32_t length)
|
|||||||
source = data;
|
source = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
processed = aislx_query_process(query, source, length);
|
processed = ax_query_process(query, source, length);
|
||||||
|
|
||||||
if (processed < 0)
|
if (processed < 0)
|
||||||
return AISL_INPUT_ERROR;
|
return AISL_INPUT_ERROR;
|
||||||
@@ -137,6 +135,7 @@ aislx_query_feed(aislx_query_t query, const char *data, int32_t length)
|
|||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
||||||
length -= processed;
|
length -= processed;
|
||||||
|
|
||||||
if (!(buffer = malloc(length)))
|
if (!(buffer = malloc(length)))
|
||||||
return AISL_MALLOC_ERROR;
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
@@ -153,3 +152,26 @@ aislx_query_feed(aislx_query_t query, const char *data, int32_t length)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_query__decode(char *e_str)
|
||||||
|
{
|
||||||
|
char *p = e_str,
|
||||||
|
hex[3] = {0,0,0};
|
||||||
|
do {
|
||||||
|
switch(*e_str) {
|
||||||
|
case '%':
|
||||||
|
hex[0] = *(++e_str);
|
||||||
|
hex[1] = *(++e_str);
|
||||||
|
*p++ = (char)strtol(hex, NULL, 16);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
*p++ = ' ';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
*p++ = *e_str;
|
||||||
|
}
|
||||||
|
} while(*e_str++ != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+15
-16
@@ -13,8 +13,8 @@
|
|||||||
* @see https://lowenware.com/aisl
|
* @see https://lowenware.com/aisl
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_QUERY_H_9306EAEB_6DFC_4936_934A_6472F00E490C
|
#ifndef QUERY_H_9306EAEB_6DFC_4936_934A_6472F00E490C
|
||||||
#define AISLX_QUERY_H_9306EAEB_6DFC_4936_934A_6472F00E490C
|
#define QUERY_H_9306EAEB_6DFC_4936_934A_6472F00E490C
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
@@ -22,14 +22,13 @@
|
|||||||
|
|
||||||
|
|
||||||
typedef int
|
typedef int
|
||||||
(*aislx_query_on_var)( const char *key, uint32_t k_len,
|
(*AxQueryHandler)(const char *key, uint32_t k_len,
|
||||||
const char *val, uint32_t v_len,
|
const char *val, uint32_t v_len,
|
||||||
void *p_ctx );
|
void *p_ctx );
|
||||||
|
|
||||||
|
|
||||||
struct aislx_query
|
struct ax_query {
|
||||||
{
|
AxQueryHandler on_var;
|
||||||
aislx_query_on_var on_var;
|
|
||||||
void *p_ctx;
|
void *p_ctx;
|
||||||
char *data;
|
char *data;
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -37,22 +36,22 @@ struct aislx_query
|
|||||||
char separator;
|
char separator;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct aislx_query * aislx_query_t;
|
typedef struct ax_query * AxQuery;
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_query_init( aislx_query_t query,
|
ax_query_init(AxQuery query, size_t total, AxQueryHandler on_var, void *p_ctx);
|
||||||
size_t total,
|
|
||||||
aislx_query_on_var on_var,
|
|
||||||
void *p_ctx );
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
aislx_query_release(aislx_query_t query);
|
ax_query_release(AxQuery query);
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_query_feed(aislx_query_t query, const char *data, int32_t length);
|
ax_query_feed(AxQuery query, const char *data, int32_t length);
|
||||||
|
|
||||||
|
|
||||||
#endif /* !AISLX_QUERY_H */
|
void
|
||||||
|
ax_query__decode(char *e_str);
|
||||||
|
|
||||||
|
#endif /* !QUERY_H */
|
||||||
|
|||||||
+3
-3
@@ -16,10 +16,10 @@
|
|||||||
#include "quick.h"
|
#include "quick.h"
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_quick_response(aisl_stream_t stream, aisl_http_response_t http_response)
|
ax_quick_response(AislStream stream, AislHttpResponse http_response)
|
||||||
{
|
{
|
||||||
aisl_status_t result;
|
AislStatus result;
|
||||||
|
|
||||||
result = aisl_response(stream, http_response, 0);
|
result = aisl_response(stream, http_response, 0);
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -13,12 +13,12 @@
|
|||||||
* @see https://lowenware.com/aisl/
|
* @see https://lowenware.com/aisl/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_QUICK_H_39A26EF5_2352_4D54_A10C_203CBBEDF1DF
|
#ifndef QUICK_H_39A26EF5_2352_4D54_A10C_203CBBEDF1DF
|
||||||
#define AISLX_QUICK_H_39A26EF5_2352_4D54_A10C_203CBBEDF1DF
|
#define QUICK_H_39A26EF5_2352_4D54_A10C_203CBBEDF1DF
|
||||||
|
|
||||||
#include <aisl/aisl.h>
|
#include <aisl/aisl.h>
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_quick_response(aisl_stream_t stream, aisl_http_response_t http_response);
|
ax_quick_response(AislStream stream, AislHttpResponse http_response);
|
||||||
|
|
||||||
#endif /* !AISLX_QUICK_H */
|
#endif /* !QUICK_H */
|
||||||
|
|||||||
@@ -0,0 +1,524 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file todo.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <uuid.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <cStuff/string.h>
|
||||||
|
#include <cStuff/file.h>
|
||||||
|
#include <components/log.h>
|
||||||
|
#include "todo.h"
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_init(AxTodo self, const char *file)
|
||||||
|
{
|
||||||
|
uuid_generate(self->list_id);
|
||||||
|
|
||||||
|
self->file = file;
|
||||||
|
|
||||||
|
if (cstuff_sprintf(&self->swap, "%s.swap", file) == -1)
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_release(AxTodo self)
|
||||||
|
{
|
||||||
|
if (self->swap)
|
||||||
|
free(self->swap);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_todo_add_project(CStuffList list, time_t completed, char *key, size_t k_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
AxTodoProject proj;
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
proj = list->items[i];
|
||||||
|
|
||||||
|
if (strncmp(proj->name, key, k_len) == 0 && !proj->name[k_len]) {
|
||||||
|
proj->ref_count++;
|
||||||
|
|
||||||
|
if (proj->last_completed < completed) {
|
||||||
|
proj->last_completed = completed;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(proj = calloc(1, sizeof (*proj))))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cstuff_strncpy(&proj->name, key, k_len) != -1) {
|
||||||
|
proj->ref_count = 1;
|
||||||
|
proj->last_completed = completed;
|
||||||
|
uuid_generate(proj->project_id);
|
||||||
|
if (cstuff_list_append(list, proj) != -1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ax_todo_project_free(proj);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_todo_add_tag(CStuffList list, char *key, size_t k_len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
AxTodoTag tag;
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
tag = list->items[i];
|
||||||
|
|
||||||
|
if (strncmp(tag->name, key, k_len) == 0 && !tag->name[k_len]) {
|
||||||
|
tag->ref_count++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(tag = calloc(1, sizeof (*tag))))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (cstuff_strncpy(&tag->name, key, k_len) != -1) {
|
||||||
|
tag->ref_count = 1;
|
||||||
|
uuid_generate(tag->tag_id);
|
||||||
|
if (cstuff_list_append(list, tag) != -1)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ax_todo_tag_free(tag);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_todo_read_keys(AxTodoTask task, CStuffList projs, CStuffList tags)
|
||||||
|
{
|
||||||
|
const char tokens[] = "+@";
|
||||||
|
char *s = task->description;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
char t;
|
||||||
|
offset = strcspn(s, tokens);
|
||||||
|
|
||||||
|
s += offset;
|
||||||
|
|
||||||
|
if ((t = *(s++)) == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
offset = strcspn(s, " ");
|
||||||
|
|
||||||
|
if (offset) {
|
||||||
|
if ((t == '+' && !ax_todo_add_project(projs, task->completed, s, offset))
|
||||||
|
|| (t == '@' && !ax_todo_add_tag(tags, s, offset))) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
s += offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_read(AxTodo self, CStuffList tasks, CStuffList projs, CStuffList tags)
|
||||||
|
{
|
||||||
|
FILE *f = NULL;
|
||||||
|
size_t sz = 256;
|
||||||
|
char *buf;
|
||||||
|
ssize_t rs;
|
||||||
|
AislStatus result = AISL_SUCCESS;
|
||||||
|
|
||||||
|
if (!(buf = malloc(sz)))
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
if (!(f = fopen(self->file, "r")))
|
||||||
|
goto e_syscall;
|
||||||
|
|
||||||
|
while ((rs = getdelim(&buf, &sz, '\n', f)) != -1) {
|
||||||
|
AxTodoTask task;
|
||||||
|
|
||||||
|
if (!(task = ax_todo_task_new(self->list_id)))
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
if (ax_todo_task_set(task, buf, rs) != 0) {
|
||||||
|
ax_todo_task_free(task);
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cstuff_list_append(tasks, task) == -1) {
|
||||||
|
ax_todo_task_free(task);
|
||||||
|
goto e_malloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((result = ax_todo_read_keys(task, projs, tags)) != AISL_SUCCESS) {
|
||||||
|
goto e_malloc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(errno) {
|
||||||
|
case 0:
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
case ENOMEM:
|
||||||
|
goto e_malloc;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto e_syscall;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_input:
|
||||||
|
result = AISL_INPUT_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_malloc:
|
||||||
|
result = AISL_MALLOC_ERROR;
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_syscall:
|
||||||
|
result = AISL_SYSCALL_ERROR;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
free(buf);
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ax_todo__write_dt(FILE *f, time_t dt)
|
||||||
|
{
|
||||||
|
char str_dt[16];
|
||||||
|
struct tm *p_stm = gmtime(&dt);
|
||||||
|
(void) strftime(str_dt, sizeof (str_dt), "%Y-%m-%d", p_stm);
|
||||||
|
fprintf(f, "%s ", str_dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_write(AxTodo self, CStuffList list)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!(f = fopen(self->swap, "w")))
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
|
||||||
|
for (i = 0; i < list->length; i++) {
|
||||||
|
AxTodoTask task = (AxTodoTask) list->items[i];
|
||||||
|
|
||||||
|
if (uuid_compare(task->list_id, self->list_id) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (task->is_done) {
|
||||||
|
fwrite("x ", 1, 2, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task->priority && task->priority != AX_TODO_ZERO_PRIORITY) {
|
||||||
|
fprintf(f, "(%c) ", task->priority);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task->is_done) {
|
||||||
|
if (task->completed) {
|
||||||
|
ax_todo__write_dt(f, task->completed);
|
||||||
|
if (task->created) {
|
||||||
|
ax_todo__write_dt(f, task->created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (task->created) {
|
||||||
|
ax_todo__write_dt(f, task->created);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, "%s\n", task->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
if (cstuff_file_move(self->swap, self->file) != 0)
|
||||||
|
return AISL_SYSCALL_ERROR;
|
||||||
|
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AxTodoTask
|
||||||
|
ax_todo_task_new(uuid_t list_id)
|
||||||
|
{
|
||||||
|
AxTodoTask result;
|
||||||
|
|
||||||
|
if ((result = calloc(1, sizeof (*result))) != NULL) {
|
||||||
|
uuid_copy(result->list_id, list_id);
|
||||||
|
uuid_generate(result->task_id);
|
||||||
|
result->priority = AX_TODO_ZERO_PRIORITY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_task_release(AxTodoTask task)
|
||||||
|
{
|
||||||
|
if (task->description)
|
||||||
|
free(task->description);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_task_free(AxTodoTask task)
|
||||||
|
{
|
||||||
|
ax_todo_task_release(task);
|
||||||
|
free(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_todo__get_priority(char *buf, char *p_priority)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
char priority = 0;
|
||||||
|
const char fmt[] = {'(', 'A', ')', ' '};
|
||||||
|
|
||||||
|
for (result = 0; result < 4; result++) {
|
||||||
|
switch (result) {
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
if (buf[result] == fmt[result])
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
priority = buf[result];
|
||||||
|
if (!(priority < 0x41 || priority > 0x5A))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*p_priority = priority;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_todo__get_dt(char *buf, time_t *p_dt)
|
||||||
|
{
|
||||||
|
struct tm stm = {0};
|
||||||
|
int result, *p_num = NULL, b_hour = 0, b_min = 0, usec = 0, z_bias = 0;
|
||||||
|
const char fmt[] = "Y-M-DTH:m:s.uZB:b ", *f = fmt;
|
||||||
|
char *ptr = NULL;
|
||||||
|
|
||||||
|
setenv("TZ", "UTC", 1);
|
||||||
|
|
||||||
|
for (result = 0; *f != 0; result++, f++) {
|
||||||
|
switch(*f) {
|
||||||
|
case 'Y':
|
||||||
|
p_num = &stm.tm_year;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
p_num = &stm.tm_mon;
|
||||||
|
break;
|
||||||
|
case 'D':
|
||||||
|
p_num = &stm.tm_mday;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
p_num = &stm.tm_hour;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
p_num = &stm.tm_min;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
p_num = &stm.tm_sec;
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
p_num = &usec;
|
||||||
|
break;
|
||||||
|
case 'B':
|
||||||
|
p_num = &b_hour;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
p_num = &b_min;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
if (buf[result] != *f) {
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case 'T':
|
||||||
|
if (buf[result] == *f)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (buf[result] == ' ') {
|
||||||
|
f = &fmt[17];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto e_input;
|
||||||
|
|
||||||
|
case 'Z':
|
||||||
|
if (buf[result] == *f) {
|
||||||
|
f += 3;
|
||||||
|
z_bias = 'Z';
|
||||||
|
} else if (buf[result] == '-') {
|
||||||
|
z_bias = -1;
|
||||||
|
} else if (buf[result] == '+') {
|
||||||
|
z_bias = 1;
|
||||||
|
} else {
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case '-':
|
||||||
|
case ':':
|
||||||
|
case ' ':
|
||||||
|
if (buf[result] == *f)
|
||||||
|
continue;
|
||||||
|
/* go through */
|
||||||
|
default:
|
||||||
|
goto e_input;
|
||||||
|
} /* switch */
|
||||||
|
|
||||||
|
*p_num = strtol(&buf[result], &ptr, 10);
|
||||||
|
|
||||||
|
if (!ptr || ptr == &buf[result]) {
|
||||||
|
if (f > &fmt[6] && buf[result] == ' ') {
|
||||||
|
f = &fmt[17];
|
||||||
|
/* skip optional part of timestamp */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
goto e_input;
|
||||||
|
}
|
||||||
|
|
||||||
|
result += (ptr - &buf[result] - 1);
|
||||||
|
} /* for */
|
||||||
|
|
||||||
|
/* validate results */
|
||||||
|
/* ToDo: improve (stm.tm_mday < 31) check */
|
||||||
|
if (!(stm.tm_year < 1900) && (stm.tm_mon) && (stm.tm_mday) &&
|
||||||
|
(stm.tm_mon < 13) && (stm.tm_mday < 31) && (stm.tm_hour < 24) &&
|
||||||
|
(stm.tm_min < 60) && (stm.tm_sec < 60)) {
|
||||||
|
stm.tm_year -= 1900;
|
||||||
|
stm.tm_mon--;
|
||||||
|
|
||||||
|
if (z_bias == 0) { /* local time zone */
|
||||||
|
*p_dt = mktime(&stm);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (z_bias != 'Z') {
|
||||||
|
stm.tm_hour += (b_hour * z_bias);
|
||||||
|
stm.tm_min += (b_min * z_bias);
|
||||||
|
}
|
||||||
|
|
||||||
|
*p_dt = mktime(&stm);
|
||||||
|
unsetenv("TZ");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
e_input:
|
||||||
|
/* AX_LOG_DEBUG("Parse error: %c(%d) at %d", *f, (int) (f - fmt), result); */
|
||||||
|
return 0;
|
||||||
|
(void) usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo__remove_line_break(char *description)
|
||||||
|
{
|
||||||
|
int move = 0;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c = *description;
|
||||||
|
|
||||||
|
if (c == '\r' || c == '\n') {
|
||||||
|
move++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(description - move) = c;
|
||||||
|
|
||||||
|
} while (c != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length)
|
||||||
|
{
|
||||||
|
bool is_done;
|
||||||
|
int l;
|
||||||
|
|
||||||
|
if (strncmp(buf, "x ", 2) == 0) {
|
||||||
|
is_done = true;
|
||||||
|
buf += 2;
|
||||||
|
} else {
|
||||||
|
is_done = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
task->is_done = is_done;
|
||||||
|
|
||||||
|
if ((l = ax_todo__get_priority(buf, &task->priority)) != 0) {
|
||||||
|
buf += l;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = ax_todo__get_dt(buf, (is_done) ? &task->completed : &task->created);
|
||||||
|
|
||||||
|
if (l != 0) {
|
||||||
|
buf += l;
|
||||||
|
if (is_done && (l = ax_todo__get_dt(buf, &task->created)) != 0) {
|
||||||
|
buf += l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((l = cstuff_strcpy(&task->description, buf)) == -1) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (l > 1 && task->description[l-1] == '\n')
|
||||||
|
task->description[l-1] = 0;
|
||||||
|
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_project_free(AxTodoProject project)
|
||||||
|
{
|
||||||
|
if (project->name)
|
||||||
|
free(project->name);
|
||||||
|
free(project);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_tag_free(AxTodoTag tag)
|
||||||
|
{
|
||||||
|
if (tag->name)
|
||||||
|
free(tag->name);
|
||||||
|
free(tag);
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file todo.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief ToDo.txt module
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef TODO_H_FAD28DF0_DA05_4436_88E5_E3715DA254E8
|
||||||
|
#define TODO_H_FAD28DF0_DA05_4436_88E5_E3715DA254E8
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <aisl/aisl.h>
|
||||||
|
#include <cStuff/list.h>
|
||||||
|
|
||||||
|
#define AX_TODO_ZERO_PRIORITY '_'
|
||||||
|
|
||||||
|
struct ax_todo {
|
||||||
|
uuid_t list_id;
|
||||||
|
const char *file;
|
||||||
|
char *swap;
|
||||||
|
/* todo: add file timestamp */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_todo * AxTodo;
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_todo_task {
|
||||||
|
uuid_t list_id;
|
||||||
|
uuid_t task_id;
|
||||||
|
time_t completed;
|
||||||
|
time_t created;
|
||||||
|
char *description;
|
||||||
|
bool is_done;
|
||||||
|
char priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_todo_task * AxTodoTask;
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_todo_project {
|
||||||
|
uuid_t project_id;
|
||||||
|
time_t last_completed;
|
||||||
|
char *name;
|
||||||
|
uint32_t ref_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_todo_project * AxTodoProject;
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_todo_tag {
|
||||||
|
uuid_t tag_id;
|
||||||
|
char *name;
|
||||||
|
uint32_t ref_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct ax_todo_tag * AxTodoTag;
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_init(AxTodo self, const char *file);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_release(AxTodo self);
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_read(AxTodo self, CStuffList tasks, CStuffList projs, CStuffList tags);
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_write(AxTodo self, CStuffList list);
|
||||||
|
|
||||||
|
|
||||||
|
AxTodoTask
|
||||||
|
ax_todo_task_new(uuid_t list_id);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_task_release(AxTodoTask task);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_task_free(AxTodoTask task);
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ax_todo__get_dt(char *buf, time_t *p_dt);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo__remove_line_break(char *description);
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_project_free(AxTodoProject project);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_todo_tag_free(AxTodoTag tag);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !TODO_H */
|
||||||
@@ -16,11 +16,12 @@
|
|||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "log.h"
|
||||||
#include "validate.h"
|
#include "validate.h"
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
aislx_validate_email(const char *value)
|
ax_validate_email(const char *value)
|
||||||
{
|
{
|
||||||
const char *at = NULL,
|
const char *at = NULL,
|
||||||
*dot = NULL,
|
*dot = NULL,
|
||||||
@@ -100,8 +101,11 @@ aislx_validate_email(const char *value)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if ( isalnum(c) == 0 )
|
if (isalnum(c))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return (int)(i-value)+1;
|
return (int)(i-value)+1;
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
* @see https://lowenware.com/
|
* @see https://lowenware.com/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_VALIDATE_H_5EEF42FB_E99B_4768_AF28_E548CF72D2E6
|
#ifndef VALIDATE_H_5EEF42FB_E99B_4768_AF28_E548CF72D2E6
|
||||||
#define AISLX_VALIDATE_H_5EEF42FB_E99B_4768_AF28_E548CF72D2E6
|
#define VALIDATE_H_5EEF42FB_E99B_4768_AF28_E548CF72D2E6
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
aislx_validate_email(const char * value);
|
ax_validate_email(const char *value);
|
||||||
|
|
||||||
#endif /* !AISLX_VALIDATE_H */
|
#endif /* !AX_VALIDATE_H */
|
||||||
|
|||||||
@@ -13,13 +13,14 @@
|
|||||||
* @see https://lowenware.com/
|
* @see https://lowenware.com/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ctx.h"
|
#include <stdlib.h>
|
||||||
|
#include "context.h"
|
||||||
|
|
||||||
|
|
||||||
aislx_ctx_t
|
AxContext
|
||||||
aislx_ctx_new(aislx_module_t mod)
|
ax_context_new(AxModule mod)
|
||||||
{
|
{
|
||||||
aislx_ctx_t ctx;
|
AxContext ctx;
|
||||||
|
|
||||||
if ((ctx = calloc(1, mod->ctx_size)) != NULL) {
|
if ((ctx = calloc(1, mod->ctx_size)) != NULL) {
|
||||||
ctx->mod = mod;
|
ctx->mod = mod;
|
||||||
@@ -30,7 +31,7 @@ aislx_ctx_new(aislx_module_t mod)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
aislx_ctx_free(aislx_ctx_t ctx)
|
ax_context_free(AxContext ctx)
|
||||||
{
|
{
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
@@ -13,36 +13,36 @@
|
|||||||
* @see https://lowenware.com/aisl/
|
* @see https://lowenware.com/aisl/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_CTX_H_683B0A86_2A15_483D_B0F9_7BFBB4BA068F
|
#ifndef CONTEXT_H_683B0A86_2A15_483D_B0F9_7BFBB4BA068F
|
||||||
#define AISLX_CTX_H_683B0A86_2A15_483D_B0F9_7BFBB4BA068F
|
#define CONTEXT_H_683B0A86_2A15_483D_B0F9_7BFBB4BA068F
|
||||||
|
|
||||||
#define AISLX_CTX(x) ((aislx_ctx_t)x)
|
#define AX_CONTEXT(x) ((AxContext)x)
|
||||||
|
|
||||||
#include <mods/module.h>
|
#include <mods/module.h>
|
||||||
|
|
||||||
/** @brief Root level ASIL mod's context structure
|
/** @brief Root level ASIL mod's context structure
|
||||||
*/
|
*/
|
||||||
struct aislx_ctx {
|
struct ax_context {
|
||||||
aislx_module_t mod; /**< Mod's pointer */
|
AxModule mod; /**< Mod's pointer */
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @brief Root level ASIL mod's context structure pointer
|
/** @brief Root level ASIL mod's context structure pointer
|
||||||
*/
|
*/
|
||||||
typedef struct aislx_ctx * aislx_ctx_t;
|
typedef struct ax_context * AxContext;
|
||||||
|
|
||||||
|
|
||||||
/** @brief Allocates zeroed #aislx_t context
|
/** @brief Allocates zeroed #aislx_t context
|
||||||
* @param mod an instance of #aislx_t
|
* @param mod an instance of #aislx_t
|
||||||
* @return pointer to newly allocated #aisl_mox_ctx_t
|
* @return pointer to newly allocated #aisl_mox_ctx_t
|
||||||
*/
|
*/
|
||||||
aislx_ctx_t
|
AxContext
|
||||||
aislx_ctx_new(aislx_module_t mod);
|
ax_context_new(AxModule mod);
|
||||||
|
|
||||||
|
|
||||||
/** @brief Frees previosly allocated #aislx_ctx_t
|
/** @brief Frees previosly allocated #aislx_ctx_t
|
||||||
* @param ctx an instance of mod's context structure
|
* @param ctx an instance of mod's context structure
|
||||||
* */
|
* */
|
||||||
void
|
void
|
||||||
aislx_ctx_free(aislx_ctx_t ctx);
|
ax_context_free(AxContext ctx);
|
||||||
|
|
||||||
#endif /* !AISLX_CTX_H */
|
#endif /* !AISLX_CTX_H */
|
||||||
+93
-82
@@ -18,27 +18,28 @@
|
|||||||
#include <components/mail.h>
|
#include <components/mail.h>
|
||||||
#include <components/validate.h>
|
#include <components/validate.h>
|
||||||
#include <components/quick.h>
|
#include <components/quick.h>
|
||||||
|
#include <components/log.h>
|
||||||
#include <cStuff/string.h>
|
#include <cStuff/string.h>
|
||||||
#include "feedback.h"
|
#include "feedback.h"
|
||||||
|
|
||||||
|
|
||||||
struct context
|
struct context {
|
||||||
{
|
struct ax_context root;
|
||||||
struct aislx_ctx root;
|
struct ax_query qs;
|
||||||
struct aislx_query qs;
|
struct ax_mail mail;
|
||||||
struct aislx_mail mail;
|
char *email;
|
||||||
|
char *msg;
|
||||||
char * email;
|
|
||||||
char * msg;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct context * context_t;
|
typedef struct context * Context;
|
||||||
|
|
||||||
|
static const char modName[] = "feedback";
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
context_free(context_t ctx)
|
context_free(Context ctx)
|
||||||
{
|
{
|
||||||
aislx_query_release(&ctx->qs);
|
ax_query_release(&ctx->qs);
|
||||||
|
|
||||||
if (ctx->email)
|
if (ctx->email)
|
||||||
free(ctx->email);
|
free(ctx->email);
|
||||||
@@ -46,41 +47,46 @@ context_free(context_t ctx)
|
|||||||
if (ctx->msg)
|
if (ctx->msg)
|
||||||
free(ctx->msg);
|
free(ctx->msg);
|
||||||
|
|
||||||
aislx_ctx_free((aislx_ctx_t)ctx);
|
ax_context_free((AxContext)ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
on_input_var( const char *key, uint32_t k_len,
|
on_input_var(const char *key, uint32_t k_len, const char *val, uint32_t v_len,
|
||||||
const char *val, uint32_t v_len,
|
|
||||||
void *p_ctx )
|
void *p_ctx )
|
||||||
{
|
{
|
||||||
context_t ctx = (context_t) p_ctx;
|
Context ctx = (Context) p_ctx;
|
||||||
aislx_feedback_t mod = (aislx_feedback_t)((aislx_ctx_t)ctx)->mod;
|
AxFeedback mod = (AxFeedback)((AxContext)ctx)->mod;
|
||||||
|
char **out = NULL;
|
||||||
|
|
||||||
if (!ctx->email && k_len == mod->name_email_length)
|
if (!ctx->email && k_len == mod->name_email_length) {
|
||||||
{
|
if (strncmp(key, mod->name_email, k_len) == 0) {
|
||||||
if (strncmp(key, mod->name_email, k_len)==0)
|
out = &ctx->email;
|
||||||
return cstuff_strncpy(&ctx->email, val, v_len);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ctx->msg && k_len == mod->name_msg_length)
|
if (!ctx->msg && k_len == mod->name_msg_length) {
|
||||||
{
|
if (strncmp(key, mod->name_msg, k_len)==0) {
|
||||||
if (strncmp(key, mod->name_msg, k_len)==0)
|
out = &ctx->msg;
|
||||||
return cstuff_strncpy(&ctx->msg, val, v_len);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (out) {
|
||||||
|
if (cstuff_strncpy(out, val, v_len) == -1)
|
||||||
|
return -1;
|
||||||
|
ax_query__decode(*out);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
on_stream_open(aislx_feedback_t mod, aisl_evt_stream_open_t const evt)
|
on_stream_open(AxFeedback mod, const struct aisl_evt_open *evt)
|
||||||
{
|
{
|
||||||
context_t ctx;
|
Context ctx;
|
||||||
aisl_stream_t s = (aisl_stream_t) (evt->evt.source);
|
AislStream s = (AislStream) (evt->evt.source);
|
||||||
|
|
||||||
if (!(ctx = (context_t)aislx_ctx_new(AISLX_MODULE(mod))))
|
if (!(ctx = (Context)ax_context_new(AX_MODULE(mod))))
|
||||||
return AISL_MALLOC_ERROR;
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
ctx->mail.from = mod->mail_from;
|
ctx->mail.from = mod->mail_from;
|
||||||
@@ -99,76 +105,84 @@ on_stream_open(aislx_feedback_t mod, aisl_evt_stream_open_t const evt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
on_stream_header(aislx_feedback_t mod, aisl_evt_stream_header_t const evt)
|
on_stream_header(AxFeedback mod, const struct aisl_evt_header *evt)
|
||||||
{
|
{
|
||||||
aisl_stream_t s = (aisl_stream_t)evt->evt.source;
|
AislStream s = (AislStream)evt->evt.source;
|
||||||
context_t ctx = aisl_get_context(s);
|
Context ctx = aisl_get_context(s);
|
||||||
|
|
||||||
if (strcmp(evt->key, "content-length")==0)
|
if (strcmp(evt->key, "content-length") == 0) {
|
||||||
{
|
|
||||||
size_t total = strtoll(evt->value, NULL, 10);
|
size_t total = strtoll(evt->value, NULL, 10);
|
||||||
|
|
||||||
if(aislx_query_init(&ctx->qs, total, on_input_var, (void*)ctx) != 0)
|
if(ax_query_init(&ctx->qs, total, on_input_var, (void*)ctx) != 0) {
|
||||||
{
|
ax_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
aislx_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
on_stream_input(aislx_feedback_t mod, aisl_evt_stream_input_t const evt)
|
on_stream_input(AxFeedback mod, const struct aisl_evt_input *evt)
|
||||||
{
|
{
|
||||||
context_t ctx = aisl_get_context((aisl_stream_t)evt->evt.source);
|
Context ctx = aisl_get_context((AislStream)evt->evt.source);
|
||||||
|
|
||||||
aislx_query_feed(&ctx->qs, evt->data, evt->size);
|
ax_query_feed(&ctx->qs, evt->data, evt->size);
|
||||||
|
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
on_stream_request(aislx_feedback_t mod, aisl_evt_t const evt)
|
on_stream_request(AxFeedback mod, const struct aisl_evt *evt)
|
||||||
{
|
{
|
||||||
aisl_status_t status;
|
int rc;
|
||||||
context_t ctx = aisl_get_context((aisl_stream_t)evt->source);
|
Context ctx = aisl_get_context((AislStream)evt->source);
|
||||||
aisl_stream_t s = (aisl_stream_t)evt->source;
|
AislStream s = (AislStream)evt->source;
|
||||||
|
|
||||||
/* verify input */
|
/* verify input */
|
||||||
if (!ctx->email || !ctx->msg || aislx_validate_email(ctx->email) != 0)
|
if (!ctx->email) {
|
||||||
aislx_quick_response(s, AISL_HTTP_BAD_REQUEST);
|
AX_LOG_ALERT("%s: email empty", modName);
|
||||||
|
goto bad_request;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->mail.to = ctx->email;
|
if (!ctx->msg) {
|
||||||
|
AX_LOG_ALERT("%s: msg empty", modName);
|
||||||
|
goto bad_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((rc = ax_validate_email(ctx->email))!= 0) {
|
||||||
|
AX_LOG_ALERT("%s: invalid email at %d", modName, rc);
|
||||||
|
goto bad_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->mail.reply_to = ctx->email;
|
||||||
ctx->mail.msg = ctx->msg;
|
ctx->mail.msg = ctx->msg;
|
||||||
uuid_generate(ctx->mail.msg_id);
|
uuid_generate(ctx->mail.msg_id);
|
||||||
|
|
||||||
/* create thread */
|
if (ax_mail_send(&ctx->mail, &mod->smtp, 0) != AISL_SUCCESS)
|
||||||
status = aislx_mail_send(&ctx->mail
|
ax_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
, mod->smtp_host
|
|
||||||
, mod->smtp_user
|
|
||||||
, mod->smtp_pass
|
|
||||||
, 0);
|
|
||||||
|
|
||||||
if (status != AISL_SUCCESS)
|
|
||||||
aislx_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
|
|
||||||
aisl_set_output_event(s, true); /**< enable output event */
|
aisl_set_output_event(s, true); /**< enable output event */
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
bad_request:
|
||||||
|
ax_quick_response(s, AISL_HTTP_BAD_REQUEST);
|
||||||
|
|
||||||
|
finally:
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
on_stream_output(aislx_feedback_t mod, aisl_evt_t const evt)
|
on_stream_output(AxFeedback mod, const struct aisl_evt *evt)
|
||||||
{
|
{
|
||||||
context_t ctx = aisl_get_context((aisl_stream_t)evt->source);
|
Context ctx = aisl_get_context((AislStream)evt->source);
|
||||||
|
|
||||||
aisl_http_response_t rc = AISL_HTTP_OK;
|
AislHttpResponse rc = AISL_HTTP_OK;
|
||||||
|
|
||||||
switch (aislx_mail_get_status(&ctx->mail))
|
switch (ax_mail_get_status(&ctx->mail)) {
|
||||||
{
|
|
||||||
case AISL_SUCCESS: break;
|
case AISL_SUCCESS: break;
|
||||||
case AISL_IDLE: return AISL_SUCCESS;
|
case AISL_IDLE: return AISL_SUCCESS;
|
||||||
|
|
||||||
@@ -176,33 +190,33 @@ on_stream_output(aislx_feedback_t mod, aisl_evt_t const evt)
|
|||||||
rc = AISL_HTTP_INTERNAL_SERVER_ERROR;
|
rc = AISL_HTTP_INTERNAL_SERVER_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
aislx_quick_response((aisl_stream_t)evt->source, rc);
|
ax_quick_response((AislStream)evt->source, rc);
|
||||||
|
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
on_stream_close(aislx_feedback_t mod, aisl_evt_t const evt)
|
on_stream_close(AxFeedback mod, const struct aisl_evt *evt)
|
||||||
{
|
{
|
||||||
context_free((context_t)aisl_get_context((aisl_stream_t)evt->source));
|
context_free((Context)aisl_get_context((AislStream)evt->source));
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static aisl_status_t
|
static AislStatus
|
||||||
aislx_feedback_on_event(aislx_feedback_t mod, aisl_evt_t const evt)
|
ax_feedback_on_event(AxFeedback mod, const struct aisl_evt *evt)
|
||||||
{
|
{
|
||||||
switch(evt->code)
|
switch(evt->code)
|
||||||
{
|
{
|
||||||
case AISL_EVENT_STREAM_OPEN:
|
case AISL_EVENT_STREAM_OPEN:
|
||||||
return on_stream_open(mod, (aisl_evt_stream_open_t)evt);
|
return on_stream_open(mod, (const struct aisl_evt_open *)evt);
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_HEADER:
|
case AISL_EVENT_STREAM_HEADER:
|
||||||
return on_stream_header(mod, (aisl_evt_stream_header_t)evt);
|
return on_stream_header(mod, (const struct aisl_evt_header *)evt);
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_INPUT:
|
case AISL_EVENT_STREAM_INPUT:
|
||||||
return on_stream_input(mod, (aisl_evt_stream_input_t)evt);
|
return on_stream_input(mod, (const struct aisl_evt_input *)evt);
|
||||||
|
|
||||||
case AISL_EVENT_STREAM_REQUEST:
|
case AISL_EVENT_STREAM_REQUEST:
|
||||||
return on_stream_request(mod, evt);
|
return on_stream_request(mod, evt);
|
||||||
@@ -219,20 +233,17 @@ aislx_feedback_on_event(aislx_feedback_t mod, aisl_evt_t const evt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_feedback_init(aislx_feedback_t mod, aislx_feedback_cfg_t cfg)
|
ax_feedback_init(AxFeedback mod, const struct ax_feedback_cfg *cfg)
|
||||||
{
|
{
|
||||||
AISLX_MODULE_INIT(aislx_feedback, cfg->end_point);
|
AX_MODULE_INIT(ax_feedback, cfg->end_point);
|
||||||
|
|
||||||
mod->mail_subject = cfg->mail_subject;
|
mod->mail_subject = cfg->mail_subject;
|
||||||
mod->mail_from = cfg->mail_from;
|
mod->mail_from = cfg->mail_from;
|
||||||
mod->mail_to = cfg->mail_to;
|
mod->mail_to = cfg->mail_to;
|
||||||
mod->name_email = cfg->name_email;
|
mod->name_email = cfg->name_email;
|
||||||
mod->name_msg = cfg->name_msg;
|
mod->name_msg = cfg->name_msg;
|
||||||
mod->smtp_host = cfg->smtp_host;
|
memcpy(&mod->smtp, &cfg->smtp, sizeof (cfg->smtp));
|
||||||
mod->smtp_user = cfg->smtp_user;
|
|
||||||
mod->smtp_pass = cfg->smtp_pass;
|
|
||||||
mod->smtp_port = cfg->smtp_port;
|
|
||||||
|
|
||||||
mod->name_email_length = strlen(cfg->name_email);
|
mod->name_email_length = strlen(cfg->name_email);
|
||||||
mod->name_msg_length = strlen(cfg->name_msg);
|
mod->name_msg_length = strlen(cfg->name_msg);
|
||||||
@@ -242,7 +253,7 @@ aislx_feedback_init(aislx_feedback_t mod, aislx_feedback_cfg_t cfg)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
aislx_feedback_release(aislx_feedback_t mod)
|
ax_feedback_release(AxFeedback mod)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-26
@@ -13,57 +13,45 @@
|
|||||||
* @see https://lowenware.com/aisl/
|
* @see https://lowenware.com/aisl/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_MOD_FEEDBACK_H_6CC516E4_A7F2_4A9D_B467_75DCF6F58108
|
#ifndef FEEDBACK_H_6CC516E4_A7F2_4A9D_B467_75DCF6F58108
|
||||||
#define AISLX_MOD_FEEDBACK_H_6CC516E4_A7F2_4A9D_B467_75DCF6F58108
|
#define FEEDBACK_H_6CC516E4_A7F2_4A9D_B467_75DCF6F58108
|
||||||
|
|
||||||
#include <mods/ctx.h>
|
#include <mods/context.h>
|
||||||
#include <mods/module.h>
|
#include <mods/module.h>
|
||||||
|
#include <components/mail.h>
|
||||||
|
|
||||||
struct aislx_feedback_cfg
|
struct ax_feedback_cfg {
|
||||||
{
|
struct ax_mail_smtp smtp;
|
||||||
const char *end_point;
|
const char *end_point;
|
||||||
const char *name_email;
|
const char *name_email;
|
||||||
const char *name_msg;
|
const char *name_msg;
|
||||||
const char *mail_subject;
|
const char *mail_subject;
|
||||||
const char *mail_from;
|
const char *mail_from;
|
||||||
const char *mail_to;
|
const char *mail_to;
|
||||||
const char *smtp_host;
|
|
||||||
const char *smtp_user;
|
|
||||||
const char *smtp_pass;
|
|
||||||
uint16_t smtp_port;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct aislx_feedback_cfg * aislx_feedback_cfg_t;
|
|
||||||
|
|
||||||
|
|
||||||
struct aislx_feedback
|
|
||||||
{
|
|
||||||
struct aislx_module root;
|
|
||||||
|
|
||||||
|
struct ax_feedback {
|
||||||
|
struct ax_module root;
|
||||||
|
struct ax_mail_smtp smtp;
|
||||||
const char *name_email;
|
const char *name_email;
|
||||||
const char *name_msg;
|
const char *name_msg;
|
||||||
const char *mail_subject;
|
const char *mail_subject;
|
||||||
const char *mail_from;
|
const char *mail_from;
|
||||||
const char *mail_to;
|
const char *mail_to;
|
||||||
const char *smtp_host;
|
|
||||||
const char *smtp_user;
|
|
||||||
const char *smtp_pass;
|
|
||||||
uint16_t smtp_port;
|
|
||||||
|
|
||||||
uint16_t name_email_length;
|
uint16_t name_email_length;
|
||||||
uint16_t name_msg_length;
|
uint16_t name_msg_length;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
typedef struct aislx_feedback * aislx_feedback_t;
|
typedef struct ax_feedback * AxFeedback;
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_feedback_init(aislx_feedback_t mod,
|
ax_feedback_init(AxFeedback mod, const struct ax_feedback_cfg *cfg);
|
||||||
aislx_feedback_cfg_t cfg);
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
aislx_feedback_release(aislx_feedback_t mod);
|
ax_feedback_release(AxFeedback mod);
|
||||||
|
|
||||||
#endif /* !AISLX_MOD_FEEDBACK_H */
|
#endif /* !FEEDBACK_H */
|
||||||
|
|||||||
+743
@@ -0,0 +1,743 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file todo.c
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief AISL ToDo.txt module code file
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <uuid.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <components/query.h>
|
||||||
|
#include <components/quick.h>
|
||||||
|
#include <components/log.h>
|
||||||
|
#include <cStuff/string.h>
|
||||||
|
#include <mods/minion.h>
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AX_MINION_UNDEFINED
|
||||||
|
, AX_MINION_TODAY
|
||||||
|
, AX_MINION_CREATE_TASK
|
||||||
|
, AX_MINION_READ_TASK
|
||||||
|
, AX_MINION_UPDATE_TASK
|
||||||
|
, AX_MINION_DELETE_TASK
|
||||||
|
} AxMinionMode;
|
||||||
|
|
||||||
|
|
||||||
|
struct context {
|
||||||
|
struct ax_context root;
|
||||||
|
struct ax_query qs;
|
||||||
|
struct ax_todo_task task;
|
||||||
|
|
||||||
|
AxMinionMode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct context * Context;
|
||||||
|
|
||||||
|
|
||||||
|
typedef int
|
||||||
|
(*AxMinionCompare)(void *object1, void *object2);
|
||||||
|
|
||||||
|
static const char modName[] = "minion";
|
||||||
|
|
||||||
|
|
||||||
|
static Context
|
||||||
|
context_new(const char *path, AislHttpMethod method, AxMinion mod)
|
||||||
|
{
|
||||||
|
Context ctx;
|
||||||
|
|
||||||
|
if (!(ctx = (Context)ax_context_new(AX_MODULE(mod))))
|
||||||
|
return ctx;
|
||||||
|
|
||||||
|
if (strcmp(path, "today/") == 0)
|
||||||
|
ctx->mode = AX_MINION_TODAY;
|
||||||
|
else if (strcmp(path, "create/") == 0)
|
||||||
|
ctx->mode = AX_MINION_CREATE_TASK;
|
||||||
|
else if (strcmp(path, "read/") == 0)
|
||||||
|
ctx->mode = AX_MINION_READ_TASK;
|
||||||
|
else if (strcmp(path, "update/") == 0)
|
||||||
|
ctx->mode = AX_MINION_UPDATE_TASK;
|
||||||
|
else if (strcmp(path, "delete/") == 0)
|
||||||
|
ctx->mode = AX_MINION_DELETE_TASK;
|
||||||
|
|
||||||
|
ctx->task.priority = AX_TODO_ZERO_PRIORITY;
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
context_free(Context ctx)
|
||||||
|
{
|
||||||
|
ax_query_release(&ctx->qs);
|
||||||
|
ax_todo_task_release(&ctx->task);
|
||||||
|
|
||||||
|
ax_context_free((AxContext)ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_minion_compare_tasks(AxTodoTask task1, AxTodoTask task2)
|
||||||
|
{
|
||||||
|
if (task1->is_done) {
|
||||||
|
if (task2->is_done) {
|
||||||
|
if (task1->completed > task2->completed) {
|
||||||
|
return -1;
|
||||||
|
} else if (task1->completed > task2->completed) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (task2->is_done) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
if (task1->priority < task2->priority) {
|
||||||
|
return -1;
|
||||||
|
} else if (task1->priority == task2->priority) {
|
||||||
|
if (task1->created > task2->created) {
|
||||||
|
return -1;
|
||||||
|
} else if (task1->created < task2->created) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_minion_compare_projects(AxTodoProject proj1, AxTodoProject proj2)
|
||||||
|
{
|
||||||
|
if (proj1->last_completed < proj2->last_completed) {
|
||||||
|
return -1;
|
||||||
|
} else if (proj1->last_completed > proj2->last_completed) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proj1->ref_count > proj2->ref_count) {
|
||||||
|
return -1;
|
||||||
|
} else if (proj1->ref_count < proj2->ref_count) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
ax_minion_compare_tags(AxTodoTag tag1, AxTodoTag tag2)
|
||||||
|
{
|
||||||
|
if (tag1->ref_count > tag2->ref_count) {
|
||||||
|
return -1;
|
||||||
|
} else if (tag1->ref_count < tag2->ref_count) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ax_minion_sort(CStuffList list, AxMinionCompare compare_objects)
|
||||||
|
{
|
||||||
|
int l = list->length, ld = l - 1, i, j;
|
||||||
|
void **data = list->items, *swap;
|
||||||
|
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
int c = i + 1;
|
||||||
|
for (j = ld; j >= c; j--) {
|
||||||
|
if (compare_objects((AxTodoTask)data[j], (AxTodoTask)data[j - 1]) == -1) {
|
||||||
|
swap = data[j];
|
||||||
|
data[j] = data[j - 1];
|
||||||
|
data[j - 1] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_input_dt(const char *val, uint32_t v_len, time_t *p_out)
|
||||||
|
{
|
||||||
|
char str_dt[36 + 1];
|
||||||
|
if (!(*p_out) && !(v_len < 10 || v_len > sizeof (str_dt) - 1)) {
|
||||||
|
strncpy(str_dt, val, v_len);
|
||||||
|
str_dt[v_len] = 0;
|
||||||
|
(void) ax_todo__get_dt(str_dt, p_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_input_uuid(const char *val, uint32_t v_len, uuid_t uuid_out)
|
||||||
|
{
|
||||||
|
char str_uuid[36 + 1];
|
||||||
|
|
||||||
|
if (v_len == 36) {
|
||||||
|
strncpy(str_uuid, val, v_len);
|
||||||
|
str_uuid[v_len] = 0;
|
||||||
|
uuid_parse(str_uuid, uuid_out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
on_input_var(const char *key, uint32_t k_len, const char *val, uint32_t v_len,
|
||||||
|
void *p_ctx)
|
||||||
|
{
|
||||||
|
Context ctx = (Context) p_ctx;
|
||||||
|
/* AxMinion mod = (AxMinion)((AxContext)ctx)->mod; */
|
||||||
|
char **out = NULL;
|
||||||
|
|
||||||
|
if (k_len == 1) {
|
||||||
|
if (*key == 't') {
|
||||||
|
out = &ctx->task.description;
|
||||||
|
} else if (*key == 'x') {
|
||||||
|
ctx->task.is_done = (v_len == 4 && strncmp(val, "true", 4) == 0);
|
||||||
|
} else if (*key == 'p') {
|
||||||
|
if (v_len == 1 && !((*val < 0x41 || *val > 0x5A))) {
|
||||||
|
ctx->task.priority = *val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (k_len == 2) {
|
||||||
|
if (strncmp(key, "id", 2) == 0) {
|
||||||
|
on_input_uuid(val, v_len, ctx->task.task_id);
|
||||||
|
} else if (strncmp(key, "li", 2) == 0) {
|
||||||
|
on_input_uuid(val, v_len, ctx->task.list_id);
|
||||||
|
} else if (strncmp(key, "co", 2) == 0) {
|
||||||
|
on_input_dt(val, v_len, &ctx->task.completed);
|
||||||
|
} else if (strncmp(key, "cr", 2) == 0) {
|
||||||
|
on_input_dt(val, v_len, &ctx->task.created);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out && !(*out)) {
|
||||||
|
if (cstuff_strncpy(out, val, v_len) == -1)
|
||||||
|
return -1;
|
||||||
|
ax_query__decode(*out);
|
||||||
|
ax_todo__remove_line_break(*out);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
on_stream_open(AxMinion mod, const struct aisl_evt_open *evt)
|
||||||
|
{
|
||||||
|
Context ctx;
|
||||||
|
AislStream s = (AislStream)evt->evt.source;
|
||||||
|
|
||||||
|
if (!(ctx = context_new(&evt->path[AX_MODULE(mod)->ep_length],
|
||||||
|
evt->http_method, mod))) {
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
aisl_set_context(s, ctx);
|
||||||
|
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
on_stream_header(AxMinion mod, const struct aisl_evt_header *evt)
|
||||||
|
{
|
||||||
|
AislStream s = (AislStream)evt->evt.source;
|
||||||
|
Context ctx = aisl_get_context(s);
|
||||||
|
|
||||||
|
AX_LOG_DEBUG("header: %s = %s", evt->key, evt->value);
|
||||||
|
|
||||||
|
if (strcmp(evt->key, "content-length") == 0) {
|
||||||
|
size_t total = strtoll(evt->value, NULL, 10);
|
||||||
|
|
||||||
|
if(ax_query_init(&ctx->qs, total, on_input_var, (void*)ctx) != 0) {
|
||||||
|
ax_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
on_stream_input(AxMinion mod, const struct aisl_evt_input *evt)
|
||||||
|
{
|
||||||
|
Context ctx = aisl_get_context((AislStream)evt->evt.source);
|
||||||
|
|
||||||
|
AX_LOG_DEBUG("input[%d]: %s", evt->size, evt->data);
|
||||||
|
ax_query_feed(&ctx->qs, evt->data, evt->size);
|
||||||
|
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ax_minion_date2str(time_t tt, char *str_dt, size_t sz)
|
||||||
|
{
|
||||||
|
struct tm *p_tm = gmtime(&tt);
|
||||||
|
strftime(str_dt, sz, "%Y-%m-%d", p_tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_minion_today(AxMinion mod, AislStream s, Context ctx)
|
||||||
|
{
|
||||||
|
/* sprint: [{task1}, {task2}]
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_minion_create_task(AxMinion mod, AislStream s, Context ctx)
|
||||||
|
{
|
||||||
|
AxTodoTask task;
|
||||||
|
char str_uuid[36 + 1];
|
||||||
|
|
||||||
|
if (!(ctx->task.description)) {
|
||||||
|
AX_LOG_STATE("%s: !description", modName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid_compare(ctx->task.list_id, mod->todo.list_id) != 0) {
|
||||||
|
AX_LOG_STATE("%s: !list_id", modName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(task = ax_todo_task_new(ctx->task.list_id)))
|
||||||
|
goto e_system;
|
||||||
|
|
||||||
|
task->is_done = ctx->task.is_done;
|
||||||
|
task->priority = ctx->task.priority;
|
||||||
|
if (!(task->created = ctx->task.created))
|
||||||
|
time(&task->created);
|
||||||
|
task->completed = ctx->task.completed;
|
||||||
|
task->description = ctx->task.description;
|
||||||
|
uuid_copy(task->list_id, ctx->task.list_id);
|
||||||
|
ctx->task.description = NULL;
|
||||||
|
|
||||||
|
if (cstuff_list_append(&mod->tasks, task) == -1) {
|
||||||
|
ax_todo_task_free(task);
|
||||||
|
goto e_system;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ax_todo_write(&mod->todo, &mod->tasks) != AISL_SUCCESS)
|
||||||
|
goto e_system;
|
||||||
|
|
||||||
|
if (aisl_header(s, "Content-Type", "text/json") == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
uuid_unparse_lower(task->list_id, str_uuid);
|
||||||
|
|
||||||
|
if (aisl_printf(s, "{\"id\": \"%s\"}", str_uuid) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_flush(s) != AISL_SUCCESS)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_reject:
|
||||||
|
aisl_reject(s);
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_system:
|
||||||
|
ax_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ax_minion_read_task(AxMinion mod, AislStream s, Context ctx)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char str_buf[36 + 1];
|
||||||
|
CStuffList lst;
|
||||||
|
|
||||||
|
if (aisl_response(s, AISL_HTTP_OK, AISL_AUTO_LENGTH) != AISL_SUCCESS)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_header(s, "Content-Type", "text/json") == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
/* tasks */
|
||||||
|
if (aisl_write(s, "{\"tasks\":[", 10) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
lst = &mod->tasks;
|
||||||
|
for (i = 0; i < lst->length; i++) {
|
||||||
|
AxTodoTask task = lst->items[i];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (i != 0 && aisl_write(s, ",", 1) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
uuid_unparse_lower(task->task_id, str_buf);
|
||||||
|
|
||||||
|
if (aisl_printf(s, "\n{\"id\":\"%s\",", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
uuid_unparse_lower(task->list_id, str_buf);
|
||||||
|
if (aisl_printf(s, "\"li\":\"%s\",", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_printf(s, "\"x\":%s,", task->is_done ? "true" : "false") == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
rc = aisl_printf(s, "\"p\":\"%c\",", task->priority ? task->priority : '0');
|
||||||
|
if (rc == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (task->is_done && task->completed) {
|
||||||
|
ax_minion_date2str(task->completed, str_buf, sizeof(str_buf));
|
||||||
|
if (aisl_printf(s, "\"co\":\"%s\",", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task->created) {
|
||||||
|
ax_minion_date2str(task->created, str_buf, sizeof(str_buf));
|
||||||
|
if (aisl_printf(s, "\"cr\":\"%s\",", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = aisl_printf(s, "\"t\":\"%s\"}", task->description);
|
||||||
|
if (rc == -1)
|
||||||
|
goto e_reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* projects */
|
||||||
|
if (aisl_write(s, "\n], \"projects\":[", 16) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
lst = &mod->projects;
|
||||||
|
for (i = 0; i < lst->length; i++) {
|
||||||
|
AxTodoProject proj = lst->items[i];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (i != 0 && aisl_write(s, ",", 1) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
uuid_unparse_lower(proj->project_id, str_buf);
|
||||||
|
|
||||||
|
if (aisl_printf(s, "\n{\"id\":\"%s\",", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_printf(s, "\"n\":\"%s\",", proj->name) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
rc = aisl_printf(s, "\"r\":%"PRIu32"", proj->ref_count);
|
||||||
|
if (rc == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (proj->last_completed) {
|
||||||
|
ax_minion_date2str(proj->last_completed, str_buf, sizeof(str_buf));
|
||||||
|
if (aisl_printf(s, ",\"lc\":\"%s\"", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aisl_write(s, "}", 1) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* tags */
|
||||||
|
if (aisl_write(s, "\n], \"tags\":[", 12) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
lst = &mod->tags;
|
||||||
|
for (i = 0; i < lst->length; i++) {
|
||||||
|
AxTodoTag tag = lst->items[i];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (i != 0 && aisl_write(s, ",", 1) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
uuid_unparse_lower(tag->tag_id, str_buf);
|
||||||
|
|
||||||
|
if (aisl_printf(s, "\n{\"id\":\"%s\",", str_buf) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_printf(s, "\"n\":\"%s\",", tag->name) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
rc = aisl_printf(s, "\"r\":%"PRIu32"}", tag->ref_count);
|
||||||
|
if (rc == -1)
|
||||||
|
goto e_reject;
|
||||||
|
}
|
||||||
|
if (aisl_write(s, "]}", 2) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_flush(s) != AISL_SUCCESS)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
e_reject:
|
||||||
|
AX_LOG_DEBUG("%s: reject", modName);
|
||||||
|
aisl_reject(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_minion_update_task(AxMinion mod, AislStream s, Context ctx)
|
||||||
|
{
|
||||||
|
AxTodoTask task = NULL;
|
||||||
|
char str_uuid[36 + 1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!(ctx->task.description)) {
|
||||||
|
AX_LOG_STATE("%s: !description", modName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid_compare(ctx->task.list_id, mod->todo.list_id) != 0) {
|
||||||
|
AX_LOG_STATE("%s: !list_id", modName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < mod->tasks.length; i++) {
|
||||||
|
task = (AxTodoTask) mod->tasks.items[i];
|
||||||
|
if (uuid_compare(task->task_id, ctx->task.task_id) == 0)
|
||||||
|
break;
|
||||||
|
task = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!task) {
|
||||||
|
AX_LOG_STATE("%s: !task_id", modName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(task->priority = ctx->task.priority))
|
||||||
|
task->priority = AX_TODO_ZERO_PRIORITY;
|
||||||
|
task->created = ctx->task.created;
|
||||||
|
task->completed = ctx->task.completed;
|
||||||
|
|
||||||
|
if ((task->is_done = ctx->task.is_done) && !task->completed) {
|
||||||
|
time(&task->completed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task->description)
|
||||||
|
free(task->description);
|
||||||
|
task->description = ctx->task.description;
|
||||||
|
ctx->task.description = NULL;
|
||||||
|
uuid_copy(task->list_id, ctx->task.list_id);
|
||||||
|
|
||||||
|
if (ax_todo_write(&mod->todo, &mod->tasks) != AISL_SUCCESS)
|
||||||
|
goto e_system;
|
||||||
|
|
||||||
|
if (aisl_header(s, "Content-Type", "text/json") == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
uuid_unparse_lower(task->list_id, str_uuid);
|
||||||
|
|
||||||
|
if (aisl_printf(s, "{\"id\": \"%s\"}", str_uuid) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_flush(s) != AISL_SUCCESS)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_reject:
|
||||||
|
aisl_reject(s);
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_system:
|
||||||
|
ax_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
ax_minion_delete_task(AxMinion mod, AislStream s, Context ctx)
|
||||||
|
{
|
||||||
|
AxTodoTask task = NULL;
|
||||||
|
char str_uuid[36 + 1];
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < mod->tasks.length; i++) {
|
||||||
|
task = (AxTodoTask) mod->tasks.items[i];
|
||||||
|
if (uuid_compare(task->task_id, ctx->task.task_id) == 0) {
|
||||||
|
cstuff_list_remove(&mod->tasks, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
task = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!task) {
|
||||||
|
AX_LOG_STATE("%s: !task_id", modName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid_unparse_lower(task->list_id, str_uuid);
|
||||||
|
ax_todo_task_free(task);
|
||||||
|
|
||||||
|
if (ax_todo_write(&mod->todo, &mod->tasks) != AISL_SUCCESS)
|
||||||
|
goto e_system;
|
||||||
|
|
||||||
|
if (aisl_header(s, "Content-Type", "text/json") == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_printf(s, "{\"id\": \"%s\"}", str_uuid) == -1)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
if (aisl_flush(s) != AISL_SUCCESS)
|
||||||
|
goto e_reject;
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_reject:
|
||||||
|
aisl_reject(s);
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
e_system:
|
||||||
|
ax_quick_response(s, AISL_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
on_stream_request(AxMinion mod, const struct aisl_evt *evt)
|
||||||
|
{
|
||||||
|
Context ctx = aisl_get_context((AislStream)evt->source);
|
||||||
|
AislStream s = (AislStream)evt->source;
|
||||||
|
|
||||||
|
/* verify input */
|
||||||
|
AX_LOG_STATE("%s: request mode = %d", modName, ctx->mode);
|
||||||
|
switch(ctx->mode) {
|
||||||
|
case AX_MINION_TODAY:
|
||||||
|
if (!ax_minion_today(mod, s, ctx))
|
||||||
|
goto bad_request;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX_MINION_CREATE_TASK:
|
||||||
|
if (!ax_minion_create_task(mod, s, ctx))
|
||||||
|
goto bad_request;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX_MINION_READ_TASK:
|
||||||
|
ax_minion_read_task(mod, s, ctx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX_MINION_UPDATE_TASK:
|
||||||
|
if (!ax_minion_update_task(mod, s, ctx))
|
||||||
|
goto bad_request;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX_MINION_DELETE_TASK:
|
||||||
|
if (!ax_minion_delete_task(mod, s, ctx))
|
||||||
|
goto bad_request;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto bad_request;
|
||||||
|
}
|
||||||
|
|
||||||
|
goto finally;
|
||||||
|
|
||||||
|
bad_request:
|
||||||
|
ax_quick_response(s, AISL_HTTP_BAD_REQUEST);
|
||||||
|
|
||||||
|
finally:
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
on_stream_close(AxMinion mod, const struct aisl_evt *evt)
|
||||||
|
{
|
||||||
|
context_free((Context)aisl_get_context((AislStream)evt->source));
|
||||||
|
return AISL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static AislStatus
|
||||||
|
ax_minion_on_event(AxMinion mod, const struct aisl_evt *evt)
|
||||||
|
{
|
||||||
|
switch(evt->code) {
|
||||||
|
case AISL_EVENT_STREAM_OPEN:
|
||||||
|
return on_stream_open(mod, (const struct aisl_evt_open *)evt);
|
||||||
|
|
||||||
|
case AISL_EVENT_STREAM_HEADER:
|
||||||
|
return on_stream_header(mod, (const struct aisl_evt_header *)evt);
|
||||||
|
|
||||||
|
case AISL_EVENT_STREAM_INPUT:
|
||||||
|
return on_stream_input(mod, (const struct aisl_evt_input *)evt);
|
||||||
|
|
||||||
|
case AISL_EVENT_STREAM_REQUEST:
|
||||||
|
return on_stream_request(mod, evt);
|
||||||
|
|
||||||
|
case AISL_EVENT_STREAM_CLOSE:
|
||||||
|
return on_stream_close(mod, evt);
|
||||||
|
|
||||||
|
default:
|
||||||
|
return AISL_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_minion_init(AxMinion mod, const struct ax_minion_cfg *cfg)
|
||||||
|
{
|
||||||
|
AislStatus result;
|
||||||
|
|
||||||
|
AX_MODULE_INIT(ax_minion, cfg->end_point);
|
||||||
|
|
||||||
|
if ((result = ax_todo_init(&mod->todo, cfg->todo_file)) != AISL_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
if ((cstuff_list_init(&mod->tasks, 32)) != CSTUFF_SUCCESS)
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
if ((cstuff_list_init(&mod->projects, 8)) != CSTUFF_SUCCESS)
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
if ((cstuff_list_init(&mod->tags, 32)) != CSTUFF_SUCCESS)
|
||||||
|
return AISL_MALLOC_ERROR;
|
||||||
|
|
||||||
|
if ((result = ax_todo_read(&mod->todo, &mod->tasks, &mod->projects,
|
||||||
|
&mod->tags)) != AISL_SUCCESS)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
ax_minion_sort(&mod->tasks, (AxMinionCompare)ax_minion_compare_tasks);
|
||||||
|
ax_minion_sort(&mod->projects, (AxMinionCompare)ax_minion_compare_projects);
|
||||||
|
ax_minion_sort(&mod->tags, (AxMinionCompare)ax_minion_compare_tags);
|
||||||
|
|
||||||
|
if (ax_todo_write(&mod->todo, &mod->tasks) != AISL_SUCCESS) {
|
||||||
|
AX_LOG_DEBUG("Write failed ;(");
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_minion_release(AxMinion mod)
|
||||||
|
{
|
||||||
|
ax_todo_release(&mod->todo);
|
||||||
|
cstuff_list_release(&mod->tasks, (CStuffListFree) ax_todo_task_free);
|
||||||
|
cstuff_list_release(&mod->projects, (CStuffListFree) ax_todo_project_free);
|
||||||
|
cstuff_list_release(&mod->tags, (CStuffListFree) ax_todo_tag_free);
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017-2019 by Löwenware Ltd
|
||||||
|
* Please, refer LICENSE file for legal information
|
||||||
|
*
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file mod-feedback.h
|
||||||
|
* @author Ilja Kartašov <ik@lowenware.com>
|
||||||
|
* @brief AISL ToDo.txt module header file
|
||||||
|
*
|
||||||
|
* @see https://lowenware.com/aisl/
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MINION_H2FC5C912_0F59_43AD_B805_B0F7C82BE2EF
|
||||||
|
#define MINION_H2FC5C912_0F59_43AD_B805_B0F7C82BE2EF
|
||||||
|
|
||||||
|
#include <cStuff/list.h>
|
||||||
|
#include <mods/context.h>
|
||||||
|
#include <mods/module.h>
|
||||||
|
#include <components/todo.h>
|
||||||
|
|
||||||
|
/* ToDo:
|
||||||
|
* Start with one todo.txt file
|
||||||
|
* Write ToDo.txt parser
|
||||||
|
* Join them together
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ax_minion_cfg {
|
||||||
|
const char *end_point;
|
||||||
|
const char *todo_file;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ax_minion {
|
||||||
|
struct ax_module root;
|
||||||
|
struct ax_todo todo;
|
||||||
|
struct cstuff_list tasks;
|
||||||
|
struct cstuff_list projects;
|
||||||
|
struct cstuff_list tags;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct ax_minion *AxMinion;
|
||||||
|
|
||||||
|
|
||||||
|
AislStatus
|
||||||
|
ax_minion_init(AxMinion mod, const struct ax_minion_cfg *cfg);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ax_minion_release(AxMinion mod);
|
||||||
|
|
||||||
|
#endif /* !MINION_H */
|
||||||
+8
-7
@@ -14,20 +14,21 @@
|
|||||||
*/
|
*/
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <components/log.h>
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "ctx.h"
|
#include "context.h"
|
||||||
|
|
||||||
|
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_module_on_event(aislx_module_t mod, aisl_evt_t const evt)
|
ax_module_on_event(AxModule mod, const struct aisl_evt *evt)
|
||||||
{
|
{
|
||||||
aislx_ctx_t ctx;
|
AxContext ctx;
|
||||||
aisl_evt_stream_open_t so_evt;
|
struct aisl_evt_open *so_evt;
|
||||||
|
|
||||||
switch(evt->code)
|
switch(evt->code)
|
||||||
{
|
{
|
||||||
case AISL_EVENT_STREAM_OPEN:
|
case AISL_EVENT_STREAM_OPEN:
|
||||||
so_evt = (aisl_evt_stream_open_t)evt;
|
so_evt = (struct aisl_evt_open *)evt;
|
||||||
|
|
||||||
if (strncmp(so_evt->path, mod->end_point, mod->ep_length))
|
if (strncmp(so_evt->path, mod->end_point, mod->ep_length))
|
||||||
return AISL_IDLE;
|
return AISL_IDLE;
|
||||||
@@ -38,7 +39,7 @@ aislx_module_on_event(aislx_module_t mod, aisl_evt_t const evt)
|
|||||||
case AISL_EVENT_STREAM_REQUEST:
|
case AISL_EVENT_STREAM_REQUEST:
|
||||||
case AISL_EVENT_STREAM_OUTPUT:
|
case AISL_EVENT_STREAM_OUTPUT:
|
||||||
case AISL_EVENT_STREAM_CLOSE:
|
case AISL_EVENT_STREAM_CLOSE:
|
||||||
if (!(ctx = aisl_get_context((aisl_stream_t)evt->source)))
|
if (!(ctx = aisl_get_context((AislStream)evt->source)))
|
||||||
return AISL_SUCCESS;
|
return AISL_SUCCESS;
|
||||||
|
|
||||||
if (ctx->mod == mod)
|
if (ctx->mod == mod)
|
||||||
|
|||||||
+18
-18
@@ -13,50 +13,50 @@
|
|||||||
* @see https://lowenware.com/aisl/
|
* @see https://lowenware.com/aisl/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef AISLX_MODULE_H_1AEFECA5_9341_431B_8194_EA0C2E76B5EA
|
#ifndef MODULE_H_1AEFECA5_9341_431B_8194_EA0C2E76B5EA
|
||||||
#define AISLX_MODULE_H_1AEFECA5_9341_431B_8194_EA0C2E76B5EA
|
#define MODULE_H_1AEFECA5_9341_431B_8194_EA0C2E76B5EA
|
||||||
|
|
||||||
#include <aisl/aisl.h>
|
#include <aisl/aisl.h>
|
||||||
|
|
||||||
#define AISLX_MODULE_INIT(MOD, END_POINT) \
|
#define AX_MODULE_INIT(MOD, END_POINT) \
|
||||||
do { \
|
do { \
|
||||||
((aislx_module_t) mod)->end_point = END_POINT; \
|
((AxModule) mod)->end_point = END_POINT; \
|
||||||
((aislx_module_t) mod)->ep_length = strlen(END_POINT); \
|
((AxModule) mod)->ep_length = strlen(END_POINT); \
|
||||||
((aislx_module_t) mod)->on_event = (aislx_observer_t)MOD##_on_event; \
|
((AxModule) mod)->on_event = (AxObserver)MOD##_on_event; \
|
||||||
((aislx_module_t) mod)->ctx_size = sizeof(struct context); \
|
((AxModule) mod)->ctx_size = sizeof (struct context); \
|
||||||
} while(0) \
|
} while(0) \
|
||||||
|
|
||||||
#define AISLX_MODULE(x) ((aislx_module_t)x)
|
#define AX_MODULE(x) ((AxModule)x)
|
||||||
|
|
||||||
/** @brief AISL module structure pointer
|
/** @brief AISL module structure pointer
|
||||||
*/
|
*/
|
||||||
typedef struct aislx_module * aislx_module_t;
|
typedef struct ax_module * AxModule;
|
||||||
|
|
||||||
|
|
||||||
/** @brief Pointer to AISL stream event observer
|
/** @brief Pointer to AISL stream event observer
|
||||||
*/
|
*/
|
||||||
typedef aisl_status_t
|
typedef AislStatus
|
||||||
(* aislx_observer_t)(aislx_module_t mod, aisl_evt_t const evt);
|
(* AxObserver)(AxModule mod, const struct aisl_evt *evt);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @brief Root level AISL mod's structure
|
/** @brief Root level AISL mod's structure
|
||||||
*/
|
*/
|
||||||
struct aislx_module {
|
struct ax_module {
|
||||||
const char *end_point; /**< Root mod's URL or NULL */
|
const char *end_point; /**< Root mod's URL or NULL */
|
||||||
aislx_observer_t on_event; /**< Mod's stream event observer */
|
AxObserver on_event; /**< Mod's stream event observer */
|
||||||
size_t ctx_size; /**< Mod's context size */
|
size_t ctx_size; /**< Mod's context size */
|
||||||
uint8_t ep_length; /**< End-Point length */
|
uint32_t ep_length; /**< End-Point length */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/** @brief Wrapper function that calles mod's observer
|
/** @brief Wrapper function that calles mod's observer
|
||||||
* @param mod an instance of #aislx_t
|
* @param mod an instance of AxModule#
|
||||||
* @param evt an AISL stream event
|
* @param evt an AISL stream event
|
||||||
* @return AISL_SUCCESS if event handled, AISL_IDLE if event not handled or an
|
* @return AISL_SUCCESS if event handled, AISL_IDLE if event not handled or an
|
||||||
* error code
|
* error code
|
||||||
*/
|
*/
|
||||||
aisl_status_t
|
AislStatus
|
||||||
aislx_module_on_event(aislx_module_t mod, aisl_evt_t const evt);
|
ax_module_on_event(AxModule mod, const struct aisl_evt *evt);
|
||||||
|
|
||||||
#endif /* !AISLX_MODULE;_H */
|
#endif /* !MODULE;_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user