Moontalk server and client (provided by many parties)
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

357 linhas
8.2KB

  1. /* moontalk.c - @BAKE cc -O2 -std=gnu99 -Wall -Wextra -Wpedantic -Wno-format-truncation $@ -o $* \
  2. -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -lncurses -ltinfo $+
  3. * Written by Emil.
  4. * Licensed under the GPLv3 only.
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <unistd.h>
  10. #include <signal.h>
  11. #include <time.h>
  12. #include <errno.h>
  13. #include <ctype.h>
  14. #include <sys/ioctl.h>
  15. #include <sys/types.h>
  16. #include <sys/socket.h>
  17. #include <netdb.h>
  18. #include <arpa/inet.h>
  19. #include <netinet/in.h>
  20. #include <ncurses.h>
  21. #define SERV "7ks473deh6ggtwqsvbqdurepv5i6iblpbkx33b6cydon3ajph73sssad.onion"
  22. #define PORT "50000"
  23. #define NAME "anonymous"
  24. #define streq(a,b) (!strcmp(a,b))
  25. #define strneq(a,b,c) (!memcmp(a,b,c))
  26. int g_sockfd;
  27. #define g_y LINES
  28. #define g_x COLS
  29. #define HELP \
  30. "%s [options ...]\n" \
  31. "\n-serv SERVER Sets the server to connect to [default: " SERV "]" \
  32. "\n-port PORT Sets the port [default: " PORT "]" \
  33. "\n-name NAME Sets your display name [default: " NAME "]\n" \
  34. "\nControls\n" \
  35. "\nC-l Refreshes the screen" \
  36. "\nC-w Delete the previous word" \
  37. "\nC-c Close the client" \
  38. "\nUp/Down Scrolls all the way up/Scrolls down by a line\n"
  39. /* I know, and I don't care */
  40. #define TAB 9 /* */
  41. #define BACKSPACE 263 /* ^G */
  42. #define C_C 4 /* ... */
  43. #define C_D 4 /* quit */
  44. #define C_A 1 /* BOL */
  45. #define C_B 2 /* BOL */
  46. #define C_E 5 /* EOL */
  47. #define C_H 8 /* BACKSPACE */
  48. #define C_L 12 /* REFRESH */
  49. #define C_U 21 /* CLR TO BOL */
  50. #define C_W 23 /* DELETE PREVWORD */
  51. #define C_L 12 /* Signal full refresh */
  52. /****/
  53. void disconnect(void) {
  54. int sockfd = g_sockfd;
  55. if (sockfd > -1) { close(sockfd); }
  56. g_sockfd = -1;
  57. }
  58. /* always returns an accessible socket */
  59. int init_connection(char * serv, char * port) {
  60. int status, sockfd;
  61. struct addrinfo hints, * res;
  62. memset(&hints, 0, sizeof(struct addrinfo));
  63. hints.ai_family = AF_UNSPEC;
  64. hints.ai_socktype = SOCK_STREAM;
  65. if ((status = getaddrinfo(serv, port, &hints, &res)) != 0) {
  66. perror("init_connection");
  67. exit(1);
  68. }
  69. if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) == -1)
  70. { goto error; }
  71. if (connect(sockfd, res->ai_addr, res->ai_addrlen))
  72. { goto error; }
  73. freeaddrinfo(res);
  74. g_sockfd = sockfd;
  75. return sockfd;
  76. error:
  77. if (sockfd > -1) { close(sockfd); }
  78. perror("init_connection");
  79. exit(1);
  80. __builtin_unreachable();
  81. }
  82. //
  83. void fillline(WINDOW * w, int y, int xstart, char c) {
  84. int i = xstart, x = g_x;
  85. for (; i < x; ++i)
  86. { mvwaddch(w,y,i,c); }
  87. }
  88. void clearline(WINDOW * w, int y) {
  89. wmove(w, y, 0);
  90. wclrtoeol(w);
  91. }
  92. void sanitize(char * buf, size_t rem) {
  93. char * base = buf;
  94. buf += rem;
  95. while (*buf && buf - base) {
  96. if (*buf < ' ' || *buf > '~') {
  97. if (*buf != '\n')
  98. { *buf = '!'; }
  99. }
  100. --buf;
  101. }
  102. }
  103. int main (int argc, char ** argv) {
  104. char * serv = SERV, * port = PORT, name[32] = NAME;
  105. int sockfd;
  106. {
  107. char * argv0 = argv[0];
  108. while (++argv, --argc) {
  109. if (streq(*argv, "-help")) {
  110. printf(HELP, argv0);
  111. exit(1);
  112. }
  113. if (argc - 1)
  114. { --argc; ++argv; }
  115. else {
  116. printf("%s: %s requires argument\n", argv0, *argv);
  117. return 1;
  118. }
  119. if (streq(*(argv-1), "-serv")) {
  120. serv = *argv;
  121. } else if (streq(*(argv-1), "-port")) {
  122. port = *argv;
  123. } else if (streq(*(argv-1), "-name")) {
  124. memset(name, 0, 31);
  125. strncpy(name, *argv, 31);
  126. }
  127. }
  128. printf("Connecting to %s:%s as %s\n", serv, port, name);
  129. atexit(disconnect);
  130. sockfd = init_connection(serv, port);
  131. }
  132. initscr();
  133. noecho();
  134. keypad(stdscr, ERR);
  135. nodelay(stdscr, TRUE);
  136. ESCDELAY = 0;
  137. curs_set(0);
  138. if (has_colors() && can_change_color()) {
  139. short bg, fg;
  140. /* leaks memory :( */
  141. start_color();
  142. for (bg = 0; bg < 8; ++bg) {
  143. for (fg = 0; fg < 8; ++fg) {
  144. init_pair(16 + fg + (bg * 8), fg, bg);
  145. }
  146. }
  147. }
  148. clear();
  149. #define WINCOUNT 3
  150. WINDOW * w[WINCOUNT];
  151. #define header w[0]
  152. #define body w[1]
  153. #define input w[2]
  154. #define SENDMAX (1 << 8) - 1
  155. #define RECVMAX 17663 /* (1 << 11) */
  156. char raw[SENDMAX + RECVMAX];
  157. char * sendbuf = raw, * recvbuf = raw + SENDMAX, * off = recvbuf;
  158. size_t sendminlen, sendlen, recvlen = 0, offlen = recvlen;
  159. size_t edit;
  160. #define TIMESTR "<%Y/%m/%d %H:%M:%S "
  161. #define TIMESTRMAX 21
  162. #define UPDATE_TIME()\
  163. do { \
  164. t = time(NULL); \
  165. tm = gmtime(&t); \
  166. strftime(sendbuf, TIMESTRMAX, TIMESTR, tm); \
  167. sendbuf[TIMESTRMAX - 1] = ' '; \
  168. } while (0)
  169. time_t t;
  170. struct tm * tm;
  171. useconds_t frame = 30;
  172. useconds_t interval = 1000000. / frame;
  173. int32_t ct;
  174. int ch, ret;
  175. size_t i;
  176. size_t namelen = strlen(name);
  177. edit = sendlen = sendminlen = TIMESTRMAX + namelen + 2;
  178. /* fill in the name */
  179. memcpy(sendbuf + TIMESTRMAX, name, namelen);
  180. memcpy(sendbuf + TIMESTRMAX + namelen, "> ", 2);
  181. int inputrefresh, bodyrefresh;
  182. hardrefresh:
  183. ct = 0;
  184. inputrefresh = bodyrefresh = 1;
  185. header = newwin(1, g_x, 0, 0);
  186. body = newwin(g_y - 4, g_x, 1, 0);
  187. input = newwin(3, g_x, g_y - 3, 0);
  188. fillline(header, 0, 0, '-');
  189. mvwprintw(header, 0, 2, " moontalk ");
  190. fillline(input, 0, 0, '-');
  191. while (1) {
  192. /* input */
  193. while ((ch = getch()) != -1) {
  194. if (ch == KEY_RESIZE || ch == C_L) {
  195. for (i = 0; i < WINCOUNT; ++i)
  196. { delwin(w[i]); }
  197. endwin();
  198. erase();
  199. refresh();
  200. clear();
  201. flushinp();
  202. goto hardrefresh;
  203. }
  204. else if ((ch > 31 && ch < 127)) {
  205. if (sendlen + 1 < SENDMAX)
  206. {
  207. memmove(sendbuf + edit + 1, sendbuf + edit, sendlen - edit);
  208. sendbuf[edit++] = ch; ++sendlen;
  209. }
  210. inputrefresh = 1;
  211. }
  212. else if (ch == '\n') {
  213. if (sendlen == sendminlen)
  214. { continue; }
  215. if (sendlen + 1 < SENDMAX)
  216. { sendbuf[sendlen++] = '\n'; }
  217. if (send(sockfd, sendbuf, sendlen, 0) > 0) {
  218. memcpy(recvbuf + recvlen, sendbuf, (sendlen + recvlen < RECVMAX) * sendlen);
  219. recvlen += sendlen;
  220. offlen += sendlen;
  221. } else {
  222. mvwprintw(input, 1, 0, "message failed: %s", strerror(errno));
  223. }
  224. bodyrefresh = inputrefresh = 1;
  225. edit = sendlen = sendminlen;
  226. }
  227. else if (ch == BACKSPACE || ch == C_H) {
  228. inputrefresh = 1;
  229. if (sendlen - 1 >= sendminlen && edit - 1 >= sendminlen)
  230. {
  231. memmove(sendbuf + edit - 1, sendbuf + edit, sendlen - edit);
  232. --sendlen; --edit;
  233. }
  234. inputrefresh = 1;
  235. }
  236. else if (ch == KEY_LEFT) {
  237. if (edit > sendminlen) { --edit; }
  238. }
  239. else if (ch == KEY_RIGHT) {
  240. if (edit < sendlen) { ++edit; }
  241. }
  242. else if (ch == KEY_DOWN) {
  243. mvwprintw(input, 1, 150, "scroll down %ld", offlen);
  244. while ((size_t)(off - recvbuf) < recvlen && *off != '\n') { ++off; }
  245. if (*off == '\n') { ++off; }
  246. wclear(body);
  247. bodyrefresh = 1;
  248. }
  249. else if (ch == KEY_UP) {
  250. mvwprintw(input, 1, 150, "scroll up %ld", offlen);
  251. if (off - 2 - recvbuf > 0) { off -= 2; }
  252. while (off - recvbuf > 0 && *off != '\n') { --off; }
  253. if (*off == '\n') { ++off; }
  254. bodyrefresh = 1;
  255. }
  256. else if (ch == C_W) {
  257. i = edit;
  258. while (i > sendminlen && isspace(sendbuf[i - 1])) { --i; }
  259. while (i > sendminlen && !isspace(sendbuf[i - 1])) { --i; }
  260. if (i == edit) { continue; }
  261. mvwprintw(input, 1, 200, "diff:%ld", sendlen - edit);
  262. /* memmove(sendbuf + i, sendbuf + edit, sendlen - edit); */
  263. /* sendlen -= edit; */
  264. /* edit = i; */
  265. /* mvwprintw(input, 1, 200, "i:%ld:%ld:sendl:%3ld", */
  266. /* i - sendminlen, (sendbuf + edit) - (sendbuf + i), sendlen - sendminlen); */
  267. inputrefresh = 1;
  268. }
  269. }
  270. /* update and rendering */
  271. if (inputrefresh) {
  272. clearline(input, 2);
  273. mvwaddnstr(input, 2, 0, sendbuf, sendlen);
  274. mvwchgat(input, 2, edit, 1, A_REVERSE, 0, NULL);
  275. }
  276. if (ct % frame == 0) {
  277. UPDATE_TIME();
  278. }
  279. if (ct % frame == 0 || bodyrefresh) {
  280. ret = recv(sockfd, recvbuf + recvlen, RECVMAX - recvlen, MSG_DONTWAIT);
  281. if (errno && errno != EAGAIN)
  282. { mvwaddstr(input, 1, 0, strerror(errno)); }
  283. if (bodyrefresh) {
  284. bodyrefresh = 0;
  285. if (!(ret > 0))
  286. goto _bodyrefresh;
  287. }
  288. if (ret > 0) {
  289. sanitize(recvbuf + recvlen, ret);
  290. if (ret + recvlen < RECVMAX)
  291. {
  292. recvlen += ret;
  293. offlen += ret;
  294. }
  295. _bodyrefresh:
  296. mvwprintw(input, 1, 50, "render ct:%d ret:%d", ct, ret);
  297. mvwaddnstr(body, 0,0, off, offlen);
  298. }
  299. }
  300. refresh();
  301. for (i = 0; i < WINCOUNT; ++i)
  302. { wnoutrefresh(w[i]); }
  303. doupdate();
  304. usleep(interval);
  305. ++ct;
  306. }
  307. endwin();
  308. }