diff --git a/.gitignore b/.gitignore
index 442798f..f15af53 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,7 @@ config/*
illusion/*
scripts/*
logs/*
+files/*
*.a
deps/lua/lua
deps/lua/luac
@@ -75,3 +76,7 @@ menus/file.mnu
menus/logoff.mnu
menus/mail.mnu
menus/main.mnu
+core
+docs/site
+utils/reset_pass/reset_pass
+.vscode
diff --git a/README.md b/README.md
index c7798b6..34e49d5 100644
--- a/README.md
+++ b/README.md
@@ -1,95 +1,5 @@
# MagickaBBS
-Linux/FreeBSD bulletin board system (Should also work on NetBSD and Mac OS X, if it doesn't it's a bug)
+A Bulletin Board System for UN*X like platforms.
-As I lost the code to my initial BBS flea, I've decided to start over from scratch and this time I'm using git hub so I dont
-lose it again!
-
-Magicka is meant to be a modern (haha) BBS system, using modern technologies, like Sqlite3, long filenames (gasp!) etc
-while still retaining the classic BBS feel. ANSI & Telnet, and good old ZModem.
-
-If you want to install Magicka BBS, follow these steps.
-
-1. Ensure you have git, c compiler, libsqlite3-dev, libreadline-dev, libssl-dev, libssh-dev libncurses5-dev and gnu make
-
- sudo apt-get install build-essential libsqlite3-dev libreadline-dev git libssl-dev libssh-dev libncurses5-dev
-
- should work on debian and debian derivatives.
-2. Clone the repo `git clone https://github.com/MagickaBBS/MagickaBBS`
-
-3. Build the BBS (You may have to adjust the Makefile for your system)
-
- `make`
-
-4. Make a directory for logs.
-
- `mkdir logs`
-
-5. Copy the config-default directory to a config directory.
-
- `cp -r dist/config config`
-
-6. Edit the config files and update essential information, like system paths and BBS name etc
-7. Copy the ansi-default directory to the one specified in your system path
-
- eg.
-
- `cp -r dist/ansis ansis`
-
-8. Copy the menus-default directory to the one specified in your system path
-
- eg.
-
- `cp -r dist/menus menus`
-
-9. Magicka also include optional lua scripts for menus and login / logoff. If you want to use these, copy
-the scripts-examples to the one specified in your system path.
-
- eg.
-
- `cp -r dist/scripts scripts`
-
-10. Make a link to the magicka.strings (or copy it if you want to modify it)
-
- eg.
-
- `ln -s dist/magicka.strings magicka.strings`
-
-11. If you are going to run SSH, you will need to create keys. To do this
-
- `mkdir keys`
-
- `ssh-keygen -f keys/ssh_host_rsa_key -N '' -t rsa`
-
- `ssh-keygen -f keys/ssh_host_dsa_key -N '' -t dsa`
-
-12. Run Magicka BBS on a port over 1024 (Below require root, and we're not ready for that).
-
- `./magicka config/bbs.ini`
-
-13. Your BBS is now running on the port you specified in the config.ini, log in and create yourself an account! (By default there is only one security level, you can add more,
-but you will need to use an SQLite Manager to modify users.sq3 and set security levels, as there is no user editor yet.
-
-For information on how to configure your BBS, check the wiki https://github.com/MagickaBBS/MagickaBBS/wiki
-
-# About the webserver
-
-Magicka now includes a built in webserver based on libmicrohttpd. It is not built by default, if you'd like to build it you will
-need a recent version of libmicrohttpd. Once you have these prerequisites, you can build magicka with `make www`
-be sure to do this from a clean source tree.
-
-The webserver will use templates in the www/ folder to create internal webpages on the fly, anything in www/static/ is served up as is.
-
-# Misc Notes:
-
-* FreeBSD requires libiconv to be installed from ports in addition to other dependencies.
-
-* macOS makefiles are intended to be built with dependencies provided by macports, homebrew support will require significant changes.
-
-* NetBSD requires libiconv to be installed from pkgsrc in addition to other dependencies.
-
-* OpenBSD as of 6.2 does not have libmicrohttpd in ports, but current does. Requires libiconv.
-
-* OpenIndiana does not have libssh in packages, so it needs to be built separately. Requires libiconv.
-
-* DragonFlyBSD also requires libiconv.
\ No newline at end of file
+For documentation, see [http://docs.magickabbs.com/](http://docs.magickabbs.com/)
diff --git a/STRINGS.CHANGES b/STRINGS.CHANGES
new file mode 100644
index 0000000..fff2b32
--- /dev/null
+++ b/STRINGS.CHANGES
@@ -0,0 +1,136 @@
+New / Changed Strings in dist/magicka.strings
+--------------------------------------------------------------
+If you are using your own custom strings file, you will need
+to add / modify the new string on the line specified. Be sure
+to remove the start and end quotation marks.
+
+
+Changes from v0.8-alpha -> v0.9-alpha
+--------------------------------------------------------------
+LINE: 255 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\r\n\e[1;37mSending file %s...\r\n"
+
+LINE 256 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\r\n\e[1;34mFilename\e[1;30m: \e[1;37m%s\e[0m\r\n"
+
+LINE 257 NEW
+OLDSTRING: (NONE)
+NEWSTRING: " \e[1;34mURL\e[1;30m: \e[1;37m%s\e[0m\r\n"
+
+LINE 258 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\r\n\e[1;31mError creating URL!\e[0m\r\n"
+
+LINE 259 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[1;33mSorry this BBS does not have the webserver enabled.\e[0m\r\n"
+
+LINE 260 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[%d;1H\e[1;30;40m[\e[1;34;44m%4d\e[1;30;40m]\e[1;32m*\e[1;37m%s\e[K"
+
+LINE 261 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[%d;1H\e[1;30;40m[\e[1;34m%4d\e[1;30;40m]\e[1;32m*\e[1;37m%s\e[K"
+
+LINE 230 MODIFIED
+OLDSTRING: "\r\n\e[1;37mAre you sure you want to reset all messages in %s to unread? \e[0m"
+NEWSTRING: "\r\n\r\n\e[1;37mReset pointers to All (\e[1;33mR\e[1;37m)ead, All (\e[1;33mU\e[1;37m)nread? or Msg #: "
+
+LINE 231 MODIFIED
+OLDSTRING: "\r\n\e[1;37mAre you sure you want to reset \e[1;31mall messages \e[1;37min all bases to unread? \e[0m"
+NEWSTRING: "\r\n\r\n\e[1;37mReset \e[1;31mALL\e[1;37m pointers in \e[1;31mALL \e[1;37mareas to (\e[1;33mR\e[1;37m)ead, (\e[1;33mU\e[1;37m)nread? \e[0m"
+
+LINE 167 MODIFIED
+OLDSTRING: "\r\nWhat is your login name: "
+NEWSTRING: "\r\n\e[0mWhat is your login name: "
+
+LINE 144 MODIFIED
+OLDSTRING: "\r\n\e[1;32mText Files Collection\r\n"
+NEWSTRING: "\e[1;37;44mChoose a Text file to view\e[K"
+
+LINE 145 MODIFIED
+OLDSTRING: "\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n"
+NEWSTRING: "\e[24;1H\e[1;37;44mUp / Down to Select, Enter to View, Q to Quit\e[K"
+
+LINE 146 CLEARED
+OLDSTRING: "\e[1;30m[\e[1;34m%3d\e[1;30m] \e[1;37m%s\r\n"
+NEWSTRING: ""
+
+LINE 147 CLEARED
+OLDSTRING: "\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n"
+NEWSTRING: ""
+
+LINE 148 CLEARED
+OLDSTRING: "Enter the number of a text file to display or Q to quit:"
+NEWSTRING: ""
+
+LINE 124 MODIFIED
+OLDSTRING: "\r\nMailing to %d:%d/%d.%d\r\n"
+NEWSTRING: "\r\nMailing to %d:%d/%d.%d (%s)\r\n"
+
+LINE 146 MODIFIED
+OLDSTRING: ""
+NEWSTRING: "\e[1;37;44mNodelist Browser\e[K"
+
+LINE 147 MODIFIED
+OLDSTRING: ""
+NEWSTRING: "\e[24;1H\e[1;37;44mUp / Down to Select, Enter to View Details, Q to Quit\e[K"
+
+LINE 148 MODIFIED
+OLDSTRING: ""
+NEWSTRING: "\e[%d;1H\e[1;30;40m[\e[1;34;44m%4d\e[1;30;40m] \e[1;37m%-15.15s %s\e[K"
+
+LINE 262 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[%d;1H\e[1;30;40m[\e[1;34m%4d\e[1;30;40m] \e[1;37m%-15.15s %s\e[K"
+
+LINE 263 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[1;37mNode Details for \e[1;33m%s\r\n"
+
+LINE 264 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n"
+
+LINE 265 NEW
+OLDSTRING: (NONE)
+NEWSTRING: " \e[1;32mSystem Name : \e[1;37m%s\r\n"
+
+LINE 266 NEW
+OLDSTRING: (NONE)
+NEWSTRING: " \e[1;32mSysop Name : \e[1;37m%s\r\n"
+
+LINE 267 NEW
+OLDSTRING: (NONE)
+NEWSTRING: " \e[1;32mLocation : \e[1;37m%s\r\n"
+
+LINE 268 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n"
+
+LINE 269 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[%d;1H\e[1;30;40m[\e[1;34m%3d\e[1;30;40m] \e[1;37m%-18.18s \e[1;33m%-16.16s \e[1;32m%-37.37s\e[K"
+
+LINE 270 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[%d;1H\e[1;30;40m[\e[1;34;44m%3d\e[1;30;40m] \e[1;37m%-18.18s \e[1;33m%-16.16s \e[1;32m%-37.37s\e[K"
+
+LINE 271 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[1;37;44mBBS Listing\e[K"
+
+LINE 272 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[24;1H\e[1;37;44mUp / Down to Select, A to Add, D to Delete, Q to Quit\e[K"
+
+LINE 273 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[8;28H\e[1;31;40mNo BBSes in the list!"
+
+LINE 274 NEW
+OLDSTRING: (NONE)
+NEWSTRING: "\e[10;22H\e[1;37mPress \e[1;33mA \e[1;37m to Add yours or \e[1;33mQ \e[1;37mto Quit\e[0m"
diff --git a/deps/aha/aha.c b/deps/aha/aha.c
index c99e39c..faa53de 100644
--- a/deps/aha/aha.c
+++ b/deps/aha/aha.c
@@ -359,9 +359,9 @@ char * aha(char *input)
else
if (c==13)
{
- for (;line<80;line++)
+ //for (;line<80;line++)
- append_output(&output, " ", &size, &outat);
+ // append_output(&output, " ", &size, &outat);
line=0;
momline++;
append_output(&output, "
\n", &size, &outat);
@@ -520,7 +520,7 @@ char * aha(char *input)
case '\xda' : append_output(&output, "┌", &size, &outat); break;
case '\xdb' : append_output(&output, "█", &size, &outat); break;
case '\xdc' : append_output(&output, "▄", &size, &outat); break;
- case '\xdd' : append_output(&output, "▼", &size, &outat); break;
+ case '\xdd' : append_output(&output, "▌", &size, &outat); break;
case '\xde' : append_output(&output, "▐", &size, &outat); break;
case '\xdf' : append_output(&output, "▀", &size, &outat); break;
case '\xe0' : append_output(&output, "α", &size, &outat); break;
diff --git a/deps/hashids/hashids.c b/deps/hashids/hashids.c
new file mode 100644
index 0000000..dfbab26
--- /dev/null
+++ b/deps/hashids/hashids.c
@@ -0,0 +1,831 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "hashids.h"
+
+/* branch prediction hinting */
+#ifndef __has_builtin
+# define __has_builtin(x) (0)
+#endif
+#if defined(__builtin_expect) || __has_builtin(__builtin_expect)
+# define HASHIDS_LIKELY(x) (__builtin_expect(!!(x), 1))
+# define HASHIDS_UNLIKELY(x) (__builtin_expect(!!(x), 0))
+#else
+# define HASHIDS_LIKELY(x) (x)
+# define HASHIDS_UNLIKELY(x) (x)
+#endif
+
+/* thread-local storage */
+#ifndef TLS
+#define TLS
+#endif
+
+/* thread-safe hashids_errno indirection */
+TLS int __hashids_errno_val;
+int *
+__hashids_errno_addr()
+{
+ return &__hashids_errno_val;
+}
+
+/* default alloc() implementation */
+static inline void *
+hashids_alloc_f(size_t size)
+{
+ return calloc(size, 1);
+}
+
+/* default free() implementation */
+static inline void
+hashids_free_f(void *ptr)
+{
+ free(ptr);
+}
+
+void *(*_hashids_alloc)(size_t size) = hashids_alloc_f;
+void (*_hashids_free)(void *ptr) = hashids_free_f;
+
+/* fast ceil(x / y) for size_t arguments */
+static inline size_t
+hashids_div_ceil_size_t(size_t x, size_t y)
+{
+ return x / y + !!(x % y);
+}
+
+/* fast ceil(x / y) for unsigned short arguments */
+static inline unsigned short
+hashids_div_ceil_unsigned_short(unsigned short x, unsigned short y) {
+ return x / y + !!(x % y);
+}
+
+/* fast log2(x) for unsigned long long */
+const unsigned short hashids_log2_64_tab[64] = {
+ 63, 0, 58, 1, 59, 47, 53, 2,
+ 60, 39, 48, 27, 54, 33, 42, 3,
+ 61, 51, 37, 40, 49, 18, 28, 20,
+ 55, 30, 34, 11, 43, 14, 22, 4,
+ 62, 57, 46, 52, 38, 26, 32, 41,
+ 50, 36, 17, 19, 29, 10, 13, 21,
+ 56, 45, 25, 31, 35, 16, 9, 12,
+ 44, 24, 15, 8, 23, 7, 6, 5
+};
+
+static inline unsigned short
+hashids_log2_64(unsigned long long x)
+{
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ x |= x >> 32;
+
+ /* pure evil : ieee abuse */
+ return hashids_log2_64_tab[
+ ((unsigned long long)((x - (x >> 1)) * 0x07EDD5E59A4E28C2)) >> 58];
+}
+
+/* shuffle loop step */
+#define hashids_shuffle_step(iter) \
+ if (i == 0) { break; } \
+ if (v == salt_length) { v = 0; } \
+ p += salt[v]; j = (salt[v] + v + p) % (iter); \
+ temp = str[(iter)]; str[(iter)] = str[j]; str[j] = temp; \
+ --i; ++v;
+
+/* consistent shuffle */
+void
+hashids_shuffle(char *str, size_t str_length, char *salt, size_t salt_length)
+{
+ ssize_t i;
+ size_t j, v, p;
+ char temp;
+
+ /* meh, meh */
+ if (!salt_length) {
+ return;
+ }
+
+ /* pure evil : loop unroll */
+ for (i = str_length - 1, v = 0, p = 0; i > 0; /* empty */) {
+ switch (i % 32) {
+ case 31: hashids_shuffle_step(i);
+ case 30: hashids_shuffle_step(i);
+ case 29: hashids_shuffle_step(i);
+ case 28: hashids_shuffle_step(i);
+ case 27: hashids_shuffle_step(i);
+ case 26: hashids_shuffle_step(i);
+ case 25: hashids_shuffle_step(i);
+ case 24: hashids_shuffle_step(i);
+ case 23: hashids_shuffle_step(i);
+ case 22: hashids_shuffle_step(i);
+ case 21: hashids_shuffle_step(i);
+ case 20: hashids_shuffle_step(i);
+ case 19: hashids_shuffle_step(i);
+ case 18: hashids_shuffle_step(i);
+ case 17: hashids_shuffle_step(i);
+ case 16: hashids_shuffle_step(i);
+ case 15: hashids_shuffle_step(i);
+ case 14: hashids_shuffle_step(i);
+ case 13: hashids_shuffle_step(i);
+ case 12: hashids_shuffle_step(i);
+ case 11: hashids_shuffle_step(i);
+ case 10: hashids_shuffle_step(i);
+ case 9: hashids_shuffle_step(i);
+ case 8: hashids_shuffle_step(i);
+ case 7: hashids_shuffle_step(i);
+ case 6: hashids_shuffle_step(i);
+ case 5: hashids_shuffle_step(i);
+ case 4: hashids_shuffle_step(i);
+ case 3: hashids_shuffle_step(i);
+ case 2: hashids_shuffle_step(i);
+ case 1: hashids_shuffle_step(i);
+ case 0: hashids_shuffle_step(i);
+ }
+ }
+}
+
+/* "destructor" */
+void
+hashids_free(hashids_t *hashids)
+{
+ if (hashids) {
+ if (hashids->alphabet) {
+ _hashids_free(hashids->alphabet);
+ }
+ if (hashids->alphabet_copy_1) {
+ _hashids_free(hashids->alphabet_copy_1);
+ }
+ if (hashids->alphabet_copy_2) {
+ _hashids_free(hashids->alphabet_copy_2);
+ }
+ if (hashids->salt) {
+ _hashids_free(hashids->salt);
+ }
+ if (hashids->separators) {
+ _hashids_free(hashids->separators);
+ }
+ if (hashids->guards) {
+ _hashids_free(hashids->guards);
+ }
+
+ _hashids_free(hashids);
+ }
+}
+
+/* common init */
+hashids_t *
+hashids_init3(const char *salt, size_t min_hash_length, const char *alphabet)
+{
+ hashids_t *result;
+ size_t i, j, len;
+ char ch, *p;
+
+ hashids_errno = HASHIDS_ERROR_OK;
+
+ /* allocate the structure */
+ result = _hashids_alloc(sizeof(hashids_t));
+ if (HASHIDS_UNLIKELY(!result)) {
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return NULL;
+ }
+
+ /* allocate enough space for the alphabet */
+ len = strlen(alphabet) + 1;
+ result->alphabet = _hashids_alloc(len);
+
+ /* extract only the unique characters */
+ result->alphabet[0] = '\0';
+ for (i = 0, j = 0; i < len; ++i) {
+ ch = alphabet[i];
+ if (!strchr(result->alphabet, ch)) {
+ result->alphabet[j++] = ch;
+ }
+ }
+ result->alphabet[j] = '\0';
+
+ /* store alphabet length */
+ result->alphabet_length = j;
+
+ /* check length and whitespace */
+ if (result->alphabet_length < HASHIDS_MIN_ALPHABET_LENGTH) {
+ hashids_free(result);
+ hashids_errno = HASHIDS_ERROR_ALPHABET_LENGTH;
+ return NULL;
+ }
+ if (strchr(result->alphabet, 0x20) || strchr(result->alphabet, 0x09)) {
+ hashids_free(result);
+ hashids_errno = HASHIDS_ERROR_ALPHABET_SPACE;
+ return NULL;
+ }
+
+ /* copy salt */
+ result->salt_length = salt ? strlen(salt) : 0;
+ result->salt = _hashids_alloc(result->salt_length + 1);
+ if (HASHIDS_UNLIKELY(!result->salt)) {
+ hashids_free(result);
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return NULL;
+ }
+ strncpy(result->salt, salt, result->salt_length);
+
+ /* allocate enough space for separators */
+ len = strlen(HASHIDS_DEFAULT_SEPARATORS);
+ j = (size_t)
+ (ceil((float)result->alphabet_length / HASHIDS_SEPARATOR_DIVISOR) + 1);
+ if (j < len + 1) {
+ j = len + 1;
+ }
+
+ result->separators = _hashids_alloc(j);
+ if (HASHIDS_UNLIKELY(!result->separators)) {
+ hashids_free(result);
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return NULL;
+ }
+
+ /* take default separators out of the alphabet */
+ for (i = 0, j = 0; i < strlen(HASHIDS_DEFAULT_SEPARATORS); ++i) {
+ ch = HASHIDS_DEFAULT_SEPARATORS[i];
+
+ /* check if separator is actually in the used alphabet */
+ if ((p = strchr(result->alphabet, ch))) {
+ result->separators[j++] = ch;
+
+ /* remove that separator */
+ memmove(p, p + 1,
+ strlen(result->alphabet) - (p - result->alphabet));
+ }
+ }
+
+ /* store separators length */
+ result->separators_count = j;
+
+ /* subtract separators count from alphabet length */
+ result->alphabet_length -= result->separators_count;
+
+ /* shuffle the separators */
+ if (result->separators_count) {
+ hashids_shuffle(result->separators, result->separators_count,
+ result->salt, result->salt_length);
+ }
+
+ /* check if we have any/enough separators */
+ if (!result->separators_count
+ || (((float)result->alphabet_length / (float)result->separators_count)
+ > HASHIDS_SEPARATOR_DIVISOR)) {
+ size_t separators_count = (size_t)ceil(
+ (float)result->alphabet_length / HASHIDS_SEPARATOR_DIVISOR);
+
+ if (separators_count == 1) {
+ separators_count = 2;
+ }
+
+ if (separators_count > result->separators_count) {
+ /* we need more separators - get some from alphabet */
+ size_t diff = separators_count - result->separators_count;
+ strncat(result->separators, result->alphabet, diff);
+ memmove(result->alphabet, result->alphabet + diff,
+ result->alphabet_length - diff + 1);
+
+ result->separators_count += diff;
+ result->alphabet_length -= diff;
+ } else {
+ /* we have more than enough - truncate */
+ result->separators[separators_count] = '\0';
+ result->separators_count = separators_count;
+ }
+ }
+
+ /* shuffle alphabet */
+ hashids_shuffle(result->alphabet, result->alphabet_length,
+ result->salt, result->salt_length);
+
+ /* allocate guards */
+ result->guards_count = hashids_div_ceil_size_t(result->alphabet_length,
+ HASHIDS_GUARD_DIVISOR);
+ result->guards = _hashids_alloc(result->guards_count + 1);
+ if (HASHIDS_UNLIKELY(!result->guards)) {
+ hashids_free(result);
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return NULL;
+ }
+
+ if (HASHIDS_UNLIKELY(result->alphabet_length < 3)) {
+ /* take some from separators */
+ strncpy(result->guards, result->separators, result->guards_count);
+ memmove(result->separators, result->separators + result->guards_count,
+ result->separators_count - result->guards_count + 1);
+
+ result->separators_count -= result->guards_count;
+ } else {
+ /* take them from alphabet */
+ strncpy(result->guards, result->alphabet, result->guards_count);
+ memmove(result->alphabet, result->alphabet + result->guards_count,
+ result->alphabet_length - result->guards_count + 1);
+
+ result->alphabet_length -= result->guards_count;
+ }
+
+ /* allocate enough space for the alphabet copies */
+ result->alphabet_copy_1 = _hashids_alloc(result->alphabet_length + 1);
+ result->alphabet_copy_2 = _hashids_alloc(result->alphabet_length + 1);
+ if (HASHIDS_UNLIKELY(!result->alphabet || !result->alphabet_copy_1
+ || !result->alphabet_copy_2)) {
+ hashids_free(result);
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return NULL;
+ }
+
+ /* set min hash length */
+ result->min_hash_length = min_hash_length;
+
+ /* return result happily */
+ return result;
+}
+
+/* init with salt and minimum hash length */
+hashids_t *
+hashids_init2(const char *salt, size_t min_hash_length)
+{
+ return hashids_init3(salt, min_hash_length, HASHIDS_DEFAULT_ALPHABET);
+}
+
+/* init with hash only */
+hashids_t *
+hashids_init(const char *salt)
+{
+ return hashids_init2(salt, HASHIDS_DEFAULT_MIN_HASH_LENGTH);
+}
+
+/* estimate buffer size (generic) */
+size_t
+hashids_estimate_encoded_size(hashids_t *hashids,
+ size_t numbers_count, unsigned long long *numbers)
+{
+ int i, result_len;
+
+ for (i = 0, result_len = 1; i < numbers_count; ++i) {
+ if (numbers[i] == 0) {
+ result_len += 2;
+ } else if (numbers[i] == 0xFFFFFFFFFFFFFFFFull) {
+ result_len += hashids_div_ceil_unsigned_short(
+ hashids_log2_64(numbers[i]),
+ hashids_log2_64(hashids->alphabet_length)) - 1;
+ } else {
+ result_len += hashids_div_ceil_unsigned_short(
+ hashids_log2_64(numbers[i] + 1),
+ hashids_log2_64(hashids->alphabet_length));
+ }
+ }
+
+ if (numbers_count > 1) {
+ result_len += numbers_count - 1;
+ }
+
+ if (result_len < hashids->min_hash_length) {
+ result_len = hashids->min_hash_length;
+ }
+
+ return result_len + 2 /* fast log2 & ceil sometimes undershoot by 1 */;
+}
+
+/* estimate buffer size (variadic) */
+size_t
+hashids_estimate_encoded_size_v(hashids_t *hashids,
+ size_t numbers_count, ...)
+{
+ size_t i, result;
+ unsigned long long *numbers;
+ va_list ap;
+
+ numbers = _hashids_alloc(numbers_count * sizeof(unsigned long long));
+
+ if (HASHIDS_UNLIKELY(!numbers)) {
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return 0;
+ }
+
+ va_start(ap, numbers_count);
+ for (i = 0; i < numbers_count; ++i) {
+ numbers[i] = va_arg(ap, unsigned long long);
+ }
+ va_end(ap);
+
+ result = hashids_estimate_encoded_size(hashids, numbers_count, numbers);
+ _hashids_free(numbers);
+
+ return result;
+}
+
+/* encode many (generic) */
+size_t
+hashids_encode(hashids_t *hashids, char *buffer,
+ size_t numbers_count, unsigned long long *numbers)
+{
+ /* bail out if no numbers */
+ if (HASHIDS_UNLIKELY(!numbers_count)) {
+ buffer[0] = '\0';
+
+ return 0;
+ }
+
+ size_t i, j, result_len, guard_index, half_length_ceil, half_length_floor;
+ unsigned long long number, number_copy, numbers_hash;
+ int p_max;
+ char lottery, ch, temp_ch, *p, *buffer_end, *buffer_temp;
+
+ /* return an estimation if no buffer */
+ if (HASHIDS_UNLIKELY(!buffer)) {
+ return hashids_estimate_encoded_size(hashids, numbers_count, numbers);
+ }
+
+ /* copy the alphabet into internal buffer 1 */
+ strncpy(hashids->alphabet_copy_1, hashids->alphabet,
+ hashids->alphabet_length);
+
+ /* walk arguments once and generate a hash */
+ for (i = 0, numbers_hash = 0; i < numbers_count; ++i) {
+ number = numbers[i];
+ numbers_hash += number % (i + 100);
+ }
+
+ /* lottery character */
+ lottery = hashids->alphabet[numbers_hash % hashids->alphabet_length];
+
+ /* start output buffer with it (or don't) */
+ buffer[0] = lottery;
+ buffer_end = buffer + 1;
+
+ /* alphabet-like buffer used for salt at each iteration */
+ hashids->alphabet_copy_2[0] = lottery;
+ hashids->alphabet_copy_2[1] = '\0';
+ strncat(hashids->alphabet_copy_2, hashids->salt,
+ hashids->alphabet_length - 1);
+ p = hashids->alphabet_copy_2 + hashids->salt_length + 1;
+ p_max = hashids->alphabet_length - 1 - hashids->salt_length;
+ if (p_max > 0) {
+ strncat(hashids->alphabet_copy_2, hashids->alphabet,
+ p_max);
+ } else {
+ hashids->alphabet_copy_2[hashids->alphabet_length] = '\0';
+ }
+
+ for (i = 0; i < numbers_count; ++i) {
+ /* take number */
+ number = number_copy = numbers[i];
+
+ /* create a salt for this iteration */
+ if (p_max > 0) {
+ strncpy(p, hashids->alphabet_copy_1, p_max);
+ }
+
+ /* shuffle the alphabet */
+ hashids_shuffle(hashids->alphabet_copy_1, hashids->alphabet_length,
+ hashids->alphabet_copy_2, hashids->alphabet_length);
+
+ /* hash the number */
+ buffer_temp = buffer_end;
+ do {
+ ch = hashids->alphabet_copy_1[number % hashids->alphabet_length];
+ *buffer_end++ = ch;
+ number /= hashids->alphabet_length;
+ } while (number);
+
+ /* reverse the hash we got */
+ for (j = 0; j < (buffer_end - buffer_temp) / 2; ++j) {
+ temp_ch = *(buffer_temp + j);
+ *(buffer_temp + j) = *(buffer_end - 1 - j);
+ *(buffer_end - 1 - j) = temp_ch;
+ }
+
+ if (i + 1 < numbers_count) {
+ number_copy %= ch + i;
+ *buffer_end = hashids->separators[number_copy %
+ hashids->separators_count];
+ ++buffer_end;
+ }
+ }
+
+ /* intermediate string length */
+ result_len = buffer_end - buffer;
+
+ if (result_len < hashids->min_hash_length) {
+ /* add a guard before the encoded numbers */
+ guard_index = (numbers_hash + buffer[0]) % hashids->guards_count;
+ memmove(buffer + 1, buffer, result_len);
+ buffer[0] = hashids->guards[guard_index];
+ ++result_len;
+
+ if (result_len < hashids->min_hash_length) {
+ /* add a guard after the encoded numbers */
+ guard_index = (numbers_hash + buffer[2]) % hashids->guards_count;
+ buffer[result_len] = hashids->guards[guard_index];
+ ++result_len;
+
+ /* pad with half alphabet before and after */
+ half_length_ceil = hashids_div_ceil_size_t(
+ hashids->alphabet_length, 2);
+ half_length_floor = floor((float)hashids->alphabet_length / 2);
+
+ /* pad, pad, pad */
+ while (result_len < hashids->min_hash_length) {
+ /* shuffle the alphabet */
+ strncpy(hashids->alphabet_copy_2, hashids->alphabet_copy_1,
+ hashids->alphabet_length);
+ hashids_shuffle(hashids->alphabet_copy_1,
+ hashids->alphabet_length, hashids->alphabet_copy_2,
+ hashids->alphabet_length);
+
+ /* left pad from the end of the alphabet */
+ i = hashids_div_ceil_size_t(
+ hashids->min_hash_length - result_len, 2);
+ /* right pad from the beginning */
+ j = floor((float)(hashids->min_hash_length - result_len) / 2);
+
+ /* check bounds */
+ if (i > half_length_ceil) {
+ i = half_length_ceil;
+ }
+ if (j > half_length_floor) {
+ j = half_length_floor;
+ }
+
+ /* handle excessively excessive excess */
+ if ((i + j) % 2 == 0 && hashids->alphabet_length % 2 == 1) {
+ ++i; --j;
+ }
+
+ /* move the current result to "center" */
+ memmove(buffer + i, buffer, result_len);
+ /* pad left */
+ memmove(buffer,
+ hashids->alphabet_copy_1 + hashids->alphabet_length - i, i);
+ /* pad right */
+ memmove(buffer + i + result_len, hashids->alphabet_copy_1, j);
+
+ /* increment result_len */
+ result_len += i + j;
+ }
+ }
+ }
+
+ buffer[result_len] = '\0';
+ return result_len;
+}
+
+/* encode many (variadic) */
+size_t
+hashids_encode_v(hashids_t *hashids, char *buffer,
+ size_t numbers_count, ...)
+{
+ int i;
+ size_t result;
+ unsigned long long *numbers;
+ va_list ap;
+
+ numbers = _hashids_alloc(numbers_count * sizeof(unsigned long long));
+
+ if (HASHIDS_UNLIKELY(!numbers)) {
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return 0;
+ }
+
+ va_start(ap, numbers_count);
+ for (i = 0; i < numbers_count; ++i) {
+ numbers[i] = va_arg(ap, unsigned long long);
+ }
+ va_end(ap);
+
+ result = hashids_encode(hashids, buffer, numbers_count, numbers);
+ _hashids_free(numbers);
+
+ return result;
+}
+
+/* encode one */
+size_t
+hashids_encode_one(hashids_t *hashids, char *buffer,
+ unsigned long long number)
+{
+ return hashids_encode(hashids, buffer, 1, &number);
+}
+
+/* numbers count */
+size_t
+hashids_numbers_count(hashids_t *hashids, char *str)
+{
+ size_t numbers_count;
+ char ch, *p;
+
+ /* skip characters until we find a guard */
+ if (hashids->min_hash_length) {
+ p = str;
+ while ((ch = *p)) {
+ if (strchr(hashids->guards, ch)) {
+ str = p + 1;
+ break;
+ }
+
+ p++;
+ }
+ }
+
+ /* parse */
+ numbers_count = 0;
+ while ((ch = *str)) {
+ if (strchr(hashids->guards, ch)) {
+ break;
+ }
+ if (strchr(hashids->separators, ch)) {
+ numbers_count++;
+ str++;
+ continue;
+ }
+ if (!strchr(hashids->alphabet, ch)) {
+ hashids_errno = HASHIDS_ERROR_INVALID_HASH;
+ return 0;
+ }
+
+ str++;
+ }
+
+ /* account for the last number */
+ return numbers_count + 1;
+}
+
+/* decode */
+size_t
+hashids_decode(hashids_t *hashids, char *str,
+ unsigned long long *numbers)
+{
+ size_t numbers_count;
+ unsigned long long number;
+ char lottery, ch, *p, *c;
+ int p_max;
+
+ numbers_count = hashids_numbers_count(hashids, str);
+
+ if (!numbers) {
+ return numbers_count;
+ }
+
+ /* skip characters until we find a guard */
+ if (hashids->min_hash_length) {
+ p = str;
+ while ((ch = *p)) {
+ if (strchr(hashids->guards, ch)) {
+ str = p + 1;
+ break;
+ }
+
+ p++;
+ }
+ }
+
+ /* get the lottery character */
+ lottery = *str++;
+
+ /* copy the alphabet into internal buffer 1 */
+ strncpy(hashids->alphabet_copy_1, hashids->alphabet,
+ hashids->alphabet_length);
+
+ /* alphabet-like buffer used for salt at each iteration */
+ hashids->alphabet_copy_2[0] = lottery;
+ hashids->alphabet_copy_2[1] = '\0';
+ strncat(hashids->alphabet_copy_2, hashids->salt,
+ hashids->alphabet_length - 1);
+ p = hashids->alphabet_copy_2 + hashids->salt_length + 1;
+ p_max = hashids->alphabet_length - 1 - hashids->salt_length;
+ if (p_max > 0) {
+ strncat(hashids->alphabet_copy_2, hashids->alphabet,
+ p_max);
+ } else {
+ hashids->alphabet_copy_2[hashids->alphabet_length] = '\0';
+ }
+
+ /* first shuffle */
+ hashids_shuffle(hashids->alphabet_copy_1, hashids->alphabet_length,
+ hashids->alphabet_copy_2, hashids->alphabet_length);
+
+ /* parse */
+ number = 0;
+ while ((ch = *str)) {
+ if (strchr(hashids->guards, ch)) {
+ break;
+ }
+ if (strchr(hashids->separators, ch)) {
+ *numbers++ = number;
+ number = 0;
+
+ /* resalt the alphabet */
+ if (p_max > 0) {
+ strncpy(p, hashids->alphabet_copy_1, p_max);
+ }
+ hashids_shuffle(hashids->alphabet_copy_1, hashids->alphabet_length,
+ hashids->alphabet_copy_2, hashids->alphabet_length);
+
+ str++;
+ continue;
+ }
+ if (!(c = strchr(hashids->alphabet_copy_1, ch))) {
+ hashids_errno = HASHIDS_ERROR_INVALID_HASH;
+ return 0;
+ }
+
+ number *= hashids->alphabet_length;
+ number += c - hashids->alphabet_copy_1;
+
+ str++;
+ }
+
+ /* store last number */
+ *numbers = number;
+
+ return numbers_count;
+}
+
+/* encode hex */
+size_t
+hashids_encode_hex(hashids_t *hashids, char *buffer,
+ const char *hex_str)
+{
+ int len;
+ char *temp, *p;
+ size_t result;
+ unsigned long long number;
+
+ len = strlen(hex_str);
+ temp = _hashids_alloc(len + 2);
+
+ if (!temp) {
+ hashids_errno = HASHIDS_ERROR_ALLOC;
+ return 0;
+ }
+
+ temp[0] = '1';
+ strncpy(temp + 1, hex_str, len);
+
+ number = strtoull(temp, &p, 16);
+
+ if (p == temp) {
+ _hashids_free(temp);
+ hashids_errno = HASHIDS_ERROR_INVALID_NUMBER;
+ return 0;
+ }
+
+ result = hashids_encode(hashids, buffer, 1, &number);
+ _hashids_free(temp);
+
+ return result;
+}
+
+/* decode hex */
+size_t
+hashids_decode_hex(hashids_t *hashids, char *str, char *output)
+{
+ size_t result, i;
+ unsigned long long number;
+ char ch, *temp;
+
+ result = hashids_numbers_count(hashids, str);
+
+ if (result != 1) {
+ return 0;
+ }
+
+ result = hashids_decode(hashids, str, &number);
+
+ if (result != 1) {
+ return 0;
+ }
+
+ temp = output;
+
+ do {
+ ch = number % 16;
+ if (ch > 9) {
+ ch += 'A' - 10;
+ } else {
+ ch += '0';
+ }
+
+ *temp++ = (char)ch;
+
+ number /= 16;
+ } while (number);
+
+ temp--;
+ *temp = 0;
+
+ for (i = 0; i < (temp - output) / 2; ++i) {
+ ch = *(output + i);
+ *(output + i) = *(temp - 1 - i);
+ *(temp - 1 - i) = ch;
+ }
+
+ return 1;
+}
diff --git a/deps/hashids/hashids.h b/deps/hashids/hashids.h
new file mode 100644
index 0000000..dd9a575
--- /dev/null
+++ b/deps/hashids/hashids.h
@@ -0,0 +1,122 @@
+#ifndef HASHIDS_H
+#define HASHIDS_H 1
+
+#include
+
+/* version constants */
+#define HASHIDS_VERSION "1.1.5"
+#define HASHIDS_VERSION_MAJOR 1
+#define HASHIDS_VERSION_MINOR 1
+#define HASHIDS_VERSION_PATCH 5
+
+/* minimal alphabet length */
+#define HASHIDS_MIN_ALPHABET_LENGTH 16u
+
+/* separator divisor */
+#define HASHIDS_SEPARATOR_DIVISOR 3.5f
+
+/* guard divisor */
+#define HASHIDS_GUARD_DIVISOR 12u
+
+/* default salt */
+#define HASHIDS_DEFAULT_SALT ""
+
+/* default minimal hash length */
+#define HASHIDS_DEFAULT_MIN_HASH_LENGTH 0u
+
+/* default alphabet */
+#define HASHIDS_DEFAULT_ALPHABET "abcdefghijklmnopqrstuvwxyz" \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
+ "1234567890"
+
+/* default separators */
+#define HASHIDS_DEFAULT_SEPARATORS "cfhistuCFHISTU"
+
+/* error codes */
+#define HASHIDS_ERROR_OK 0
+#define HASHIDS_ERROR_ALLOC -1
+#define HASHIDS_ERROR_ALPHABET_LENGTH -2
+#define HASHIDS_ERROR_ALPHABET_SPACE -3
+#define HASHIDS_ERROR_INVALID_HASH -4
+#define HASHIDS_ERROR_INVALID_NUMBER -5
+
+/* thread-safe hashids_errno indirection */
+extern int *__hashids_errno_addr();
+#define hashids_errno (*__hashids_errno_addr())
+
+/* alloc & free */
+extern void *(*_hashids_alloc)(size_t size);
+extern void (*_hashids_free)(void *ptr);
+
+/* the hashids "object" */
+struct hashids_s {
+ char *alphabet;
+ char *alphabet_copy_1;
+ char *alphabet_copy_2;
+ size_t alphabet_length;
+
+ char *salt;
+ size_t salt_length;
+
+ char *separators;
+ size_t separators_count;
+
+ char *guards;
+ size_t guards_count;
+
+ size_t min_hash_length;
+};
+typedef struct hashids_s hashids_t;
+
+/* exported function definitions */
+void
+hashids_shuffle(char *str, size_t str_length, char *salt, size_t salt_length);
+
+void
+hashids_free(hashids_t *hashids);
+
+hashids_t *
+hashids_init3(const char *salt, size_t min_hash_length,
+ const char *alphabet);
+
+hashids_t *
+hashids_init2(const char *salt, size_t min_hash_length);
+
+hashids_t *
+hashids_init(const char *salt);
+
+size_t
+hashids_estimate_encoded_size(hashids_t *hashids,
+ size_t numbers_count, unsigned long long *numbers);
+
+size_t
+hashids_estimate_encoded_size_v(hashids_t *hashids,
+ size_t numbers_count, ...);
+
+size_t
+hashids_encode(hashids_t *hashids, char *buffer,
+ size_t numbers_count, unsigned long long *numbers);
+
+size_t
+hashids_encode_v(hashids_t *hashids, char *buffer,
+ size_t numbers_count, ...);
+
+size_t
+hashids_encode_one(hashids_t *hashids, char *buffer,
+ unsigned long long number);
+
+size_t
+hashids_numbers_count(hashids_t *hashids, char *str);
+
+size_t
+hashids_decode(hashids_t *hashids, char *str,
+ unsigned long long *numbers);
+
+size_t
+hashids_encode_hex(hashids_t *hashids, char *buffer,
+ const char *hex_str);
+
+size_t
+hashids_decode_hex(hashids_t *hashids, char *str, char *output);
+
+#endif
diff --git a/dist/ansis/bulletin0.ans b/dist/ansis/bulletin0.ans
index 2e1a4a3..7270a2c 100644
Binary files a/dist/ansis/bulletin0.ans and b/dist/ansis/bulletin0.ans differ
diff --git a/dist/ansis/bulletin1.ans b/dist/ansis/bulletin1.ans
index db96af3..04be840 100644
Binary files a/dist/ansis/bulletin1.ans and b/dist/ansis/bulletin1.ans differ
diff --git a/dist/ansis/doors.ans b/dist/ansis/doors.ans
index 5ca0fc7..c873e23 100644
Binary files a/dist/ansis/doors.ans and b/dist/ansis/doors.ans differ
diff --git a/dist/ansis/filemenu.ans b/dist/ansis/filemenu.ans
index 5202b6c..ef369a3 100644
Binary files a/dist/ansis/filemenu.ans and b/dist/ansis/filemenu.ans differ
diff --git a/dist/ansis/goodbye.ans b/dist/ansis/goodbye.ans
index f4b393a..912498b 100644
Binary files a/dist/ansis/goodbye.ans and b/dist/ansis/goodbye.ans differ
diff --git a/dist/ansis/issue.ans b/dist/ansis/issue.ans
index 2f6524c..db3217b 100644
Binary files a/dist/ansis/issue.ans and b/dist/ansis/issue.ans differ
diff --git a/dist/ansis/logoff.ans b/dist/ansis/logoff.ans
index 519ba8a..5570abd 100644
Binary files a/dist/ansis/logoff.ans and b/dist/ansis/logoff.ans differ
diff --git a/dist/ansis/mailmenu.ans b/dist/ansis/mailmenu.ans
index 66e98d5..e57a87c 100644
Binary files a/dist/ansis/mailmenu.ans and b/dist/ansis/mailmenu.ans differ
diff --git a/dist/ansis/mainmenu.ans b/dist/ansis/mainmenu.ans
index 53c9e3d..8d0f1a4 100644
Binary files a/dist/ansis/mainmenu.ans and b/dist/ansis/mainmenu.ans differ
diff --git a/dist/ansis/newuser.ans b/dist/ansis/newuser.ans
index cd2800e..1cf28b4 100644
Binary files a/dist/ansis/newuser.ans and b/dist/ansis/newuser.ans differ
diff --git a/dist/config/bbs.ini b/dist/config/bbs.ini
index 3a2736a..1e0c3e0 100644
--- a/dist/config/bbs.ini
+++ b/dist/config/bbs.ini
@@ -16,6 +16,7 @@ Automessage Write Level = 10
Fork = false
Enable WWW = false
WWW Port = 8080
+WWW URL = http://127.0.0.1:8080/
Enable SSH = false
SSH Port = 2024
SSH DSA Key = /home/andrew/MagickaBBS/keys/ssh_host_dsa_key
@@ -48,10 +49,11 @@ Menu Path = /home/andrew/MagickaBBS/menus
[mail conferences]
Local Mail = config/localmail.ini
-IllusionNet = config/illusionnet.ini
+HappyNet = config/happynet.ini
[file directories]
General Files = config/filesgen.ini
[text files]
-Warning = ansis/bulletin0.ans
+Magicka Advertisement = ansis/bulletin0.ans
+Whats New = ansis/bulletin1.ans
diff --git a/dist/config/happynet.ini b/dist/config/happynet.ini
new file mode 100644
index 0000000..b93404d
--- /dev/null
+++ b/dist/config/happynet.ini
@@ -0,0 +1,29 @@
+; For information on joining happynet, go here:
+;
+; https://magickabbs.com/index.php/happynet/
+
+[main]
+Visible Sec Level = 10
+Networked = true
+Real Names = false
+
+[network]
+type = fido
+fido node = 637:1/999
+domain = happynet
+
+[General]
+Read Sec Level = 10
+Write Sec Level = 10
+Path = /home/andrew/MagickaBBS/msgs/hnet_general
+; local / echo or netmail
+Type = Echo
+QWK Name = HN_GEN
+
+[Netmail]
+Read Sec Level = 10
+Write Sec Level = 10
+Path = /home/andrew/MagickaBBS/msgs/hnet_netmail
+; local / echo or netmail
+Type = Netmail
+QWK Name = HN_NET
diff --git a/dist/config/illusionnet.ini b/dist/config/illusionnet.ini
deleted file mode 100644
index 3515e5c..0000000
--- a/dist/config/illusionnet.ini
+++ /dev/null
@@ -1,16 +0,0 @@
-[main]
-Visible Sec Level = 10
-Networked = true
-Real Names = false
-
-[network]
-type = fido
-fido node = 867:61/2
-
-[General]
-Read Sec Level = 10
-Write Sec Level = 10
-Path = /home/andrew/MagickaBBS/msgs/il_general
-; local / echo or netmail
-Type = Echo
-QWK Name = ILLGEN
diff --git a/dist/magicka.strings b/dist/magicka.strings
index 723d2bf..5b7b778 100644
--- a/dist/magicka.strings
+++ b/dist/magicka.strings
@@ -121,7 +121,7 @@ Change Subject? (Y/N)
Read message [1-%d] or N for New:
\r\nADDR:
\r\n\r\nInvalid Address\r\n
-\r\nMailing to %d:%d/%d.%d\r\n
+\r\nMailing to %d:%d/%d.%d (%s)\r\n
\r\nMailing to @%d\r\n
Start at message [1-%d] or N for New?
\e[2J\e[1;1H\e[1;37;44m[MSG#] Subject From To Date \r\n\e[0m
@@ -141,11 +141,11 @@ Enter the area number:
\r\n\e[1;32m%d. %s\e[0m\r\n
\e[1;37m --> %d. %s (%d new)\e[0m\r\n
\r\n\e[0mTL: %dm :>
-\r\n\e[1;32mText Files Collection\r\n
-\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
-\e[1;30m[\e[1;34m%3d\e[1;30m] \e[1;37m%s\r\n
-\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
-Enter the number of a text file to display or Q to quit:
+\e[1;37;44mChoose a Text file to view\e[K
+\e[24;1H\e[1;37;44mUp / Down to Select, Enter to View, Q to Quit\e[K
+\e[1;37;44mNodelist Browser\e[K
+\e[24;1H\e[1;37;44mUp / Down to Select, Enter to View Details, Q to Quit\e[K
+\e[%d;1H\e[1;30;40m[\e[1;34;44m%4d\e[1;30;40m] \e[1;37m%-15.15s %s\e[K
\r\nSorry, there are no text files to display\r\n
\e[2J\e[1;1H\e[1;32mYour Settings\r\n
\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
@@ -164,7 +164,7 @@ User Name Location Times On\r\n
\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
\e[1;37m%-16s \e[1;36m%-32s \e[1;32m%5d\r\n
\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
-\r\nWhat is your login name:
+\r\n\e[0mWhat is your login name:
Sorry, that name is too short.\r\n
Sorry, invalid character, can only use alpha characters.\r\n
Sorry, that name is reserved.\r\n
@@ -227,8 +227,8 @@ File exists!\r\n
\e[1;30m[\e[1;37m%3d\e[1;30m] [%s\e[1;30m] \e[1;37m%s\e[0m\r\n
\e[1;32mSUB\e[0m
\e[1;31mUNSUB\e[0m
-\r\n\e[1;37mAre you sure you want to reset all messages in %s to unread? \e[0m
-\r\n\e[1;37mAre you sure you want to reset \e[1;31mall messages \e[1;37min all bases to unread? \e[0m
+\r\n\r\n\e[1;37mReset pointers to All (\e[1;33mR\e[1;37m)ead, All (\e[1;33mU\e[1;37m)nread? or Msg #:
+\r\n\r\n\e[1;37mReset \e[1;31mALL\e[1;37m pointers in \e[1;31mALL \e[1;37mareas to (\e[1;33mR\e[1;37m)ead, (\e[1;33mU\e[1;37m)nread? \e[0m
\r\n\r\n\e[1;30m[\e[1;34m%3d\e[1;30m] \e[1;33m%3ddloads \e[1;36m%4d%c \e[1;37m%-56s\r\n \e[1;31mNEW \e[0;32m
\r\nScan for new files? (Y/N) :
\r\n\e[1;37mOrder by (\e[1;32mF\e[1;37m)ilename, (\e[1;32mU\e[1;37m)pload Date, (\e[1;32mP\e[1;37m)opularity, (\e[1;32mN\e[1;37m)ew Files Only: \e[0m
@@ -252,3 +252,23 @@ File exists!\r\n
\e[1;37;44mChoose an Area in %s\e[K
\e[1;37;44mChoose an Subdir in %s\e[K
\e[1;37;44mChoose a Directory\e[K
+\r\n\e[1;37mSending file %s...\r\n
+\r\n\e[1;34mFilename\e[1;30m: \e[1;37m%s\e[0m\r\n
+ \e[1;34mURL\e[1;30m: \e[1;37m%s\e[0m\r\n
+\r\n\e[1;31mError creating URL!\e[0m\r\n
+\e[1;33mSorry this BBS does not have the webserver enabled.\e[0m\r\n
+\e[%d;1H\e[1;30;40m[\e[1;34;44m%4d\e[1;30;40m]\e[1;32m*\e[1;37m%s\e[K
+\e[%d;1H\e[1;30;40m[\e[1;34m%4d\e[1;30;40m]\e[1;32m*\e[1;37m%s\e[K
+\e[%d;1H\e[1;30;40m[\e[1;34m%4d\e[1;30;40m] \e[1;37m%-15.15s %s\e[K
+\e[1;37mNode Details for \e[1;33m%s\r\n
+\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
+ \e[1;32mSystem Name : \e[1;37m%s\r\n
+ \e[1;32mSysop Name : \e[1;37m%s\r\n
+ \e[1;32mLocation : \e[1;37m%s\r\n
+\e[1;30m-------------------------------------------------------------------------------\e[0m\r\n
+\e[%d;1H\e[1;30;40m[\e[1;34m%3d\e[1;30;40m] \e[1;37m%-18.18s \e[1;33m%-16.16s \e[1;32m%-37.37s\e[K
+\e[%d;1H\e[1;30;40m[\e[1;34;44m%3d\e[1;30;40m] \e[1;37m%-18.18s \e[1;33m%-16.16s \e[1;32m%-37.37s\e[K
+\e[1;37;44mBBS Listing\e[K
+\e[24;1H\e[1;37;44mUp / Down to Select, A to Add, D to Delete, Q to Quit\e[K
+\e[8;28H\e[1;31;40mNo BBSes in the list!
+\e[10;22H\e[1;37mPress \e[1;33mA \e[1;37m to Add yours or \e[1;33mQ \e[1;37mto Quit\e[0m
diff --git a/dist/menus/file.mnu b/dist/menus/file.mnu
index 12c2c41..ffa9c02 100644
--- a/dist/menus/file.mnu
+++ b/dist/menus/file.mnu
@@ -16,6 +16,9 @@ COMMAND UPLOAD
HOTKEY D
COMMAND DOWNLOAD
+HOTKEY W
+COMMAND GENWWWURLS
+
HOTKEY C
COMMAND CLEARTAGGED
diff --git a/dist/menus/logoff.mnu b/dist/menus/logoff.mnu
index bf69e0f..d8b1698 100644
--- a/dist/menus/logoff.mnu
+++ b/dist/menus/logoff.mnu
@@ -1,8 +1,11 @@
+LUASCRIPT logoff
ANSIFILE logoff
-CLEARSCREEN
HOTKEY Y
COMMAND LOGOFF
HOTKEY N
COMMAND PREVMENU
+
+HOTKEY F
+COMMAND SENDFEEDBACK
diff --git a/dist/menus/mail.mnu b/dist/menus/mail.mnu
index 9b3e29b..bf9bd41 100644
--- a/dist/menus/mail.mnu
+++ b/dist/menus/mail.mnu
@@ -58,3 +58,6 @@ COMMAND RESETMSGPTRS
HOTKEY X
COMMAND RESETALLMSGPTRS
+
+HOTKEY N
+COMMAND NLBROWSER
diff --git a/dist/menus/main.mnu b/dist/menus/main.mnu
index cda75ff..dd47711 100644
--- a/dist/menus/main.mnu
+++ b/dist/menus/main.mnu
@@ -43,3 +43,6 @@ COMMAND SENDNODEMSG
HOTKEY G
COMMAND SUBMENU
DATA logoff
+
+HOTKEY F
+COMMAND SENDFEEDBACK
diff --git a/dist/scripts/taglines.txt b/dist/scripts/data/taglines.txt
similarity index 100%
rename from dist/scripts/taglines.txt
rename to dist/scripts/data/taglines.txt
diff --git a/dist/scripts/login_stanza.lua b/dist/scripts/login_stanza.lua
index 69a72bc..99ef565 100644
--- a/dist/scripts/login_stanza.lua
+++ b/dist/scripts/login_stanza.lua
@@ -19,8 +19,9 @@ end
-- Display Bulletins
while(true) do
if file_exists(bulletin_path .. "/bulletin" .. string.format("%d", i) .. ".ans") then
- bbs_display_ansi("bulletin" .. string.format("%d", i));
- bbs_write_string("\027[0mPress any key to continue...\r\n");
+ bbs_write_string("\027[2J\027[1;1H");
+ bbs_display_ansi_pause("bulletin" .. string.format("%d", i));
+ bbs_write_string("\027[1;37mPress any key to continue...\027[0m");
bbs_read_char();
else
break;
@@ -37,7 +38,7 @@ local machinename;
bbsname, sysopname, systemname, machinename = bbs_get_info();
-bbs_write_string("\027[1;37mSystem Information\r\n");
+bbs_write_string("\r\n\r\n\027[1;37mSystem Information\r\n");
bbs_write_string("\027[1;30m----------------------------------------------\r\n");
bbs_write_string("\027[1;32mBBS Name : \027[1;37m" .. bbsname .. "\r\n");
bbs_write_string("\027[1;32mSysOp Name : \027[1;37m" .. sysopname .. "\r\n");
@@ -45,7 +46,7 @@ bbs_write_string("\027[1;32mNode : \027[1;37m" .. string.format("%d", bbs
bbs_write_string("\027[1;32mBBS Version : \027[1;37m" .. bbs_version() .. "\r\n");
bbs_write_string("\027[1;32mSystem : \027[1;37m" .. systemname .. " (" .. machinename .. ")\r\n");
bbs_write_string("\027[1;30m----------------------------------------------\r\n");
-bbs_write_string("\027[0mPress any key to continue...\r\n");
+bbs_write_string("\027[1;37mPress any key to continue...\027[0m");
bbs_read_char();
-- Display Last 10 Callers
@@ -55,7 +56,7 @@ local user;
local location;
local ltime;
-bbs_write_string("\r\n\027[1;37mLast 10 callers:\r\n");
+bbs_write_string("\r\n\r\n\027[1;37mLast 10 callers:\r\n");
bbs_write_string("\027[1;30m-------------------------------------------------------------------------------\r\n");
while (i < 10) do
@@ -67,7 +68,7 @@ while (i < 10) do
i = i + 1;
end
bbs_write_string("\027[1;30m-------------------------------------------------------------------------------\r\n");
-bbs_write_string("\027[0mPress any key to continue...\r\n");
+bbs_write_string("\027[1;37mPress any key to continue...\027[0m");
bbs_read_char();
-- Check email
@@ -75,9 +76,9 @@ bbs_read_char();
local email = bbs_get_emailcount();
if (email > 0) then
- bbs_write_string(string.format("\r\nYou have %d emails in your inbox\r\n", email));
+ bbs_write_string(string.format("\r\n\r\nYou have %d emails in your inbox\r\n", email));
else
- bbs_write_string("\r\nYou have no email\r\n");
+ bbs_write_string("\r\n\r\nYou have no email\r\n");
end
bbs_mail_scan();
diff --git a/dist/scripts/logoff.lua b/dist/scripts/logoff.lua
new file mode 100644
index 0000000..f6ad2d7
--- /dev/null
+++ b/dist/scripts/logoff.lua
@@ -0,0 +1,19 @@
+function menu()
+ -- display menu ansi
+ bbs_write_string("\027[2J");
+ bbs_display_ansi("logoff");
+
+
+ -- display prompt
+ bbs_write_string(string.format("\r\n\027[1;34m [\027[0;36mTime Left\027[1;37m %dm\027[34m]-> \027[0m", bbs_time_left()));
+
+ -- read char entered
+ cmd = bbs_read_char();
+
+ -- do stuff if you want
+
+
+ -- return the char entered
+
+ return cmd;
+end
diff --git a/dist/scripts/logout_stanza.lua b/dist/scripts/logout_stanza.lua
index f0cf0f5..f828476 100644
--- a/dist/scripts/logout_stanza.lua
+++ b/dist/scripts/logout_stanza.lua
@@ -1,4 +1,5 @@
function logout()
+ bbs_write_string("\027[2J");
bbs_display_ansi("goodbye");
return 1;
end
diff --git a/dist/scripts/mainmenu.lua b/dist/scripts/mainmenu.lua
index e9f6b39..d82c498 100644
--- a/dist/scripts/mainmenu.lua
+++ b/dist/scripts/mainmenu.lua
@@ -20,7 +20,7 @@ function menu()
-- display tagline
- local tLines = readLines("scripts/taglines.txt");
+ local tLines = readLines(bbs_data_path() .. "taglines.txt");
local rand = math.random(#tLines);
diff --git a/dist/www-bootstrap/401.tpl b/dist/www-bootstrap/401.tpl
new file mode 100644
index 0000000..f63524b
--- /dev/null
+++ b/dist/www-bootstrap/401.tpl
@@ -0,0 +1,2 @@
+401 - Not authorized
+The page you are looking for can not be accessed.
diff --git a/dist/www-bootstrap/403.tpl b/dist/www-bootstrap/403.tpl
new file mode 100644
index 0000000..9bd457e
--- /dev/null
+++ b/dist/www-bootstrap/403.tpl
@@ -0,0 +1,2 @@
+403 - Forbidden
+The page you are looking for can not be accessed.
diff --git a/dist/www-bootstrap/404.tpl b/dist/www-bootstrap/404.tpl
new file mode 100644
index 0000000..0c731a1
--- /dev/null
+++ b/dist/www-bootstrap/404.tpl
@@ -0,0 +1,2 @@
+404 - Page not found
+The page you are looking for can not be found.
diff --git a/dist/www-bootstrap/footer.tpl b/dist/www-bootstrap/footer.tpl
new file mode 100644
index 0000000..2a8005a
--- /dev/null
+++ b/dist/www-bootstrap/footer.tpl
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+