Compare commits
	
		
			3 Commits
		
	
	
		
			08e771eaa0
			...
			45b4f6bee0
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
									
								
								 | 
						45b4f6bee0 | |
| 
							
							
								
									
								
								 | 
						c9c9bbbff6 | |
| 
							
							
								
									
								
								 | 
						cbdf7b2523 | 
							
								
								
									
										101
									
								
								cStuff/log.c
								
								
								
								
							
							
						
						
									
										101
									
								
								cStuff/log.c
								
								
								
								
							| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										62
									
								
								cStuff/log.h
								
								
								
								
							
							
						
						
									
										62
									
								
								cStuff/log.h
								
								
								
								
							| 
						 | 
				
			
			@ -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 */
 | 
			
		||||
| 
						 | 
				
			
			@ -1,28 +0,0 @@
 | 
			
		|||
/******************************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 *                Copyright (c) 2017-2019 by Löwenware Ltd
 | 
			
		||||
 *             Please, refer LICENSE file for legal information
 | 
			
		||||
 *
 | 
			
		||||
 ******************************************************************************/
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file retcode.h
 | 
			
		||||
 * @author Ilja Kartašov <ik@lowenware.com>
 | 
			
		||||
 * @brief cStuff return codes
 | 
			
		||||
 *
 | 
			
		||||
 * @see https://lowenware.com/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef CSTUFF_RETCODE_H_CBA3C16B_88D6_49F4_966D_DBDA727583FE
 | 
			
		||||
#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 */
 | 
			
		||||
							
								
								
									
										104
									
								
								cStuff/string.c
								
								
								
								
							
							
						
						
									
										104
									
								
								cStuff/string.c
								
								
								
								
							| 
						 | 
				
			
			@ -1,104 +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;
 | 
			
		||||
 | 
			
		||||
	*out = s;
 | 
			
		||||
	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,383 @@
 | 
			
		|||
/******************************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 *                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 <components/log.h>
 | 
			
		||||
#include "todo.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AislStatus
 | 
			
		||||
ax_todo_init(AxTodo self, const char *file)
 | 
			
		||||
{
 | 
			
		||||
	FILE *f;
 | 
			
		||||
	uuid_generate(self->id);
 | 
			
		||||
 | 
			
		||||
	if (!(f = fopen(file, "a+"))) {
 | 
			
		||||
		return AISL_SYSCALL_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cstuff_list_init(&self->list, 16) != CSTUFF_SUCCESS) {
 | 
			
		||||
		fclose(f);
 | 
			
		||||
		return AISL_MALLOC_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	self->fd = f;
 | 
			
		||||
 | 
			
		||||
	return AISL_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ax_todo_release(AxTodo self)
 | 
			
		||||
{
 | 
			
		||||
	if (self->fd)
 | 
			
		||||
		fclose(self->fd);
 | 
			
		||||
 | 
			
		||||
	cstuff_list_release(&self->list, (CStuffListFree)ax_todo_task_free);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AislStatus
 | 
			
		||||
ax_todo_read(AxTodo self)
 | 
			
		||||
{
 | 
			
		||||
	FILE *f = self->fd;
 | 
			
		||||
	size_t sz = 256;
 | 
			
		||||
	char *buf;
 | 
			
		||||
	ssize_t rs;
 | 
			
		||||
	AislStatus result = AISL_SUCCESS;
 | 
			
		||||
	
 | 
			
		||||
	if ((fseek(f, 0L, SEEK_SET) != 0))
 | 
			
		||||
		return AISL_SYSCALL_ERROR;
 | 
			
		||||
 | 
			
		||||
	if (!(buf = malloc(sz)))
 | 
			
		||||
		return AISL_MALLOC_ERROR;
 | 
			
		||||
 | 
			
		||||
	while ((rs = getdelim(&buf, &sz, '\n', f)) != -1) {
 | 
			
		||||
		AxTodoTask task;
 | 
			
		||||
 | 
			
		||||
		if (!(task = ax_todo_task_new()))
 | 
			
		||||
			goto e_malloc;
 | 
			
		||||
 | 
			
		||||
		if (ax_todo_task_set(task, buf, rs) != 0) {
 | 
			
		||||
			ax_todo_task_free(task);
 | 
			
		||||
			goto e_input;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (cstuff_list_append(&self->list, task) == -1) {
 | 
			
		||||
			ax_todo_task_free(task);
 | 
			
		||||
			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);
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	FILE *f = self->fd;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if ((fseek(f, 0L, SEEK_SET) != 0))
 | 
			
		||||
		return AISL_SYSCALL_ERROR;
 | 
			
		||||
 | 
			
		||||
	f = self->fd;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < self->list.length; i++) {
 | 
			
		||||
		AxTodoTask task = (AxTodoTask) self->list.items[i];
 | 
			
		||||
 | 
			
		||||
		if (task->is_done) {
 | 
			
		||||
			fwrite("x ", 1, 2, f);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (task->priority) {
 | 
			
		||||
			fprintf(f, "(%c) ", task->priority);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (task->is_done) {
 | 
			
		||||
			if (task->completion) {
 | 
			
		||||
				ax_todo__write_dt(f, task->completion);
 | 
			
		||||
				if (task->creation) {
 | 
			
		||||
					ax_todo__write_dt(f, task->creation);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else if (task->creation) {
 | 
			
		||||
			ax_todo__write_dt(f, task->creation);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		fprintf(f, "%s\n", task->description);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return (fflush(f) == 0) ? AISL_SUCCESS : AISL_SYSCALL_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AxTodoTask
 | 
			
		||||
ax_todo_task_new(void)
 | 
			
		||||
{
 | 
			
		||||
	AxTodoTask result;
 | 
			
		||||
 | 
			
		||||
	if ((result = calloc(1, sizeof (struct ax_todo_task))) != NULL) {
 | 
			
		||||
		uuid_generate(result->task_id);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static 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;
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		setenv("TZ", "UTC", 1);
 | 
			
		||||
		*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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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->completion : &task->creation);
 | 
			
		||||
 | 
			
		||||
	if (l != 0) {
 | 
			
		||||
		buf += l;
 | 
			
		||||
		if (is_done && (l = ax_todo__get_dt(buf, &task->creation)) != 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,79 @@
 | 
			
		|||
/******************************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 *                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>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct ax_todo {
 | 
			
		||||
	uuid_t id;
 | 
			
		||||
	FILE *fd;
 | 
			
		||||
	struct cstuff_list list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct ax_todo * AxTodo;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct ax_todo_task {
 | 
			
		||||
	uuid_t task_id;
 | 
			
		||||
	char priority;
 | 
			
		||||
	time_t completion;
 | 
			
		||||
	time_t creation;
 | 
			
		||||
	char *description;
 | 
			
		||||
	bool  is_done;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct ax_todo_task * AxTodoTask;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AislStatus
 | 
			
		||||
ax_todo_init(AxTodo self, const char *file);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ax_todo_release(AxTodo self);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AislStatus
 | 
			
		||||
ax_todo_read(AxTodo self);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AislStatus
 | 
			
		||||
ax_todo_write(AxTodo self);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AxTodoTask
 | 
			
		||||
ax_todo_task_new(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ax_todo_task_release(AxTodoTask task);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ax_todo_task_free(AxTodoTask task);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
AislStatus
 | 
			
		||||
ax_todo_task_set(AxTodoTask task, char *buf, ssize_t length);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif /* !TODO_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +13,7 @@
 | 
			
		|||
 * @see https://lowenware.com/
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include "context.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,11 +23,10 @@
 | 
			
		|||
#include "feedback.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct context
 | 
			
		||||
{
 | 
			
		||||
struct context {
 | 
			
		||||
	struct ax_context root;
 | 
			
		||||
	struct ax_query   qs;
 | 
			
		||||
	struct ax_mail    mail;
 | 
			
		||||
	struct ax_query qs;
 | 
			
		||||
	struct ax_mail mail;
 | 
			
		||||
	char *email;
 | 
			
		||||
	char *msg;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -53,9 +52,8 @@ context_free(Context ctx)
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
static int
 | 
			
		||||
on_input_var( const char *key, uint32_t k_len,
 | 
			
		||||
              const char *val, uint32_t v_len,
 | 
			
		||||
              void       *p_ctx )
 | 
			
		||||
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;
 | 
			
		||||
	AxFeedback mod = (AxFeedback)((AxContext)ctx)->mod;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,302 @@
 | 
			
		|||
/******************************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 *                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 <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;
 | 
			
		||||
	uuid_t file_id;
 | 
			
		||||
 | 
			
		||||
	AxMinionMode mode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct context * Context;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 (!(*path))
 | 
			
		||||
		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;
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
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 (!ctx->task.description && k_len == 11) {
 | 
			
		||||
		if (strncmp(key, "description", k_len) == 0) {
 | 
			
		||||
			out = &ctx->task.description;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (out) {
 | 
			
		||||
		if (cstuff_strncpy(out, val, v_len) == -1)
 | 
			
		||||
			return -1;
 | 
			
		||||
		ax_query__decode(*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);
 | 
			
		||||
 | 
			
		||||
	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_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 void
 | 
			
		||||
ax_minion_stream_today(AxMinion mod, AislStream s, Context ctx)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	CStuffList lst = &mod->todo.list;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
 | 
			
		||||
	if (aisl_write(s, "{\"tasks\":[", 10) == -1)
 | 
			
		||||
		goto e_reject;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < lst->length; i++) {
 | 
			
		||||
		AxTodoTask task = lst->items[i];
 | 
			
		||||
		int rc;
 | 
			
		||||
		char dt[32];
 | 
			
		||||
 | 
			
		||||
		if (i != 0 && aisl_write(s, ",", 1) == -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->completion) {
 | 
			
		||||
			ax_minion_date2str(task->completion, dt, sizeof(dt));
 | 
			
		||||
			if (aisl_printf(s, "\"co\":\"%s\",", dt) == -1)
 | 
			
		||||
				goto e_reject;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (task->creation) {
 | 
			
		||||
			ax_minion_date2str(task->creation, dt, sizeof(dt));
 | 
			
		||||
			if (aisl_printf(s, "\"cr\":\"%s\",", dt) == -1)
 | 
			
		||||
				goto e_reject;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		rc = aisl_printf(s, "\"d\":\"%s\"}", task->description);
 | 
			
		||||
		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:
 | 
			
		||||
	aisl_reject(s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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:
 | 
			
		||||
		ax_minion_stream_today(mod, s, ctx);
 | 
			
		||||
		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 ((result = ax_todo_read(&mod->todo)) != AISL_SUCCESS)
 | 
			
		||||
		return result;
 | 
			
		||||
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
ax_minion_release(AxMinion mod)
 | 
			
		||||
{
 | 
			
		||||
	ax_todo_release(&mod->todo);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,52 @@
 | 
			
		|||
/******************************************************************************
 | 
			
		||||
 *
 | 
			
		||||
 *                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;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
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 */
 | 
			
		||||
		Loading…
	
		Reference in New Issue