X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fxmatrix.c;h=09fe155f846964b50d5f069446651538b5e69ddd;hb=6cee540bdbb571485cd5e519f89f389faebd0495;hp=016ec771f225f2075e1a0565e16be6275d15a44a;hpb=a94197e76a5dea5cb60542840809d6c20d0abbf3;p=xscreensaver diff --git a/hacks/xmatrix.c b/hacks/xmatrix.c index 016ec771..09fe155f 100644 --- a/hacks/xmatrix.c +++ b/hacks/xmatrix.c @@ -111,9 +111,12 @@ static unsigned char char_map[256] = { 176,177,178,195,180,181,182,183,184,185,186,187,188,189,190,191 /* 240 */ }; +#define CURSOR_GLYPH 97 + typedef enum { TRACE0, TRACE1, TRACE2, KNOCK0, KNOCK1, KNOCK2, KNOCK3, KNOCK4, KNOCK5, KNOCK6, KNOCK7, + NMAP0, NMAP1, MATRIX, DNA, BINARY, HEX } m_mode; typedef struct { @@ -124,8 +127,10 @@ typedef struct { int grid_width, grid_height; int char_width, char_height; m_cell *cells; + m_cell *cursor; m_feeder *feeders; int nspinners; + Bool knock_knock_p; Bool small_p; Bool insert_top_p, insert_bottom_p; m_mode mode; @@ -325,12 +330,15 @@ init_matrix (Display *dpy, Window window) state->grid_height = state->xgwa.height / state->char_height; state->grid_width++; state->grid_height++; + if (state->grid_width < 5) state->grid_width = 5; + if (state->grid_height < 5) state->grid_height = 5; state->glyph_map = matrix_encoding; state->nglyphs = countof(matrix_encoding); state->cells = (m_cell *) calloc (sizeof(m_cell), state->grid_width * state->grid_height); + state->cursor = NULL; state->feeders = (m_feeder *) calloc (sizeof(m_feeder), state->grid_width); state->density = get_integer_resource ("density", "Integer"); @@ -366,9 +374,13 @@ init_matrix (Display *dpy, Window window) if (insert) free (insert); + state->knock_knock_p = get_boolean_resource ("knockKnock", "KnockKnock"); + mode = get_string_resource ("mode", "Mode"); if (mode && !strcasecmp(mode, "trace")) state->mode = TRACE0; + else if (mode && !strcasecmp(mode, "crack")) + state->mode = NMAP0; else if (mode && !strcasecmp(mode, "dna")) state->mode = DNA; else if (mode && !strcasecmp(mode, "binary")) @@ -408,6 +420,8 @@ init_matrix (Display *dpy, Window window) } else if (state->mode == TRACE0) init_trace (state); + else if (state->mode == NMAP0) + ; else { flip_images (state); @@ -500,6 +514,97 @@ feed_matrix (m_state *state) } } + +static void +redraw_cells (m_state *state, Bool active) +{ + int x, y; + int count = 0; + + for (y = 0; y < state->grid_height; y++) + for (x = 0; x < state->grid_width; x++) + { + m_cell *cell = &state->cells[state->grid_width * y + x]; + + if (cell->glyph) + count++; + + if (state->mode == TRACE2 && active) + { + int xx = x % strlen(state->tracing); + Bool dead_p = state->tracing[xx] > 0; + + if (y == 0 && x == xx) + cell->glyph = (dead_p + ? state->glyph_map[state->tracing[xx]-'0'] + 1 + : 0); + else if (y == 0) + cell->glyph = 0; + else + cell->glyph = (dead_p ? 0 : + (state->glyph_map[(random()%state->nglyphs)] + + 1)); + + cell->changed = 1; + } + + if (!cell->changed) + continue; + + if (cell->glyph == 0 && cell != state->cursor) + XFillRectangle (state->dpy, state->window, state->erase_gc, + x * state->char_width, + y * state->char_height, + state->char_width, + state->char_height); + else + { + int g = (cell == state->cursor ? CURSOR_GLYPH : cell->glyph); + int cx = (g - 1) % CHAR_COLS; + int cy = (g - 1) / CHAR_COLS; + int map = ((cell->glow > 0 || cell->spinner) ? GLOW_MAP : + (cell->glow < 0) ? FADE_MAP : + PLAIN_MAP); + + XCopyArea (state->dpy, state->images[map], + state->window, state->draw_gc, + cx * state->char_width, + cy * state->char_height, + state->char_width, + state->char_height, + x * state->char_width, + y * state->char_height); + } + + cell->changed = 0; + + if (cell->glow > 0) + { + cell->glow--; + cell->changed = 1; + } + else if (cell->glow < 0) + { + cell->glow++; + if (cell->glow == 0) + cell->glyph = 0; + cell->changed = 1; + } + + if (cell->spinner && active) + { + cell->glyph = (state->glyph_map[(random()%state->nglyphs)] + 1); + cell->changed = 1; + } + } + + if (state->cursor) + { + state->cursor->changed = 1; + } +} + + static int densitizer (m_state *state) { @@ -522,72 +627,447 @@ densitizer (m_state *state) } +static void drain_matrix (m_state *); + static void -hack_text (m_state *state) +handle_events (m_state *state) { - int i; - int x = 0; - const char *s; - switch (state->mode) + XSync (state->dpy, False); + while (XPending (state->dpy)) { - case TRACE0: s = "Call trans opt: received.\n" - "2-19-98 13:24:18 REC:Log>_"; break; - case TRACE1: s = "Trace program: running_"; break; + XEvent event; + XNextEvent (state->dpy, &event); - case KNOCK0: s = "Wake up, Neo..."; break; - case KNOCK1: s = ""; break; - case KNOCK2: s = "The Matrix has you..."; break; - case KNOCK3: s = ""; break; - case KNOCK4: s = "Follow the white rabbit..."; break; - case KNOCK5: s = ""; break; - case KNOCK6: s = "Knock knock, Neo."; break; - case KNOCK7: s = ""; break; + if (event.xany.type == ConfigureNotify) + { + int ow = state->grid_width; + int oh = state->grid_height; + XGetWindowAttributes (state->dpy, state->window, &state->xgwa); + state->grid_width = state->xgwa.width / state->char_width; + state->grid_height = state->xgwa.height / state->char_height; + state->grid_width++; + state->grid_height++; + if (state->grid_width < 5) state->grid_width = 5; + if (state->grid_height < 5) state->grid_height = 5; + + if (ow != state->grid_width || + oh != state->grid_height) + { + m_cell *ncells = (m_cell *) + calloc (sizeof(m_cell), + state->grid_width * state->grid_height); + m_feeder *nfeeders = (m_feeder *) + calloc (sizeof(m_feeder), state->grid_width); + int x, y, i; + + /* fprintf(stderr, "resize: %d x %d ==> %d x %d\n", + ow, oh, state->grid_width, state->grid_height); */ + + for (y = 0; y < oh; y++) + for (x = 0; x < ow; x++) + if (x < ow && x < state->grid_width && + y < oh && y < state->grid_height) + ncells[y * state->grid_width + x] = + state->cells[y * ow + x]; + free (state->cells); + state->cells = ncells; + + x = (ow < state->grid_width ? ow : state->grid_width); + for (i = 0; i < x; i++) + nfeeders[i] = state->feeders[i]; + free (state->feeders); + state->feeders = nfeeders; + } + } + else if (event.xany.type == KeyPress) + { + KeySym keysym; + char c = 0; + XLookupString (&event.xkey, &c, 1, &keysym, 0); + if (c == '0') + { + drain_matrix (state); + return; + } + else if (c == '+' || c == '=' || c == '>' || c == '.') + { + state->density += 10; + if (state->density > 100) + state->density = 100; + else + return; + } + else if (c == '-' || c == '_' || c == '<' || c == ',') + { + state->density -= 10; + if (state->density < 0) + state->density = 0; + else + return; + } + } - default: abort(); break; + screenhack_handle_event (state->dpy, &event); } +} - for (i = 0; i < state->grid_height * state->grid_width; i++) + +static void +matrix_usleep (m_state *state, unsigned long delay) +{ + if (!delay) return; + + if (state->cursor) { - m_cell *cell = &state->cells[i]; - cell->changed = (cell->glyph != 0); - cell->glyph = 0; + int blink_delay = 333000; + int tot_delay = 0; + m_cell *cursor = state->cursor; + while (tot_delay < delay) + { + if (state->cursor) + { + usleep (blink_delay * 2); + tot_delay += (2 * blink_delay); + state->cursor = NULL; + } + else + { + usleep (blink_delay); + tot_delay += blink_delay; + state->cursor = cursor; + } + cursor->changed = 1; + redraw_cells (state, False); + XSync (state->dpy, False); + handle_events (state); + } } - - if (state->mode == TRACE0 || state->mode == TRACE1) - i = 0; else { - int y; - x = ((int)state->grid_width - (int)strlen(s)) / 2; - y = (state->grid_height / 2) - 1; - if (y < 0) y = 0; - if (x < 0) x = 0; - i = (y * state->grid_width) + x; + XSync (state->dpy, False); + handle_events (state); + usleep (delay); } +} + + +static void +hack_text_1 (m_state *state, + int *xP, int *yP, + const char *s, + Bool typing_delay, + Bool transmit_delay, + Bool long_delay, + Bool visible_cursor, + Bool scroll_p) +{ + int x = *xP; + int y = *yP; + int i = state->grid_width * y + x; + Bool glow_p = False; + + if (y >= state->grid_height-1) return; while (*s) { + m_cell *cell; + Bool done_p = s[1] == '\000'; + + long_delay = done_p; + if (*s == '\n') { - i = ((i / state->grid_width) + 1) * state->grid_width; x = 0; + y++; + i = state->grid_width * y + x; + + if (scroll_p) + { + int xx, yy; + for (yy = 0; yy < state->grid_height-1; yy++) + for (xx = 0; xx < state->grid_width; xx++) + { + int ii = yy * state->grid_width + xx; + int jj = (yy+1) * state->grid_width + xx; + state->cells[ii] = state->cells[jj]; + state->cells[ii].changed = 1; + } + /* clear bottom row */ + for (xx = 0; xx < state->grid_width; xx++) + { + int ii = yy * state->grid_width + xx; + state->cells[ii].glyph = 0; + state->cells[ii].changed = 1; + } + y--; /* move it back */ + i = state->grid_width * y + x; + } + + if (y >= state->grid_height) return; + + cell = &state->cells[i]; + if (visible_cursor) + { + cell->changed = 1; + state->cursor = cell; + } } + else if (*s == '\010') + ; + else if (*s == '\002') + glow_p = True; else { - m_cell *cell = &state->cells[i]; + cell = &state->cells[i]; if (x < state->grid_width-1) { cell->glyph = char_map[(unsigned char) *s] + 1; if (*s == ' ' || *s == '\t') cell->glyph = 0; cell->changed = 1; + cell->glow = (glow_p ? 8 : 0); + if (visible_cursor) + { + m_cell *next = &state->cells[i + 1]; + next->changed = 1; + state->cursor = next; + } i++; } x++; } s++; + if (typing_delay || transmit_delay || long_delay) + { + redraw_cells (state, False); + XSync (state->dpy, False); + handle_events (state); + if (typing_delay) + { + usleep (50000); + if (typing_delay && 0 == random() % 3) + usleep (0xFFFFFF & ((random() % 250000) + 1)); + } + else + if (long_delay) + matrix_usleep (state, 1000000); + else + usleep (20000); + } } + + *xP = x; + *yP = y; } + +static void +hack_text (m_state *state) +{ + int i; + int x = 0; + int y = 0; + const char *s; + Bool typing_delay = False; + Bool transmit_delay = False; + Bool long_delay = False; + Bool visible_cursor = False; + switch (state->mode) + { + case TRACE0: if (state->grid_width >= 52) + s = "Call trans opt: received. 2-19-98 13:24:18 REC:Log>"; + else + s = "Call trans opt: received.\n2-19-98 13:24:18 REC:Log>"; + transmit_delay = True; + visible_cursor = True; + break; + case TRACE1: s = "Trace program: running"; + transmit_delay = True; + visible_cursor = True; + break; + case KNOCK0: s = "Wake up, Neo..."; break; + case KNOCK1: s = ""; break; + case KNOCK2: s = "The Matrix has you..."; typing_delay = True; break; + case KNOCK3: s = ""; break; + case KNOCK4: s = "Follow the white rabbit."; typing_delay = True; break; + case KNOCK5: s = ""; break; + case KNOCK6: s = "Knock, knock, Neo."; break; + case KNOCK7: + case NMAP0: + case NMAP1: s = ""; break; + + default: abort(); break; + } + + for (i = 0; i < state->grid_height * state->grid_width; i++) + { + m_cell *cell = &state->cells[i]; + cell->changed = (cell->glyph != 0); + cell->glyph = 0; + } + + if (state->mode == NMAP0) + { + /* Note that what Trinity is using here is moderately accurate: + She runs nmap (http://www.insecure.org/nmap/) then breaks in + with a (hypothetical) program called "sshnuke" that exploits + the (very real) SSHv1 CRC32 compensation attack detector bug + (http://staff.washington.edu/dittrich/misc/ssh-analysis.txt). + + The command syntax of the power grid control software looks a + lot like Cisco IOS to me. (IOS is a descendant of VMS.) + */ + const char *blocks[] = { + "# ", + + "\001nmap 10.2.2.2\n", + "Starting nmap V. 2.54BETA25\n" + + "\010", "\010", "\010", + + "Insufficient responses for TCP sequencing (3), OS detection " + "may be less\n" + "accurate\n" + "Interesting ports on 10.2.2.2:\n" + "(The 1538 ports scanned but not shown below are in state: filtered)\n" + "Port state service\n" + "22/tcp open ssh\n" + "\n" + "No exact OS matches for host\n" + "\n" + "Nmap run completed -- 1 IP address (1 host up) scanned\n" + "# ", + + "\001sshnuke 10.2.2.2 -rootpw=\"Z1ON0101\"\n", + + "Connecting to 10.2.2.2:ssh ... ", + + "successful.\n" + "Attempting to exploit SSHv1 CRC32 ... ", + + "successful.\n" + "Resetting root password to \"Z1ON0101\".\n", + + "System open: Access Level <9>\n" + "# ", + + "\001ssh 10.2.2.2 -l root\n", + + "root@10.2.2.2's password: ", + + "\001\010\010\010\010\010\010\010\010\n", + + "\n" + "FFF-CONTROL> ", + + "\001disable grid nodes 21 - 40\n", + + "Warning: Disabling nodes 21-40 will disconnect sector 11 (27 nodes)\n" + "\n" + "\002 ARE YOU SURE? (y/n) ", + + "\001\010\010y\n", + "\n" + }; + + int nblocks = countof(blocks); + int y = state->grid_height - 2; + int j; + + visible_cursor = True; + x = 0; + for (j = 0; j < nblocks; j++) + { + const char *s = blocks[j]; + typing_delay = (*s == '\001'); + if (typing_delay) s++; + + long_delay = False; + hack_text_1 (state, &x, &y, s, + typing_delay, transmit_delay, long_delay, + visible_cursor, True); + } + + typing_delay = False; + long_delay = False; + for (j = 21; j <= 40; j++) + { + char buf[100]; + sprintf (buf, "Grid Node %d offline...\n", j); + hack_text_1 (state, &x, &y, buf, + typing_delay, transmit_delay, long_delay, + visible_cursor, True); + + } + hack_text_1 (state, &x, &y, "\nFFF-CONTROL> ", + typing_delay, transmit_delay, long_delay, + visible_cursor, True); + return; + } + else + { + if (state->mode == TRACE0 || state->mode == TRACE1) + x = y = 0; + else + { + x = ((int)state->grid_width - (int)strlen(s)) / 2; + y = (state->grid_height / 2) - 1; + if (y < 0) y = 0; + if (x < 0) x = 0; + } + + hack_text_1 (state, &x, &y, s, + typing_delay, transmit_delay, long_delay, + visible_cursor, False); + } +} + + +static void +drain_matrix (m_state *state) +{ + int delay = get_integer_resource ("delay", "Integer"); + int i; + + /* Fill the top row with empty top-feeders, to clear the screen. */ + for (i = 0; i < state->grid_width; i++) + { + m_feeder *f = &state->feeders[i]; + f->y = -1; + f->remaining = 0; + f->throttle = 0; + } + + /* Turn off all the spinners, else they never go away. */ + for (i = 0; i < state->grid_width * state->grid_height; i++) + if (state->cells[i].spinner) + { + state->cells[i].spinner = 0; + state->cells[i].changed = 1; + } + + /* Run the machine until there are no live cells left. */ + while (1) + { + Bool any_cells_p = False; + for (i = 0; i < state->grid_width * state->grid_height; i++) + if (state->cells[i].glyph) + { + any_cells_p = True; + goto FOUND; + } + FOUND: + if (! any_cells_p) + return; + + feed_matrix (state); + redraw_cells (state, True); + XSync (state->dpy, False); + handle_events (state); + if (delay) usleep (delay); + } +} + + static void roll_state (m_state *state) { @@ -614,7 +1094,7 @@ roll_state (m_state *state) if (!any) { XSync (state->dpy, False); - sleep (3); + matrix_usleep (state, 3000000); state->mode = MATRIX; state->glyph_map = matrix_encoding; state->nglyphs = countof(matrix_encoding); @@ -638,7 +1118,12 @@ roll_state (m_state *state) case KNOCK4: delay = 2; state->mode++; break; /* rabbit */ case KNOCK5: delay = 4; state->mode++; break; case KNOCK6: delay = 4; state->mode++; break; /* knock */ + + case NMAP0: delay = 4; state->mode++; break; /* knock */ + case KNOCK7: + delay = 4; + case NMAP1: state->mode = MATRIX; state->glyph_map = matrix_encoding; state->nglyphs = countof(matrix_encoding); @@ -646,9 +1131,14 @@ roll_state (m_state *state) break; case MATRIX: - if (! (random() % 5000)) + if (state->knock_knock_p && (! (random() % 3500))) { - state->mode = KNOCK0; + drain_matrix (state); + if (! (random() % 5)) + state->mode = NMAP0; + else + state->mode = KNOCK0; + flip_images (state); } break; @@ -661,11 +1151,8 @@ roll_state (m_state *state) break; } - if (delay) - { - XSync (state->dpy, False); - sleep (delay); - } + matrix_usleep (state, delay * 1000000); + state->cursor = NULL; } @@ -679,6 +1166,7 @@ hack_matrix (m_state *state) case TRACE0: case TRACE1: case KNOCK0: case KNOCK1: case KNOCK2: case KNOCK3: case KNOCK4: case KNOCK5: case KNOCK6: case KNOCK7: + case NMAP0: case NMAP1: hack_text (state); return; case TRACE2: case MATRIX: case DNA: case BINARY: case HEX: @@ -744,88 +1232,9 @@ hack_matrix (m_state *state) static void draw_matrix (m_state *state) { - int x, y; - int count = 0; - feed_matrix (state); hack_matrix (state); - - for (y = 0; y < state->grid_height; y++) - for (x = 0; x < state->grid_width; x++) - { - m_cell *cell = &state->cells[state->grid_width * y + x]; - - if (cell->glyph) - count++; - - if (state->mode == TRACE2) - { - int xx = x % strlen(state->tracing); - Bool dead_p = state->tracing[xx] > 0; - - if (y == 0 && x == xx) - cell->glyph = (dead_p - ? state->glyph_map[state->tracing[xx]-'0'] + 1 - : 0); - else if (y == 0) - cell->glyph = 0; - else - cell->glyph = (dead_p ? 0 : - (state->glyph_map[(random()%state->nglyphs)] - + 1)); - - cell->changed = 1; - } - - if (!cell->changed) - continue; - - if (cell->glyph == 0) - XFillRectangle (state->dpy, state->window, state->erase_gc, - x * state->char_width, - y * state->char_height, - state->char_width, - state->char_height); - else - { - int cx = (cell->glyph - 1) % CHAR_COLS; - int cy = (cell->glyph - 1) / CHAR_COLS; - int map = ((cell->glow > 0 || cell->spinner) ? GLOW_MAP : - (cell->glow == 0) ? PLAIN_MAP : - GLOW_MAP); - - XCopyArea (state->dpy, state->images[map], - state->window, state->draw_gc, - cx * state->char_width, - cy * state->char_height, - state->char_width, - state->char_height, - x * state->char_width, - y * state->char_height); - } - - cell->changed = 0; - - if (cell->glow > 0) - { - cell->glow--; - cell->changed = 1; - } - else if (cell->glow < 0) - { - cell->glow++; - if (cell->glow == 0) - cell->glyph = 0; - cell->changed = 1; - } - - if (cell->spinner) - { - cell->glyph = (state->glyph_map[(random()%state->nglyphs)] + 1); - cell->changed = 1; - } - } - + redraw_cells (state, True); roll_state (state); #if 0 @@ -854,7 +1263,7 @@ char *progclass = "XMatrix"; char *defaults [] = { ".background: black", - ".foreground: green", + ".foreground: #00AA00", "*small: ", "*delay: 10000", "*insert: both", @@ -862,6 +1271,8 @@ char *defaults [] = { "*tracePhone: (212) 555-0690", "*spinners: 5", "*density: 75", + "*knockKnock: False", + "*geometry: 800x600", 0 }; @@ -874,10 +1285,12 @@ XrmOptionDescRec options [] = { { "-both", ".insert", XrmoptionNoArg, "both" }, { "-density", ".density", XrmoptionSepArg, 0 }, { "-trace", ".mode", XrmoptionNoArg, "trace" }, + { "-crack", ".mode", XrmoptionNoArg, "crack"}, { "-phone", ".tracePhone", XrmoptionSepArg, 0 }, { "-dna", ".mode", XrmoptionNoArg, "DNA" }, { "-binary", ".mode", XrmoptionNoArg, "binary" }, { "-hexadecimal", ".mode", XrmoptionNoArg, "hexadecimal"}, + { "-knock-knock", ".knockKnock", XrmoptionNoArg, "True" }, { 0, 0, 0, 0 } }; @@ -891,7 +1304,7 @@ screenhack (Display *dpy, Window window) { draw_matrix (state); XSync (dpy, False); - screenhack_handle_events (dpy); + handle_events (state); if (delay) usleep (delay); } }