mystic.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <unistd.h> // usleep()
  4. #include <pty.h>
  5. #include <termios.h>
  6. #include <fcntl.h>
  7. #include <sys/select.h>
  8. #include <sys/wait.h>
  9. #include <signal.h> // handle Ctrl-C/SIGINT
  10. #include <time.h> // usleep(), nanonsleep() ?
  11. #include <strings.h> // strcasecmp
  12. #include <stdlib.h> // random()
  13. #include <ctype.h>
  14. #define TARGET "./mySTIC"
  15. #define BSIZE 1024
  16. #define LOGGING
  17. #ifdef LOGGING
  18. FILE * fp;
  19. #endif
  20. const char * it_is_now(void) {
  21. static char buffer[100];
  22. time_t timer;
  23. struct tm* tm_info;
  24. timer = time(NULL);
  25. tm_info = localtime(&timer);
  26. strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tm_info);
  27. return buffer;
  28. }
  29. void slow_write(int fd, int speed, char * buffer, int len) {
  30. int x;
  31. for( x = 0; x < len; x++) {
  32. usleep(speed);
  33. write( fd, &buffer[x], 1);
  34. }
  35. }
  36. struct render {
  37. int speed;
  38. int effect;
  39. } current_render;
  40. int render_overlimit = 0;
  41. void reset_render(void) {
  42. current_render.speed = 0;
  43. current_render.effect = 0;
  44. render_overlimit = 0;
  45. }
  46. #define TRIGGER "^"
  47. #define SLEEP_LIMIT 30
  48. int ms_sleep(unsigned int ms) {
  49. int result = 0;
  50. struct timespec ts = {
  51. ms / 1000,
  52. (ms % 1000) * 1000000L
  53. };
  54. do {
  55. struct timespec ts_sleep = ts;
  56. result = nanosleep(&ts_sleep, &ts);
  57. } while ( (-1 == result));
  58. return result;
  59. }
  60. void nsleep(long ns) {
  61. struct timespec ts;
  62. ts.tv_sec = 0;
  63. ts.tv_nsec = ns;
  64. nanosleep(&ts, &ts);
  65. }
  66. void render_sleep(void) {
  67. if (render_overlimit)
  68. return;
  69. if (current_render.speed) {
  70. // usleep(current_render.speed * 2500);
  71. // nsleep( current_render.speed * 250000l);
  72. ms_sleep(current_render.speed * 100);
  73. // nanosleep(current_render.speed * 2500);
  74. }
  75. }
  76. const char * process_trigger(int fd, const char * cp) {
  77. char ch;
  78. int i, x, y;
  79. ch = toupper(*cp);
  80. cp++;
  81. switch(ch) {
  82. case 'D':
  83. i = 0;
  84. if (isdigit(*cp)) {
  85. i = (*cp) - '0';
  86. cp++;
  87. };
  88. if (isdigit(*cp)) {
  89. i *= 10;
  90. i += (*cp) - '0';
  91. cp++;
  92. };
  93. if ((i > 0) && (i < 80)) {
  94. #ifdef LOGGING
  95. fprintf(fp, "DEL %02d\n", i);
  96. #endif
  97. for (x = 0; x < i; x++ ) {
  98. write(fd, "\b \b", 3);
  99. }
  100. };
  101. break;
  102. case 'C':
  103. i = 0;
  104. if (isdigit(*cp)) {
  105. i = (*cp) - '0';
  106. cp++;
  107. };
  108. if (isdigit(*cp)) {
  109. i *= 10;
  110. i += (*cp) - '0';
  111. cp++;
  112. };
  113. break;
  114. case 'G':
  115. x = 0;
  116. if (isdigit(*cp)) {
  117. x = (*cp) - '0';
  118. cp++;
  119. };
  120. if (isdigit(*cp)) {
  121. x *= 10;
  122. x += (*cp) - '0';
  123. cp++;
  124. };
  125. y = 0;
  126. if (isdigit(*cp)) {
  127. y = (*cp) - '0';
  128. cp++;
  129. };
  130. if (isdigit(*cp)) {
  131. y *= 10;
  132. y += (*cp) - '0';
  133. cp++;
  134. };
  135. break;
  136. case 'R':
  137. i = 0;
  138. if (isdigit(*cp)) {
  139. i = (*cp) - '0';
  140. cp++;
  141. };
  142. if ( ( i > 0 ) && ( i < 10) ) {
  143. #ifdef LOGGING
  144. fprintf(fp, "RENDER %d\n", i);
  145. #endif
  146. current_render.effect = i;
  147. } else {
  148. current_render.effect = 0;
  149. }
  150. break;
  151. case 'S':
  152. i = 0;
  153. if (isdigit(*cp)) {
  154. i = (*cp) - '0';
  155. cp++;
  156. };
  157. if ( ( i > 0 ) && ( i < 10) ) {
  158. #ifdef LOGGING
  159. fprintf(fp, "SPEED %d\n", i);
  160. #endif
  161. current_render.speed = i;
  162. } else {
  163. current_render.speed = 0;
  164. }
  165. break;
  166. case 'P':
  167. i = 0;
  168. if (isdigit(*cp)) {
  169. i = (*cp) - '0';
  170. cp++;
  171. };
  172. if ( ( i > 0 ) && ( i < 10) ) {
  173. #ifdef LOGGING
  174. fprintf(fp, "PAWS %d\n", i);
  175. #endif
  176. // sleep(i);
  177. if (!render_overlimit) {
  178. sleep(i);
  179. // nsleep(i * 10000l);
  180. /*
  181. struct timespec ts;
  182. ts.tv_sec = 0;
  183. ts.tv_nsec = i * 10000;
  184. nanosleep(&ts, &ts);*/
  185. };
  186. }
  187. break;
  188. }
  189. return cp;
  190. }
  191. void render_effect(int fd, char ch) {
  192. int effect = current_render.effect;
  193. render_sleep();
  194. int x = write(fd, &ch, 1);
  195. #ifdef LOGGING
  196. fprintf(fp, "write %c to %d result: %d\n", ch, fd, x);
  197. fflush(fp);
  198. #endif
  199. return;
  200. switch (effect) {
  201. case 0:
  202. default:
  203. write(fd, &ch, 1);
  204. break;
  205. }
  206. }
  207. void render( int fd, const char * string_out ) {
  208. const char * cp = string_out;
  209. const char * trigger = cp;
  210. time_t start = time(NULL);
  211. int elapsed;
  212. int over = 0;
  213. reset_render();
  214. #ifdef LOGGING
  215. fprintf(fp, "render(%d, %s)\n", fd, string_out);
  216. fflush(fp);
  217. #endif
  218. // Check our time from time to time.
  219. // If we start running long, kill sleeps.
  220. while ( (trigger = strstr(cp, TRIGGER)) != NULL) {
  221. // There is special things to handle in here.
  222. while ( cp != trigger ) {
  223. elapsed = time(NULL)-start;
  224. if (elapsed > SLEEP_LIMIT) {
  225. render_overlimit = 1;
  226. current_render.speed = 0;
  227. };
  228. #ifdef LOGGING
  229. fprintf(fp, "re(%c)\n", *cp);
  230. fflush(fp);
  231. #endif
  232. // write(fd, cp, 1 );
  233. render_effect(fd, *cp);
  234. cp++;
  235. };
  236. #ifdef LOGGING
  237. fprintf(fp, "at trigger: (%s)\n", cp);
  238. fflush(fp);
  239. #endif
  240. cp += strlen(TRIGGER);
  241. // Ok, we're pointing at the trigger -- do something.
  242. cp = process_trigger(fd, cp);
  243. #ifdef LOGGING
  244. fprintf(fp, "after trigger: (%s)\n", cp);
  245. fflush(fp);
  246. #endif
  247. };
  248. // We still might be under a rendering effect.
  249. while (*cp != 0) {
  250. // write(fd, cp, 1);
  251. render_effect(fd, *cp);
  252. cp++;
  253. }
  254. }
  255. void harry_event(int fd) {
  256. // Make something happen
  257. char buffer[100];
  258. int r = random() % 5;
  259. const char * phrases[] =
  260. {
  261. "Hahaha",
  262. "Snicker, snicker",
  263. "Boo!",
  264. "MeOW",
  265. "I see U"
  266. };
  267. const char * cp;
  268. #ifdef LOGGING
  269. fprintf(fp, "harry_event(%d)\n", fd);
  270. fflush(fp);
  271. #endif
  272. cp = phrases[r];
  273. sprintf(buffer, "^S2%s^P2^D%02d", cp, (int)strlen(cp));
  274. // write(fd, ) is working just fine here!
  275. // write(fd, buffer, strlen(buffer));
  276. #ifdef LOGGING
  277. fprintf(fp, "harry_event: render(%d, \"%s\")\n", fd, buffer);
  278. fflush(fp);
  279. #endif
  280. render(fd, buffer);
  281. // render(fd, cp);
  282. // This also works just fine!
  283. //write(fd, buffer, strlen(buffer));
  284. /*
  285. char clear[] = "\b \b";
  286. int x;
  287. char haha[] = "Hahaha hahaha!!!";
  288. char beep = '\a';
  289. slow_write(fd, 11500, haha, strlen(haha) );
  290. write(fd, &beep, 1);
  291. sleep(3);
  292. for( x = 0; x < strlen(haha); x++ ) {
  293. write(fd, clear, strlen(clear) );
  294. };
  295. */
  296. }
  297. /*
  298. NOTE: Logging is single file, don't use in production!
  299. It won't handle multiple writers.
  300. */
  301. char * username = NULL;
  302. char * fullname = NULL;
  303. void pcopy(char * pstring, char * str) {
  304. int len = (int)*pstring;
  305. strncpy( str, pstring+1, len );
  306. str[len] = 0;
  307. }
  308. int locate_user(const char *alias) {
  309. FILE * user;
  310. char buffer[0x600];
  311. char temp[100];
  312. user = fopen("data/users.dat", "rb");
  313. if (user == NULL)
  314. return 0;
  315. // Carry on!
  316. while (fread(buffer, 0x600, 1, user) == 1) {
  317. pcopy( buffer + 0x6d, temp );
  318. if ( strcasecmp( temp, username) == 0) {
  319. pcopy(buffer + 0x8c, temp );
  320. fullname = strdup(temp);
  321. break;
  322. }
  323. /*
  324. printf("Alias: %s\n", temp);
  325. pcopy(buffer + 0x8c, temp );
  326. printf("Full Name: %s\n", temp );
  327. */
  328. }
  329. fclose(user);
  330. return 1;
  331. }
  332. // Buffers are BSIZE + 1, so a buffer that size can strcpy safely.
  333. void mangle( char * buffer ) {
  334. // Ok, we want to look for words to:
  335. // MaNGlE , or transpose (both?!)
  336. // or possibly transpose words
  337. }
  338. int main(int argc, char * argv[])
  339. {
  340. int master;
  341. pid_t pid;
  342. #ifdef LOGGING
  343. // FILE * fp;
  344. fp = fopen("mystic_pipe.data", "wb");
  345. if ( fp == NULL ) {
  346. return 2;
  347. }
  348. #endif
  349. srandom(time(NULL));
  350. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUWISHPASSWORD
  351. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
  352. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUP2LAT3
  353. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
  354. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
  355. // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML0 -SL1 -ST0 -CUnknown
  356. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown -Ubugz -PUP2LAT3
  357. // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML1 -SL1 -ST2 -CUnknown -Ubugz -PUP2LAT3
  358. // SSH: -ML1 -ST2
  359. // Telnet: -ML0 -ST0
  360. //
  361. // -U<username>
  362. for (int x = 0; x < argc; x++) {
  363. if (strncmp("-U", argv[x], 2) == 0) {
  364. username = argv[x] + 2;
  365. #ifdef LOGGING
  366. fprintf(fp, "Username: [%s]\n", username);
  367. #endif
  368. break;
  369. }
  370. }
  371. if (username != NULL) {
  372. locate_user(username);
  373. #ifdef LOGGING
  374. fprintf(fp, "Username: [%s] A.K.A. [%s]\n", username, fullname);
  375. #endif
  376. }
  377. // With IGNBRK I don't think I need this anymore.
  378. // signal(SIGINT, SIG_IGN);
  379. pid = forkpty(&master, NULL, NULL, NULL);
  380. // impossible to fork
  381. if (pid < 0) {
  382. return 1;
  383. }
  384. // child
  385. else if (pid == 0) {
  386. char *args[20]; // max 20 args
  387. int x;
  388. args[0] = TARGET;
  389. for ( x = 1; x < argc; x++ ) {
  390. args[x] = argv[x];
  391. };
  392. args[x] = NULL;
  393. // char *args[] = { "vim", "test.txt", NULL }; // argv; //{ NULL };
  394. // run Mystic, run!
  395. execvp( TARGET, args);
  396. }
  397. // parent
  398. else {
  399. // remove the echo
  400. // ICANON - raw mode. No more line buffering!
  401. struct termios tios, orig1;
  402. struct timeval timeout;
  403. int last_event;
  404. tcgetattr(master, &tios);
  405. tios.c_lflag &= ~(ECHO | ECHONL | ICANON );
  406. tcsetattr(master, TCSAFLUSH, &tios);
  407. tcgetattr(1, &orig1);
  408. tios = orig1;
  409. tios.c_iflag &= ~(ICRNL | IXON); // Disable software flow control
  410. tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN );
  411. // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
  412. // ISIG should be Ctrl-C and Ctrl-Z IGNBRK +
  413. tcsetattr(1, TCSAFLUSH, &tios);
  414. for (;;) {
  415. // define estruturas para o select, que serve para verificar qual
  416. // se tornou "pronto pra uso"
  417. fd_set read_fd;
  418. fd_set write_fd;
  419. fd_set except_fd;
  420. // inicializa as estruturas
  421. FD_ZERO(&read_fd);
  422. FD_ZERO(&write_fd);
  423. FD_ZERO(&except_fd);
  424. // atribui o descritor master, obtido pelo forkpty, ao read_fd
  425. FD_SET(master, &read_fd);
  426. // atribui o stdin ao read_fd
  427. FD_SET(STDIN_FILENO, &read_fd);
  428. // o descritor tem que ser unico para o programa, a documentacao
  429. // recomenda um calculo entre os descritores sendo usados + 1
  430. // we're in luck! The last parameter is time interval/timeout. :D
  431. timeout.tv_sec = 10;
  432. timeout.tv_usec = 0;
  433. // select(master+1, &read_fd, &write_fd, &except_fd, NULL);
  434. if ( select(master+1, &read_fd, &write_fd, &except_fd, &timeout) == 0 ) {
  435. // This means timeout!
  436. harry_event(STDOUT_FILENO);
  437. #ifdef LOGGING
  438. fprintf(fp, "%s : TICK\n", it_is_now());
  439. fprintf(fp, "STDOUT is %d\n", STDOUT_FILENO);
  440. #endif
  441. }
  442. char input[BSIZE + 1];
  443. char output[BSIZE + 1];
  444. int total;
  445. // read_fd esta atribuido com read_fd?
  446. if (FD_ISSET(master, &read_fd))
  447. {
  448. // leia o que bc esta mandando
  449. if ((total = read(master, &output, BSIZE)) != -1) {
  450. // e escreva isso na saida padrao
  451. output[total] = 0;
  452. if (random() % 20 < 3) {
  453. mangle( output );
  454. }
  455. write(STDOUT_FILENO, &output, total);
  456. // This is OUTPUT from the BBS
  457. #ifdef LOGGING
  458. fprintf(fp, ">> [%s]\n", output);
  459. #endif
  460. } else
  461. break;
  462. }
  463. // read_fd esta atribuido com a entrada padrao?
  464. if (FD_ISSET(STDIN_FILENO, &read_fd))
  465. {
  466. // leia a entrada padrao
  467. total = read(STDIN_FILENO, &input, BSIZE);
  468. input[total] = 0;
  469. // e escreva no bc
  470. write(master, &input, total);
  471. // This is INPUT from the USER
  472. #ifdef LOGGING
  473. fprintf(fp, "<< [%s]\n", input);
  474. #endif
  475. }
  476. }
  477. tcsetattr(1, TCSAFLUSH, &orig1);
  478. #ifdef LOGGING
  479. fclose(fp);
  480. #endif
  481. }
  482. return 0;
  483. }