mystic.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118
  1. #include <assert.h>
  2. #include <fcntl.h>
  3. #include <pty.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/select.h>
  7. #include <sys/wait.h>
  8. #include <termios.h>
  9. #include <unistd.h>
  10. // #include <signal.h> // handle Ctrl-C/SIGINT
  11. #include <strings.h> // strcasecmp
  12. #include <time.h> // usleep(), nanonsleep() ?
  13. #include <ctype.h>
  14. #include <stdlib.h> // random()
  15. #include <regex.h>
  16. /* Log level guideline:
  17. * - ZF_LOG_FATAL - happened something impossible and absolutely unexpected.
  18. * Process can't continue and must be terminated.
  19. * Example: division by zero, unexpected modifications from other thread.
  20. * - ZF_LOG_ERROR - happened something possible, but highly unexpected. The
  21. * process is able to recover and continue execution.
  22. * Example: out of memory (could also be FATAL if not handled properly).
  23. * - ZF_LOG_WARN - happened something that *usually* should not happen and
  24. * significantly changes application behavior for some period of time.
  25. * Example: configuration file not found, auth error.
  26. * - ZF_LOG_INFO - happened significant life cycle event or major state
  27. * transition.
  28. * Example: app started, user logged in.
  29. * - ZF_LOG_DEBUG - minimal set of events that could help to reconstruct the
  30. * execution path. Usually disabled in release builds.
  31. * - ZF_LOG_VERBOSE - all other events. Usually disabled in release builds.
  32. *
  33. * *Ideally*, log file of debugged, well tested, production ready application
  34. * should be empty or very small. Choosing a right log level is as important as
  35. * providing short and self descriptive log message.
  36. */
  37. /*
  38. #define ZF_LOG_VERBOSE 1
  39. #define ZF_LOG_DEBUG 2
  40. #define ZF_LOG_INFO 3
  41. #define ZF_LOG_WARN 4
  42. #define ZF_LOG_ERROR 5
  43. #define ZF_LOG_FATAL 6
  44. */
  45. // LOGGING with file output
  46. #include "zf_log.h"
  47. FILE *g_log_file;
  48. static void file_output_callback(const zf_log_message *msg, void *arg) {
  49. (void)arg;
  50. *msg->p = '\n';
  51. fwrite(msg->buf, msg->p - msg->buf + 1, 1, g_log_file);
  52. fflush(g_log_file);
  53. }
  54. static void file_output_close(void) { fclose(g_log_file); }
  55. static void file_output_open(const char *const log_path) {
  56. g_log_file = fopen(log_path, "a");
  57. if (!g_log_file) {
  58. ZF_LOGW("Failed to open log file %s", log_path);
  59. return;
  60. }
  61. atexit(file_output_close);
  62. zf_log_set_output_v(ZF_LOG_PUT_STD, 0, file_output_callback);
  63. }
  64. #include "terminal.h"
  65. struct console_details console;
  66. #include "utils.h"
  67. // END LOGGING
  68. #include "lastseen.h"
  69. /*
  70. What is the name of the actual, real Mystic executable
  71. that we'll be executing and mangling?
  72. */
  73. #define TARGET "./mySTIC"
  74. // Size of our input and output buffers.
  75. #define BSIZE 1024
  76. /*
  77. * string_insert()
  78. * Inserts a string into a given position.
  79. * This safely checks to make sure the buffer isn't overrun.
  80. */
  81. int string_insert(char *buffer, int max_length, int pos, const char *insert) {
  82. assert(max_length > pos);
  83. assert(buffer != NULL);
  84. assert(insert != NULL);
  85. if (strlen(buffer) + strlen(insert) >= max_length) {
  86. ZF_LOGD("string_insert() failed inserting [%s]", repr(insert));
  87. return 0;
  88. }
  89. memmove(buffer + pos + strlen(insert), buffer + pos,
  90. strlen(buffer + pos) + 1);
  91. // cp + strlen(display), cp, strlen(cp) + 1);
  92. strncpy(buffer + pos, insert, strlen(insert));
  93. // (cp, display, strlen(display));
  94. return 1; // success
  95. }
  96. // Should this be passed around to the functions that use it?
  97. #include "render.h"
  98. /*
  99. These are harry "timeout" events.
  100. These happen when we've been sitting around awhile.
  101. */
  102. #ifdef CPP_MADMAN_STL_CODE
  103. const char *random_phrase(const char *words, int len, int last_seen) {
  104. // ooh. a map of char *s to last_seen_events. :P
  105. static map<const char *, array<int>> tracker;
  106. map<const char *, array<int>>::iterator it;
  107. array<int, last_seen> it = tracker.find(words);
  108. if (it == tracker.end()) {
  109. // key does not exist.
  110. array<int, last_seen> last;
  111. for (int i = 0; i < last_seen; i++) {
  112. last[i] = -1;
  113. };
  114. tracker.insert(words, last);
  115. it = tracker.find(words);
  116. };
  117. }
  118. #endif
  119. void harry_idle_event(int fd) {
  120. // Make something happen
  121. char buffer[100];
  122. int r;
  123. // This is no where near finished, BUT!
  124. const char *phrases[] = {"Hahaha", "Snicker, snicker", "Boo!",
  125. "MeOW", "I see U", "Arrooo!",
  126. "Ahh-wooo!", "Aaaooo!"};
  127. const char *cp;
  128. static LastSeen last_seen_harry_event(2);
  129. // Remember the last phrase used,
  130. // and don't repeat (the last two)!
  131. do {
  132. r = randint((sizeof(phrases) / sizeof(char *)));
  133. // r = random() % ((sizeof(phrases) / sizeof(char *)) - 1);
  134. } while (last_seen_harry_event.seen_before(r));
  135. // ZF_LOGD("%d => %d %d", r, last_seen_harry_event[0],
  136. // last_seen_harry_event[1]);
  137. cp = phrases[r];
  138. int color = random() % 15 + 1;
  139. /*
  140. int color = random() % 16;
  141. if (color == 0) {
  142. color++;
  143. } // If it's 0 let's make it 1. // color = (random() % 15) + 1
  144. */
  145. sprintf(buffer, "^S2^C%02d%s^P2^CR^D%02d", color, cp, (int)strlen(cp));
  146. ZF_LOGD("harry_event: render(%d, \"%s\")", fd, buffer);
  147. render(fd, buffer, strlen(buffer));
  148. }
  149. void init_harry() {
  150. // init_have_seen(last_seen_harry_event, MAX_HARRY_EVENT_DUPS);
  151. // ZF_LOGD("init => %d %d", last_seen_harry_event[0],
  152. // last_seen_harry_event[1]);
  153. console_init(&console);
  154. }
  155. /*
  156. The code to get the username and fullname is useless on telnet
  157. connections.
  158. */
  159. const char *username = NULL;
  160. const char *fullname = NULL;
  161. /*
  162. Pascal String Copy. Copy from pascal string, to C String.
  163. First char is pascal string length. (Max 255).
  164. */
  165. void pcopy(char *pstring, char *str) {
  166. int len = (int)*pstring;
  167. strncpy(str, pstring + 1, len);
  168. str[len] = 0;
  169. }
  170. /*
  171. This only works for those few idiots that use the
  172. horribly broken SSH crap that Mystic uses.
  173. */
  174. int locate_user(const char *alias) {
  175. FILE *user;
  176. char buffer[0x600];
  177. char temp[100];
  178. user = fopen("data/users.dat", "rb");
  179. if (user == NULL)
  180. return 0;
  181. // Carry on!
  182. while (fread(buffer, 0x600, 1, user) == 1) {
  183. pcopy(buffer + 0x6d, temp);
  184. if (strcasecmp(temp, username) == 0) {
  185. pcopy(buffer + 0x8c, temp);
  186. fullname = strdup(temp);
  187. break;
  188. }
  189. /*
  190. printf("Alias: %s\n", temp);
  191. pcopy(buffer + 0x8c, temp );
  192. printf("Full Name: %s\n", temp );
  193. */
  194. }
  195. fclose(user);
  196. return 1;
  197. }
  198. // Buffers are BSIZE + 1, so a buffer that size can strcpy safely.
  199. regex_t ANSI;
  200. regex_t WORDS;
  201. regex_t WORD;
  202. int init_regex(void) {
  203. int ret;
  204. char ansi[] = "\x1b\[[0-9]+(;[0-9]+)*?[a-zA-Z]";
  205. char words[] = "[a-zA-Z]+( [a-zA-Z]+)+";
  206. char word[] = "[a-zA-Z]+";
  207. char errorbuf[100];
  208. if (ret = regcomp(&ANSI, ansi, REG_EXTENDED | REG_NEWLINE)) {
  209. regerror(ret, &ANSI, errorbuf, sizeof(errorbuf));
  210. ZF_LOGW("Regex %s failed to compile: %s", ansi, errorbuf);
  211. return 0;
  212. };
  213. if (ret = regcomp(&WORDS, words, REG_EXTENDED | REG_NEWLINE)) {
  214. regerror(ret, &WORDS, errorbuf, sizeof(errorbuf));
  215. ZF_LOGW("Regex %s failed to compile: %s", words, errorbuf);
  216. return 0;
  217. };
  218. if (ret = regcomp(&WORD, word, REG_EXTENDED | REG_NEWLINE)) {
  219. regerror(ret, &WORD, errorbuf, sizeof(errorbuf));
  220. ZF_LOGW("Regex %s failed to compile: %s", word, errorbuf);
  221. return 0;
  222. };
  223. return 1;
  224. }
  225. int regmatch(regex_t *preg, const char *string, size_t nmatch,
  226. regmatch_t pmatch[], int eflags) {
  227. // returns number of matches found. (Max nmatch)
  228. int matches = 0;
  229. int offset = 0;
  230. while (matches < nmatch) {
  231. int ret = regexec(preg, string + offset, nmatch - matches, pmatch + matches,
  232. eflags);
  233. if (!ret) {
  234. int current = offset;
  235. offset += pmatch[matches].rm_eo;
  236. pmatch[matches].rm_so += current;
  237. pmatch[matches].rm_eo += current;
  238. matches++;
  239. } else if (ret == REG_NOMATCH) {
  240. break;
  241. } else {
  242. break;
  243. }
  244. }
  245. return matches;
  246. }
  247. #define MAX_MATCH 32
  248. regmatch_t rxmatch[MAX_MATCH];
  249. int rx_match(regex_t *regex, const char *buffer) {
  250. int ret;
  251. ret = regmatch(regex, buffer, MAX_MATCH, rxmatch, 0);
  252. if (0) {
  253. for (int i = 0; i < ret; i++) {
  254. ZF_LOGI("%d : (%d-%d)", i, rxmatch[i].rm_so, rxmatch[i].rm_eo);
  255. }
  256. }
  257. return ret;
  258. }
  259. /**
  260. * random_activate()
  261. *
  262. * Is a weight (1-10),
  263. * tests if random number is < weight * 10.
  264. *
  265. * So random_activate(9) happens more frequently
  266. * then random_activate(8) or lower.
  267. *
  268. * This probably needs to be fixed.
  269. * We need a better randint(RANGE) code.
  270. */
  271. int random_activate(int w) {
  272. int r = randint(100);
  273. if (r <= (w * 10)) {
  274. return 1;
  275. };
  276. return 0;
  277. }
  278. /*
  279. word_state(): // deprecated
  280. -1 only lower
  281. +1 only upper
  282. 0 mixed
  283. */
  284. int word_state(const char *buffer, int len) {
  285. int p;
  286. int upper = 0;
  287. int lower = 0;
  288. int ret;
  289. float pct;
  290. for (p = 0; p < len; p++) {
  291. char c = buffer[p];
  292. if (isalpha(c)) {
  293. if (isupper(c)) {
  294. upper++;
  295. };
  296. if (islower(c)) {
  297. lower++;
  298. };
  299. }
  300. }
  301. if (upper == lower) {
  302. return 0;
  303. }
  304. if (upper > lower) {
  305. ret = 1;
  306. pct = ((float)lower / (float)upper) * 100.0;
  307. } else {
  308. ret = -1;
  309. pct = ((float)upper / (float)lower) * 100.0;
  310. }
  311. // ZF_LOGD("So far %d with %f %%", ret, pct);
  312. if (pct < 40.0) {
  313. return ret;
  314. }
  315. return 0;
  316. }
  317. /*
  318. Given a buffer and length, mangle away.
  319. toupper, tolower, flipper
  320. */
  321. int word_mangler(char *buffer, int len) {
  322. int p;
  323. int count = 0;
  324. int state;
  325. // state = word_state(buffer, len);
  326. // ZF_LOGD("word_state(%.*s) %d", len, buffer, state);
  327. state = randrange(-1, 1);
  328. // TODO: Transposer
  329. for (p = 0; p < len; p++) {
  330. char c = buffer[p];
  331. if (randint(len) == p) {
  332. break;
  333. }
  334. switch (state) {
  335. case -1:
  336. // upper
  337. if (islower(c)) {
  338. count++;
  339. buffer[p] = toupper(c);
  340. }
  341. break;
  342. case 1:
  343. // lower
  344. if (isupper(c)) {
  345. count++;
  346. buffer[p] = tolower(c);
  347. }
  348. break;
  349. case 0:
  350. // flipper
  351. if (islower(c)) {
  352. count++;
  353. buffer[p] = toupper(c);
  354. } else {
  355. if (isupper(c)) {
  356. count++;
  357. buffer[p] = tolower(c);
  358. }
  359. }
  360. break;
  361. }
  362. }
  363. return count;
  364. }
  365. int word_wrangler(char *buffer, int len) {
  366. int p;
  367. int count;
  368. int state;
  369. // state = word_state(buffer, len);
  370. // ZF_LOGD("word_state(%.*s) %d", len, buffer, state);
  371. if (len < 5) {
  372. return 0;
  373. }
  374. p = randint(len - 4) + 2;
  375. for (count = 0; count < 4; count++) {
  376. if (!isalpha(buffer[p + count]))
  377. break;
  378. }
  379. ZF_LOGV_MEM(buffer, len, "wrangler %d len %d:", p, count);
  380. if (count >= 2) {
  381. for (int x = 0; x < count / 2; x++) {
  382. char ch = buffer[p + x];
  383. buffer[p + x] = buffer[p + count - 1 - x];
  384. buffer[p + count - 1 - x] = ch;
  385. }
  386. ZF_LOGV_MEM(buffer, len, "word now:");
  387. return 1;
  388. } else
  389. return 0;
  390. }
  391. int buffer_insert(char *buffer, int len, int max_length, int pos,
  392. const char *insert) {
  393. if (strlen(insert) == 0)
  394. return 0;
  395. if (len + strlen(insert) > max_length) {
  396. ZF_LOGD("buffer_insert failed [%s]", repr(insert));
  397. return 0;
  398. }
  399. memmove(buffer + pos + strlen(insert), buffer + pos, len - pos);
  400. strncpy(buffer + pos, insert, strlen(insert));
  401. return 1;
  402. }
  403. /*
  404. * The buffer that we've been given is much larger now.
  405. *
  406. * We can no longer mangle or insert into the given buffer.
  407. * Why? Because we don't know what is behind it now!
  408. */
  409. int mangle(int fd, const char *buffer, int len) {
  410. int x, i;
  411. int need_render = 0; // changing word case around doesn't need the render
  412. int mangled = 0;
  413. int mangled_chars = 0;
  414. char play[BSIZE * 2];
  415. const char *cp;
  416. // Make a copy of buffer, since it can no longer be changed
  417. // inserted into.
  418. memcpy(play, buffer, len);
  419. // NEVER reference buffer from this point on!
  420. char work[BSIZE * 2];
  421. // Use terminal - clean out ANSI
  422. // ZF_LOGI("mangle:");
  423. ZF_LOGI_MEM(play, len, "Mangle (%u bytes):", len);
  424. // strcpy(work, buffer);
  425. /*
  426. NOTE: We copy the buffer, so we can clear out ANSI codes, etc.
  427. Otherwise we might mess some ANSI up in the manglying
  428. process.
  429. */
  430. /*
  431. Is there a way to track -- what I've inserted, and make it exempt from
  432. other modifications / mangler, wrangler?
  433. */
  434. /*
  435. (random) Look for ANSI CLS and:
  436. display random spooky texts around, with delays ... then CLS.
  437. display ANSI graphic file, with delays ... then CLS
  438. */
  439. const char *ANSI_CLS = "\x1b[2J";
  440. cp = strnstr(play, len, ANSI_CLS); // strstr(buffer, ANSI_CLS);
  441. if (cp != NULL) {
  442. static int ANSI_CLS_count = 0; // count the number we've seen
  443. ZF_LOGI("seen: ANSI_CLS");
  444. ANSI_CLS_count++;
  445. // Don't activate on the very first CLS. Too soon, don't screw up the ANSI
  446. // detection.
  447. if (ANSI_CLS_count > 1) {
  448. // Ok, figure out the restore color, just in case
  449. struct console_details temp_console;
  450. // Make exact copy of our current console state.
  451. memcpy(&temp_console, &console, sizeof(console));
  452. // Play the buffer into the console
  453. console_receive(&temp_console, play, cp - play);
  454. char restore_color[30]; // ansi color
  455. strcpy(restore_color, color_restore(&temp_console));
  456. if (0) { // random_activate(3)) {
  457. char display[100] = "";
  458. int needs_cls = 0;
  459. struct file_need {
  460. const char *filename;
  461. int cls;
  462. int rand_pos;
  463. } possibles[] = {
  464. {"goofy_head", 1, 0}, {"bat", 1, 0}, {"panther", 1, 0},
  465. {"wolf", 1, 0}, {"skull", 0, 1}, {"skull2", 0, 1},
  466. {"guy", 0, 1}, {"blinkman", 0, 1}, {"ghost", 1, 0}};
  467. static LastSeen last_files(2);
  468. int r;
  469. do {
  470. r = randint((sizeof(possibles) / sizeof(file_need)));
  471. } while (last_files.seen_before(r));
  472. int x, y;
  473. x = randint(50) + 1;
  474. y = randint(12) + 1;
  475. char fgoto[10];
  476. if (possibles[r].rand_pos) {
  477. int rlen;
  478. rlen = snprintf(fgoto, sizeof(fgoto), "^f%02d%02d", x, y);
  479. if (rlen >= sizeof(fgoto)) {
  480. ZF_LOGE("snprintf %d > buffer size %d", rlen, (int)sizeof(fgoto));
  481. }
  482. } else {
  483. strcpy(fgoto, "^F");
  484. }
  485. // (2); // (sizeof(possibles) / sizeof(file_need)) - 1);
  486. needs_cls = possibles[r].cls;
  487. // I get what's happening. Mystic moves cursor to home, CLS, cursor
  488. // home. When we get here, we're ALWAYS at the top of the screen...
  489. // Hence our bat isn't displayed at the end of the screen.
  490. // This is before the actual CLS, so we CLS before displaying our files.
  491. // I tried a ^P2 before doing this .. but I'd rather have the picture up
  492. // right away I think.
  493. sprintf(display, "%s%s%s.^P3%s", needs_cls ? "\x1b[2J" : "", fgoto,
  494. possibles[r].filename, restore_color);
  495. ZF_LOGI("mangle(ANSI_CLS): %d file inserted %s", r, repr(display));
  496. // Move the buffer so there's room for the display string.
  497. if (buffer_insert(play, len, sizeof(play), cp - play, display)) {
  498. len += strlen(display);
  499. // if (string_insert(buffer, 1024, cp - buffer, display)) {
  500. ZF_LOGI_MEM(play, len, "mangle(ANSI_CLS) (%u bytes):", len);
  501. // ZF_LOGI("mangle(ANSI_CLS):");
  502. // ZF_LOGI_REPR(buffer);
  503. // ZF_LOGI("mangle(ANSI_CLS): [%s]", repr(buffer));
  504. need_render = 1;
  505. /*
  506. Copy the new buffer over, but hide our "render" code
  507. from the remaining mangler steps.
  508. */
  509. memcpy(work, play, len);
  510. // strcpy(work, buffer);
  511. i = cp - play;
  512. // find offset into "buffer"
  513. // apply to work.
  514. memset(work + i, ' ', strlen(display));
  515. } else {
  516. ZF_LOGD("insert failed [%s].", repr(display));
  517. }
  518. } else {
  519. if (1) { // random_activate(4)) {
  520. int r;
  521. char display[100] = "";
  522. /*
  523. Interesting note here:
  524. "Anyone there" qualifies as a valid WORDS regex match.
  525. It is possible that it can get mangled/wrangled!
  526. */
  527. const char *phrasing[] = {"^R1Haha^P1ha^P1ha",
  528. "Poof!",
  529. "Got U",
  530. "Anyone there?",
  531. "^R1Knock, ^P1Knock",
  532. "^G0101^C07^S6Segmentation Fault "
  533. "^P1^S9(core ^C12^C24dumped^C07)^P2"};
  534. static LastSeen last_phrasing(2);
  535. ZF_LOGI("mangle(ANSI_CLS)");
  536. // sprintf( display, "^P2...");
  537. // This string actually screws up ANSI detection (takes too long)
  538. // strcpy(display, "^P2^S501234567890^P1abcdef^P2g^P3h^P4i^S0^P2");
  539. // strcpy(display, "^P2^S301234^P15^S0^P2");
  540. // Add in random text, plus color!
  541. do {
  542. r = random() % ((sizeof(phrasing) / sizeof(char *)) - 1);
  543. // Does this drop the last element in phrasing? (Seems like it takes
  544. // awhile to get Seg Fault spoof, might be why)
  545. } while (last_phrasing.seen_before(r));
  546. r = 5;
  547. int color = random() % 15 + 1;
  548. int x = random() % 30 + 1;
  549. int y = random() % 15 + 1;
  550. /*
  551. Don't have it pause there before moving the cursor.
  552. Move the cursor, get the color changed, THEN pause.
  553. Then act all crazy.
  554. NOTE: Make sure if you use any ^R Render effects, turn them off
  555. before trying to display the restore_color. :P ^R0 Also, make
  556. sure you re-home the cursor ^G0101 because that's where they are
  557. expecting the cursor to be! (At least it's how Mystic does it.)
  558. HOME, CLS, HOME, ... Not sure what others do there. We'll see.
  559. */
  560. int slen = snprintf(display, sizeof(display),
  561. "^G%02d%02d^S3^C%02d^P1%s^S0^R0%s^P1^G0101", x, y,
  562. color, phrasing[r], restore_color);
  563. if (slen >= sizeof(display)) {
  564. ZF_LOGE("display snprintf failed %d > buffer size %d (%s)", slen,
  565. (int)sizeof(display), phrasing[r]);
  566. display[0] = 0;
  567. }
  568. ZF_LOGD("snprintf %d, max %d", slen, (int)sizeof(display));
  569. // sprintf(display, "^P1^S3^C%02d%s^S0^R0%s^P1", color, phrasing[r],
  570. // restore_color);
  571. // Added debug statement so we can identify what was sent... color,
  572. // number picked and what that is
  573. ZF_LOGD("mangle(ANSI_CLS): Inserted color=%02d r=%d phrase='%s'",
  574. color, r, phrasing[r]);
  575. ZF_LOGI_MEM(play, len, "mangle(ANSI_CLS) :");
  576. // Move the buffer so there's room for the display string.
  577. if (buffer_insert(play, len, sizeof(play), cp - play, display)) {
  578. len += strlen(display);
  579. // if (string_insert(buffer, BSIZE * 4, cp - buffer, display)) {
  580. ZF_LOGI_MEM(play, len, "mangle(ANSI_CLS) + :");
  581. // ZF_LOGI("mangle(ANSI_CLS):");
  582. // ZF_LOGI_REPR(buffer);
  583. need_render = 1;
  584. /*
  585. Copy the new buffer over, but hide our "render" code
  586. from the remaining mangler steps.
  587. */
  588. memcpy(work, play, len);
  589. // strcpy(work, buffer);
  590. i = cp - play;
  591. // find offset into "buffer"
  592. // apply to work.
  593. memset(work + i, ' ', strlen(display));
  594. } else {
  595. ZF_LOGD("insert failed [%s].", repr(display));
  596. }
  597. }
  598. }
  599. }
  600. }
  601. memcpy(work, play, len);
  602. // strcpy(work, buffer); // sure.
  603. // NOTE: This is NOT aware of my ^TRIGGERS, so they will show up
  604. // as valid things to mangle in work. (Keep this in mind).
  605. const char replace_with = ' ';
  606. for (x = 0; x < len; x++) {
  607. int ansi = console_char(&console, play[x]);
  608. if (ansi) {
  609. work[x] = replace_with;
  610. }
  611. // fixup "work" so it's a valid C string
  612. if (buffer[x] == 0) {
  613. work[x] = replace_with;
  614. }
  615. }
  616. // fixup "work" buffer so it's a valid c string
  617. // (required for regex to work.)
  618. work[len] = 0;
  619. ZF_LOGI_MEM(work, len, "Work now:");
  620. /*
  621. (random) Locate words (in work), and possibly flip them around.
  622. Transpose words. Transpose case. Transpose letters.
  623. Ok, what would be interesting, is if we could find
  624. W\x1[0;34mORDS with color changes in them, and work with them.
  625. without screwing up the color changes, of course. :P
  626. Example:
  627. Y\x1b[0;1mes \x1b[0;1;34m\x1b[0;1;34;44m N\x1b[0;1;44mo
  628. Yes No
  629. ^ This would be a job for a crazy regex.
  630. I'd have to map the characters to positions in the buffer. :S
  631. I'd want mangle and wrangle to work.
  632. The Message menu -- doesn't hardly get mangled at all (at least on
  633. my test site). Because all of the color changes break up the
  634. words in the menu.
  635. */
  636. x = rx_match(&WORDS, work);
  637. ZF_LOGD("found %d word groups", x);
  638. if (x > 0) {
  639. for (i = 0; i < x; i++) {
  640. // Yes! Be random!
  641. if (random_activate(8)) {
  642. int c = word_mangler(play + rxmatch[i].rm_so,
  643. rxmatch[i].rm_eo - rxmatch[i].rm_so);
  644. if (c) {
  645. mangled++;
  646. mangled_chars += c;
  647. }
  648. }
  649. if (random_activate(4)) {
  650. word_wrangler(play + rxmatch[i].rm_so,
  651. rxmatch[i].rm_eo - rxmatch[i].rm_so);
  652. }
  653. }
  654. }
  655. /*
  656. (random) Locate single words, and transpose words.
  657. Transpose letters.
  658. */
  659. /*
  660. (random) Display up to certain point. Delay.
  661. Print some characters slowly. Delay.
  662. */
  663. if (need_render) {
  664. ZF_LOGD_MEM(play, len, "Ready to render:");
  665. // ZF_LOGD("HH %d : (%d) %s", need_render, (int)strlen(buffer),
  666. // repr(buffer));
  667. } else {
  668. if (mangled) {
  669. ZF_LOGD_MEM(play, len, "Mangled %d words, %d chars:", mangled,
  670. mangled_chars);
  671. /* ZF_LOGD("Mangled %d words, %d chars : %s", mangled, mangled_chars,
  672. repr(buffer)); */
  673. }
  674. }
  675. if (need_render) {
  676. render(fd, play, len);
  677. } else {
  678. write(fd, play, len); // strlen(buffer));
  679. };
  680. return need_render && mangled;
  681. }
  682. int harry_happens(time_t *last_event, int wakeup) {
  683. time_t now = time(NULL);
  684. int elapsed = now - *last_event;
  685. if (elapsed > wakeup) {
  686. // Ok! It's been too long since we've done something.
  687. *last_event = now;
  688. return 1;
  689. }
  690. return 0;
  691. }
  692. /*
  693. This is done. :D My buffering system works with stack'em.
  694. TO FIX: Stop using c strings, must use char * buffer + int length.
  695. MAY CONTAIN NULL VALUES.
  696. Rework some things here.
  697. Here's the "plan":
  698. if buffer is EMPTY:
  699. time_idle = 1;
  700. // setup for "random timeout value mess"
  701. // we're in luck! The last parameter is time interval/timeout. :D
  702. timeout.tv_sec = 10; // randrange(10-25)
  703. timeout.tv_usec = 0;
  704. NOT EMPTY:
  705. // we're in luck! The last parameter is time interval/timeout. :D
  706. timeout.tv_sec = 0;
  707. timeout.tv_usec = 10; // Wild Guess Here? Maybe higher, maybe lower?
  708. time_idle = 0;
  709. ON READ:
  710. read/append to current buffer.
  711. We can't use nulls -- what if they are using ZModem, there's nulls in the
  712. file! Look for trailing / the very last "\r\n".
  713. (I could mangle/chunk it line by line. But I'm not sure I'd need to do
  714. that.)
  715. Optional "mangle" buffer up to that very point -- and send up to that point.
  716. Option #2: Maybe we send everything if program has been running for under
  717. 20 seconds. This would allow the ANSI detect to not get screwed up by this
  718. new idea.
  719. ON TIMEOUT:
  720. if time_idle:
  721. Activate funny harry timeout events.
  722. else:
  723. Ok, we *STILL* haven't received any more characters into the buffer --
  724. even after waiting. (Maybe we haven't waited long enough?)
  725. send the pending information in the buffer and clear it out.
  726. Maybe this is a prompt, and there won't be a \r\n.
  727. This allows for cleaner process of "lines" of buffer. We shouldn't break
  728. in the midDLE OF A WORD. Downside is that we sit on buffer contents a little
  729. while / some amount of time -- which will add some lag to prompts showing up.
  730. (LAG? Are you kidding?)
  731. ZModem:
  732. start: "rz^M**"...
  733. 05-12 18:12:15.916 >> rz^M**^XB00000000000000^M<8A>^Q
  734. 05-12 18:12:15.928 << **\x18B0100000023be50\r\n\x11
  735. 05-12 18:12:15.928 >> *^XC^D
  736. 05-12 18:12:15.939 << **\x18B0900000000a87c\r\n\x11
  737. 05-12 18:12:15.940 >> *^XC
  738. # Start of PK zipfile.
  739. 05-12 18:12:15.941 >> PK^C^D^T
  740. end:
  741. 05-12 18:26:38.700 << **\x18B0100000023be50\r\n\x11
  742. 05-12 18:26:38.700 >> **^XB0823a77600344c^M<8A>
  743. 05-12 18:26:38.711 << **\x18B0800000000022d\r\n
  744. 05-12 18:26:38.712 >> OO^MESC[0m
  745. */
  746. int main(int argc, char *argv[]) {
  747. int master;
  748. pid_t pid;
  749. int node = -1;
  750. file_output_open("horrible_harry.log");
  751. init_harry();
  752. srandom(time(NULL));
  753. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown
  754. // -Ubugz -PUWISHPASSWORD
  755. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
  756. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown
  757. // -Ubugz -PUWISH
  758. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
  759. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML0 -SL0 -ST0 -CUnknown
  760. // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML0 -SL1 -ST0 -CUnknown
  761. // ./mystic -TID7 -IP192.168.0.1 -HOSTUnknown -ML1 -SL0 -ST2 -CUnknown
  762. // -Ubugz -PDUMBWAYTODOTHIS
  763. // ./mystic -TID9 -IP192.168.0.1 -HOSTUnknown -ML1 -SL1 -ST2 -CUnknown
  764. // -Ubugz -PIDONTUSEPASCAL
  765. // SSH: -ML1 -ST2
  766. // Telnet: -ML0 -ST0
  767. // Locate username (if given) in the command line
  768. // -U<username>
  769. for (int x = 0; x < argc; x++) {
  770. if (strncmp("-U", argv[x], 2) == 0) {
  771. username = argv[x] + 2;
  772. ZF_LOGI("Username: [%s]", username);
  773. };
  774. if (strncmp("-SL", argv[x], 3) == 0) {
  775. node = argv[x][3] - '0' + 1;
  776. ZF_LOGI("Node: %d", node);
  777. }
  778. }
  779. if (username != NULL) {
  780. locate_user(username);
  781. ZF_LOGD("Username: [%s] A.K.A. [%s]", username, fullname);
  782. }
  783. if (!init_regex())
  784. return 2;
  785. pid = forkpty(&master, NULL, NULL, NULL);
  786. // impossible to fork
  787. if (pid < 0) {
  788. return 1;
  789. }
  790. // child
  791. else if (pid == 0) {
  792. char *args[20]; // max 20 args
  793. int x;
  794. char new_exec[] = TARGET;
  795. args[0] = new_exec;
  796. for (x = 1; x < argc; x++) {
  797. args[x] = argv[x];
  798. };
  799. args[x] = NULL;
  800. // run Mystic, run!
  801. execvp(TARGET, args);
  802. }
  803. // parent
  804. else {
  805. struct termios tios, orig1;
  806. struct timeval timeout;
  807. time_t last_event = 0; // time(NULL);
  808. ZF_LOGD("starting");
  809. tcgetattr(master, &tios);
  810. tios.c_lflag &= ~(ECHO | ECHONL | ICANON);
  811. /*
  812. tios.c_iflag &= ~(ICRNL | IXON | BRKINT);
  813. tios.c_iflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  814. tios.c_oflag &= ~(OPOST);
  815. */
  816. tcsetattr(master, TCSAFLUSH, &tios);
  817. tcgetattr(1, &orig1);
  818. tios = orig1;
  819. tios.c_iflag &= ~(ICRNL | IXON | BRKINT);
  820. tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
  821. tios.c_oflag &= ~(OPOST);
  822. // https://viewsourcecode.org/snaptoken/kilo/02.enteringRawMode.html
  823. tcsetattr(1, TCSAFLUSH, &tios);
  824. char buffer[BSIZE + 1];
  825. int size = 0;
  826. for (;;) {
  827. int time_idle;
  828. // define estruturas para o select, que serve para verificar qual
  829. // se tornou "pronto pra uso"
  830. fd_set read_fd;
  831. fd_set write_fd;
  832. fd_set except_fd;
  833. // inicializa as estruturas
  834. FD_ZERO(&read_fd);
  835. FD_ZERO(&write_fd);
  836. FD_ZERO(&except_fd);
  837. // atribui o descritor master, obtido pelo forkpty, ao read_fd
  838. FD_SET(master, &read_fd);
  839. // atribui o stdin ao read_fd
  840. FD_SET(STDIN_FILENO, &read_fd);
  841. // o descritor tem que ser unico para o programa, a documentacao
  842. // recomenda um calculo entre os descritores sendo usados + 1
  843. /*
  844. TODO: Figure out how this would work.
  845. I'm thinking something like timeouts 30-50 seconds?
  846. And as we get closer, 15-25 seconds.
  847. */
  848. if (size == 0) {
  849. // buffer is empty
  850. timeout.tv_sec = randrange(10, 20);
  851. timeout.tv_usec = 0;
  852. time_idle = 1;
  853. } else {
  854. // buffer is not empty
  855. timeout.tv_sec = 0;
  856. timeout.tv_usec = 1;
  857. time_idle = 0;
  858. }
  859. if (select(master + 1, &read_fd, &write_fd, &except_fd, &timeout) == 0) {
  860. ZF_LOGI("TIMEOUT");
  861. // This means timeout!
  862. if (time_idle) {
  863. harry_idle_event(STDOUT_FILENO);
  864. } else {
  865. ZF_LOGV_MEM(buffer, size, "TIMEOUT buffer size=%d", size);
  866. console_receive(&console, buffer, size);
  867. write(STDOUT_FILENO, buffer, size);
  868. size = 0;
  869. // buffer is empty now
  870. }
  871. }
  872. /*
  873. static char output[(BSIZE * 4) + 1];
  874. */
  875. int total;
  876. // read_fd esta atribuido com read_fd?
  877. if (FD_ISSET(master, &read_fd)) {
  878. // leia o que bc esta mandando
  879. // ZF_LOGD("read (%d) %d bytes", size, BSIZE - size);
  880. if ((total = read(master, buffer + size, BSIZE - size)) != -1) {
  881. // Ok, we've read more into the buffer.
  882. ZF_LOGV_MEM(buffer + size, total, "Read %d bytes:", total);
  883. size += total;
  884. ZF_LOGV_MEM(buffer, size, "Buffer now:");
  885. int pos = rstrnstr(buffer, size, "\r\n");
  886. if (pos >= 0) {
  887. // found something!
  888. pos += 2;
  889. ZF_LOGD_MEM(buffer, pos, "mangle buffer %d bytes:", pos);
  890. mangle(STDOUT_FILENO, buffer, pos);
  891. memmove(buffer, buffer + pos, size - pos);
  892. size -= pos;
  893. } else {
  894. ZF_LOGV("position of /r/n not found.");
  895. }
  896. } else
  897. break;
  898. }
  899. // read_fd esta atribuido com a entrada padrao?
  900. if (FD_ISSET(STDIN_FILENO, &read_fd)) {
  901. // leia a entrada padrao
  902. char input[BSIZE];
  903. int r = read(STDIN_FILENO, &input, BSIZE);
  904. input[r] = 0;
  905. // e escreva no bc
  906. ZF_LOGI("<< %s", repr(input));
  907. write(master, &input, r);
  908. // This is INPUT from the USER
  909. // ZF_LOGI_MEM( input, strlen(input), "<< ");
  910. }
  911. }
  912. // Restore terminal
  913. tcsetattr(1, TCSAFLUSH, &orig1);
  914. ZF_LOGD("exit");
  915. }
  916. return 0;
  917. }