Multiplayer terminal drawing application
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

autistdraw.c 39KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608
  1. /*
  2. * autistdraw.c: terminal drawing for NEET autists^Wartists
  3. *
  4. * Copyright (c) 2014, Přemysl Janouch <p@janouch.name>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any
  7. * purpose with or without fee is hereby granted.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  12. * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  14. * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  15. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. *
  17. */
  18. #include "config.h"
  19. #include "liberty/liberty.c"
  20. #include "termo.h"
  21. #include <locale.h>
  22. #include <termios.h>
  23. #ifndef TIOCGWINSZ
  24. #include <sys/ioctl.h>
  25. #endif // ! TIOCGWINSZ
  26. #include <ev.h>
  27. #include <curses.h>
  28. #define PALETTE_WIDTH 9 ///< Width of the palette
  29. #define TOP_BAR_CUTOFF 3 ///< Height of the top bar
  30. #define BITMAP_BLOCK_SIZE 50 ///< Step for extending bitmap size
  31. #define PROTOCOL_VERSION 1 ///< Network protocol version
  32. enum
  33. {
  34. MESSAGE_HELLO, ///< Server/client hello
  35. MESSAGE_GET_BITMAP, ///< Request bitmap data
  36. MESSAGE_PUT_POINT, ///< Request to place a point
  37. MESSAGE_COUNT ///< Total number of messages
  38. };
  39. enum network_mode
  40. {
  41. NETWORK_MODE_STANDALONE, ///< No networking taking place
  42. NETWORK_MODE_SERVER, ///< We're the server
  43. NETWORK_MODE_CLIENT ///< We're a client
  44. };
  45. struct client
  46. {
  47. LIST_HEADER (struct client)
  48. int fd; ///< Client connection
  49. ev_io read_watcher; ///< Client readability watcher
  50. ev_io write_watcher; ///< Client writability watcher
  51. struct msg_reader msg_reader; ///< Client message reader
  52. struct write_queue write_queue; ///< Write queue
  53. };
  54. #define BITMAP_PIXEL(app, x, y) (app)->bitmap[(y) * (app)->bitmap_w + (x)]
  55. struct app_context
  56. {
  57. termo_t *tk; ///< Termo instance
  58. ev_io tty_watcher; ///< TTY input watcher
  59. ev_timer tty_timer; ///< TTY timeout timer
  60. ev_signal winch_watcher; ///< SIGWINCH watcher
  61. enum network_mode mode; ///< Networking mode
  62. // Client:
  63. int server_fd; ///< Server connection
  64. ev_io server_read_watcher; ///< Server readability watcher
  65. ev_io server_write_watcher; ///< Server writability watcher
  66. struct msg_reader msg_reader; ///< Server message reader
  67. struct write_queue write_queue; ///< Server write queue
  68. bool no_wait; ///< Don't wait for server confirmations
  69. // Server:
  70. int listen_fd; ///< Listening FD
  71. ev_io listen_watcher; ///< Listening FD watcher
  72. struct client *clients; ///< Client connections
  73. chtype palette[2 * 9]; ///< Attribute palette
  74. uint8_t *bitmap; ///< Canvas data for drawing
  75. int bitmap_x; ///< X coord. of left top bitmap corner
  76. int bitmap_y; ///< Y coord. of left top bitmap corner
  77. size_t bitmap_w; ///< Canvas data width
  78. size_t bitmap_h; ///< Canvas data height
  79. int center_x; ///< X coordinate at center
  80. int center_y; ///< Y coordinate at center
  81. // These two are computed from `center_x' and `center_y':
  82. int corner_x; ///< X coordinate of LT screen corner
  83. int corner_y; ///< Y coordinate of LT screen corner
  84. int move_saved_x; ///< Saved X coord. for moving
  85. int move_saved_y; ///< Saved Y coord. for moving
  86. uint8_t current_color_left; ///< Left mouse button color
  87. uint8_t current_color_right; ///< Right mouse button color
  88. };
  89. static void remove_client (struct app_context *app, struct client *client);
  90. static void on_server_disconnected (struct app_context *app);
  91. static void
  92. app_init (struct app_context *self)
  93. {
  94. memset (self, 0, sizeof *self);
  95. self->server_fd = -1;
  96. self->listen_fd = -1;
  97. self->msg_reader = msg_reader_make ();
  98. self->write_queue = write_queue_make ();
  99. }
  100. static void
  101. app_free (struct app_context *self)
  102. {
  103. if (self->tk)
  104. termo_destroy (self->tk);
  105. while (self->clients)
  106. // XXX: we probably shouldn't do this from here
  107. remove_client (self, self->clients);
  108. free (self->bitmap);
  109. msg_reader_free (&self->msg_reader);
  110. write_queue_free (&self->write_queue);
  111. }
  112. // --- Server-client messaging -------------------------------------------------
  113. static bool
  114. read_loop (EV_P_ ev_io *watcher,
  115. bool (*cb) (EV_P_ ev_io *, const void *, ssize_t))
  116. {
  117. char buf[8192];
  118. while (true)
  119. {
  120. ssize_t n_read = recv (watcher->fd, buf, sizeof buf, 0);
  121. if (n_read < 0)
  122. {
  123. if (errno == EAGAIN)
  124. break;
  125. if (errno == EINTR)
  126. continue;
  127. }
  128. if (n_read <= 0 || !cb (EV_A_ watcher, buf, n_read))
  129. return false;
  130. }
  131. return true;
  132. }
  133. static bool
  134. flush_queue (struct write_queue *queue, ev_io *watcher)
  135. {
  136. struct iovec vec[queue->len], *vec_iter = vec;
  137. for (struct write_req *iter = queue->head; iter; iter = iter->next)
  138. *vec_iter++ = iter->data;
  139. ssize_t written;
  140. again:
  141. written = writev (watcher->fd, vec, N_ELEMENTS (vec));
  142. if (written < 0)
  143. {
  144. if (errno == EAGAIN)
  145. goto skip;
  146. if (errno == EINTR)
  147. goto again;
  148. return false;
  149. }
  150. write_queue_processed (queue, written);
  151. skip:
  152. if (write_queue_is_empty (queue))
  153. ev_io_stop (EV_DEFAULT_ watcher);
  154. else
  155. ev_io_start (EV_DEFAULT_ watcher);
  156. return true;
  157. }
  158. static struct write_req *
  159. flush_writer (struct msg_writer *writer)
  160. {
  161. struct write_req *req = xcalloc (1, sizeof *req);
  162. req->data.iov_base = msg_writer_flush (writer, &req->data.iov_len);
  163. return req;
  164. }
  165. static void
  166. flush_writer_to_client (struct msg_writer *writer, struct client *client)
  167. {
  168. write_queue_add (&client->write_queue, flush_writer (writer));
  169. ev_io_start (EV_DEFAULT_ &client->write_watcher);
  170. }
  171. static void
  172. flush_writer_to_server (struct msg_writer *writer, struct app_context *app)
  173. {
  174. write_queue_add (&app->write_queue, flush_writer (writer));
  175. ev_io_start (EV_DEFAULT_ &app->server_write_watcher);
  176. }
  177. static void
  178. send_draw_point_response (struct client *client, int x, int y, uint8_t color)
  179. {
  180. struct msg_writer writer = msg_writer_make ();
  181. str_pack_u8 (&writer.buf, MESSAGE_PUT_POINT);
  182. str_pack_i32 (&writer.buf, x);
  183. str_pack_i32 (&writer.buf, y);
  184. str_pack_u8 (&writer.buf, color);
  185. flush_writer_to_client (&writer, client);
  186. }
  187. static void
  188. send_draw_point_request (struct app_context *app, int x, int y, uint8_t color)
  189. {
  190. struct msg_writer writer = msg_writer_make ();
  191. str_pack_u8 (&writer.buf, MESSAGE_PUT_POINT);
  192. str_pack_i32 (&writer.buf, x);
  193. str_pack_i32 (&writer.buf, y);
  194. str_pack_u8 (&writer.buf, color);
  195. flush_writer_to_server (&writer, app);
  196. }
  197. static void
  198. send_hello_request (struct app_context *app)
  199. {
  200. struct msg_writer writer = msg_writer_make ();
  201. str_pack_u8 (&writer.buf, MESSAGE_HELLO);
  202. str_pack_u8 (&writer.buf, PROTOCOL_VERSION);
  203. flush_writer_to_server (&writer, app);
  204. }
  205. static void
  206. send_hello_response (struct client *client)
  207. {
  208. struct msg_writer writer = msg_writer_make ();
  209. str_pack_u8 (&writer.buf, MESSAGE_HELLO);
  210. str_pack_u8 (&writer.buf, PROTOCOL_VERSION);
  211. flush_writer_to_client (&writer, client);
  212. }
  213. static void
  214. send_get_bitmap_request (struct app_context *app)
  215. {
  216. struct msg_writer writer = msg_writer_make ();
  217. str_pack_u8 (&writer.buf, MESSAGE_GET_BITMAP);
  218. flush_writer_to_server (&writer, app);
  219. }
  220. static void
  221. send_get_bitmap_response (struct client *client, struct app_context *app)
  222. {
  223. struct msg_writer writer = msg_writer_make ();
  224. str_pack_u8 (&writer.buf, MESSAGE_GET_BITMAP);
  225. str_pack_i32 (&writer.buf, app->bitmap_x);
  226. str_pack_i32 (&writer.buf, app->bitmap_y);
  227. str_pack_u64 (&writer.buf, app->bitmap_w);
  228. str_pack_u64 (&writer.buf, app->bitmap_h);
  229. // Simple RLE compression
  230. size_t size = app->bitmap_w * app->bitmap_h;
  231. uint8_t last_value = 0, count = 0;
  232. for (size_t i = 0; i < size; i++)
  233. {
  234. uint8_t value = app->bitmap[i];
  235. if ((count && value != last_value) || count == 0xFF)
  236. {
  237. str_pack_u8 (&writer.buf, count);
  238. str_pack_u8 (&writer.buf, last_value);
  239. count = 0;
  240. }
  241. count++;
  242. last_value = value;
  243. }
  244. if (count)
  245. {
  246. str_pack_u8 (&writer.buf, count);
  247. str_pack_u8 (&writer.buf, last_value);
  248. }
  249. flush_writer_to_client (&writer, client);
  250. }
  251. // --- Server-client messaging -------------------------------------------------
  252. static void
  253. display (const char *format, ...)
  254. {
  255. va_list ap;
  256. mvwhline (stdscr, 0, 0, A_REVERSE, COLS);
  257. attron (A_REVERSE);
  258. va_start (ap, format);
  259. vw_printw (stdscr, format, ap);
  260. va_end (ap);
  261. attroff (A_REVERSE);
  262. refresh ();
  263. }
  264. static void
  265. init_palette (struct app_context *app)
  266. {
  267. start_color ();
  268. // Also does init_pair (0, -1, -1);
  269. use_default_colors ();
  270. // Duplicate it for convenience.
  271. init_pair (9, -1, -1);
  272. // Add the basic 8 colors to the default pair. Once normally, once
  273. // inverted to workaround VTE's inability to set a bright background.
  274. for (int i = 0; i < 8; i++)
  275. {
  276. init_pair (1 + i, COLOR_WHITE, COLOR_BLACK + i);
  277. init_pair (10 + i, COLOR_BLACK + i, COLOR_WHITE);
  278. }
  279. // Initialize the palette of characters with attributes
  280. for (int i = 0; i < PALETTE_WIDTH; i++)
  281. {
  282. app->palette[i] = ' ' | COLOR_PAIR (i);
  283. app->palette[i + 9] = ' ' | COLOR_PAIR (i + 9) | A_REVERSE | A_BOLD;
  284. }
  285. // This usually creates a solid black or white.
  286. app->current_color_left = app->current_color_right = 9;
  287. }
  288. static void
  289. update_canvas_for_screen (struct app_context *app)
  290. {
  291. app->corner_x = app->center_x - COLS / 2;
  292. app->corner_y = app->center_y - (LINES - TOP_BAR_CUTOFF) / 2;
  293. }
  294. static void
  295. redraw (struct app_context *app)
  296. {
  297. int i;
  298. mvwhline (stdscr, 1, 0, A_REVERSE, COLS);
  299. mvwhline (stdscr, 2, 0, A_REVERSE, COLS);
  300. for (i = 0; i < COLS; i++)
  301. {
  302. int pair = (float) i / COLS * PALETTE_WIDTH;
  303. mvaddch (1, i, app->palette[pair]);
  304. mvaddch (2, i, app->palette[pair + PALETTE_WIDTH]);
  305. }
  306. display ("Choose a color from the palette and draw. "
  307. "Press Escape or ^C to quit.");
  308. refresh ();
  309. }
  310. static bool
  311. is_in_bitmap_data (struct app_context *app, int x, int y)
  312. {
  313. return x >= app->bitmap_x
  314. && y >= app->bitmap_y
  315. && x < app->bitmap_x + (int) app->bitmap_w
  316. && y < app->bitmap_y + (int) app->bitmap_h;
  317. }
  318. static void
  319. redraw_canvas (struct app_context *app)
  320. {
  321. int y = app->corner_y;
  322. for (int screen_y = TOP_BAR_CUTOFF; screen_y < LINES; screen_y++, y++)
  323. {
  324. move (screen_y, 0);
  325. int x = app->corner_x;
  326. for (int screen_x = 0; screen_x < COLS; screen_x++, x++)
  327. {
  328. uint8_t color = 0;
  329. if (is_in_bitmap_data (app, x, y))
  330. color = BITMAP_PIXEL (app,
  331. x - app->bitmap_x, y - app->bitmap_y);
  332. addch (app->palette[color]);
  333. }
  334. }
  335. refresh ();
  336. }
  337. static bool
  338. is_visible (struct app_context *app, int x, int y)
  339. {
  340. return x >= app->corner_x
  341. && y >= app->corner_y
  342. && x < app->corner_x + COLS
  343. && y < app->corner_y + LINES - TOP_BAR_CUTOFF;
  344. }
  345. static void
  346. make_place_for_point (struct app_context *app, int x, int y)
  347. {
  348. if (is_in_bitmap_data (app, x, y))
  349. return;
  350. // Make sure the point has some place to go
  351. int new_bitmap_x = app->bitmap_x;
  352. int new_bitmap_y = app->bitmap_y;
  353. while (new_bitmap_x > x)
  354. new_bitmap_x -= BITMAP_BLOCK_SIZE;
  355. while (new_bitmap_y > y)
  356. new_bitmap_y -= BITMAP_BLOCK_SIZE;
  357. int new_bitmap_w = app->bitmap_w + (app->bitmap_x - new_bitmap_x);
  358. int new_bitmap_h = app->bitmap_h + (app->bitmap_y - new_bitmap_y);
  359. while (new_bitmap_x + new_bitmap_w <= x)
  360. new_bitmap_w += BITMAP_BLOCK_SIZE;
  361. while (new_bitmap_y + new_bitmap_h <= y)
  362. new_bitmap_h += BITMAP_BLOCK_SIZE;
  363. uint8_t *new_bitmap = xcalloc (new_bitmap_w * new_bitmap_h,
  364. sizeof *new_bitmap);
  365. if (app->bitmap)
  366. {
  367. // Copy data, assuming that the area can only get larger
  368. for (size_t data_y = 0; data_y < app->bitmap_h; data_y++)
  369. memcpy (new_bitmap
  370. + ((data_y + app->bitmap_y - new_bitmap_y) * new_bitmap_w)
  371. + (app->bitmap_x - new_bitmap_x),
  372. app->bitmap + (data_y * app->bitmap_w),
  373. app->bitmap_w * sizeof *new_bitmap);
  374. free (app->bitmap);
  375. }
  376. // Replace the bitmap with the reallocated version
  377. app->bitmap_x = new_bitmap_x;
  378. app->bitmap_y = new_bitmap_y;
  379. app->bitmap_w = new_bitmap_w;
  380. app->bitmap_h = new_bitmap_h;
  381. app->bitmap = new_bitmap;
  382. }
  383. static void
  384. draw_point_internal (struct app_context *app, int x, int y, uint8_t color)
  385. {
  386. make_place_for_point (app, x, y);
  387. BITMAP_PIXEL (app, x - app->bitmap_x, y - app->bitmap_y) = color;
  388. if (is_visible (app, x, y))
  389. {
  390. int screen_x = x - app->corner_x;
  391. int screen_y = y - app->corner_y + TOP_BAR_CUTOFF;
  392. move (screen_y, screen_x);
  393. addch (app->palette[color]);
  394. refresh ();
  395. }
  396. }
  397. static void
  398. draw_point (struct app_context *app, int x, int y, uint8_t color)
  399. {
  400. if (app->mode == NETWORK_MODE_CLIENT)
  401. {
  402. send_draw_point_request (app, x, y, color);
  403. // We don't usually draw anything immediately in client mode,
  404. // instead we wait for confirmation from the server
  405. if (!app->no_wait)
  406. return;
  407. }
  408. draw_point_internal (app, x, y, color);
  409. // Broadcast clients about the event
  410. if (app->mode == NETWORK_MODE_SERVER)
  411. for (struct client *iter = app->clients; iter; iter = iter->next)
  412. send_draw_point_response (iter, x, y, color);
  413. }
  414. static void
  415. draw_line (struct app_context *app, int x0, int x1, int y0, int y1,
  416. uint8_t color)
  417. {
  418. // Integer version of Bresenham's line drawing algorithm,
  419. // loosely based on code from libcaca because screw math
  420. int dx = abs (x1 - x0);
  421. int dy = abs (y1 - y0);
  422. bool steep = dx < dy;
  423. if (steep)
  424. {
  425. // Flip the coordinate system on input
  426. int tmp;
  427. tmp = x0; x0 = y0; y0 = tmp;
  428. tmp = x1; x1 = y1; y1 = tmp;
  429. tmp = dx; dx = dy; dy = tmp;
  430. }
  431. int step_x = x0 > x1 ? -1 : 1;
  432. int step_y = y0 > y1 ? -1 : 1;
  433. int dpr = dy * 2;
  434. int delta = dpr - dx;
  435. int dpru = delta - dx;
  436. while (dx-- >= 0)
  437. {
  438. // Unflip the coordinate system on output
  439. if (steep)
  440. draw_point (app, y0, x0, color);
  441. else
  442. draw_point (app, x0, y0, color);
  443. x0 += step_x;
  444. if (delta > 0)
  445. {
  446. y0 += step_y;
  447. delta += dpru;
  448. }
  449. else
  450. delta += dpr;
  451. }
  452. }
  453. // --- Exports -----------------------------------------------------------------
  454. static bool
  455. is_data_row_empty (struct app_context *app, int y)
  456. {
  457. for (size_t x = 0; x < app->bitmap_w; x++)
  458. if (app->bitmap[y * app->bitmap_w + x])
  459. return false;
  460. return true;
  461. }
  462. static bool
  463. is_data_column_empty (struct app_context *app, int x)
  464. {
  465. for (size_t y = 0; y < app->bitmap_h; y++)
  466. if (app->bitmap[y * app->bitmap_w + x])
  467. return false;
  468. return true;
  469. }
  470. static void
  471. find_data_bounding_rect (struct app_context *app,
  472. size_t *x, size_t *y, size_t *w, size_t *h)
  473. {
  474. size_t my_x = 0, my_y = 0;
  475. size_t my_w = app->bitmap_w, my_h = app->bitmap_h;
  476. size_t i;
  477. i = 0;
  478. while (i < app->bitmap_h && is_data_row_empty (app, i++))
  479. my_y++;
  480. // Special case: the whole canvas is empty
  481. if (my_y == my_h)
  482. {
  483. my_x = my_w;
  484. goto end;
  485. }
  486. i = app->bitmap_h;
  487. while (i-- && is_data_row_empty (app, i))
  488. my_h--;
  489. i = 0;
  490. while (i < app->bitmap_w && is_data_column_empty (app, i++))
  491. my_x++;
  492. i = app->bitmap_w;
  493. while (i-- && is_data_column_empty (app, i))
  494. my_w--;
  495. end:
  496. *x = my_x;
  497. *y = my_y;
  498. *w = my_w - my_x;
  499. *h = my_h - my_y;
  500. }
  501. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  502. static const char *g_ansi_table[2 * PALETTE_WIDTH] =
  503. {
  504. "\033[0m",
  505. "\033[0;40m",
  506. "\033[0;41m",
  507. "\033[0;42m",
  508. "\033[0;43m",
  509. "\033[0;44m",
  510. "\033[0;45m",
  511. "\033[0;46m",
  512. "\033[0;47m",
  513. "\033[0;1;7m",
  514. "\033[0;1;7;30m",
  515. "\033[0;1;7;31m",
  516. "\033[0;1;7;32m",
  517. "\033[0;1;7;33m",
  518. "\033[0;1;7;34m",
  519. "\033[0;1;7;35m",
  520. "\033[0;1;7;36m",
  521. "\033[0;1;7;37m",
  522. };
  523. static const char *
  524. color_to_ansi (uint8_t color)
  525. {
  526. if (color < N_ELEMENTS (g_ansi_table))
  527. return g_ansi_table[color];
  528. return NULL;
  529. }
  530. static void
  531. export_ansi (struct app_context *app)
  532. {
  533. FILE *fp = fopen ("export-ansi.asc", "wb");
  534. if (!fp)
  535. {
  536. display ("Error opening file for writing.");
  537. beep ();
  538. return;
  539. }
  540. size_t x, y, w, h;
  541. find_data_bounding_rect (app, &x, &y, &w, &h);
  542. for (size_t row = 0; row < h; row++)
  543. {
  544. const char *color = NULL;
  545. for (size_t column = 0; column < w; column++)
  546. {
  547. const char *new_color = color_to_ansi
  548. (BITMAP_PIXEL (app, x + column, y + row));
  549. if (color != new_color)
  550. fputs (new_color, fp);
  551. color = new_color;
  552. fputc (' ', fp);
  553. }
  554. // We need to reset the attributes
  555. fputs (color_to_ansi (0), fp);
  556. fputc ('\n', fp);
  557. }
  558. fclose (fp);
  559. }
  560. // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  561. enum
  562. {
  563. MIRC_NONE = -1,
  564. MIRC_WHITE = 0,
  565. MIRC_BLACK = 1,
  566. MIRC_BLUE = 2,
  567. MIRC_GREEN = 3,
  568. MIRC_L_RED = 4,
  569. MIRC_RED = 5,
  570. MIRC_PURPLE = 6,
  571. MIRC_ORANGE = 7,
  572. MIRC_YELLOW = 8,
  573. MIRC_L_GREEN = 9,
  574. MIRC_CYAN = 10,
  575. MIRC_L_CYAN = 11,
  576. MIRC_L_BLUE = 12,
  577. MIRC_L_PURPLE = 13,
  578. MIRC_GRAY = 14,
  579. MIRC_L_GRAY = 15,
  580. MIRC_TRANSPARENT = 99
  581. };
  582. static int
  583. color_to_mirc (uint8_t color)
  584. {
  585. static const int table[2 * PALETTE_WIDTH] =
  586. {
  587. // XXX: not sure what to map the default color pair to;
  588. // the mIRC code for reverse colours seems to not be well supported
  589. MIRC_TRANSPARENT, MIRC_BLACK, MIRC_RED, MIRC_GREEN, MIRC_YELLOW,
  590. MIRC_BLUE, MIRC_PURPLE, MIRC_CYAN, MIRC_L_GRAY,
  591. MIRC_BLACK, MIRC_GRAY, MIRC_L_RED, MIRC_L_GREEN, MIRC_YELLOW,
  592. MIRC_L_BLUE, MIRC_L_PURPLE, MIRC_L_CYAN, MIRC_WHITE
  593. };
  594. if (color >= sizeof table / sizeof table[0])
  595. return MIRC_NONE;
  596. return table[color];
  597. }
  598. static void
  599. export_irc (struct app_context *app)
  600. {
  601. FILE *fp = fopen ("export-irc.asc", "wb");
  602. if (!fp)
  603. {
  604. display ("Error opening file for writing.");
  605. beep ();
  606. return;
  607. }
  608. size_t x, y, w, h;
  609. find_data_bounding_rect (app, &x, &y, &w, &h);
  610. // This is tricky and needs to be tested with major IRC clients. Currently
  611. // works with: weechat 1.0, xchat 2.8.8, freenode's qwebirc.
  612. // We cannot use the same non-space character for transparent and opaque
  613. // pixels because many clients don't understand the transparent 99 colour
  614. // that is needed for the foreground of transparent pixels. Therefore it
  615. // is not possible to display correctly using non-monospace fonts.
  616. for (size_t row = 0; row < h; row++)
  617. {
  618. // qwebirc is retarded and in some cases it reduces spaces, misaligning
  619. // the picture. Appending two spaces after the attribute reset and
  620. // rendering opaque pixels as something different from a space seems
  621. // to prevent that behaviour.
  622. int color = MIRC_TRANSPARENT;
  623. fprintf (fp, "\x0f ");
  624. for (size_t column = 0; column < w; column++)
  625. {
  626. int new_color = color_to_mirc
  627. (BITMAP_PIXEL (app, x + column, y + row));
  628. if (color != new_color)
  629. {
  630. color = new_color;
  631. if (color == MIRC_TRANSPARENT)
  632. fprintf (fp, "\x0f");
  633. else
  634. fprintf (fp, "\x03%02d,%02d", color, color);
  635. }
  636. fputc ("# "[color == MIRC_TRANSPARENT], fp);
  637. }
  638. fputc ('\n', fp);
  639. }
  640. fclose (fp);
  641. }
  642. // --- Loading, saving ---------------------------------------------------------
  643. static void
  644. load (struct app_context *app)
  645. {
  646. // Client cannot load at all, the server would have send the new bitmap out
  647. if (app->mode != NETWORK_MODE_STANDALONE)
  648. {
  649. display ("Cannot load bitmaps in networked mode.");
  650. beep ();
  651. return;
  652. }
  653. FILE *fp = fopen ("drawing.bin", "rb");
  654. if (!fp)
  655. {
  656. display ("Error opening file for reading.");
  657. beep ();
  658. return;
  659. }
  660. // Some way of loading/saving is better than no way, let's just do our job.
  661. // The format neither standardised nor effective but it works for us.
  662. // We just eat everything and make sure to not crash.
  663. int x, y;
  664. size_t w, h;
  665. if (fscanf (fp, "%d %d %zu %zu", &x, &y, &w, &h) != 4)
  666. goto error;
  667. if (w && h > SIZE_MAX / w)
  668. goto error;
  669. size_t size = w * h;
  670. uint8_t *bitmap = calloc (size, sizeof *bitmap);
  671. if (!bitmap)
  672. goto error;
  673. int c;
  674. uint8_t pixel = 0;
  675. bool have_nibble = false;
  676. size_t loaded = 0;
  677. while (loaded < size && (c = fgetc (fp)) != EOF)
  678. {
  679. static const char digits[] = "0123456789abcdef";
  680. const char *value = strchr (digits, c);
  681. if (value && c != '\0')
  682. {
  683. pixel = pixel << 4 | (value - digits);
  684. if (have_nibble)
  685. bitmap[loaded++] = pixel;
  686. have_nibble = !have_nibble;
  687. }
  688. }
  689. free (app->bitmap);
  690. app->bitmap = bitmap;
  691. app->bitmap_h = h; app->bitmap_x = x;
  692. app->bitmap_w = w; app->bitmap_y = y;
  693. redraw_canvas (app);
  694. error:
  695. fclose (fp);
  696. }
  697. static void
  698. save (struct app_context *app)
  699. {
  700. FILE *fp = fopen ("drawing.bin", "wb");
  701. if (!fp)
  702. {
  703. display ("Error opening file for writing.");
  704. return;
  705. }
  706. int x = app->bitmap_x, y = app->bitmap_y;
  707. size_t w = app->bitmap_w, h = app->bitmap_h;
  708. fprintf (fp, "%d %d %zu %zu\n", x, y, w, h);
  709. for (size_t row = 0; row < h; row++)
  710. {
  711. for (size_t column = 0; column < w; column++)
  712. fprintf (fp, "%02x", BITMAP_PIXEL (app, column, row));
  713. fputc ('\n', fp);
  714. }
  715. fclose (fp);
  716. }
  717. // --- Event handlers ----------------------------------------------------------
  718. static void
  719. move_canvas (struct app_context *app, int x, int y)
  720. {
  721. app->corner_x += x;
  722. app->corner_y += y;
  723. app->center_x += x;
  724. app->center_y += y;
  725. redraw_canvas (app);
  726. }
  727. static void
  728. on_mouse (struct app_context *app, termo_key_t *key)
  729. {
  730. int screen_y, screen_x, button;
  731. termo_mouse_event_t event;
  732. termo_interpret_mouse (app->tk, key, &event, &button, &screen_y, &screen_x);
  733. if (event != TERMO_MOUSE_PRESS && event != TERMO_MOUSE_DRAG)
  734. return;
  735. // Middle mouse button, or Ctrl + left mouse button, moves the canvas
  736. if (button == 2 || (button == 1 && key->modifiers == TERMO_KEYMOD_CTRL))
  737. {
  738. if (event == TERMO_MOUSE_DRAG)
  739. move_canvas (app,
  740. app->move_saved_x - screen_x,
  741. app->move_saved_y - screen_y);
  742. app->move_saved_x = screen_x;
  743. app->move_saved_y = screen_y;
  744. return;
  745. }
  746. uint8_t *color;
  747. if (button == 1)
  748. color = &app->current_color_left;
  749. else if (button == 3)
  750. color = &app->current_color_right;
  751. else
  752. return;
  753. int canvas_x = app->corner_x + screen_x;
  754. int canvas_y = app->corner_y + screen_y - TOP_BAR_CUTOFF;
  755. if (screen_y >= TOP_BAR_CUTOFF)
  756. {
  757. if (event == TERMO_MOUSE_DRAG)
  758. draw_line (app,
  759. app->move_saved_x, canvas_x,
  760. app->move_saved_y, canvas_y,
  761. *color);
  762. else
  763. draw_point (app, canvas_x, canvas_y, *color);
  764. app->move_saved_x = canvas_x;
  765. app->move_saved_y = canvas_y;
  766. }
  767. else if (screen_y > 0 && event != TERMO_MOUSE_DRAG)
  768. {
  769. int pair = (float) screen_x / COLS * PALETTE_WIDTH;
  770. *color = pair + (screen_y - 1) * PALETTE_WIDTH;
  771. }
  772. }
  773. static bool
  774. on_key (struct app_context *app, termo_key_t *key)
  775. {
  776. if (key->type == TERMO_TYPE_KEYSYM)
  777. {
  778. if (key->code.sym == TERMO_SYM_ESCAPE)
  779. return false;
  780. if (key->modifiers)
  781. return true;
  782. switch (key->code.sym)
  783. {
  784. case TERMO_SYM_UP: move_canvas (app, 0, -1); break;
  785. case TERMO_SYM_DOWN: move_canvas (app, 0, 1); break;
  786. case TERMO_SYM_LEFT: move_canvas (app, -1, 0); break;
  787. case TERMO_SYM_RIGHT: move_canvas (app, 1, 0); break;
  788. default: break;
  789. }
  790. return true;
  791. }
  792. if (key->type == TERMO_TYPE_KEY)
  793. {
  794. if ((key->modifiers & TERMO_KEYMOD_CTRL)
  795. && (key->code.codepoint == 'C' || key->code.codepoint == 'c'))
  796. return false;
  797. if (key->modifiers)
  798. return true;
  799. if (key->code.codepoint == 'l') load (app);
  800. if (key->code.codepoint == 's') save (app);
  801. if (key->code.codepoint == 'e') export_ansi (app);
  802. if (key->code.codepoint == 'E') export_irc (app);
  803. return true;
  804. }
  805. if (key->type == TERMO_TYPE_MOUSE)
  806. on_mouse (app, key);
  807. return true;
  808. }
  809. static void
  810. on_winch (EV_P_ ev_signal *handle, int revents)
  811. {
  812. struct app_context *app = ev_userdata (loop);
  813. (void) handle;
  814. (void) revents;
  815. #if defined (HAVE_RESIZETERM) && defined (TIOCGWINSZ)
  816. struct winsize size;
  817. if (!ioctl (STDOUT_FILENO, TIOCGWINSZ, (char *) &size))
  818. {
  819. char *row = getenv ("LINES");
  820. char *col = getenv ("COLUMNS");
  821. unsigned long tmp;
  822. resizeterm (
  823. (row && xstrtoul (&tmp, row, 10)) ? (int) tmp : size.ws_row,
  824. (col && xstrtoul (&tmp, col, 10)) ? (int) tmp : size.ws_col);
  825. }
  826. #else // ! HAVE_RESIZETERM || ! TIOCGWINSZ
  827. endwin ();
  828. refresh ();
  829. #endif // ! HAVE_RESIZETERM || ! TIOCGWINSZ
  830. update_canvas_for_screen (app);
  831. redraw (app);
  832. redraw_canvas (app);
  833. }
  834. static void
  835. on_key_timer (EV_P_ ev_timer *handle, int revents)
  836. {
  837. struct app_context *app = ev_userdata (loop);
  838. (void) handle;
  839. (void) revents;
  840. termo_key_t key;
  841. if (termo_getkey_force (app->tk, &key) == TERMO_RES_KEY)
  842. if (!on_key (app, &key))
  843. ev_break (EV_A_ EVBREAK_ONE);
  844. }
  845. static void
  846. on_tty_readable (EV_P_ ev_io *handle, int revents)
  847. {
  848. // Ignoring and hoping for the best
  849. (void) handle;
  850. (void) revents;
  851. struct app_context *app = ev_userdata (loop);
  852. ev_timer_stop (EV_A_ &app->tty_timer);
  853. termo_advisereadable (app->tk);
  854. termo_key_t key;
  855. termo_result_t ret;
  856. while ((ret = termo_getkey (app->tk, &key)) == TERMO_RES_KEY)
  857. if (!on_key (app, &key))
  858. ev_break (EV_A_ EVBREAK_ONE);
  859. if (ret == TERMO_RES_AGAIN)
  860. ev_timer_start (EV_A_ &app->tty_timer);
  861. }
  862. // --- Client-specific stuff ---------------------------------------------------
  863. typedef bool (*server_handler_fn) (struct app_context *, struct msg_unpacker *);
  864. static void
  865. on_server_disconnected (struct app_context *app)
  866. {
  867. write_queue_free (&app->write_queue);
  868. app->write_queue = write_queue_make ();
  869. ev_io_stop (EV_DEFAULT_ &app->server_read_watcher);
  870. ev_io_stop (EV_DEFAULT_ &app->server_write_watcher);
  871. xclose (app->server_fd);
  872. app->server_fd = -1;
  873. display ("Disconnected!");
  874. beep (); // Beep beep! Made a boo-boo.
  875. // Let the user save the picture at least.
  876. // Also prevents us from trying to use the dead server handle.
  877. app->mode = NETWORK_MODE_STANDALONE;
  878. }
  879. static bool
  880. on_server_hello (struct app_context *app, struct msg_unpacker *unpacker)
  881. {
  882. (void) app;
  883. uint8_t version;
  884. if (!msg_unpacker_u8 (unpacker, &version))
  885. return false; // Not enough data
  886. if (version != PROTOCOL_VERSION)
  887. return false; // Incompatible version
  888. return true;
  889. }
  890. static bool
  891. on_server_get_bitmap (struct app_context *app, struct msg_unpacker *unpacker)
  892. {
  893. int32_t x, y;
  894. uint64_t w, h;
  895. if (!msg_unpacker_i32 (unpacker, &x)
  896. || !msg_unpacker_i32 (unpacker, &y)
  897. || !msg_unpacker_u64 (unpacker, &w)
  898. || !msg_unpacker_u64 (unpacker, &h))
  899. return false; // Not enough data
  900. size_t size = w * h;
  901. if ((h && w > SIZE_MAX / h) || w > SIZE_MAX || h > SIZE_MAX)
  902. return false; // The server is flooding us
  903. uint8_t *bitmap = xcalloc (size, sizeof *app->bitmap);
  904. // RLE decompression
  905. size_t i = 0;
  906. uint8_t len, value;
  907. while (msg_unpacker_u8 (unpacker, &len)
  908. && msg_unpacker_u8 (unpacker, &value))
  909. {
  910. // Don't allow overflow
  911. if (i + len > size || i + len < i)
  912. break;
  913. for (size_t x = 0; x < len; x++)
  914. bitmap[i++] = value;
  915. }
  916. free (app->bitmap);
  917. app->bitmap = bitmap;
  918. app->bitmap_x = x;
  919. app->bitmap_y = y;
  920. app->bitmap_w = w;
  921. app->bitmap_h = h;
  922. redraw_canvas (app);
  923. return true;
  924. }
  925. static bool
  926. on_server_put_point (struct app_context *app, struct msg_unpacker *unpacker)
  927. {
  928. int32_t x, y;
  929. uint8_t color;
  930. if (!msg_unpacker_i32 (unpacker, &x)
  931. || !msg_unpacker_i32 (unpacker, &y)
  932. || !msg_unpacker_u8 (unpacker, &color))
  933. return false; // Not enough data
  934. // Either a confirmation of our own request, or an event notification;
  935. // let's just put the pixel in place without further ado
  936. draw_point_internal (app, x, y, color);
  937. return true;
  938. }
  939. static bool
  940. on_server_data (EV_P_ ev_io *watcher, const void *buf, ssize_t n_read)
  941. {
  942. struct app_context *app = ev_userdata (loop);
  943. (void) watcher;
  944. msg_reader_feed (&app->msg_reader, buf, n_read);
  945. static const server_handler_fn handlers[MESSAGE_COUNT] =
  946. {
  947. [MESSAGE_HELLO] = on_server_hello,
  948. [MESSAGE_GET_BITMAP] = on_server_get_bitmap,
  949. [MESSAGE_PUT_POINT] = on_server_put_point,
  950. };
  951. void *msg;
  952. size_t len;
  953. while ((msg = msg_reader_get (&app->msg_reader, &len)))
  954. {
  955. struct msg_unpacker unpacker = msg_unpacker_make (msg, len);
  956. uint8_t type;
  957. if (!msg_unpacker_u8 (&unpacker, &type)
  958. || type >= MESSAGE_COUNT)
  959. return false; // Unknown message
  960. server_handler_fn handler = handlers[type];
  961. if (!handler)
  962. return false; // Unknown message
  963. if (!handler (app, &unpacker))
  964. return false; // Invalid message
  965. if (msg_unpacker_get_available (&unpacker) > 0)
  966. return false; // Overlong message
  967. }
  968. return true;
  969. }
  970. static void
  971. on_server_ready (EV_P_ ev_io *watcher, int revents)
  972. {
  973. struct app_context *app = ev_userdata (loop);
  974. if (revents & EV_READ)
  975. if (!read_loop (EV_A_ watcher, on_server_data))
  976. goto error;
  977. if (revents & EV_WRITE)
  978. if (!flush_queue (&app->write_queue, watcher))
  979. goto error;
  980. return;
  981. error:
  982. on_server_disconnected (app);
  983. }
  984. // --- Server-specific stuff ---------------------------------------------------
  985. typedef bool (*client_handler_fn)
  986. (struct app_context *, struct client *, struct msg_unpacker *);
  987. static void
  988. remove_client (struct app_context *app, struct client *client)
  989. {
  990. ev_io_stop (EV_DEFAULT_ &client->read_watcher);
  991. ev_io_stop (EV_DEFAULT_ &client->write_watcher);
  992. xclose (client->fd);
  993. msg_reader_free (&client->msg_reader);
  994. write_queue_free (&client->write_queue);
  995. LIST_UNLINK (app->clients, client);
  996. free (client);
  997. }
  998. static bool
  999. on_client_hello (struct app_context *app, struct client *client,
  1000. struct msg_unpacker *unpacker)
  1001. {
  1002. (void) app;
  1003. uint8_t version;
  1004. if (!msg_unpacker_u8 (unpacker, &version)
  1005. || version != PROTOCOL_VERSION)
  1006. // Nope, I don't like you
  1007. return false;
  1008. send_hello_response (client);
  1009. return true;
  1010. }
  1011. static bool
  1012. on_client_get_bitmap (struct app_context *app, struct client *client,
  1013. struct msg_unpacker *unpacker)
  1014. {
  1015. (void) unpacker;
  1016. send_get_bitmap_response (client, app);
  1017. return true;
  1018. }
  1019. static bool
  1020. on_client_put_point (struct app_context *app, struct client *client,
  1021. struct msg_unpacker *unpacker)
  1022. {
  1023. (void) client;
  1024. int32_t x, y;
  1025. uint8_t color;
  1026. if (!msg_unpacker_i32 (unpacker, &x)
  1027. || !msg_unpacker_i32 (unpacker, &y)
  1028. || !msg_unpacker_u8 (unpacker, &color))
  1029. return false;
  1030. // The function takes care of broadcasting to all the other clients,
  1031. // as well as back to the original sender
  1032. draw_point (app, x, y, color);
  1033. return true;
  1034. }
  1035. static bool
  1036. on_client_data (EV_P_ ev_io *watcher, const void *buf, ssize_t n_read)
  1037. {
  1038. struct app_context *app = ev_userdata (loop);
  1039. struct client *client = watcher->data;
  1040. msg_reader_feed (&client->msg_reader, buf, n_read);
  1041. static const client_handler_fn handlers[MESSAGE_COUNT] =
  1042. {
  1043. [MESSAGE_HELLO] = on_client_hello,
  1044. [MESSAGE_GET_BITMAP] = on_client_get_bitmap,
  1045. [MESSAGE_PUT_POINT] = on_client_put_point,
  1046. };
  1047. void *msg;
  1048. size_t len;
  1049. while ((msg = msg_reader_get (&client->msg_reader, &len)))
  1050. {
  1051. struct msg_unpacker unpacker = msg_unpacker_make (msg, len);
  1052. uint8_t type;
  1053. if (!msg_unpacker_u8 (&unpacker, &type))
  1054. return false; // Invalid message
  1055. if (type >= MESSAGE_COUNT)
  1056. return false; // Unknown message
  1057. client_handler_fn handler = handlers[type];
  1058. if (!handler)
  1059. return false; // Unknown message
  1060. if (!handler (app, client, &unpacker))
  1061. return false; // Invalid message
  1062. if (msg_unpacker_get_available (&unpacker) > 0)
  1063. return false; // Overlong message data
  1064. }
  1065. return true;
  1066. }
  1067. static void
  1068. on_client_ready (EV_P_ ev_io *watcher, int revents)
  1069. {
  1070. struct app_context *app = ev_userdata (loop);
  1071. struct client *client = watcher->data;
  1072. if (revents & EV_READ)
  1073. if (!read_loop (EV_A_ watcher, on_client_data))
  1074. goto error;
  1075. if (revents & EV_WRITE)
  1076. if (!flush_queue (&client->write_queue, watcher))
  1077. goto error;
  1078. return;
  1079. error:
  1080. remove_client (app, client);
  1081. }
  1082. static void
  1083. on_new_client (EV_P_ ev_io *watcher, int revents)
  1084. {
  1085. struct app_context *app = ev_userdata (loop);
  1086. (void) revents;
  1087. while (true)
  1088. {
  1089. int sock_fd = accept (watcher->fd, NULL, NULL);
  1090. if (sock_fd == -1)
  1091. {
  1092. if (errno == EAGAIN)
  1093. break;
  1094. if (errno == EINTR
  1095. || errno == ECONNABORTED)
  1096. continue;
  1097. // Stop accepting connections to prevent busy looping
  1098. // TODO: indicate the error to the user
  1099. ev_io_stop (EV_A_ watcher);
  1100. break;
  1101. }
  1102. struct client *client = xcalloc (1, sizeof *client);
  1103. client->fd = sock_fd;
  1104. client->msg_reader = msg_reader_make ();
  1105. client->write_queue = write_queue_make ();
  1106. set_blocking (sock_fd, false);
  1107. ev_io_init (&client->read_watcher, on_client_ready, sock_fd, EV_READ);
  1108. ev_io_init (&client->write_watcher, on_client_ready, sock_fd, EV_WRITE);
  1109. client->read_watcher.data = client;
  1110. client->write_watcher.data = client;
  1111. // We're only interested in reading as the write queue is empty now
  1112. ev_io_start (EV_A_ &client->read_watcher);
  1113. LIST_PREPEND (app->clients, client);
  1114. }
  1115. }
  1116. // --- Program startup ---------------------------------------------------------
  1117. struct app_options
  1118. {
  1119. struct addrinfo *client_address; ///< Address to connect to
  1120. struct addrinfo *server_address; ///< Address to listen at
  1121. bool no_wait; ///< Don't wait for server confirmations
  1122. };
  1123. static void
  1124. app_options_init (struct app_options *self)
  1125. {
  1126. memset (self, 0, sizeof *self);
  1127. }
  1128. static void
  1129. app_options_free (struct app_options *self)
  1130. {
  1131. if (self->client_address) freeaddrinfo (self->client_address);
  1132. if (self->server_address) freeaddrinfo (self->server_address);
  1133. }
  1134. static struct addrinfo *
  1135. parse_address (const char *address, int flags)
  1136. {
  1137. char address_copy[strlen (address) + 1];
  1138. strcpy (address_copy, address);
  1139. char *colon = strrchr (address_copy, ':');
  1140. if (!colon)
  1141. {
  1142. print_error ("no port number specified in `%s'", address);
  1143. return false;
  1144. }
  1145. char *host = address_copy, *service = colon + 1;
  1146. if (host == colon)
  1147. host = NULL;
  1148. else if (host < colon && *host == '[' && colon[-1] == ']')
  1149. {
  1150. // Remove IPv6 RFC 2732-style [] brackets from the host, if present.
  1151. // This also makes it possible to take the usage string literally. :))
  1152. host++;
  1153. colon[-1] = '\0';
  1154. }
  1155. else
  1156. *colon = '\0';
  1157. struct addrinfo *result, hints =
  1158. {
  1159. .ai_socktype = SOCK_STREAM,
  1160. .ai_protocol = IPPROTO_TCP,
  1161. .ai_flags = flags,
  1162. };
  1163. int err = getaddrinfo (host, service, &hints, &result);
  1164. if (err)
  1165. {
  1166. print_error ("cannot resolve `%s', port `%s': %s",
  1167. host, service, gai_strerror (err));
  1168. return false;
  1169. }
  1170. return result;
  1171. }
  1172. static void
  1173. parse_program_arguments (struct app_options *options, int argc, char **argv)
  1174. {
  1175. static const struct opt opts[] =
  1176. {
  1177. { 'h', "help", NULL, 0, "display this help and exit" },
  1178. { 'V', "version", NULL, 0, "output version information and exit" },
  1179. { 's', "server", "[ADDRESS]:PORT", 0, "start a server" },
  1180. { 'c', "client", "[ADDRESS]:PORT", 0, "connect to a server" },
  1181. { 'n', "no-wait", NULL, OPT_LONG_ONLY,
  1182. "don't wait for server confirmations" },
  1183. { 0, NULL, NULL, 0, NULL }
  1184. };
  1185. struct opt_handler oh = opt_handler_make (argc, argv, opts,
  1186. NULL, "Terminal drawing for NEET autists^Wartists");
  1187. int c;
  1188. while ((c = opt_handler_get (&oh)) != -1)
  1189. switch (c)
  1190. {
  1191. case 'h':
  1192. opt_handler_usage (&oh, stdout);
  1193. exit (EXIT_SUCCESS);
  1194. case 'V':
  1195. printf (PROGRAM_NAME " " PROGRAM_VERSION "\n");
  1196. exit (EXIT_SUCCESS);
  1197. case 's':
  1198. if (options->server_address)
  1199. exit_fatal ("cannot specify multiple listening addresses");
  1200. if (!(options->server_address = parse_address (optarg, AI_PASSIVE)))
  1201. exit (EXIT_FAILURE);
  1202. break;
  1203. case 'c':
  1204. if (options->client_address)
  1205. exit_fatal ("cannot specify multiple addresses to connect to");
  1206. if (!(options->client_address = parse_address (optarg, 0)))
  1207. exit (EXIT_FAILURE);
  1208. break;
  1209. case 'n':
  1210. options->no_wait = true;
  1211. break;
  1212. default:
  1213. print_error ("wrong options");
  1214. opt_handler_usage (&oh, stderr);
  1215. exit (EXIT_FAILURE);
  1216. }
  1217. if (options->client_address && options->server_address)
  1218. exit_fatal ("cannot be both a server and a client");
  1219. argc -= optind;
  1220. argv += optind;
  1221. if (argc)
  1222. {
  1223. opt_handler_usage (&oh, stderr);
  1224. exit (EXIT_FAILURE);
  1225. }
  1226. opt_handler_free (&oh);
  1227. }
  1228. static void
  1229. initialize_client (struct app_context *app, struct addrinfo *address)
  1230. {
  1231. app->mode = NETWORK_MODE_CLIENT;
  1232. int sock_fd, err;
  1233. for (; address; address = address->ai_next)
  1234. {
  1235. sock_fd = socket (address->ai_family,
  1236. address->ai_socktype, address->ai_protocol);
  1237. if (sock_fd == -1)
  1238. continue;
  1239. char host_buf[NI_MAXHOST], serv_buf[NI_MAXSERV];
  1240. err = getnameinfo (address->ai_addr, address->ai_addrlen,
  1241. host_buf, sizeof host_buf, serv_buf, sizeof serv_buf,
  1242. NI_NUMERICHOST | NI_NUMERICSERV);
  1243. if (err)
  1244. {
  1245. print_error ("%s: %s", "getnameinfo", gai_strerror (err));
  1246. print_status ("connecting...");
  1247. }
  1248. else
  1249. {
  1250. char *x = format_host_port_pair (host_buf, serv_buf);
  1251. print_status ("connecting to %s...", x);
  1252. free (x);
  1253. }
  1254. if (!connect (sock_fd, address->ai_addr, address->ai_addrlen))
  1255. break;
  1256. xclose (sock_fd);
  1257. }
  1258. if (!address)
  1259. exit_fatal ("connection failed");
  1260. int yes = 1;
  1261. (void) setsockopt (sock_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof yes);
  1262. set_blocking (sock_fd, false);
  1263. app->server_fd = sock_fd;
  1264. ev_io_init (&app->server_read_watcher, on_server_ready, sock_fd, EV_READ);
  1265. ev_io_init (&app->server_write_watcher, on_server_ready, sock_fd, EV_WRITE);
  1266. // We're only interested in reading as the write queue is empty now
  1267. ev_io_start (EV_DEFAULT_ &app->server_read_watcher);
  1268. send_hello_request (app);
  1269. send_get_bitmap_request (app);
  1270. }
  1271. static void
  1272. initialize_server (struct app_context *app, struct addrinfo *address)
  1273. {
  1274. app->mode = NETWORK_MODE_SERVER;
  1275. int sock_fd = socket (address->ai_family,
  1276. address->ai_socktype, address->ai_protocol);
  1277. if (sock_fd == -1)
  1278. goto fail_socket;
  1279. if (bind (sock_fd, address->ai_addr, address->ai_addrlen)
  1280. || listen (sock_fd, 10))
  1281. goto fail;
  1282. int yes = 1;
  1283. (void) setsockopt (sock_fd, SOL_SOCKET, SO_KEEPALIVE, &yes, sizeof yes);
  1284. (void) setsockopt (sock_fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
  1285. set_blocking (sock_fd, false);
  1286. app->listen_fd = sock_fd;
  1287. ev_io_init (&app->listen_watcher, on_new_client, sock_fd, EV_READ);
  1288. ev_io_start (EV_DEFAULT_ &app->listen_watcher);
  1289. return;
  1290. fail:
  1291. xclose (sock_fd);
  1292. fail_socket:
  1293. exit_fatal ("%s: %s", "initialization failed", strerror (errno));
  1294. }
  1295. int
  1296. main (int argc, char *argv[])
  1297. {
  1298. TERMO_CHECK_VERSION;
  1299. setlocale (LC_CTYPE, "");
  1300. struct app_context app;
  1301. app_init (&app);
  1302. struct ev_loop *loop = EV_DEFAULT;
  1303. if (!loop)
  1304. exit_fatal ("cannot initialize libev");
  1305. struct app_options options;
  1306. app_options_init (&options);
  1307. parse_program_arguments (&options, argc, argv);
  1308. if (options.client_address)
  1309. initialize_client (&app, options.client_address);
  1310. else if (options.server_address)
  1311. initialize_server (&app, options.server_address);
  1312. else
  1313. app.mode = NETWORK_MODE_STANDALONE;
  1314. app.no_wait = options.no_wait;
  1315. app_options_free (&options);
  1316. termo_t *tk = termo_new (STDIN_FILENO, NULL, 0);
  1317. if (!tk)
  1318. exit_fatal ("cannot allocate termo instance");
  1319. app.tk = tk;
  1320. termo_set_mouse_tracking_mode (tk, TERMO_MOUSE_TRACKING_DRAG);
  1321. // Set up curses for our drawing needs
  1322. if (!initscr () || nonl () == ERR || curs_set (0) == ERR)
  1323. exit_fatal ("cannot initialize curses");
  1324. ev_set_userdata (loop, &app);
  1325. ev_signal_init (&app.winch_watcher, on_winch, SIGWINCH);
  1326. ev_signal_start (EV_DEFAULT_ &app.winch_watcher);
  1327. ev_io_init (&app.tty_watcher, on_tty_readable, STDIN_FILENO, EV_READ);
  1328. ev_io_start (EV_DEFAULT_ &app.tty_watcher);
  1329. ev_timer_init (&app.tty_timer, on_key_timer,
  1330. termo_get_waittime (app.tk) / 1000., 0);
  1331. init_palette (&app);
  1332. update_canvas_for_screen (&app);
  1333. redraw (&app);
  1334. redraw_canvas (&app);
  1335. ev_run (loop, 0);
  1336. endwin ();
  1337. app_free (&app);
  1338. ev_loop_destroy (loop);
  1339. return 0;
  1340. }