|
@@ -2,66 +2,59 @@
|
|
|
#include <string.h>
|
|
|
#include <unistd.h> // usleep()
|
|
|
|
|
|
+#include <fcntl.h>
|
|
|
#include <pty.h>
|
|
|
#include <termios.h>
|
|
|
-#include <fcntl.h>
|
|
|
|
|
|
#include <sys/select.h>
|
|
|
#include <sys/wait.h>
|
|
|
|
|
|
-#include <signal.h> // handle Ctrl-C/SIGINT
|
|
|
+#include <signal.h> // handle Ctrl-C/SIGINT
|
|
|
|
|
|
-#include <time.h> // usleep(), nanonsleep() ?
|
|
|
-#include <strings.h> // strcasecmp
|
|
|
+#include <strings.h> // strcasecmp
|
|
|
+#include <time.h> // usleep(), nanonsleep() ?
|
|
|
|
|
|
-#include <stdlib.h> // random()
|
|
|
#include <ctype.h>
|
|
|
+#include <stdlib.h> // random()
|
|
|
|
|
|
#include <regex.h>
|
|
|
|
|
|
// LOGGING with file output
|
|
|
|
|
|
+#include "zf_log.h"
|
|
|
#include <stdio.h>
|
|
|
#include <stdlib.h>
|
|
|
-#include "zf_log.h"
|
|
|
|
|
|
FILE *g_log_file;
|
|
|
|
|
|
-static void file_output_callback(const zf_log_message *msg, void *arg)
|
|
|
-{
|
|
|
- (void)arg;
|
|
|
- *msg->p = '\n';
|
|
|
- fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_log_file);
|
|
|
- fflush(g_log_file);
|
|
|
+static void file_output_callback(const zf_log_message *msg, void *arg) {
|
|
|
+ (void)arg;
|
|
|
+ *msg->p = '\n';
|
|
|
+ fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_log_file);
|
|
|
+ fflush(g_log_file);
|
|
|
}
|
|
|
|
|
|
-static void file_output_close(void)
|
|
|
-{
|
|
|
- fclose(g_log_file);
|
|
|
-}
|
|
|
+static void file_output_close(void) { fclose(g_log_file); }
|
|
|
|
|
|
-static void file_output_open(const char *const log_path)
|
|
|
-{
|
|
|
- g_log_file = fopen(log_path, "a");
|
|
|
- if (!g_log_file)
|
|
|
- {
|
|
|
- ZF_LOGW("Failed to open log file %s", log_path);
|
|
|
- return;
|
|
|
- }
|
|
|
- atexit(file_output_close);
|
|
|
- zf_log_set_output_v(ZF_LOG_PUT_STD, 0, file_output_callback);
|
|
|
+static void file_output_open(const char *const log_path) {
|
|
|
+ g_log_file = fopen(log_path, "a");
|
|
|
+ if (!g_log_file) {
|
|
|
+ ZF_LOGW("Failed to open log file %s", log_path);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ atexit(file_output_close);
|
|
|
+ zf_log_set_output_v(ZF_LOG_PUT_STD, 0, file_output_callback);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
// END LOGGING
|
|
|
|
|
|
-/*
|
|
|
+/*
|
|
|
What is the name of the actual, real Mystic executable
|
|
|
that we'll be executing and mangling?
|
|
|
*/
|
|
|
|
|
|
#define TARGET "./mySTIC"
|
|
|
-// Size of our input and output buffers.
|
|
|
+// Size of our input and output buffers.
|
|
|
#define BSIZE 128
|
|
|
|
|
|
/*
|
|
@@ -87,377 +80,447 @@ void slow_write(int fd, int speed, char * buffer, int len) {
|
|
|
}
|
|
|
*/
|
|
|
|
|
|
-const char * repr( const char * data) {
|
|
|
- static char buffer[4096];
|
|
|
- char * cp;
|
|
|
-
|
|
|
- strcpy( buffer, data );
|
|
|
- cp = buffer;
|
|
|
- while ( *cp != 0) {
|
|
|
- char c = *cp;
|
|
|
-
|
|
|
- if (isspace(c)) {
|
|
|
- if (c == ' ') {
|
|
|
- cp++;
|
|
|
- continue;
|
|
|
- };
|
|
|
- /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical tab ('\v') */
|
|
|
- memmove( cp + 1, cp, strlen(cp) + 1);
|
|
|
- *cp = '\\';
|
|
|
- cp++;
|
|
|
- switch(c) {
|
|
|
- case '\f':
|
|
|
- *cp = 'f';
|
|
|
- cp++;
|
|
|
- break;
|
|
|
- case '\n':
|
|
|
- *cp = 'n';
|
|
|
- cp++;
|
|
|
- break;
|
|
|
- case '\r':
|
|
|
- *cp = 'r';
|
|
|
- cp++;
|
|
|
- break;
|
|
|
- case '\t':
|
|
|
- *cp = 't';
|
|
|
- cp++;
|
|
|
- break;
|
|
|
- case '\v':
|
|
|
- *cp = 'v';
|
|
|
- cp++;
|
|
|
- break;
|
|
|
- default:
|
|
|
- *cp = '?';
|
|
|
- cp++;
|
|
|
- break;
|
|
|
- }
|
|
|
- continue;
|
|
|
- }
|
|
|
+/**
|
|
|
+ * Display a repr of the given string.
|
|
|
+ *
|
|
|
+ * This converts most \n\r\v\f\t codes,
|
|
|
+ * defaults to \xHH (hex value).
|
|
|
+ */
|
|
|
+const char *repr(const char *data) {
|
|
|
+ static char buffer[4096];
|
|
|
+ char *cp;
|
|
|
|
|
|
- if (isprint(c)) {
|
|
|
- cp++;
|
|
|
- continue;
|
|
|
- };
|
|
|
-
|
|
|
- // Ok, default to \xHH output.
|
|
|
- memmove( cp + 3, cp, strlen(cp) + 1);
|
|
|
- *cp = '\\'; cp++;
|
|
|
- *cp = 'x'; cp++;
|
|
|
- char buffer[3];
|
|
|
- sprintf(buffer, "%02x", (int)c & 0xff);
|
|
|
- *cp = buffer[0]; cp++;
|
|
|
- *cp = buffer[1]; cp++;
|
|
|
+ strcpy(buffer, data);
|
|
|
+ cp = buffer;
|
|
|
+ while (*cp != 0) {
|
|
|
+ char c = *cp;
|
|
|
+
|
|
|
+ if (isspace(c)) {
|
|
|
+ if (c == ' ') {
|
|
|
+ cp++;
|
|
|
continue;
|
|
|
+ };
|
|
|
+ /* Ok, it's form-feed ('\f'), newline ('\n'), carriage return ('\r'),
|
|
|
+ * horizontal tab ('\t'), and vertical tab ('\v') */
|
|
|
+ memmove(cp + 1, cp, strlen(cp) + 1);
|
|
|
+ *cp = '\\';
|
|
|
+ cp++;
|
|
|
+ switch (c) {
|
|
|
+ case '\f':
|
|
|
+ *cp = 'f';
|
|
|
+ cp++;
|
|
|
+ break;
|
|
|
+ case '\n':
|
|
|
+ *cp = 'n';
|
|
|
+ cp++;
|
|
|
+ break;
|
|
|
+ case '\r':
|
|
|
+ *cp = 'r';
|
|
|
+ cp++;
|
|
|
+ break;
|
|
|
+ case '\t':
|
|
|
+ *cp = 't';
|
|
|
+ cp++;
|
|
|
+ break;
|
|
|
+ case '\v':
|
|
|
+ *cp = 'v';
|
|
|
+ cp++;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ *cp = '?';
|
|
|
+ cp++;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ continue;
|
|
|
}
|
|
|
|
|
|
- /*
|
|
|
- int len = strlen(buffer);
|
|
|
- if (len > 100 ) {
|
|
|
- ZF_LOGW("len is %d, resetting to 100.", len);
|
|
|
- buffer[100] = 0;
|
|
|
+ if (isprint(c)) {
|
|
|
+ cp++;
|
|
|
+ continue;
|
|
|
};
|
|
|
- */
|
|
|
|
|
|
- return buffer;
|
|
|
-}
|
|
|
+ // Ok, default to \xHH output.
|
|
|
+ memmove(cp + 3, cp, strlen(cp) + 1);
|
|
|
+ *cp = '\\';
|
|
|
+ cp++;
|
|
|
+ *cp = 'x';
|
|
|
+ cp++;
|
|
|
+ char buffer[3];
|
|
|
+ sprintf(buffer, "%02x", (int)c & 0xff);
|
|
|
+ *cp = buffer[0];
|
|
|
+ cp++;
|
|
|
+ *cp = buffer[1];
|
|
|
+ cp++;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
+ return buffer;
|
|
|
+}
|
|
|
|
|
|
struct render {
|
|
|
- int speed;
|
|
|
- int effect;
|
|
|
+ int speed;
|
|
|
+ int effect;
|
|
|
} current_render;
|
|
|
|
|
|
int render_overlimit = 0;
|
|
|
|
|
|
void reset_render(void) {
|
|
|
- current_render.speed = 0;
|
|
|
- current_render.effect = 0;
|
|
|
- render_overlimit = 0;
|
|
|
+ current_render.speed = 0;
|
|
|
+ current_render.effect = 0;
|
|
|
+ render_overlimit = 0;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
#define TRIGGER "^"
|
|
|
// Max limit we'll sleep before ignoring effects/speed.
|
|
|
#define SLEEP_LIMIT 30
|
|
|
|
|
|
int ms_sleep(unsigned int ms) {
|
|
|
- int result = 0;
|
|
|
- struct timespec ts = {
|
|
|
- ms / 1000,
|
|
|
- (ms % 1000) * 1000000L
|
|
|
- };
|
|
|
-
|
|
|
- do {
|
|
|
- struct timespec ts_sleep = ts;
|
|
|
- result = nanosleep(&ts_sleep, &ts);
|
|
|
- } while ( (-1 == result));
|
|
|
- return result;
|
|
|
+ int result = 0;
|
|
|
+ struct timespec ts = {ms / 1000, (ms % 1000) * 1000000L};
|
|
|
+
|
|
|
+ do {
|
|
|
+ struct timespec ts_sleep = ts;
|
|
|
+ result = nanosleep(&ts_sleep, &ts);
|
|
|
+ } while ((-1 == result));
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
void render_sleep(void) {
|
|
|
- if (render_overlimit)
|
|
|
- return;
|
|
|
+ if (render_overlimit)
|
|
|
+ return;
|
|
|
|
|
|
- if (current_render.speed) { // * 100 still too slow.
|
|
|
- ms_sleep(current_render.speed * 10);
|
|
|
- }
|
|
|
+ if (current_render.speed) { // * 100 still too slow.
|
|
|
+ ms_sleep(current_render.speed * 10);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// This needs work.
|
|
|
void write_color(int fd, int color) {
|
|
|
- char buffer[10];
|
|
|
- sprintf(buffer, "\x1b[%dm", color);
|
|
|
- write(fd, buffer, strlen(buffer));
|
|
|
+ char buffer[10];
|
|
|
+ sprintf(buffer, "\x1b[%dm", color);
|
|
|
+ write(fd, buffer, strlen(buffer));
|
|
|
}
|
|
|
|
|
|
-const char * process_trigger(int fd, const char * cp) {
|
|
|
- char ch;
|
|
|
- int i, x, y;
|
|
|
- ch = toupper(*cp);
|
|
|
- cp++;
|
|
|
+/**
|
|
|
+ * process_trigger( fd, *cp )
|
|
|
+ *
|
|
|
+ * This process a command trigger.
|
|
|
+ * It has seen TRIGGER, and now it is
|
|
|
+ * processing whatever comes after it.
|
|
|
+ * It will perform the process, and
|
|
|
+ * return the char * of whatever is next.
|
|
|
+ */
|
|
|
+const char *process_trigger(int fd, const char *cp) {
|
|
|
+ char ch;
|
|
|
+ int i, x, y;
|
|
|
+ ch = toupper(*cp);
|
|
|
+ cp++;
|
|
|
+
|
|
|
+ switch (ch) {
|
|
|
+ case 'D':
|
|
|
+ i = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i *= 10;
|
|
|
+ i += (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
|
|
|
- switch(ch) {
|
|
|
- case 'D':
|
|
|
- i = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i *= 10;
|
|
|
- i += (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
-
|
|
|
- if ((i > 0) && (i < 80)) {
|
|
|
- ZF_LOGI("DEL %02d", i);
|
|
|
-
|
|
|
- for (x = 0; x < i; x++ ) {
|
|
|
- write(fd, "\b \b", 3);
|
|
|
- }
|
|
|
- };
|
|
|
- break;
|
|
|
-
|
|
|
- case 'C':
|
|
|
- i = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i *= 10;
|
|
|
- i += (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- write_color(fd, i);
|
|
|
- break;
|
|
|
-
|
|
|
- case 'G':
|
|
|
- x = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- x = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if (isdigit(*cp)) {
|
|
|
- x *= 10;
|
|
|
- x += (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- y = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- y = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if (isdigit(*cp)) {
|
|
|
- y *= 10;
|
|
|
- y += (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- break;
|
|
|
-
|
|
|
- case 'R':
|
|
|
- i = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if ( ( i > 0 ) && ( i < 10) ) {
|
|
|
- ZF_LOGI("RENDER %d", i);
|
|
|
- current_render.effect = i;
|
|
|
- } else {
|
|
|
- current_render.effect = 0;
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'S':
|
|
|
- i = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if ( ( i > 0 ) && ( i < 10) ) {
|
|
|
- ZF_LOGI( "SPEED %d", i);
|
|
|
- current_render.speed = i;
|
|
|
- } else {
|
|
|
- current_render.speed = 0;
|
|
|
- }
|
|
|
- break;
|
|
|
- case 'P':
|
|
|
- i = 0;
|
|
|
- if (isdigit(*cp)) {
|
|
|
- i = (*cp) - '0';
|
|
|
- cp++;
|
|
|
- };
|
|
|
- if ( ( i > 0 ) && ( i < 10) ) {
|
|
|
- ZF_LOGI( "PAWS %d", i);
|
|
|
- // sleep(i);
|
|
|
- if (!render_overlimit) {
|
|
|
- sleep(i);
|
|
|
- };
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
+ if ((i > 0) && (i < 80)) {
|
|
|
+ ZF_LOGI("DEL %02d", i);
|
|
|
+
|
|
|
+ for (x = 0; x < i; x++) {
|
|
|
+ write(fd, "\b \b", 3);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'C':
|
|
|
+ i = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i *= 10;
|
|
|
+ i += (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ write_color(fd, i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'G':
|
|
|
+ x = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ x = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ x *= 10;
|
|
|
+ x += (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ y = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ y = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ y *= 10;
|
|
|
+ y += (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'R':
|
|
|
+ i = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if ((i > 0) && (i < 10)) {
|
|
|
+ ZF_LOGI("RENDER %d", i);
|
|
|
+ current_render.effect = i;
|
|
|
+ } else {
|
|
|
+ current_render.effect = 0;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'S':
|
|
|
+ i = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if ((i > 0) && (i < 10)) {
|
|
|
+ ZF_LOGI("SPEED %d", i);
|
|
|
+ current_render.speed = i;
|
|
|
+ } else {
|
|
|
+ current_render.speed = 0;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 'P':
|
|
|
+ i = 0;
|
|
|
+ if (isdigit(*cp)) {
|
|
|
+ i = (*cp) - '0';
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
+ if ((i > 0) && (i < 10)) {
|
|
|
+ ZF_LOGI("PAWS %d", i);
|
|
|
+ // sleep(i);
|
|
|
+ if (!render_overlimit) {
|
|
|
+ sleep(i);
|
|
|
+ };
|
|
|
}
|
|
|
- return cp;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return cp;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * render_effect( fd, ch )
|
|
|
+ *
|
|
|
+ * Displays the given character with whatever
|
|
|
+ * rendering effect is currently active.
|
|
|
+ * (If any).
|
|
|
+ */
|
|
|
void render_effect(int fd, char ch) {
|
|
|
- int effect = current_render.effect;
|
|
|
- int l;
|
|
|
- char space = ' ';
|
|
|
- char bs = '\b';
|
|
|
-
|
|
|
- switch (effect) {
|
|
|
- case 1:
|
|
|
- // CHAR + SPC + BS
|
|
|
- render_sleep();
|
|
|
- write(fd, &ch, 1);
|
|
|
- render_sleep(); // Maybe extra sleep here? This is hard to see.
|
|
|
- write(fd, &space, 1);
|
|
|
- render_sleep();
|
|
|
- write(fd, &bs, 1);
|
|
|
- break;
|
|
|
- case 2:
|
|
|
- // CHAR + 8 spaces + 8 BS
|
|
|
- render_sleep();
|
|
|
- write(fd, &ch, 1);
|
|
|
- for(l = 0; l < 8; l++) {
|
|
|
- render_sleep();
|
|
|
- write(fd, &space, 1);
|
|
|
- }
|
|
|
- for(l = 0; l < 8; l++) {
|
|
|
- render_sleep();
|
|
|
- write(fd, &bs, 1);
|
|
|
- }
|
|
|
- break;
|
|
|
- case 0:
|
|
|
- default:
|
|
|
- // NORMAL
|
|
|
- render_sleep();
|
|
|
- write(fd, &ch, 1);
|
|
|
- break;
|
|
|
+ int effect = current_render.effect;
|
|
|
+ int l;
|
|
|
+ char space = ' ';
|
|
|
+ char bs = '\b';
|
|
|
+
|
|
|
+ switch (effect) {
|
|
|
+ case 1:
|
|
|
+ // CHAR + SPC + BS
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &ch, 1);
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &space, 1);
|
|
|
+ render_sleep();
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &bs, 1);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ // CHAR + 8 spaces + 8 BS
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &ch, 1);
|
|
|
+ for (l = 0; l < 8; l++) {
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &space, 1);
|
|
|
}
|
|
|
+ for (l = 0; l < 8; l++) {
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &bs, 1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ default:
|
|
|
+ // NORMAL
|
|
|
+ render_sleep();
|
|
|
+ write(fd, &ch, 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-void render( int fd, const char * string_out ) {
|
|
|
- const char * cp = string_out;
|
|
|
- const char * trigger = cp;
|
|
|
- time_t start = time(NULL);
|
|
|
- int elapsed;
|
|
|
- int over = 0;
|
|
|
+/**
|
|
|
+ * render( fd, string_out )
|
|
|
+ *
|
|
|
+ * Render an entire string.
|
|
|
+ * Handles TRIGGER.
|
|
|
+ * Renders with effects.
|
|
|
+ */
|
|
|
+void render(int fd, const char *string_out) {
|
|
|
+ const char *cp = string_out;
|
|
|
+ const char *trigger = cp;
|
|
|
+ time_t start = time(NULL);
|
|
|
+ int elapsed;
|
|
|
+ int over = 0;
|
|
|
+
|
|
|
+ reset_render();
|
|
|
+
|
|
|
+ ZF_LOGD("render(%d, %s)", fd, repr(string_out));
|
|
|
+
|
|
|
+ // Check our time from time to time.
|
|
|
+ // If we start running long, disable sleeps.
|
|
|
+
|
|
|
+ while ((trigger = strstr(cp, TRIGGER)) != NULL) {
|
|
|
+ // There is special things to handle in here.
|
|
|
+ while (cp != trigger) {
|
|
|
+ elapsed = time(NULL) - start;
|
|
|
+ if (elapsed > SLEEP_LIMIT) {
|
|
|
+ render_overlimit = 1;
|
|
|
+ current_render.speed = 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ // write(fd, cp, 1 );
|
|
|
+ render_effect(fd, *cp);
|
|
|
+ cp++;
|
|
|
+ };
|
|
|
|
|
|
- reset_render();
|
|
|
+ // ZF_LOGI( "at trigger: (%s)", cp);
|
|
|
+ cp += strlen(TRIGGER);
|
|
|
|
|
|
- ZF_LOGD( "render(%d, %s)", fd, string_out);
|
|
|
+ // Ok, we're pointing at the trigger -- do something.
|
|
|
+ cp = process_trigger(fd, cp);
|
|
|
|
|
|
- // Check our time from time to time.
|
|
|
- // If we start running long, kill sleeps.
|
|
|
+ // ZF_LOGI( "after trigger: (%s)", cp);
|
|
|
+ };
|
|
|
|
|
|
- while ( (trigger = strstr(cp, TRIGGER)) != NULL) {
|
|
|
- // There is special things to handle in here.
|
|
|
- while ( cp != trigger ) {
|
|
|
- elapsed = time(NULL)-start;
|
|
|
- if (elapsed > SLEEP_LIMIT) {
|
|
|
- render_overlimit = 1;
|
|
|
- current_render.speed = 0;
|
|
|
- };
|
|
|
+ // We still might be under a rendering effect.
|
|
|
+ while (*cp != 0) {
|
|
|
+ elapsed = time(NULL) - start;
|
|
|
+ if (elapsed > SLEEP_LIMIT) {
|
|
|
+ render_overlimit = 1;
|
|
|
+ current_render.speed = 0;
|
|
|
+ };
|
|
|
+ // write(fd, cp, 1);
|
|
|
+ render_effect(fd, *cp);
|
|
|
+ cp++;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- // write(fd, cp, 1 );
|
|
|
- render_effect(fd, *cp);
|
|
|
- cp++;
|
|
|
- };
|
|
|
+// Beanzilla'a no repeats
|
|
|
|
|
|
- // ZF_LOGI( "at trigger: (%s)", cp);
|
|
|
- cp += strlen(TRIGGER);
|
|
|
+/**
|
|
|
+ * have_seen( list, len, item )
|
|
|
+ *
|
|
|
+ * Returns 1 (true) if item is in the list.
|
|
|
+ * Rotates the list [x] = [x+1], and
|
|
|
+ * list[len-1] = item, return 0 (false)
|
|
|
+ */
|
|
|
+int have_seen(int *list, int len, int item) {
|
|
|
+ int x;
|
|
|
|
|
|
- // Ok, we're pointing at the trigger -- do something.
|
|
|
- cp = process_trigger(fd, cp);
|
|
|
+ for (x = 0; x < len; x++) {
|
|
|
+ if (list[x] == item) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // Ok, it is something different
|
|
|
+ for (x = 0; x < len - 1; x++) {
|
|
|
+ list[x] = list[x + 1];
|
|
|
+ };
|
|
|
+ list[x] = item;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- // ZF_LOGI( "after trigger: (%s)", cp);
|
|
|
- };
|
|
|
+/**
|
|
|
+ * init_have_seen( list, len )
|
|
|
+ *
|
|
|
+ * Initialize the have_seen list with -1.
|
|
|
+ * (-1 isn't a valid index, so we start
|
|
|
+ * out with all invalid.)
|
|
|
+ */
|
|
|
+void init_have_seen(int *list, int len) {
|
|
|
+ int x;
|
|
|
|
|
|
- // We still might be under a rendering effect.
|
|
|
- while (*cp != 0) {
|
|
|
- elapsed = time(NULL)-start;
|
|
|
- if (elapsed > SLEEP_LIMIT) {
|
|
|
- render_overlimit = 1;
|
|
|
- current_render.speed = 0;
|
|
|
- };
|
|
|
- // write(fd, cp, 1);
|
|
|
- render_effect(fd, *cp);
|
|
|
- cp++;
|
|
|
- }
|
|
|
+ for (x = 0; x < len; x++) {
|
|
|
+ list[x] = -1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
These are harry "timeout" events.
|
|
|
|
|
|
These happen when we've been sitting around awhile.
|
|
|
-
|
|
|
+
|
|
|
*/
|
|
|
+
|
|
|
+#define MAX_HARRY_EVENT_DUPS 2
|
|
|
+int last_seen_harry_event[MAX_HARRY_EVENT_DUPS];
|
|
|
+
|
|
|
void harry_event(int fd) {
|
|
|
- // Make something happen
|
|
|
- char buffer[100];
|
|
|
- int r = random() % 5;
|
|
|
-
|
|
|
- // This is no where near finished, BUT!
|
|
|
- // TO FIX: Remember the last phrase used,
|
|
|
- // and don't repeat (the last two)!
|
|
|
-
|
|
|
- const char * phrases[] =
|
|
|
- {
|
|
|
- "Hahaha",
|
|
|
- "Snicker, snicker",
|
|
|
- "Boo!",
|
|
|
- "MeOW",
|
|
|
- "I see U"
|
|
|
- };
|
|
|
- const char * cp;
|
|
|
+ // Make something happen
|
|
|
+ char buffer[100];
|
|
|
+ int r;
|
|
|
+ // This is no where near finished, BUT!
|
|
|
+ const char *phrases[] = {"Hahaha", "Snicker, snicker", "Boo!", "MeOW",
|
|
|
+ "I see U"};
|
|
|
+ const char *cp;
|
|
|
|
|
|
- cp = phrases[r];
|
|
|
+ // Remember the last phrase used,
|
|
|
+ // and don't repeat (the last two)!
|
|
|
|
|
|
- sprintf(buffer, "^S2%s^P2^D%02d", cp, (int)strlen(cp));
|
|
|
+ do {
|
|
|
+ r = random() % 5;
|
|
|
+ } while (have_seen(last_seen_harry_event, MAX_HARRY_EVENT_DUPS, r));
|
|
|
|
|
|
- ZF_LOGD( "harry_event: render(%d, \"%s\")", fd, buffer);
|
|
|
+ ZF_LOGD("%d => %d %d", r, last_seen_harry_event[0], last_seen_harry_event[1]);
|
|
|
|
|
|
- render(fd, buffer);
|
|
|
+ cp = phrases[r];
|
|
|
+
|
|
|
+ sprintf(buffer, "^S2%s^P2^D%02d", cp, (int)strlen(cp));
|
|
|
+
|
|
|
+ ZF_LOGD("harry_event: render(%d, \"%s\")", fd, buffer);
|
|
|
+
|
|
|
+ render(fd, buffer);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
+void init_harry() {
|
|
|
+ init_have_seen(last_seen_harry_event, MAX_HARRY_EVENT_DUPS);
|
|
|
+ ZF_LOGD("init => %d %d", last_seen_harry_event[0], last_seen_harry_event[1]);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
NOTE: Logging is single file, don't use in production!
|
|
|
It won't handle multiple writers.
|
|
|
*/
|
|
|
-char * username = NULL;
|
|
|
-char * fullname = NULL;
|
|
|
+char *username = NULL;
|
|
|
+char *fullname = NULL;
|
|
|
|
|
|
/*
|
|
|
Pascal String Copy. Copy from pascal string, to C String.
|
|
|
|
|
|
-First char is pascal string length. (Max 255).
|
|
|
+First char is pascal string length. (Max 255).
|
|
|
*/
|
|
|
-void pcopy(char * pstring, char * str) {
|
|
|
- int len = (int)*pstring;
|
|
|
- strncpy( str, pstring+1, len );
|
|
|
- str[len] = 0;
|
|
|
+void pcopy(char *pstring, char *str) {
|
|
|
+ int len = (int)*pstring;
|
|
|
+ strncpy(str, pstring + 1, len);
|
|
|
+ str[len] = 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -465,384 +528,457 @@ This only works for those few idiots that use the
|
|
|
horribly broken SSH crap that Mystic uses.
|
|
|
*/
|
|
|
int locate_user(const char *alias) {
|
|
|
- FILE * user;
|
|
|
- char buffer[0x600];
|
|
|
- char temp[100];
|
|
|
-
|
|
|
- user = fopen("data/users.dat", "rb");
|
|
|
- if (user == NULL)
|
|
|
- return 0;
|
|
|
-
|
|
|
- // Carry on!
|
|
|
- while (fread(buffer, 0x600, 1, user) == 1) {
|
|
|
- pcopy( buffer + 0x6d, temp );
|
|
|
- if ( strcasecmp( temp, username) == 0) {
|
|
|
- pcopy(buffer + 0x8c, temp );
|
|
|
- fullname = strdup(temp);
|
|
|
- break;
|
|
|
- }
|
|
|
- /*
|
|
|
- printf("Alias: %s\n", temp);
|
|
|
- pcopy(buffer + 0x8c, temp );
|
|
|
- printf("Full Name: %s\n", temp );
|
|
|
- */
|
|
|
+ FILE *user;
|
|
|
+ char buffer[0x600];
|
|
|
+ char temp[100];
|
|
|
+
|
|
|
+ user = fopen("data/users.dat", "rb");
|
|
|
+ if (user == NULL)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ // Carry on!
|
|
|
+ while (fread(buffer, 0x600, 1, user) == 1) {
|
|
|
+ pcopy(buffer + 0x6d, temp);
|
|
|
+ if (strcasecmp(temp, username) == 0) {
|
|
|
+ pcopy(buffer + 0x8c, temp);
|
|
|
+ fullname = strdup(temp);
|
|
|
+ break;
|
|
|
}
|
|
|
- fclose(user);
|
|
|
- return 1;
|
|
|
+ /*
|
|
|
+ printf("Alias: %s\n", temp);
|
|
|
+ pcopy(buffer + 0x8c, temp );
|
|
|
+ printf("Full Name: %s\n", temp );
|
|
|
+ */
|
|
|
+ }
|
|
|
+ fclose(user);
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
// Buffers are BSIZE + 1, so a buffer that size can strcpy safely.
|
|
|
|
|
|
-
|
|
|
regex_t ANSI;
|
|
|
regex_t WORDS;
|
|
|
regex_t WORD;
|
|
|
|
|
|
int init_regex(void) {
|
|
|
- int ret;
|
|
|
- char ansi[] = "\x1b\[[0-9]+(;[0-9]+)*?[a-zA-Z]";
|
|
|
- char words[] = "[a-zA-Z]+( [a-zA-Z]+)+";
|
|
|
- char word[] = "[a-zA-Z]+";
|
|
|
- char errorbuf[100];
|
|
|
-
|
|
|
- if ( ret = regcomp( &ANSI, ansi, REG_EXTENDED|REG_NEWLINE ) ) {
|
|
|
- regerror( ret, &ANSI, errorbuf, sizeof(errorbuf));
|
|
|
- ZF_LOGW( "Regex %s failed to compile: %s", ansi, errorbuf);
|
|
|
- return 0;
|
|
|
- };
|
|
|
+ int ret;
|
|
|
+ char ansi[] = "\x1b\[[0-9]+(;[0-9]+)*?[a-zA-Z]";
|
|
|
+ char words[] = "[a-zA-Z]+( [a-zA-Z]+)+";
|
|
|
+ char word[] = "[a-zA-Z]+";
|
|
|
+ char errorbuf[100];
|
|
|
+
|
|
|
+ if (ret = regcomp(&ANSI, ansi, REG_EXTENDED | REG_NEWLINE)) {
|
|
|
+ regerror(ret, &ANSI, errorbuf, sizeof(errorbuf));
|
|
|
+ ZF_LOGW("Regex %s failed to compile: %s", ansi, errorbuf);
|
|
|
+ return 0;
|
|
|
+ };
|
|
|
|
|
|
- if ( ret = regcomp( &WORDS, words, REG_EXTENDED|REG_NEWLINE ) ) {
|
|
|
- regerror( ret, &WORDS, errorbuf, sizeof(errorbuf));
|
|
|
- ZF_LOGW( "Regex %s failed to compile: %s", words, errorbuf);
|
|
|
- return 0;
|
|
|
- };
|
|
|
+ if (ret = regcomp(&WORDS, words, REG_EXTENDED | REG_NEWLINE)) {
|
|
|
+ regerror(ret, &WORDS, errorbuf, sizeof(errorbuf));
|
|
|
+ ZF_LOGW("Regex %s failed to compile: %s", words, errorbuf);
|
|
|
+ return 0;
|
|
|
+ };
|
|
|
|
|
|
- if ( ret = regcomp( &WORD, word, REG_EXTENDED|REG_NEWLINE ) ) {
|
|
|
- regerror( ret, &WORD, errorbuf, sizeof(errorbuf));
|
|
|
- ZF_LOGW( "Regex %s failed to compile: %s", word, errorbuf);
|
|
|
- return 0;
|
|
|
- };
|
|
|
+ if (ret = regcomp(&WORD, word, REG_EXTENDED | REG_NEWLINE)) {
|
|
|
+ regerror(ret, &WORD, errorbuf, sizeof(errorbuf));
|
|
|
+ ZF_LOGW("Regex %s failed to compile: %s", word, errorbuf);
|
|
|
+ return 0;
|
|
|
+ };
|
|
|
|
|
|
- return 1;
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
-int regmatch( regex_t *preg, const char * string, size_t nmatch, regmatch_t pmatch[], int eflags) {
|
|
|
- // returns number of matches found. (Max nmatch)
|
|
|
- int matches = 0;
|
|
|
- int offset = 0;
|
|
|
- int ret;
|
|
|
-
|
|
|
- while (matches < nmatch) {
|
|
|
- ret = regexec( preg, string + offset, nmatch - matches, pmatch + matches, eflags);
|
|
|
- if (!ret) {
|
|
|
- int current = offset;
|
|
|
- offset += pmatch[matches].rm_eo;
|
|
|
- pmatch[matches].rm_so += current;
|
|
|
- pmatch[matches].rm_eo += current;
|
|
|
- matches++;
|
|
|
- } else if (ret == REG_NOMATCH ) {
|
|
|
- break;
|
|
|
- } else {
|
|
|
- break;
|
|
|
- }
|
|
|
+int regmatch(regex_t *preg, const char *string, size_t nmatch,
|
|
|
+ regmatch_t pmatch[], int eflags) {
|
|
|
+ // returns number of matches found. (Max nmatch)
|
|
|
+ int matches = 0;
|
|
|
+ int offset = 0;
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ while (matches < nmatch) {
|
|
|
+ ret = regexec(preg, string + offset, nmatch - matches, pmatch + matches,
|
|
|
+ eflags);
|
|
|
+ if (!ret) {
|
|
|
+ int current = offset;
|
|
|
+ offset += pmatch[matches].rm_eo;
|
|
|
+ pmatch[matches].rm_so += current;
|
|
|
+ pmatch[matches].rm_eo += current;
|
|
|
+ matches++;
|
|
|
+ } else if (ret == REG_NOMATCH) {
|
|
|
+ break;
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
}
|
|
|
- return matches;
|
|
|
-}
|
|
|
+ }
|
|
|
+ return matches;
|
|
|
+}
|
|
|
|
|
|
-#define MAX_MATCH 10
|
|
|
-regmatch_t rxmatch[ MAX_MATCH ];
|
|
|
+#define MAX_MATCH 32
|
|
|
+regmatch_t rxmatch[MAX_MATCH];
|
|
|
|
|
|
-int rx_match(regex_t * regex, const char * buffer) {
|
|
|
- int ret;
|
|
|
+int rx_match(regex_t *regex, const char *buffer) {
|
|
|
+ int ret;
|
|
|
|
|
|
- ret = regmatch(regex, buffer, MAX_MATCH, rxmatch, 0);
|
|
|
- for( int i = 0; i < ret; i++ ) {
|
|
|
- ZF_LOGI("%d : (%d-%d)", i, rxmatch[i].rm_so, rxmatch[i].rm_eo);
|
|
|
+ ret = regmatch(regex, buffer, MAX_MATCH, rxmatch, 0);
|
|
|
+ if (0) {
|
|
|
+ for (int i = 0; i < ret; i++) {
|
|
|
+ ZF_LOGI("%d : (%d-%d)", i, rxmatch[i].rm_so, rxmatch[i].rm_eo);
|
|
|
}
|
|
|
- return ret;
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
-int mangle( int fd, char * buffer ) {
|
|
|
- int x, i;
|
|
|
- int m = 0;
|
|
|
-
|
|
|
- // Ok, we want to look for words to:
|
|
|
- // MaNGlE , or transpose (both?!)
|
|
|
- // or possibly transpose words
|
|
|
- char work[ BSIZE + 1];
|
|
|
+/*
|
|
|
+Terminal processing section.
|
|
|
|
|
|
- ZF_LOGI("mangle: %s", repr(buffer));
|
|
|
- strcpy( work, buffer );
|
|
|
+Monitor lines, position, color.
|
|
|
|
|
|
- /*
|
|
|
- NOTE: We copy the buffer, so we can clear out ANSI codes, etc.
|
|
|
- Otherwise we might mess some ANSI up!
|
|
|
- */
|
|
|
-
|
|
|
- /*
|
|
|
- (random) Look for ANSI CLS and:
|
|
|
+What screen size do I want to emulate?
|
|
|
|
|
|
- display random spooky texts around, with delays ... then CLS.
|
|
|
+ANSI codes.
|
|
|
|
|
|
- display ANSI graphic file, with delays ... then CLS
|
|
|
- */
|
|
|
+Do I need this??
|
|
|
|
|
|
- /* work -- clear out ANSI so we don't mangle ANSI codes. */
|
|
|
- x = rx_match(&ANSI, work );
|
|
|
- if ( x > 0) {
|
|
|
- ZF_LOGD("found %d ANSI", x);
|
|
|
- for( i = 0; i < x; i++ ) {
|
|
|
- memset(work + rxmatch[i].rm_so, '-', rxmatch[i].rm_eo - rxmatch[i].rm_so);
|
|
|
- ZF_LOGD( "Now %d : %s", i, repr(work));
|
|
|
- };
|
|
|
- }
|
|
|
+*/
|
|
|
|
|
|
- ZF_LOGI("mangle: %s", repr(work));
|
|
|
+int random_activate(int w) {
|
|
|
+ int r = random() % 100;
|
|
|
+ if (r <= (w * 10)) {
|
|
|
+ return 1;
|
|
|
+ };
|
|
|
+ return 0;
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- (random) Locate words (in work), and possibly flip them around.
|
|
|
- Transpose words. Transpose case. Transpose letters.
|
|
|
- */
|
|
|
- x = rx_match(&WORDS, work );
|
|
|
- ZF_LOGD("found %d WORDS", x );
|
|
|
-
|
|
|
- if ( x > 0 ) {
|
|
|
- for( i = 0; i < x; i++ ) {
|
|
|
- // Do things here.
|
|
|
- if ( i % 3 == 0 ) {
|
|
|
- for( int p = rxmatch[i].rm_so; p < rxmatch[i].rm_eo; p++ ) {
|
|
|
- buffer[p] = tolower(buffer[p]);
|
|
|
- m++;
|
|
|
- }
|
|
|
- } else {
|
|
|
- if ( i % 3 == 1 ) {
|
|
|
- for( int p = rxmatch[i].rm_so; p < rxmatch[i].rm_eo; p++ ) {
|
|
|
- buffer[p] = toupper(buffer[p]);
|
|
|
- m++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
+/*
|
|
|
+ * The buffer that we've been given is much larger now.
|
|
|
+ *
|
|
|
+ */
|
|
|
+int mangle(int fd, char *buffer) {
|
|
|
+ int x, i;
|
|
|
+ int need_render = 0; // changing word case around doesn't need the render
|
|
|
+ int mangled = 0;
|
|
|
+
|
|
|
+ char *cp;
|
|
|
+
|
|
|
+ // Ok, we want to look for words to:
|
|
|
+ // MaNGlE , or transpose (both?!)
|
|
|
+ // or possibly transpose words
|
|
|
+ char work[(BSIZE * 4) + 1];
|
|
|
+
|
|
|
+ ZF_LOGI("mangle(%s)", repr(buffer));
|
|
|
+ strcpy(work, buffer);
|
|
|
+
|
|
|
+ /*
|
|
|
+ NOTE: We copy the buffer, so we can clear out ANSI codes, etc.
|
|
|
+ Otherwise we might mess some ANSI up in the manglying
|
|
|
+ process.
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ (random) Look for ANSI CLS and:
|
|
|
+
|
|
|
+ display random spooky texts around, with delays ... then CLS.
|
|
|
+
|
|
|
+ display ANSI graphic file, with delays ... then CLS
|
|
|
+ */
|
|
|
+ const char *ANSI_CLS = "\x1b[2J";
|
|
|
+ cp = strstr(buffer, ANSI_CLS);
|
|
|
+
|
|
|
+ if (cp != NULL) {
|
|
|
+ ZF_LOGI("seen: ANSI_CLS");
|
|
|
+
|
|
|
+ if (random_activate(9)) {
|
|
|
+ char display[100] = "";
|
|
|
+
|
|
|
+ ZF_LOGI("mangle(ANSI_CLS)");
|
|
|
+ // sprintf( display, "^P2...");
|
|
|
+ // This string actually screws up ANSI detection (takes too long)
|
|
|
+ // strcpy(display, "^P2^S501234567890^P1abcdef^P2g^P3h^P4i^S0^P2");
|
|
|
+
|
|
|
+ strcpy(display, "^P2^S301234^P15^S0^P2");
|
|
|
+ // Move the buffer so there's room for the display string.
|
|
|
+ memmove(cp + strlen(display), cp, strlen(cp) + 1);
|
|
|
+ strncpy(cp, display, strlen(display));
|
|
|
+ ZF_LOGI("mangle(ANSI_CLS): (%d) %s", (int)strlen(buffer), repr(buffer));
|
|
|
+ need_render = 1;
|
|
|
+
|
|
|
+ /*
|
|
|
+ Copy the new buffer over, but hide our "render" code
|
|
|
+ from the remaining mangler steps.
|
|
|
+ */
|
|
|
+ strcpy(work, buffer);
|
|
|
+ i = cp - buffer;
|
|
|
+ // find offset into "buffer"
|
|
|
+ // apply to work.
|
|
|
+ memset(work + i, ' ', strlen(display));
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /* work -- clear out ANSI so we don't mangle ANSI codes. */
|
|
|
+ x = rx_match(&ANSI, work);
|
|
|
+ char replace_with = ' ';
|
|
|
+ if (x > 0) {
|
|
|
+ ZF_LOGD("found %d ANSI", x);
|
|
|
+ for (i = 0; i < x; i++) {
|
|
|
+ memset(work + rxmatch[i].rm_so, replace_with,
|
|
|
+ rxmatch[i].rm_eo - rxmatch[i].rm_so);
|
|
|
+ };
|
|
|
+ ZF_LOGD("Work Now : (%d) %s", (int)strlen(work), repr(work));
|
|
|
+ }
|
|
|
+
|
|
|
+ // ZF_LOGI("mangle: %s", repr(work));
|
|
|
+
|
|
|
+ /*
|
|
|
+ (random) Locate words (in work), and possibly flip them around.
|
|
|
+ Transpose words. Transpose case. Transpose letters.
|
|
|
+ */
|
|
|
+ x = rx_match(&WORDS, work);
|
|
|
+ ZF_LOGD("found %d WORDS", x);
|
|
|
+
|
|
|
+ if (x > 0) {
|
|
|
+ for (i = 0; i < x; i++) {
|
|
|
+ // Do things here.
|
|
|
+ if (i % 3 == 0) {
|
|
|
+ for (int p = rxmatch[i].rm_so; p < rxmatch[i].rm_eo; p++) {
|
|
|
+ buffer[p] = tolower(buffer[p]);
|
|
|
+ mangled++;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ if (i % 3 == 1) {
|
|
|
+ for (int p = rxmatch[i].rm_so; p < rxmatch[i].rm_eo; p++) {
|
|
|
+ buffer[p] = toupper(buffer[p]);
|
|
|
+ mangled++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- /*
|
|
|
- (random) Locate single words, and transpose them. Transpose case.
|
|
|
- Transpose letters.
|
|
|
- */
|
|
|
-
|
|
|
- /*
|
|
|
- (random) Display up to certain point. Delay.
|
|
|
- Print some characters slowly. Delay.
|
|
|
- */
|
|
|
-
|
|
|
- if (m) {
|
|
|
- ZF_LOGD("HH %d : %s", m, repr(buffer));
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ (random) Locate single words, and transpose them. Transpose case.
|
|
|
+ Transpose letters.
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ (random) Display up to certain point. Delay.
|
|
|
+ Print some characters slowly. Delay.
|
|
|
+ */
|
|
|
+
|
|
|
+ if (need_render) {
|
|
|
+ ZF_LOGD("HH %d : (%d) %s", need_render, (int)strlen(buffer), repr(buffer));
|
|
|
+ } else {
|
|
|
+ if (mangled) {
|
|
|
+ ZF_LOGD("Mangled %d : %s", mangled, repr(buffer));
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
+ if (need_render) {
|
|
|
+ render(fd, buffer);
|
|
|
+ } else {
|
|
|
write(fd, buffer, strlen(buffer));
|
|
|
- return m;
|
|
|
+ };
|
|
|
+ return need_render && mangled;
|
|
|
}
|
|
|
|
|
|
-int harry_happens( time_t *last_event, int wakeup ) {
|
|
|
- time_t now = time(NULL);
|
|
|
- int elapsed = now - *last_event;
|
|
|
+int harry_happens(time_t *last_event, int wakeup) {
|
|
|
+ time_t now = time(NULL);
|
|
|
+ int elapsed = now - *last_event;
|
|
|
|
|
|
- if ( elapsed > wakeup ) {
|
|
|
- // Ok! It's been too long since we've done something.
|
|
|
- *last_event = now;
|
|
|
- return 1;
|
|
|
- }
|
|
|
- return 0;
|
|
|
+ if (elapsed > wakeup) {
|
|
|
+ // Ok! It's been too long since we've done something.
|
|
|
+ *last_event = now;
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-int main(int argc, char * argv[])
|
|
|
-{
|
|
|
- int master;
|
|
|
- pid_t pid;
|
|
|
- int node = -1;
|
|
|
-
|
|
|
- file_output_open("horrible_harry.log");
|
|
|
-
|
|
|
- srandom(time(NULL));
|
|
|
+int main(int argc, char *argv[]) {
|
|
|
+ int master;
|
|
|
+ pid_t pid;
|
|
|
+ int node = -1;
|
|
|
|
|
|
- // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUWISHPASSWORD
|
|
|
- // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
|
|
|
+ file_output_open("horrible_harry.log");
|
|
|
+ init_harry();
|
|
|
|
|
|
- // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUP2LAT3
|
|
|
- // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
|
|
|
+ srandom(time(NULL));
|
|
|
|
|
|
- // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
|
|
|
- // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML0 -SL1 -ST0 -CUnknown
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz
|
|
|
+ // -PUWISHPASSWORD
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
|
|
|
|
|
|
- // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUP2LAT3
|
|
|
- // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML1 -SL1 -ST2 -CUnknown -Ubugz -PUP2LAT3
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz
|
|
|
+ // -PUP2LAT3
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
|
|
|
|
|
|
- // SSH: -ML1 -ST2
|
|
|
- // Telnet: -ML0 -ST0
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
|
|
|
+ // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML0 -SL1 -ST0 -CUnknown
|
|
|
|
|
|
+ // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz
|
|
|
+ // -PUP2LAT3
|
|
|
+ // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML1 -SL1 -ST2 -CUnknown -Ubugz
|
|
|
+ // -PUP2LAT3
|
|
|
|
|
|
- // Locate username (if given) in the command line
|
|
|
- // -U<username>
|
|
|
- for (int x = 0; x < argc; x++) {
|
|
|
- if (strncmp("-U", argv[x], 2) == 0) {
|
|
|
- username = argv[x] + 2;
|
|
|
- ZF_LOGI( "Username: [%s]", username);
|
|
|
- };
|
|
|
- if (strncmp("-SL", argv[x], 3) == 0) {
|
|
|
- node = argv[x][3] - '0' + 1;
|
|
|
- ZF_LOGI( "Node: %d", node);
|
|
|
- }
|
|
|
- }
|
|
|
+ // SSH: -ML1 -ST2
|
|
|
+ // Telnet: -ML0 -ST0
|
|
|
|
|
|
- if (username != NULL) {
|
|
|
- locate_user(username);
|
|
|
- ZF_LOGD( "Username: [%s] A.K.A. [%s]", username, fullname);
|
|
|
- }
|
|
|
-
|
|
|
- if ( !init_regex() )
|
|
|
- return 2;
|
|
|
-
|
|
|
- // With IGNBRK I don't think I need this anymore. (Nope!)
|
|
|
- // signal(SIGINT, SIG_IGN);
|
|
|
-
|
|
|
- pid = forkpty(&master, NULL, NULL, NULL);
|
|
|
-
|
|
|
- // impossible to fork
|
|
|
- if (pid < 0) {
|
|
|
- return 1;
|
|
|
- }
|
|
|
-
|
|
|
- // child
|
|
|
- else if (pid == 0) {
|
|
|
- char *args[20]; // max 20 args
|
|
|
- int x;
|
|
|
- args[0] = TARGET;
|
|
|
-
|
|
|
- for ( x = 1; x < argc; x++ ) {
|
|
|
- args[x] = argv[x];
|
|
|
- };
|
|
|
- args[x] = NULL;
|
|
|
- // run Mystic, run!
|
|
|
- execvp( TARGET, args);
|
|
|
+ // Locate username (if given) in the command line
|
|
|
+ // -U<username>
|
|
|
+ for (int x = 0; x < argc; x++) {
|
|
|
+ if (strncmp("-U", argv[x], 2) == 0) {
|
|
|
+ username = argv[x] + 2;
|
|
|
+ ZF_LOGI("Username: [%s]", username);
|
|
|
+ };
|
|
|
+ if (strncmp("-SL", argv[x], 3) == 0) {
|
|
|
+ node = argv[x][3] - '0' + 1;
|
|
|
+ ZF_LOGI("Node: %d", node);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- // parent
|
|
|
- else {
|
|
|
- // remove the echo
|
|
|
- // ICANON - raw mode. No more line buffering!
|
|
|
- struct termios tios, orig1;
|
|
|
- struct timeval timeout;
|
|
|
- time_t last_event = 0; // time(NULL);
|
|
|
-
|
|
|
- ZF_LOGD("starting");
|
|
|
+ if (username != NULL) {
|
|
|
+ locate_user(username);
|
|
|
+ ZF_LOGD("Username: [%s] A.K.A. [%s]", username, fullname);
|
|
|
+ }
|
|
|
|
|
|
- tcgetattr(master, &tios);
|
|
|
- tios.c_lflag &= ~(ECHO | ECHONL | ICANON );
|
|
|
- tcsetattr(master, TCSAFLUSH, &tios);
|
|
|
+ if (!init_regex())
|
|
|
+ return 2;
|
|
|
|
|
|
- tcgetattr(1, &orig1);
|
|
|
- tios = orig1;
|
|
|
- tios.c_iflag &= ~(ICRNL | IXON); // Disable software flow control
|
|
|
+ // With IGNBRK I don't think I need this anymore. (Nope!)
|
|
|
+ // signal(SIGINT, SIG_IGN);
|
|
|
|
|
|
- tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN );
|
|
|
+ pid = forkpty(&master, NULL, NULL, NULL);
|
|
|
|
|
|
- // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
|
|
|
- // ISIG should be Ctrl-C and Ctrl-Z IGNBRK +
|
|
|
- tcsetattr(1, TCSAFLUSH, &tios);
|
|
|
-
|
|
|
-
|
|
|
- for (;;) {
|
|
|
-
|
|
|
- // define estruturas para o select, que serve para verificar qual
|
|
|
- // se tornou "pronto pra uso"
|
|
|
- fd_set read_fd;
|
|
|
- fd_set write_fd;
|
|
|
- fd_set except_fd;
|
|
|
-
|
|
|
- // inicializa as estruturas
|
|
|
- FD_ZERO(&read_fd);
|
|
|
- FD_ZERO(&write_fd);
|
|
|
- FD_ZERO(&except_fd);
|
|
|
-
|
|
|
- // atribui o descritor master, obtido pelo forkpty, ao read_fd
|
|
|
- FD_SET(master, &read_fd);
|
|
|
- // atribui o stdin ao read_fd
|
|
|
- FD_SET(STDIN_FILENO, &read_fd);
|
|
|
-
|
|
|
- // o descritor tem que ser unico para o programa, a documentacao
|
|
|
- // recomenda um calculo entre os descritores sendo usados + 1
|
|
|
-
|
|
|
- /*
|
|
|
- TODO: Figure out how this would work.
|
|
|
-
|
|
|
- I'm thinking something like timeouts 30-50 seconds?
|
|
|
- And as we get closer, 15-25 seconds.
|
|
|
- */
|
|
|
-
|
|
|
- // we're in luck! The last parameter is time interval/timeout. :D
|
|
|
- timeout.tv_sec = 10;
|
|
|
- timeout.tv_usec = 0;
|
|
|
+ // impossible to fork
|
|
|
+ if (pid < 0) {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
|
|
|
- // select(master+1, &read_fd, &write_fd, &except_fd, NULL);
|
|
|
- if ( select(master+1, &read_fd, &write_fd, &except_fd, &timeout) == 0 ) {
|
|
|
- // This means timeout!
|
|
|
- ZF_LOGI("TIMEOUT");
|
|
|
- harry_event(STDOUT_FILENO);
|
|
|
- }
|
|
|
+ // child
|
|
|
+ else if (pid == 0) {
|
|
|
+ char *args[20]; // max 20 args
|
|
|
+ int x;
|
|
|
+ args[0] = TARGET;
|
|
|
|
|
|
- char input[BSIZE + 1];
|
|
|
- char output[BSIZE + 1];
|
|
|
- int total;
|
|
|
-
|
|
|
- // read_fd esta atribuido com read_fd?
|
|
|
- if (FD_ISSET(master, &read_fd))
|
|
|
- {
|
|
|
- // leia o que bc esta mandando
|
|
|
- if ((total = read(master, &output, BSIZE)) != -1) {
|
|
|
- // e escreva isso na saida padrao
|
|
|
- output[total] = 0;
|
|
|
-
|
|
|
- if (harry_happens( &last_event, 5)) {
|
|
|
- ZF_LOGI( "harry_happens");
|
|
|
- if ( mangle( STDOUT_FILENO, output ) == 0 ) {
|
|
|
- // failed, so. Try again.
|
|
|
- last_event = 0;
|
|
|
- }
|
|
|
- } else {
|
|
|
- write(STDOUT_FILENO, &output, total);
|
|
|
- // This is OUTPUT from the BBS
|
|
|
- // ZF_LOGI( ">> %s", repr(output));
|
|
|
- ZF_LOGI( ">> %d chars", (int)strlen(output));
|
|
|
- // I think repr is flipping out here. :(
|
|
|
- // ZF_LOGI( ">> %d", (int)strlen(repr(output)));
|
|
|
- }
|
|
|
-
|
|
|
- } else
|
|
|
- break;
|
|
|
+ for (x = 1; x < argc; x++) {
|
|
|
+ args[x] = argv[x];
|
|
|
+ };
|
|
|
+ args[x] = NULL;
|
|
|
+ // run Mystic, run!
|
|
|
+ execvp(TARGET, args);
|
|
|
+ }
|
|
|
+
|
|
|
+ // parent
|
|
|
+ else {
|
|
|
+ // remove the echo
|
|
|
+ // ICANON - raw mode. No more line buffering!
|
|
|
+ struct termios tios, orig1;
|
|
|
+ struct timeval timeout;
|
|
|
+ time_t last_event = 0; // time(NULL);
|
|
|
+
|
|
|
+ ZF_LOGD("starting");
|
|
|
+
|
|
|
+ tcgetattr(master, &tios);
|
|
|
+ tios.c_lflag &= ~(ECHO | ECHONL | ICANON);
|
|
|
+ tcsetattr(master, TCSAFLUSH, &tios);
|
|
|
+
|
|
|
+ tcgetattr(1, &orig1);
|
|
|
+ tios = orig1;
|
|
|
+ tios.c_iflag &= ~(ICRNL | IXON); // Disable software flow control
|
|
|
+
|
|
|
+ tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
|
|
+
|
|
|
+ // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
|
|
|
+ // ISIG should be Ctrl-C and Ctrl-Z IGNBRK +
|
|
|
+ tcsetattr(1, TCSAFLUSH, &tios);
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+
|
|
|
+ // define estruturas para o select, que serve para verificar qual
|
|
|
+ // se tornou "pronto pra uso"
|
|
|
+ fd_set read_fd;
|
|
|
+ fd_set write_fd;
|
|
|
+ fd_set except_fd;
|
|
|
+
|
|
|
+ // inicializa as estruturas
|
|
|
+ FD_ZERO(&read_fd);
|
|
|
+ FD_ZERO(&write_fd);
|
|
|
+ FD_ZERO(&except_fd);
|
|
|
+
|
|
|
+ // atribui o descritor master, obtido pelo forkpty, ao read_fd
|
|
|
+ FD_SET(master, &read_fd);
|
|
|
+ // atribui o stdin ao read_fd
|
|
|
+ FD_SET(STDIN_FILENO, &read_fd);
|
|
|
+
|
|
|
+ // o descritor tem que ser unico para o programa, a documentacao
|
|
|
+ // recomenda um calculo entre os descritores sendo usados + 1
|
|
|
+
|
|
|
+ /*
|
|
|
+ TODO: Figure out how this would work.
|
|
|
+
|
|
|
+ I'm thinking something like timeouts 30-50 seconds?
|
|
|
+ And as we get closer, 15-25 seconds.
|
|
|
+ */
|
|
|
+
|
|
|
+ // we're in luck! The last parameter is time interval/timeout. :D
|
|
|
+ timeout.tv_sec = 10;
|
|
|
+ timeout.tv_usec = 0;
|
|
|
+
|
|
|
+ // select(master+1, &read_fd, &write_fd, &except_fd, NULL);
|
|
|
+ if (select(master + 1, &read_fd, &write_fd, &except_fd, &timeout) == 0) {
|
|
|
+ // This means timeout!
|
|
|
+ ZF_LOGI("TIMEOUT");
|
|
|
+ harry_event(STDOUT_FILENO);
|
|
|
+ }
|
|
|
+
|
|
|
+ char input[BSIZE + 1];
|
|
|
+ static char output[(BSIZE * 4) + 1];
|
|
|
+ int total;
|
|
|
+
|
|
|
+ // read_fd esta atribuido com read_fd?
|
|
|
+ if (FD_ISSET(master, &read_fd)) {
|
|
|
+ // leia o que bc esta mandando
|
|
|
+ if ((total = read(master, &output, BSIZE)) != -1) {
|
|
|
+ // e escreva isso na saida padrao
|
|
|
+ output[total] = 0;
|
|
|
+
|
|
|
+ // if ( harry_happens( &last_event, 5)) {
|
|
|
+ if (1) {
|
|
|
+ ZF_LOGI("harry_happens");
|
|
|
+ if (mangle(STDOUT_FILENO, output) == 0) {
|
|
|
+ // failed, so. Try again.
|
|
|
+ last_event = 0;
|
|
|
}
|
|
|
-
|
|
|
- // read_fd esta atribuido com a entrada padrao?
|
|
|
- if (FD_ISSET(STDIN_FILENO, &read_fd))
|
|
|
- {
|
|
|
- // leia a entrada padrao
|
|
|
- total = read(STDIN_FILENO, &input, BSIZE);
|
|
|
- input[total] = 0;
|
|
|
- // e escreva no bc
|
|
|
- ZF_LOGI( "<< %s", repr(input));
|
|
|
-
|
|
|
- write(master, &input, total);
|
|
|
-
|
|
|
- // This is INPUT from the USER
|
|
|
- // ZF_LOGI_MEM( input, strlen(input), "<< ");
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- // Restore terminal
|
|
|
- tcsetattr(1, TCSAFLUSH, &orig1);
|
|
|
- ZF_LOGD("exit");
|
|
|
+ } else {
|
|
|
+ write(STDOUT_FILENO, &output, total);
|
|
|
+ // This is OUTPUT from the BBS
|
|
|
+ // ZF_LOGI( ">> %s", repr(output));
|
|
|
+ ZF_LOGI(">> %d chars", (int)strlen(output));
|
|
|
+ // I think repr is flipping out here. :(
|
|
|
+ // ZF_LOGI( ">> %d", (int)strlen(repr(output)));
|
|
|
+ }
|
|
|
+
|
|
|
+ } else
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // read_fd esta atribuido com a entrada padrao?
|
|
|
+ if (FD_ISSET(STDIN_FILENO, &read_fd)) {
|
|
|
+ // leia a entrada padrao
|
|
|
+ total = read(STDIN_FILENO, &input, BSIZE);
|
|
|
+ input[total] = 0;
|
|
|
+ // e escreva no bc
|
|
|
+ ZF_LOGI("<< %s", repr(input));
|
|
|
+
|
|
|
+ write(master, &input, total);
|
|
|
+
|
|
|
+ // This is INPUT from the USER
|
|
|
+ // ZF_LOGI_MEM( input, strlen(input), "<< ");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ // Restore terminal
|
|
|
+ tcsetattr(1, TCSAFLUSH, &orig1);
|
|
|
+ ZF_LOGD("exit");
|
|
|
+ }
|
|
|
|
|
|
+ return 0;
|
|
|
+}
|