summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Kconfig60
-rw-r--r--Makefile10
-rw-r--r--articles.c7
-rw-r--r--articles.h2
-rw-r--r--bbsconfig.c1
-rw-r--r--bbsconfig.h7
-rw-r--r--buildinfo.h2
-rw-r--r--captcha.c16
-rw-r--r--captcha.h18
-rw-r--r--file_use.c198
-rw-r--r--file_use.h40
-rw-r--r--ini.c181
-rw-r--r--ini.h77
-rw-r--r--inih/LICENSE.txt27
-rw-r--r--inih/README.txt5
-rw-r--r--kconf2h/kconf2h.c50
-rw-r--r--kconf2h/kconf2h.h10
-rw-r--r--kconf2h/kconf2h_parser.c327
-rw-r--r--kconfig.h7
-rw-r--r--list.c180
-rw-r--r--list.h83
-rw-r--r--login.c3
-rw-r--r--login.h6
-rw-r--r--microbbs.c108
-rw-r--r--motd.c6
-rw-r--r--motd.h2
-rw-r--r--session.c1
-rw-r--r--session.h4
-rw-r--r--statistics.c1
-rw-r--r--statistics.h4
-rw-r--r--telnetd.c0
-rw-r--r--telnetd.h0
-rw-r--r--textview.c0
-rw-r--r--textview.h0
34 files changed, 1428 insertions, 15 deletions
diff --git a/Kconfig b/Kconfig
new file mode 100644
index 0000000..3e5af48
--- /dev/null
+++ b/Kconfig
@@ -0,0 +1,60 @@
+menuconfig TODO
+ bool "List of todo"
+ option todo
+
+if TODO
+endif
+
+menuconfig TWIT
+ bool "Twit soem short messages"
+ option twit
+ default n
+
+if TWIT
+endif
+
+menuconfig DOORGAMES
+ bool "Door games"
+ option doorgames
+ default n
+
+if DOORGAMES
+endif
+
+menuconfig BOARD
+ bool "Messaging board"
+ option board
+ default n
+
+if BOARD
+endif
+
+menuconfig LOGIN
+ bool "User login support"
+ option login
+ default n
+
+if LOGIN
+endif
+
+menuconfig ARTICLES
+ bool "Read articles"
+ option articles
+ default y
+
+if ARTICLES
+endif
+
+menuconfig MOTD
+ bool "Motd message"
+ option motd
+ default y
+
+if MOTD
+endif
+
+
+
+config CAPTCHA
+ bool "Enable simple captcha"
+ default y
diff --git a/Makefile b/Makefile
index 0d61766..1ee8390 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
PROJECT=microbbs
CC=gcc
CFLAGS=
-SOURCES=motd.c buildinfo.c sysinfo.c articles.c logs.c vote.c list.c mmm.c
+SOURCES=articles.c bbsconfig.c buildinfo.c captcha.c file_use.c ini.c list.c login.c logs.c mmm.c motd.c session.c statistics.c sysinfo.c telnetd.c textview.c vote.c
OBJECTS=$(SOURCES:.c=.o)
BUILD_DIR=build_dir
@@ -10,6 +10,14 @@ all: mkdir $(OBJECTS) $(PROJECT)
mkdir:
mkdir -p $(BUILD_DIR)
+kconfig2h:
+ $(CC) -c kconf2h/kconf2h_parser.c
+ $(CC) kconf2h/kconf2h.c kconf2h_parser.o -o kconf2h/kconf2h
+
+menuconfig: kconfig2h
+ ./mconf Kconfig
+ kconf2h/kconf2h .config kconfig.h
+
$(PROJECT): $(SOURCES)
cd ./libterm; make
$(CC) $(addprefix $(BUILD_DIR)/,$(OBJECTS)) $(CFLAGS) libterm/libterm.o microbbs.c -o $(PROJECT)
diff --git a/articles.c b/articles.c
index cf5f40d..8b4af8d 100644
--- a/articles.c
+++ b/articles.c
@@ -1,5 +1,7 @@
#include "articles.h"
+#ifdef CONFIG_ARTICLES
+
//TODO add checkout on size of art it will fix,
// warn about cutted images
int bbs_article( term_screen *ts, const char *fname )
@@ -26,7 +28,7 @@ int bbs_article( term_screen *ts, const char *fname )
max_y = 24;
}
- bbs_log_article( NULL );
+ bbs_log_article( fname );
if ( fname != NULL )
{
@@ -161,7 +163,6 @@ int bbs_article_list( term_screen *ts, const char *dir_name )
if ( path_node.st_mode & S_IFREG )
{
llist_push( dir_list, cnct_path );
- printf("-->%s\n", cnct_path);
}
}
}
@@ -236,3 +237,5 @@ int bbs_article_list( term_screen *ts, const char *dir_name )
return ret;
}
+
+#endif
diff --git a/articles.h b/articles.h
index 5f773a3..fde6dda 100644
--- a/articles.h
+++ b/articles.h
@@ -10,6 +10,8 @@
#include <unistd.h>
#include <fcntl.h>
+#include "kconfig.h"
+
//part of libterm
#include "libterm/term.h"
#include "logs.h"
diff --git a/bbsconfig.c b/bbsconfig.c
new file mode 100644
index 0000000..53267b8
--- /dev/null
+++ b/bbsconfig.c
@@ -0,0 +1 @@
+#include "bbsconfig.h" \ No newline at end of file
diff --git a/bbsconfig.h b/bbsconfig.h
new file mode 100644
index 0000000..c1eb80f
--- /dev/null
+++ b/bbsconfig.h
@@ -0,0 +1,7 @@
+#ifndef __MICROBBS_BBSCONFIG_H
+#define __MICROBBS_BBSCONFIG_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#endif \ No newline at end of file
diff --git a/buildinfo.h b/buildinfo.h
index 3b5964d..2d91704 100644
--- a/buildinfo.h
+++ b/buildinfo.h
@@ -4,7 +4,7 @@
#include <stdio.h>
#include <stdlib.h>
-#define BUILD_VERSION "0.1.9"
+#define BUILD_VERSION "0.2.0"
#define BUILD_DATE (__DATE__)
void print_build_info();
diff --git a/captcha.c b/captcha.c
new file mode 100644
index 0000000..ad614be
--- /dev/null
+++ b/captcha.c
@@ -0,0 +1,16 @@
+#include "captcha.h"
+
+#ifdef CONFIG_CAPTCHA
+
+int captcha_test1()
+{
+ int ret = 0;
+ char s[2];
+ printf("Are you bot?(y/n):\n");
+ fgets(s,2,stdin);
+ if ( s[0] == 'n' || s[0] == 'N')
+ ret = 1;
+ return ret;
+}
+
+#endif \ No newline at end of file
diff --git a/captcha.h b/captcha.h
new file mode 100644
index 0000000..d294955
--- /dev/null
+++ b/captcha.h
@@ -0,0 +1,18 @@
+#ifndef __MICROBBS_CAPTCHA_H
+#define __MICROBBS_CAPTCHA_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "kconfig.h"
+
+//ask question if you are bot or no. In 99% cases should protect from random
+//bots.
+// Return:
+// 0 - test not passed
+// 1 - test passed
+int captcha_test1();
+
+
+
+#endif \ No newline at end of file
diff --git a/file_use.c b/file_use.c
new file mode 100644
index 0000000..cd816bc
--- /dev/null
+++ b/file_use.c
@@ -0,0 +1,198 @@
+#include "file_use.h"
+
+
+void f_file_null( f_file *f_f )
+{
+ if ( f_f )
+ {
+ f_f->fid = NULL;
+ f_f->flags = 0;
+ f_f->size = -1;
+ f_f->seek = -1;
+ }
+}
+
+int f_file_seek( f_file *f_f, long offset, int seek )
+{
+ int ret=-1;
+ PRINT("\n");
+ if ( f_f )
+ {
+ if ( offset < 0 )
+ {
+ ERROR("\n");
+ return -1;
+ }
+
+ if ( offset > f_f->size )
+ {
+ ERROR("\n");
+ return -1;
+ }
+
+
+ ret = fseek( f_f->fid, offset , seek );
+ PRINT("ret=%d\n",ret);
+ if ( ret == 0 )
+ {
+ f_f->seek = ret;
+ }
+ else
+ {
+ ERROR("cannot seek to %d\n", offset);
+ return -1;
+ }
+ PRINT("ret=%d\n",ret);
+ }
+ return ret;
+}
+
+
+size_t f_file_read( f_file *f_f, size_t size, void *ptr )
+{
+ size_t ret=-1;
+ PRINT("\n");
+ if ( f_f )
+ {
+ if ( (f_f->flags == F_FILE_READ) ||
+ (f_f->flags == F_FILE_RW))
+ {
+ if ( f_f->size >= f_f->seek + f_f->size )
+ {
+ ret = fread( ptr, 1, size, f_f->fid );
+ /*
+ if ( ret != size )
+ {
+ ERROR("%d != %d\n", ret, size );
+ return -1;
+ }
+ else
+ */
+ if ( ret < 0 )
+ {
+ ERROR("\n");
+ return ret;
+ }
+ } else
+ {
+ ERROR("\n");
+ }
+ } else
+ {
+ ERROR("file writable only");
+ }
+ }
+ return ret;
+}
+
+
+int f_file_size( f_file *f_f )
+{
+ int ret=-1;
+ long old_seek;
+
+ PRINT("\n");
+ if ( f_f )
+ {
+ //could make some logic break
+ if ( f_f->size < 0 )
+ {
+ old_seek = ftell( f_f->fid );
+ fseek( f_f->fid, 0, SEEK_END );
+ ret = ftell( f_f->fid );
+ fseek( f_f->fid, old_seek, SEEK_CUR );
+ }
+ }
+ return ret;
+}
+
+
+//f_file_read_bl();
+
+
+size_t f_file_write( f_file *f_f, size_t size, void *ptr )
+{
+ PRINT("%s\n");
+ if ( f_f )
+ {
+ if ((f_f->flags == F_FILE_WRITE) ||
+ (f_f->flags == F_FILE_RW) )
+ {
+ ERROR("Not yet ready\n");
+ }
+ }
+
+}
+
+
+//f_file_write_bl();
+
+
+f_file* f_file_open( const char *fname, int flags )
+{
+ f_file *ret = NULL;
+
+ const char *f_flags_write="r";
+ const char *f_flags_read="w";
+ const char *f_flags_rw="r+";
+ char *f_flags_tmp=NULL;
+
+ if ( fname != NULL )
+ {
+ ret = malloc( sizeof( f_file ) );
+ if ( ret == NULL )
+ {
+ ERROR("Cannot alloc mem\n");
+ return NULL;
+ }
+ memset( ret, 0, sizeof( f_file ));
+ f_file_null( ret );
+ switch ( flags )
+ {
+ case F_FILE_READ:
+ f_flags_tmp = f_flags_read;
+ ret->flags = F_FILE_READ;
+ break;
+
+ case F_FILE_WRITE:
+ f_flags_tmp = f_flags_write;
+ ret->flags = F_FILE_WRITE;
+ break;
+
+ case F_FILE_RW:
+ f_flags_tmp = f_flags_rw;
+ ret->flags = F_FILE_RW;
+ break;
+
+ default:
+ ERROR("Unknown flag for opening \n");
+ goto exit_close_f;
+ }
+ ret->fid = fopen( fname, "r" );
+ if ( ret->fid == NULL )
+ {
+ ERROR("Cannot open file\n");
+ goto exit_close_f;
+ }
+ ret->size = f_file_size( ret );
+ }
+ return ret;
+
+exit_close_f:
+ if ( ret != NULL )
+ free( ret );
+ return NULL;
+}
+
+
+int f_file_close( f_file *f_f )
+{
+ PRINT("\n");
+ if ( f_f )
+ {
+ fclose( f_f->fid );
+ free( f_f );
+ f_f = NULL;
+ }
+}
+
diff --git a/file_use.h b/file_use.h
new file mode 100644
index 0000000..fe7cc08
--- /dev/null
+++ b/file_use.h
@@ -0,0 +1,40 @@
+#ifndef __LIBUTILS_FILE_USE_H
+#define __LIBUTILS_FILE_USE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "debug.h"
+
+#define F_FILE_NONE 0
+#define F_FILE_READ 1
+#define F_FILE_WRITE 2
+#define F_FILE_RW 3
+
+#define F_SEEK_CUR SEEK_CUR
+#define F_SEEK_END SEEK_END
+#define F_SEEK_SET SEEK_SET
+
+//simple file using things
+typedef struct f_file
+{
+ FILE *fid;
+ int flags;
+ long size;
+ int seek;
+} f_file;
+
+void f_file_null( f_file* );
+int f_file_seek( f_file*, long, int );
+size_t f_file_read( f_file*, size_t, void* );
+//f_file_read_bl();
+int f_file_size( f_file* );
+size_t f_file_write( f_file*, size_t, void* );
+//f_file_write_bl();
+f_file* f_file_open( const char*, int );
+int f_file_close( f_file* );
+//f_file_flush();
+//f_file_mmap();
+
+#endif
diff --git a/ini.c b/ini.c
new file mode 100644
index 0000000..27062af
--- /dev/null
+++ b/ini.c
@@ -0,0 +1,181 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "ini.h"
+
+#if !INI_USE_STACK
+#include <stdlib.h>
+#endif
+
+#define MAX_SECTION 50
+#define MAX_NAME 50
+
+/* Strip whitespace chars off end of given string, in place. Return s. */
+static char* rstrip(char* s)
+{
+ char* p = s + strlen(s);
+ while (p > s && isspace((unsigned char)(*--p)))
+ *p = '\0';
+ return s;
+}
+
+/* Return pointer to first non-whitespace char in given string. */
+static char* lskip(const char* s)
+{
+ while (*s && isspace((unsigned char)(*s)))
+ s++;
+ return (char*)s;
+}
+
+/* Return pointer to first char c or ';' comment in given string, or pointer to
+ null at end of string if neither found. ';' must be prefixed by a whitespace
+ character to register as a comment. */
+static char* find_char_or_comment(const char* s, char c)
+{
+ int was_whitespace = 0;
+ while (*s && *s != c && !(was_whitespace && *s == ';')) {
+ was_whitespace = isspace((unsigned char)(*s));
+ s++;
+ }
+ return (char*)s;
+}
+
+/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
+static char* strncpy0(char* dest, const char* src, size_t size)
+{
+ strncpy(dest, src, size);
+ dest[size - 1] = '\0';
+ return dest;
+}
+
+/* See documentation in header file. */
+int ini_parse_file(FILE* file,
+ int (*handler)(void*, const char*, const char*,
+ const char*),
+ void* user)
+{
+ /* Uses a fair bit of stack (use heap instead if you need to) */
+#if INI_USE_STACK
+ char line[INI_MAX_LINE];
+#else
+ char* line;
+#endif
+ char section[MAX_SECTION] = "";
+ char prev_name[MAX_NAME] = "";
+
+ char* start;
+ char* end;
+ char* name;
+ char* value;
+ int lineno = 0;
+ int error = 0;
+
+#if !INI_USE_STACK
+ line = (char*)malloc(INI_MAX_LINE);
+ if (!line) {
+ return -2;
+ }
+#endif
+
+ /* Scan through file line by line */
+ while (fgets(line, INI_MAX_LINE, file) != NULL) {
+ lineno++;
+
+ start = line;
+#if INI_ALLOW_BOM
+ if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
+ (unsigned char)start[1] == 0xBB &&
+ (unsigned char)start[2] == 0xBF) {
+ start += 3;
+ }
+#endif
+ start = lskip(rstrip(start));
+
+ if (*start == ';' || *start == '#') {
+ /* Per Python ConfigParser, allow '#' comments at start of line */
+ }
+#if INI_ALLOW_MULTILINE
+ else if (*prev_name && *start && start > line) {
+ /* Non-black line with leading whitespace, treat as continuation
+ of previous name's value (as per Python ConfigParser). */
+ if (!handler(user, section, prev_name, start) && !error)
+ error = lineno;
+ }
+#endif
+ else if (*start == '[') {
+ /* A "[section]" line */
+ end = find_char_or_comment(start + 1, ']');
+ if (*end == ']') {
+ *end = '\0';
+ strncpy0(section, start + 1, sizeof(section));
+ *prev_name = '\0';
+ }
+ else if (!error) {
+ /* No ']' found on section line */
+ error = lineno;
+ }
+ }
+ else if (*start && *start != ';') {
+ /* Not a comment, must be a name[=:]value pair */
+ end = find_char_or_comment(start, '=');
+ if (*end != '=') {
+ end = find_char_or_comment(start, ':');
+ }
+ if (*end == '=' || *end == ':') {
+ *end = '\0';
+ name = rstrip(start);
+ value = lskip(end + 1);
+ end = find_char_or_comment(value, '\0');
+ if (*end == ';')
+ *end = '\0';
+ rstrip(value);
+
+ /* Valid name[=:]value pair found, call handler */
+ strncpy0(prev_name, name, sizeof(prev_name));
+ if (!handler(user, section, name, value) && !error)
+ error = lineno;
+ }
+ else if (!error) {
+ /* No '=' or ':' found on name[=:]value line */
+ error = lineno;
+ }
+ }
+
+#if INI_STOP_ON_FIRST_ERROR
+ if (error)
+ break;
+#endif
+ }
+
+#if !INI_USE_STACK
+ free(line);
+#endif
+
+ return error;
+}
+
+/* See documentation in header file. */
+int ini_parse(const char* filename,
+ int (*handler)(void*, const char*, const char*, const char*),
+ void* user)
+{
+ FILE* file;
+ int error;
+
+ file = fopen(filename, "r");
+ if (!file)
+ return -1;
+ error = ini_parse_file(file, handler, user);
+ fclose(file);
+ return error;
+}
diff --git a/ini.h b/ini.h
new file mode 100644
index 0000000..5390706
--- /dev/null
+++ b/ini.h
@@ -0,0 +1,77 @@
+/* inih -- simple .INI file parser
+
+inih is released under the New BSD license (see LICENSE.txt). Go to the project
+home page for more info:
+
+http://code.google.com/p/inih/
+
+*/
+
+#ifndef __INI_H__
+#define __INI_H__
+
+/* Make this header file easier to include in C++ code */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Parse given INI-style file. May have [section]s, name=value pairs
+ (whitespace stripped), and comments starting with ';' (semicolon). Section
+ is "" if name=value pair parsed before any section heading. name:value
+ pairs are also supported as a concession to Python's ConfigParser.
+
+ For each name=value pair parsed, call handler function with given user
+ pointer as well as section, name, and value (data only valid for duration
+ of handler call). Handler should return nonzero on success, zero on error.
+
+ Returns 0 on success, line number of first error on parse error (doesn't
+ stop on first error), -1 on file open error, or -2 on memory allocation
+ error (only when INI_USE_STACK is zero).
+*/
+int ini_parse(const char* filename,
+ int (*handler)(void* user, const char* section,
+ const char* name, const char* value),
+ void* user);
+
+/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
+ close the file when it's finished -- the caller must do that. */
+int ini_parse_file(FILE* file,
+ int (*handler)(void* user, const char* section,
+ const char* name, const char* value),
+ void* user);
+
+/* Nonzero to allow multi-line value parsing, in the style of Python's
+ ConfigParser. If allowed, ini_parse() will call the handler with the same
+ name for each subsequent line parsed. */
+#ifndef INI_ALLOW_MULTILINE
+#define INI_ALLOW_MULTILINE 1
+#endif
+
+/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
+ the file. See http://code.google.com/p/inih/issues/detail?id=21 */
+#ifndef INI_ALLOW_BOM
+#define INI_ALLOW_BOM 1
+#endif
+
+/* Nonzero to use stack, zero to use heap (malloc/free). */
+#ifndef INI_USE_STACK
+#define INI_USE_STACK 1
+#endif
+
+/* Stop parsing on first error (default is to keep parsing). */
+#ifndef INI_STOP_ON_FIRST_ERROR
+#define INI_STOP_ON_FIRST_ERROR 0
+#endif
+
+/* Maximum line length for any line in INI file. */
+#ifndef INI_MAX_LINE
+#define INI_MAX_LINE 200
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INI_H__ */
diff --git a/inih/LICENSE.txt b/inih/LICENSE.txt
new file mode 100644
index 0000000..1d31de2
--- /dev/null
+++ b/inih/LICENSE.txt
@@ -0,0 +1,27 @@
+
+The "inih" library is distributed under the New BSD license:
+
+Copyright (c) 2009, Brush Technology
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Brush Technology nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY BRUSH TECHNOLOGY ''AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL BRUSH TECHNOLOGY BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/inih/README.txt b/inih/README.txt
new file mode 100644
index 0000000..8e5f8b1
--- /dev/null
+++ b/inih/README.txt
@@ -0,0 +1,5 @@
+
+inih is a simple .INI file parser written in C, released under the New BSD
+license (see LICENSE.txt). Go to the project home page for more info:
+
+http://code.google.com/p/inih/
diff --git a/kconf2h/kconf2h.c b/kconf2h/kconf2h.c
new file mode 100644
index 0000000..91ef6c7
--- /dev/null
+++ b/kconf2h/kconf2h.c
@@ -0,0 +1,50 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/stat.h>
+
+#include "kconf2h.h"
+
+int main( int argc, char **argv )
+{
+ FILE *fin = NULL;
+ FILE *fout = NULL;
+ struct stat st;
+
+ char *buf=NULL;
+ if ( argc == 3 )
+ {
+ fin = fopen( argv[1], "r+" );
+ fout = fopen( argv[2], "w+" );
+ fseek( fin, 0, SEEK_SET );
+ if ( fin && fout )
+ {
+ if ( stat( argv[1], &st ) )
+ {
+ goto error_exit;
+ }
+ buf = malloc( st.st_size ); memset( buf, 0, st.st_size );
+ size_t r_size = fread( buf, 1, st.st_size, fin );
+ if ( r_size > 0 )
+ {
+ int ret = parse_kconf2h( buf, fout );
+ printf("Kconfig file parsed %d %d bytes\n", ret, r_size );
+ } else
+ {
+ printf("ERR: while reading file %s [%d]\n", argv[1], r_size);
+ }
+error_exit:
+ if ( buf ) free( buf );
+ fclose( fin );
+ fclose( fout );
+ } else
+ {
+ printf("ERR: Cannot open file\n");
+ }
+ } else
+ {
+ printf("ERR: usage ./kconf2h [conffile] [outputheader]\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/kconf2h/kconf2h.h b/kconf2h/kconf2h.h
new file mode 100644
index 0000000..165d4cc
--- /dev/null
+++ b/kconf2h/kconf2h.h
@@ -0,0 +1,10 @@
+#ifndef __KCONF2H_H
+#define __KCONF2H_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int parse_kconf2h( const char*, FILE* );
+
+#endif
diff --git a/kconf2h/kconf2h_parser.c b/kconf2h/kconf2h_parser.c
new file mode 100644
index 0000000..5269c14
--- /dev/null
+++ b/kconf2h/kconf2h_parser.c
@@ -0,0 +1,327 @@
+
+#line 1 "kconf2h_parser.ragel"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "kconf2h.h"
+
+#define TYPE_YM 1
+#define TYPE_HEX 2
+#define TYPE_STR 3
+#define TYPE_DEC 4
+
+char *new_string( const char *start, const char *end )
+{
+ int str_s = end-start+1;
+ char *new_str=malloc( str_s+1 );
+ memcpy( new_str, start, str_s );
+ if ( new_str != NULL )
+ new_str[str_s]=0x0;
+ return new_str;
+}
+
+int o_head_def( FILE *f, int type, const char *s_define, const char *e_define,
+ const char *s_value, const char *e_value )
+{
+ if ( f != NULL )
+ {
+ if ( (s_define != NULL) && (e_define != NULL) && (s_define <= e_define) &&
+ (s_value != NULL) && ( e_value != NULL ) && ( s_value <= e_value ))
+ {
+ char *def = new_string( s_define, e_define );
+ char *val = NULL;
+ //printf( "%s\n", def );
+ fprintf( f, "#define %s", def );
+ free( def );
+
+ if ( type != TYPE_YM )
+ {
+ val = new_string( s_value, e_value );
+ fprintf( f, " %s", val );
+ free( val );
+ }
+ /*
+ switch ( type )
+ {
+ case TYPE_HEX:
+ fprintf( f, " %s", val );
+ break;
+ case TYPE_STR:
+ fprintf( f, " %s", val );
+ break;
+ case TYPE_DEC:
+ fprintf( f, " %s", val );
+ break;
+ default:
+ printf("Unknown Kconfig type %d\n", type);
+ }
+ */
+
+ fprintf( f, "\n" );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+#line 71 "kconf2h_parser.c"
+static const char _k2h_actions[] = {
+ 0, 1, 0, 1, 2, 1, 7, 1,
+ 11, 2, 9, 1, 4, 3, 8, 10,
+ 11, 4, 4, 8, 10, 11, 4, 5,
+ 8, 10, 11, 4, 6, 8, 10, 11
+
+};
+
+static const char _k2h_key_offsets[] = {
+ 0, 0, 3, 6, 7, 8, 9, 10,
+ 11, 12, 17, 23, 30, 33, 37, 39,
+ 42, 46, 52, 59, 60
+};
+
+static const char _k2h_trans_keys[] = {
+ 10, 35, 67, 10, 32, 126, 79, 78,
+ 70, 73, 71, 95, 95, 48, 57, 65,
+ 90, 61, 95, 48, 57, 65, 90, 34,
+ 45, 48, 109, 121, 49, 57, 34, 32,
+ 126, 10, 34, 32, 126, 48, 57, 10,
+ 48, 57, 10, 120, 48, 57, 48, 57,
+ 65, 70, 97, 102, 10, 48, 57, 65,
+ 70, 97, 102, 10, 10, 35, 67, 0
+};
+
+static const char _k2h_single_lengths[] = {
+ 0, 3, 1, 1, 1, 1, 1, 1,
+ 1, 1, 2, 5, 1, 2, 0, 1,
+ 2, 0, 1, 1, 3
+};
+
+static const char _k2h_range_lengths[] = {
+ 0, 0, 1, 0, 0, 0, 0, 0,
+ 0, 2, 2, 1, 1, 1, 1, 1,
+ 1, 3, 3, 0, 0
+};
+
+static const char _k2h_index_offsets[] = {
+ 0, 0, 4, 7, 9, 11, 13, 15,
+ 17, 19, 23, 28, 35, 38, 42, 44,
+ 47, 51, 55, 60, 62
+};
+
+static const char _k2h_indicies[] = {
+ 0, 2, 3, 1, 0, 4, 1, 5,
+ 1, 6, 1, 7, 1, 8, 1, 9,
+ 1, 10, 1, 11, 11, 11, 1, 12,
+ 11, 11, 11, 1, 13, 14, 15, 17,
+ 17, 16, 1, 19, 18, 1, 20, 19,
+ 18, 1, 21, 1, 22, 21, 1, 22,
+ 23, 21, 1, 24, 24, 24, 1, 25,
+ 24, 24, 24, 1, 26, 1, 0, 2,
+ 3, 1, 0
+};
+
+static const char _k2h_trans_targs[] = {
+ 20, 0, 2, 3, 2, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 14, 16,
+ 15, 19, 12, 13, 20, 15, 20, 17,
+ 18, 20, 20
+};
+
+static const char _k2h_trans_actions[] = {
+ 7, 0, 1, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 3, 5, 5, 5,
+ 5, 5, 0, 0, 22, 0, 17, 0,
+ 0, 27, 12
+};
+
+static const int k2h_start = 1;
+static const int k2h_first_final = 20;
+static const int k2h_error = 0;
+
+static const int k2h_en_main = 1;
+
+
+#line 87 "kconf2h_parser.ragel"
+
+
+int parse_kconf2h( const char *str, FILE *outf )
+{
+
+
+
+ static uint8_t cs;
+ const int stacksize = 10;
+ int res=0, *top=0, *stack=NULL;
+ stack = malloc( sizeof(stack)*stacksize );
+ char *p=(char *)str, *pe = (char *)str + strlen( str ), *eof=NULL;
+
+ /*
+ variables used in state machine
+ */
+ char *token_s=NULL, *token_e=NULL;
+ char *value_s=NULL, *value_e=NULL;
+ int token_type=0;
+ fprintf( outf, "#ifndef __KCONFIG_H\n" );
+ fprintf( outf, "#define __KCONFIG_H\n" );
+
+
+#line 172 "kconf2h_parser.c"
+ {
+ cs = k2h_start;
+ }
+
+#line 110 "kconf2h_parser.ragel"
+
+#line 179 "kconf2h_parser.c"
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _k2h_trans_keys + _k2h_key_offsets[cs];
+ _trans = _k2h_index_offsets[cs];
+
+ _klen = _k2h_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _k2h_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const char *_lower = _keys;
+ const char *_mid;
+ const char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ _trans = _k2h_indicies[_trans];
+ cs = _k2h_trans_targs[_trans];
+
+ if ( _k2h_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _k2h_actions + _k2h_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+#line 72 "kconf2h_parser.ragel"
+ {}
+ break;
+ case 1:
+#line 73 "kconf2h_parser.ragel"
+ {token_s = p;}
+ break;
+ case 2:
+#line 73 "kconf2h_parser.ragel"
+ {token_e = p-1;}
+ break;
+ case 3:
+#line 76 "kconf2h_parser.ragel"
+ {token_type=TYPE_YM;}
+ break;
+ case 4:
+#line 77 "kconf2h_parser.ragel"
+ {token_type=TYPE_DEC;}
+ break;
+ case 5:
+#line 78 "kconf2h_parser.ragel"
+ {token_type=TYPE_STR;}
+ break;
+ case 6:
+#line 79 "kconf2h_parser.ragel"
+ {token_type=TYPE_HEX;}
+ break;
+ case 7:
+#line 79 "kconf2h_parser.ragel"
+ {value_s = p;}
+ break;
+ case 8:
+#line 79 "kconf2h_parser.ragel"
+ {value_e = p-1;}
+ break;
+ case 9:
+#line 80 "kconf2h_parser.ragel"
+ {}
+ break;
+ case 10:
+#line 80 "kconf2h_parser.ragel"
+ { o_head_def( outf, token_type, token_s, token_e, value_s, value_e ); }
+ break;
+ case 11:
+#line 82 "kconf2h_parser.ragel"
+ {}
+ break;
+#line 301 "kconf2h_parser.c"
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ _out: {}
+ }
+
+#line 111 "kconf2h_parser.ragel"
+
+ if ( cs == k2h_error )
+ {
+ printf("ERR state [%d] pos[%d]:[%s]\n", res, p-str, p);
+ res = -1;
+ }
+
+ fprintf( outf, "#endif\n" );
+
+ return res;
+}
+
+
+
diff --git a/kconfig.h b/kconfig.h
new file mode 100644
index 0000000..bb80b88
--- /dev/null
+++ b/kconfig.h
@@ -0,0 +1,7 @@
+#ifndef __KCONFIG_H
+#define __KCONFIG_H
+#define CONFIG_TODO
+#define CONFIG_ARTICLES
+#define CONFIG_MOTD
+#define CONFIG_CAPTCHA
+#endif
diff --git a/list.c b/list.c
index 83655cd..7e7f732 100644
--- a/list.c
+++ b/list.c
@@ -39,8 +39,9 @@ int llist_index( struct List *list, void *ptr )
}
-void llist_reverse( struct List **list )
+void llist_reverse( struct List *list )
{
+ ERROR("\n");
//abort(0);
}
@@ -108,6 +109,67 @@ void llist_push( struct List *list, void *ptr )
}
+void* llist_removen( struct List *l, struct ListNode *ln )
+{
+ ListNode *ret=NULL;
+ ListNode *iter = l->first;
+ ListNode *prev_iter = NULL;
+
+ if ( iter == NULL )
+ goto result_ready;
+
+ while ( iter->next != NULL )
+ {
+ if ( iter == ln )
+ {
+ break;
+ }
+ prev_iter = iter;
+ iter = iter->next;
+ }
+ ret = iter;
+ iter = NULL; //dont use iter anymore pls
+
+ if ( ret != NULL )
+ {
+ //if first element of list
+ //the prev=NULL
+ if ( prev_iter == NULL )
+ {
+ //if only one element in da list?
+
+ if ( l->first == l->last )
+ {
+ l->first = NULL;
+ l->last = NULL;
+ } else
+ //if more then one element
+ {
+ l->first = l->first->next;
+ }
+ ret->next = NULL;
+ goto result_ready;
+ }
+
+ //if last element of the list
+ if ( ret == l->last )
+ {
+ prev_iter->next = NULL;
+ l->last = prev_iter;
+ goto result_ready;
+ }
+
+ //if in da middle
+ prev_iter->next = ((ListNode *)ret)->next;
+ ((ListNode *)ret)->next = NULL;
+
+
+ }
+
+result_ready:
+ return ret;
+}
+
void llist_free( struct List *list )
{
@@ -137,6 +199,122 @@ void llist_free( struct List *list )
void llist_freen( struct ListNode *node )
{
+ ERROR("\n");
+}
+
+
+
+void llist_sortn( struct List *list, clb_llist_cmp clb_cmp)
+{
+ int print_list( List *ln )
+ {
+ if ( ln == NULL ) return;
+ char *ptr=NULL;
+ ListNode *l = ln->first;
+
+ while ( l != NULL )
+ {
+ ptr = l->val;
+ printf("%s", ptr);
+ if ( l->next != NULL )
+ {
+ printf("(->%s) ",(char*)l->next->val );
+ }
+ //printf("\n");
+ l = l->next;
+ }
+ printf("\n");
+
+ return 1;
+ }
+
+ int print_node( ListNode *n )
+ {
+ if ( n == NULL ) return;
+ while ( n != NULL )
+ {
+ printf("%s ", (char*)n->val);
+ n = n->next;
+ }
+ printf("\n");
+ }
+
+
+ //creat new empty list and add all elements sorted
+ struct ListNode *sorted=NULL, *last=NULL, *get=NULL;
+
+ get = llist_removen( list, list->first );
+ sorted = get;
+ get = llist_removen( list, list->first );
+
+ while ( get != NULL )
+ {
+ //add to empty in sorted like place
+ struct ListNode *iter = sorted;
+ struct ListNode *prev_iter = malloc( sizeof(struct ListNode));
+ memset( prev_iter, 0, sizeof(struct ListNode));
+ prev_iter->next = iter;
+ while ( iter != NULL )
+ {
+ //there could be that no empty element in da list
+ if ( get == NULL ) break;
+ if ( clb_cmp( iter->val, get->val ) >= 0 )
+ {
+ //add to sorted list end if everything is ok
+ if ( iter->next == NULL )
+ {
+ iter->next = get;
+ break;
+ }
+ } else
+ {
+ prev_iter->next = get;
+ prev_iter = get;
+ get->next = iter;
+ if ( iter == sorted )
+ {
+ sorted = prev_iter;
+ }
+ iter = prev_iter;
+
+ break;
+ }
+ prev_iter = iter;
+ iter = iter->next;
+ }
+ get = llist_removen( list, list->first );
+ }
+ list->first = sorted;
+}
+
+int llist_save( struct List *l, clb_llist_save clb_save )
+{
+ int ret=0, frc=0;
+ if ( l == NULL ) return ret;
+ if ( clb_save == NULL ) return ret;
+
+ /*
+ struct ListNode *iter = llist_first( l );
+
+ while ( iter != NULL )
+ {
+ clb_save( );
+ iter = iter->next;
+ }
+ */
+ frc = clb_save( "/tmp/binlist.txt", l );
+ if ( frc != 0)
+ ret = -1;
+ return ret;
}
+struct List* llist_load( clb_llist_load clb_load, const char *fname )
+{
+ int ret = 0;
+ struct List *loaded = NULL;
+
+ ret = clb_load( (char *)fname, (void **)loaded );
+
+ return loaded;
+}
diff --git a/list.h b/list.h
index c443430..94794f0 100644
--- a/list.h
+++ b/list.h
@@ -10,42 +10,102 @@
//use stack memallocation features. need to make some changes in api
+//!TODO give for_each macros that can be used
+//!TODO add insert element in list for sorting stuff
+//!TODO save/load could be just void* list->val that to save, sequently
+
+
+//when need to compare 2 nodes values with are pointers on anything
+// return:
+// -1 (<) void 1 is less then void 2
+// 0 (=) void 1 is equal to void 2
+// 1 (>) void 1 is bigger then void 2
+typedef int (*clb_llist_cmp)(void *, void *);
+
+//when need to free whole list and also values of list with are just pointer
+//to anything
+// param void* - list->val
+typedef int (*clb_llist_free)(void *);
+
+//load and save data to file if possible
+//return
+// 0 - everything is ok
+// non-zero - something went wrong
+// can put different errors that you whant
+//param
+//void* - string where to save, or how to save
+//void* - linked list that need to save
+typedef int (*clb_llist_save)(void *, void *);
+//return
+// non-zero - some error happened
+// 0 - everything is ok
+//param
+//void* - string from where to load
+//void* - list where to save
+typedef int (*clb_llist_load)(void *, void **);
typedef struct ListNode
{
struct ListNode *next;
- void *val;
+ void *val;
} ListNode;
typedef struct List
{
- int count;
+ int count;
ListNode *first;
ListNode *last;
} List;
+typedef struct ListManager
+{
+ List *list;
+ int sorted; //auto sort if needed
+ int mode; // read only
+ char *name; // list name
+ clb_llist_cmp *cmp;
+ clb_llist_free *free;
+ clb_llist_save *save;
+ clb_llist_load *load;
+} ListManager;
+
+
+
+
struct List* llist_new();
struct ListNode* llist_newn( void* );
+struct ListManager* llist_newm();
//#define __LLIST_NEW()
//#define __LLIST_NEWN()
int llist_length( struct List* );
int llist_index( struct List*, void* );
//llist_find( struct List );
-//find by pointer
-//find by value
-void llist_reverse( struct List** );
+//!find by pointer
+//!find by value
+
+void llist_reverse( struct List* );
+
+//void llist_append( struct List*, void* );
-void llist_append( struct List*, void* );
void llist_appendn( struct List**, void*, struct ListNode* );
//#define __LIST_APPEND()
+// get one element from list and erease it from list
void* llist_pop( struct List* );
+//add at the end one element
void llist_push( struct List*, void* );
+//remove node from list and return value of element
+//void* llist_remove( struct List*, struct ListNode* );
+void* llist_removen( struct List*, struct ListNode* );
+//delete one element from the list
+//void llist_delete( struct List*, void*);
+
void llist_free( struct List* );
void llist_freen( struct ListNode* );
+
//void llist_merge( struct List**, struct List* );
//void llist_compare( struct List
//void llist_split( struct List*,
@@ -53,8 +113,12 @@ void llist_freen( struct ListNode* );
//void llist_splitp( struct List*, void*
//void llist_splitc( struct List*, void (*)(void*)
//void llist_sort(
-//sort by pointer
-//sort by value
+//!sort by pointer
+//!sort by val value, need compare callback
+void llist_sortn( struct List*, clb_llist_cmp );
+
+int llist_save( struct List*, clb_llist_save );
+struct List* llist_load( clb_llist_load, const char* );
#define llist_first(A) ((A)->first)
#define llist_last(A) ((A)->last)
@@ -66,4 +130,7 @@ void llist_freen( struct ListNode* );
//#define llist_isfirstn(A) ()
//#define llist_getfirstn(A) ((A))
//#define llist_getlastn(A) ()
+
+
+
#endif
diff --git a/login.c b/login.c
new file mode 100644
index 0000000..c43e9bb
--- /dev/null
+++ b/login.c
@@ -0,0 +1,3 @@
+#include "login.h"
+
+
diff --git a/login.h b/login.h
new file mode 100644
index 0000000..dbfa63c
--- /dev/null
+++ b/login.h
@@ -0,0 +1,6 @@
+#ifndef __MICROBBS_LOGIN_H
+#define __MICROBBS_LOGIN_H
+
+
+
+#endif \ No newline at end of file
diff --git a/microbbs.c b/microbbs.c
index 6a6c098..8387cb8 100644
--- a/microbbs.c
+++ b/microbbs.c
@@ -1,6 +1,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "kconfig.h"
#include "logs.h"
#include "motd.h"
#include "libterm/term.h"
@@ -16,36 +17,139 @@ int main( int argc, char **argv )
term_init_data( &ts );
//printf("%d %d\n", ts.term_col, ts.term_row);
+ //lunch captcha and try to detect if its random bot
+#ifdef CONFIG_CAPTCHA
+ if ( captcha_test1() != 1)
+ return 1;
+#endif
+
//write to log that some user have accesed bbs
+ //too much fake stuff comes to log
//bbs_log( NULL ); //write to default place
+#ifdef CONFIG_MOTD
bbs_login_motd( &ts, "art/motd.txt" );
print_build_info();
+#endif
+
while ( strncmp( str, "q", 1 ) && strncmp( str, "Q", 1 ) )
{
- printf("(M)otd (Q)uit (S)ysinfo (A)rticles: ");
+ #ifdef CONFIG_MOTD
+ printf("(M)otd ");
+ #endif
+
+ #ifdef CONFIG_ARTICLES
+ printf("(A)rticles ");
+ #endif
+
+ #ifdef CONFIG_DOORGAMES
+ printf("(D)oor games ");
+ #endif
+
+ #ifdef CONFIG_TWIT
+ printf("(T)wit ");
+ #endif
+
+ #ifdef CONFIG_BOARD
+ printf("(B)oard ");
+ #endif
+
+ #ifdef CONFIG_LOGIN
+ printf("(L)ogin ");
+ #endif
+
+ #ifdef CONFIG_TODO
+ printf("T(o)do ");
+ #endif
+ printf("(Q)uit (S)ysinfo Mesa(G)es: ");
ret_len = getline( &str, &str_size, stdin );
if ( ret_len > 0)
{
switch ( str[0] )
{
+ //------------------------------------------------------------------
+ #ifdef CONFIG_MOTD
case 'm':
case 'M':
{
bbs_login_motd( &ts, "art/motd.txt" );
}
break;
+ #endif
case 's':
case 'S':
{
bbs_sysinfo( &ts );
}
break;
+
+ //------------------------------------------------------------------
+ #ifdef CONFIG_ARTICLES
case 'a':
case 'A':
{
bbs_article_list( &ts, "./article/" );
}
break;
+ #endif
+
+ //------------------------------------------------------------------
+ #ifdef CONFIG_TWIT
+ case 't':
+ case 'T':
+ {
+ printf("Twitter like\n");
+ }
+ break;
+ #endif
+
+ //------------------------------------------------------------------
+ #ifdef CONFIG_DOORGAMES
+ case 'd':
+ case 'D':
+ {
+ printf("Door games\n");
+ }
+ break;
+ #endif
+
+ case 'g':
+ case 'G':
+ {
+ printf("Messages\n");
+ }
+ break;
+
+ //------------------------------------------------------------------
+ #ifdef CONFIG_BOARD
+ case 'b':
+ case 'B':
+ {
+ printf("Board\n");
+ }
+ break;
+ #endif
+
+
+ //------------------------------------------------------------------
+ #ifdef CONFIG_LOGIN
+ case 'l':
+ case 'L':
+ {
+ printf("Login?\n");
+ }
+ break;
+ #endif
+
+ //------------------------------------------------------------------
+ #ifdef CONFIG_TODO
+ case 'o':
+ case 'O':
+ {
+ printf("Todo list\n");
+ }
+ break;
+ #endif
+
case 'q':
case 'Q':
bbs_log_quit( NULL );
@@ -55,6 +159,8 @@ int main( int argc, char **argv )
}
}
}
+#ifdef CONFIG_MOTD
bbs_quit_motd( &ts, "art/quit.txt" );
+#endif
return 0;
}
diff --git a/motd.c b/motd.c
index ce68f77..8d11b3f 100644
--- a/motd.c
+++ b/motd.c
@@ -1,5 +1,7 @@
#include "motd.h"
+#ifdef CONFIG_MOTD
+
//TODO merge 2 functions in one proper
//TODO complcations with libterm
int bbs_login_motd( term_screen *ts, const char *fname )
@@ -100,4 +102,6 @@ int bbs_quit_motd( term_screen *ts, const char *fname )
//printf("%d %d %d\n",y,posy,ts->term_row);
return 0;
-} \ No newline at end of file
+}
+
+#endif \ No newline at end of file
diff --git a/motd.h b/motd.h
index e64d06c..5837645 100644
--- a/motd.h
+++ b/motd.h
@@ -5,6 +5,8 @@
#include <stdlib.h>
#include <string.h>
+#include "kconfig.h"
+
#include "libterm/print_utils.h"
#include "libterm/term.h"
diff --git a/session.c b/session.c
new file mode 100644
index 0000000..ca88985
--- /dev/null
+++ b/session.c
@@ -0,0 +1 @@
+#include "session.h" \ No newline at end of file
diff --git a/session.h b/session.h
new file mode 100644
index 0000000..e91c679
--- /dev/null
+++ b/session.h
@@ -0,0 +1,4 @@
+#ifndef __MICROBBS_SESSION_H
+#define __MICROBBS_SESSION_H
+
+#endif \ No newline at end of file
diff --git a/statistics.c b/statistics.c
new file mode 100644
index 0000000..3e0ff33
--- /dev/null
+++ b/statistics.c
@@ -0,0 +1 @@
+#include "statistics.h" \ No newline at end of file
diff --git a/statistics.h b/statistics.h
new file mode 100644
index 0000000..a91e988
--- /dev/null
+++ b/statistics.h
@@ -0,0 +1,4 @@
+#ifndef __MICROBBS_STATISTICS_H
+#define __MICROBBS_STATISTICS_H
+
+#endif \ No newline at end of file
diff --git a/telnetd.c b/telnetd.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/telnetd.c
diff --git a/telnetd.h b/telnetd.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/telnetd.h
diff --git a/textview.c b/textview.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/textview.c
diff --git a/textview.h b/textview.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/textview.h