瀏覽代碼

Cleanup of mystic Horrible Harry project.

Steve Thielemann 5 年之前
當前提交
ee620c3dc1
共有 3 個文件被更改,包括 432 次插入0 次删除
  1. 52 0
      CMakeLists.txt
  2. 274 0
      mystic.c
  3. 106 0
      try-re.c

+ 52 - 0
CMakeLists.txt

@@ -0,0 +1,52 @@
+cmake_minimum_required(VERSION 3.10)
+
+project(MyProject)
+
+
+###########
+# Debug or Release
+###########
+if (NOT CMAKE_BUILD_TYPE)
+  ## set default to Debug
+  set(CMAKE_BUILD_TYPE Debug)  # override with -DCMAKE_BUILD_TYPE=Release
+  message("==> CMAKE_BUILD_TYPE empty. Changing it to Debug.")
+else()
+  message("==> CMAKE_BUILD_TYPE == ${CMAKE_BUILD_TYPE}.")
+endif()
+
+
+
+## https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_macros.html
+## During Debug, use debug version of libstdc++ (asserts on access to invalid iterators, etc!)
+set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_GLIBCXX_DEBUG")
+
+
+###########
+# Suppress certain warnings
+###########
+# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-deprecated-declarations")
+
+
+##############
+# C++ Standard
+##############
+set(CMAKE_CXX_STANDARD   14)
+set(CMAKE_CXX_EXTENSIONS OFF)
+
+
+# Enable testing
+# set(BUILD_TESTING ON)
+# include(CTest)
+
+
+
+# Example for how to define a test which uses gtest_gmock
+# add_executable(mytest tester.cpp)
+# target_link_libraries(mytest gmock_main)
+
+add_executable(mystic mystic.c)
+target_link_libraries(mystic util)
+
+add_executable(try-re try-re.c)
+
+

+ 274 - 0
mystic.c

@@ -0,0 +1,274 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.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 <time.h>       // usleep(), nanonsleep() ? 
+#include <strings.h>    // strcasecmp
+
+#include <stdlib.h>     // random()
+
+#define TARGET "./mySTIC"
+#define BSIZE 1024
+#define LOGGING
+
+const char * it_is_now(void) {
+    static char buffer[100];
+    time_t timer;
+    struct tm* tm_info;
+
+    timer = time(NULL);
+    tm_info = localtime(&timer);
+    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
+    return buffer;
+}
+
+void slow_write(int fd, int speed, char * buffer, int len) {
+    int x;
+    for( x = 0; x < len; x++) {
+        usleep(speed);
+        write( fd, &buffer[x], 1);
+    }
+}
+
+void harry_event(int fd) {
+    // Make something happen
+    char clear[] = "\b \b";
+    int x;
+    char haha[] = "Hahaha hahaha!!!";
+    char beep = '\a';
+
+    slow_write(fd, 11500, haha, strlen(haha) );
+    write(fd, &beep, 1);
+    sleep(3);
+    for( x = 0; x < strlen(haha); x++ ) {
+        write(fd, clear, strlen(clear) );
+    };
+}
+
+/* 
+NOTE: Logging is single file, don't use in production!
+It won't handle multiple writers.
+*/
+char * username = NULL;
+char * fullname = NULL;
+
+void pcopy(char * pstring, char * str) {
+    int len = (int)*pstring;
+    strncpy( str, pstring+1, len );
+    str[len] = 0;
+}
+
+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 );
+        */
+    }
+    fclose(user);
+    return 1;
+}
+
+// Buffers are BSIZE + 1, so a buffer that size can strcpy safely.
+
+void mangle( char * buffer ) {
+    // Ok, we want to look for words to:
+    // MaNGlE , or transpose (both?!)
+    // or possibly transpose words
+
+}
+
+int main(int argc, char * argv[])
+{
+    int master;
+    pid_t pid;
+    
+#ifdef LOGGING    
+    FILE * fp;
+
+    fp = fopen("mystic_pipe.data", "wb");
+    if ( fp == NULL ) {
+        return 2;
+    }
+#endif
+
+    srandom(time(NULL));
+
+    // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUWISHPASSWORD
+
+    // -U<username>
+    for (int x = 0; x < argc; x++) {
+        if (strncmp("-U", argv[x], 2) == 0) {
+            username = argv[x] + 2;
+#ifdef LOGGING
+            fprintf(fp, "Username: [%s]\n", username);
+#endif            
+            break;
+        }
+    }
+
+    if (username != NULL) {
+        locate_user(username);
+#ifdef LOGGING
+        fprintf(fp, "Username: [%s] A.K.A. [%s]\n", username, fullname);
+#endif        
+    }
+
+    // With IGNBRK  I don't think I need this anymore.
+    // 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;
+        // char *args[] = { "vim", "test.txt", NULL }; // argv; //{ 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;
+        int last_event;
+
+        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
+
+            // 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!
+                harry_event(STDOUT_FILENO);
+#ifdef LOGGING
+                fprintf(fp, "%s : TICK\n", it_is_now());
+#endif                
+            }
+
+            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 (random() % 20 < 3) {
+                        mangle( output );
+                    }
+
+                    write(STDOUT_FILENO, &output, total);
+
+                    // This is OUTPUT from the BBS
+#ifdef LOGGING
+                    fprintf(fp, ">> [%s]\n", output);
+#endif
+                } 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
+                write(master, &input, total);
+
+                // This is INPUT from the USER
+#ifdef LOGGING
+                fprintf(fp, "<< [%s]\n", input);
+#endif
+             }
+        }
+
+        tcsetattr(1, TCSAFLUSH, &orig1);
+#ifdef LOGGING
+        fclose(fp);
+#endif        
+    }
+    return 0;
+}
+

+ 106 - 0
try-re.c

@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <string.h>
+#include <regex.h>
+
+regex_t regex;
+#define MAX_MATCH 5
+// This is the number of capture groups + 1
+#define RESET "\x1b[0m"
+
+void test( const char * trythis) {
+    int ret;
+    char msgbuf[100];
+    const char * p = trythis;
+
+    // safe printing (maybe)
+    strcpy(msgbuf, trythis);
+    char * fixup = msgbuf;
+    while ( ( fixup = strstr(fixup, "\x1b") ) != NULL ) {
+        *fixup = '^';
+    };
+
+    printf("Test: [%s]%s\n", msgbuf, RESET);
+
+    regmatch_t matches[ MAX_MATCH ];
+    while (1) {
+        ret = regexec( &regex, p, MAX_MATCH, matches, 0 );
+
+        if (!ret) {
+            printf("MATCH!\n");
+            for (int i = 0; i < MAX_MATCH; i++) {
+                int start, finish;
+                if (matches[i].rm_so == -1 )
+                    break;
+
+                start = matches[i].rm_so;
+                finish = matches[i].rm_eo;
+		// %.*s  = length to print, char * to use
+                strncpy(msgbuf, p+start, (finish-start));
+                msgbuf[finish-start] = 0;
+                fixup = msgbuf;
+                while ( ( fixup = strstr(fixup, "\x1b") ) != NULL ) {
+                    *fixup = '^';
+                };
+
+                // printf("'%.*s'%s %d : %d - %d\n", (finish - start), p + start, RESET, i, start, finish);
+                printf("'%s' %d : %d - %d\n", msgbuf, i, start, finish);
+            };
+            p += matches[0].rm_eo;
+        }
+        else if (ret == REG_NOMATCH) {
+            printf("Sorry, no matches.\n");
+            break;
+        }
+        else {
+            regerror( ret, &regex, msgbuf, sizeof(msgbuf));
+            fprintf(stderr, "Regex match failed: %s\n", msgbuf);
+        }
+    }
+    return;
+}
+
+int main(int argc, char * argv[]) {
+    // char RX[] = "(\x1b\[(?:\\d+|;)+[a-zA-Z])";
+    //char RX[] = "([a-z][a-z]([0-9]+))";
+    char RX[] = "([a-z][a-z]([0-9]+))";
+    char msgbuf[100];
+    int ret;
+
+    if ( ret = regcomp( &regex, RX, REG_EXTENDED|REG_NEWLINE ) ) {
+        regerror( ret, &regex, msgbuf, sizeof(msgbuf));
+        fprintf(stderr, "Regex compile failed: %s\n", msgbuf);
+        return 1;
+    }
+
+    test("this will fail.");
+    test("this has ab5 ab55 zd3 three matches.");
+
+    regfree(&regex);
+    // if ( regcomp( &regex, "(\x1b\[(?:[0-9]|;)+[a-zA-Z])", REG_EXTENDED|REG_NEWLINE ) ) {
+    // if ( regcomp( &regex, "(\x1b\[([0-9]+|;)+[a-zA-Z])", REG_EXTENDED|REG_NEWLINE ) ) {
+    // if ( regcomp( &regex, "\x1b\[[0-9]+(;[0-9]+)+?[a-zA-Z]", REG_EXTENDED|REG_NEWLINE ) ) {
+    if ( regcomp( &regex, "\x1b\[[0-9]+(;[0-9]+)*?[a-zA-Z]", REG_EXTENDED|REG_NEWLINE ) ) {
+        regerror( ret, &regex, msgbuf, sizeof(msgbuf));
+        fprintf(stderr, "Regex compile failed: %s\n", msgbuf);
+        return 1;
+    };
+
+    test("\x1b[1;1H\x1b[2J\x0cMystic BBS\x1b[6n");
+    test("\x1b[5;1HMEEP.");
+    test("\x1b[0;1;34;47mHello");
+    regfree(&regex);
+
+    //   \s matches space, FORM FEED.  Ouch!  NO!
+
+    if ( regcomp( &regex, "[a-zA-Z]+( [a-zA-Z]+)+", REG_EXTENDED|REG_NEWLINE ) ) {
+        regerror( ret, &regex, msgbuf, sizeof(msgbuf));
+        fprintf(stderr, "Regex compile failed: %s\n", msgbuf);
+        return 1;
+    };
+
+    test("\x1b[1;1H\x1b[2J\x0cMystic BBS\x1b[6n");
+    test("\x1b[5;1HMEEP is cool for cats.");
+     
+    regfree(&regex);
+    return 0;
+}