#include #include #include #include #include #include #include #include #include // handle Ctrl-C/SIGINT #include // usleep(), nanonsleep() ? #include // strcasecmp #include // 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 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; }