diff options
Diffstat (limited to 'testing/toxic/chat.c')
-rw-r--r-- | testing/toxic/chat.c | 445 |
1 files changed, 0 insertions, 445 deletions
diff --git a/testing/toxic/chat.c b/testing/toxic/chat.c deleted file mode 100644 index 9454010f..00000000 --- a/testing/toxic/chat.c +++ /dev/null | |||
@@ -1,445 +0,0 @@ | |||
1 | /* | ||
2 | * Toxic -- Tox Curses Client | ||
3 | */ | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <stdint.h> | ||
8 | #include <ctype.h> | ||
9 | #include <time.h> | ||
10 | #include <limits.h> | ||
11 | |||
12 | #include "../../core/Messenger.h" | ||
13 | #include "../../core/network.h" | ||
14 | |||
15 | #include "windows.h" | ||
16 | #include "friendlist.h" | ||
17 | #include "chat.h" | ||
18 | |||
19 | #define CURS_Y_OFFSET 3 | ||
20 | |||
21 | typedef struct { | ||
22 | int friendnum; | ||
23 | wchar_t line[MAX_STR_SIZE]; | ||
24 | size_t pos; | ||
25 | WINDOW *history; | ||
26 | WINDOW *linewin; | ||
27 | } ChatContext; | ||
28 | |||
29 | void print_help(ChatContext *self); | ||
30 | void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd); | ||
31 | |||
32 | struct tm *get_time(void) | ||
33 | { | ||
34 | struct tm *timeinfo; | ||
35 | time_t now; | ||
36 | time(&now); | ||
37 | timeinfo = localtime(&now); | ||
38 | return timeinfo; | ||
39 | } | ||
40 | |||
41 | static void chat_onMessage(ToxWindow *self, Messenger *m, int num, uint8_t *msg, uint16_t len) | ||
42 | { | ||
43 | ChatContext *ctx = (ChatContext *) self->x; | ||
44 | uint8_t nick[MAX_NAME_LENGTH] = {0}; | ||
45 | struct tm *timeinfo = get_time(); | ||
46 | |||
47 | if (ctx->friendnum != num) | ||
48 | return; | ||
49 | |||
50 | getname(m, num, (uint8_t *) &nick); | ||
51 | msg[len - 1] = '\0'; | ||
52 | nick[MAX_NAME_LENGTH - 1] = '\0'; | ||
53 | |||
54 | wattron(ctx->history, COLOR_PAIR(2)); | ||
55 | wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); | ||
56 | wattroff(ctx->history, COLOR_PAIR(2)); | ||
57 | wattron(ctx->history, COLOR_PAIR(4)); | ||
58 | wprintw(ctx->history, "%s: ", nick); | ||
59 | wattroff(ctx->history, COLOR_PAIR(4)); | ||
60 | wprintw(ctx->history, "%s\n", msg); | ||
61 | |||
62 | self->blink = true; | ||
63 | beep(); | ||
64 | } | ||
65 | |||
66 | static void chat_onAction(ToxWindow *self, Messenger *m, int num, uint8_t *action, uint16_t len) | ||
67 | { | ||
68 | ChatContext *ctx = (ChatContext *) self->x; | ||
69 | struct tm *timeinfo = get_time(); | ||
70 | |||
71 | if (ctx->friendnum != num) | ||
72 | return; | ||
73 | |||
74 | action[len - 1] = '\0'; | ||
75 | |||
76 | wattron(ctx->history, COLOR_PAIR(2)); | ||
77 | wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); | ||
78 | wattroff(ctx->history, COLOR_PAIR(2)); | ||
79 | |||
80 | wattron(ctx->history, COLOR_PAIR(5)); | ||
81 | wprintw(ctx->history, "%s\n", action); | ||
82 | wattroff(ctx->history, COLOR_PAIR(5)); | ||
83 | |||
84 | self->blink = true; | ||
85 | beep(); | ||
86 | } | ||
87 | |||
88 | static void chat_onNickChange(ToxWindow *self, int num, uint8_t *nick, uint16_t len) | ||
89 | { | ||
90 | ChatContext *ctx = (ChatContext *) self->x; | ||
91 | struct tm *timeinfo = get_time(); | ||
92 | |||
93 | if (ctx->friendnum != num) | ||
94 | return; | ||
95 | |||
96 | wattron(ctx->history, COLOR_PAIR(2)); | ||
97 | wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); | ||
98 | wattroff(ctx->history, COLOR_PAIR(2)); | ||
99 | |||
100 | nick[len - 1] = '\0'; | ||
101 | snprintf(self->title, sizeof(self->title), "[%s (%d)]", nick, num); | ||
102 | |||
103 | wattron(ctx->history, COLOR_PAIR(3)); | ||
104 | wprintw(ctx->history, "* Your partner changed nick to '%s'\n", nick); | ||
105 | wattroff(ctx->history, COLOR_PAIR(3)); | ||
106 | } | ||
107 | |||
108 | static void chat_onStatusChange(ToxWindow *self, int num, uint8_t *status, uint16_t len) | ||
109 | { | ||
110 | ChatContext *ctx = (ChatContext *) self->x; | ||
111 | struct tm *timeinfo = get_time(); | ||
112 | |||
113 | if (ctx->friendnum != num) | ||
114 | return; | ||
115 | |||
116 | wattron(ctx->history, COLOR_PAIR(2)); | ||
117 | wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); | ||
118 | wattroff(ctx->history, COLOR_PAIR(2)); | ||
119 | |||
120 | status[len - 1] = '\0'; | ||
121 | snprintf(self->title, sizeof(self->title), "[%s (%d)]", status, num); | ||
122 | |||
123 | wattron(ctx->history, COLOR_PAIR(3)); | ||
124 | wprintw(ctx->history, "* Your partner changed status to '%s'\n", status); | ||
125 | wattroff(ctx->history, COLOR_PAIR(3)); | ||
126 | |||
127 | } | ||
128 | |||
129 | /* check that the string has one non-space character */ | ||
130 | int string_is_empty(char *string) | ||
131 | { | ||
132 | int rc = 0; | ||
133 | char *copy = strdup(string); | ||
134 | rc = ((strtok(copy, " ") == NULL) ? 1 : 0); | ||
135 | free(copy); | ||
136 | return rc; | ||
137 | } | ||
138 | |||
139 | /* convert wide characters to null terminated string */ | ||
140 | static char *wcs_to_char(wchar_t *string) | ||
141 | { | ||
142 | size_t len = 0; | ||
143 | char *ret = NULL; | ||
144 | |||
145 | len = wcstombs(NULL, string, 0); | ||
146 | if (len != (size_t) -1) { | ||
147 | len++; | ||
148 | ret = malloc(len); | ||
149 | wcstombs(ret, string, len); | ||
150 | } else { | ||
151 | ret = malloc(2); | ||
152 | ret[0] = ' '; | ||
153 | ret[1] = '\0'; | ||
154 | } | ||
155 | return ret; | ||
156 | } | ||
157 | |||
158 | /* convert a wide char to null terminated string */ | ||
159 | static char *wc_to_char(wchar_t ch) | ||
160 | { | ||
161 | int len = 0; | ||
162 | static char ret[MB_LEN_MAX + 1]; | ||
163 | |||
164 | len = wctomb(ret, ch); | ||
165 | if (len == -1) { | ||
166 | ret[0] = ' '; | ||
167 | ret[1] = '\0'; | ||
168 | } else { | ||
169 | ret[len] = '\0'; | ||
170 | } | ||
171 | |||
172 | return ret; | ||
173 | } | ||
174 | |||
175 | static void chat_onKey(ToxWindow *self, Messenger *m, wint_t key) | ||
176 | { | ||
177 | ChatContext *ctx = (ChatContext *) self->x; | ||
178 | struct tm *timeinfo = get_time(); | ||
179 | |||
180 | int x, y, y2, x2; | ||
181 | getyx(self->window, y, x); | ||
182 | getmaxyx(self->window, y2, x2); | ||
183 | |||
184 | /* Add printable chars to buffer and print on input space */ | ||
185 | #if HAVE_WIDECHAR | ||
186 | if (iswprint(key)) { | ||
187 | #else | ||
188 | if (isprint(key)) { | ||
189 | #endif | ||
190 | if (ctx->pos != sizeof(ctx->line) - 1) { | ||
191 | mvwaddstr(self->window, y, x, wc_to_char(key)); | ||
192 | ctx->line[ctx->pos++] = key; | ||
193 | ctx->line[ctx->pos] = L'\0'; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | /* BACKSPACE key: Remove one character from line */ | ||
198 | else if (key == 0x107 || key == 0x8 || key == 0x7f) { | ||
199 | if (ctx->pos > 0) { | ||
200 | ctx->line[--ctx->pos] = L'\0'; | ||
201 | |||
202 | if (x == 0) | ||
203 | mvwdelch(self->window, y - 1, x2 - 1); | ||
204 | else | ||
205 | mvwdelch(self->window, y, x - 1); | ||
206 | } | ||
207 | } | ||
208 | |||
209 | /* RETURN key: Execute command or print line */ | ||
210 | else if (key == '\n') { | ||
211 | char *line = wcs_to_char(ctx->line); | ||
212 | wclear(ctx->linewin); | ||
213 | wmove(self->window, y2 - CURS_Y_OFFSET, 0); | ||
214 | wclrtobot(self->window); | ||
215 | |||
216 | if (line[0] == '/') | ||
217 | execute(self, ctx, m, line); | ||
218 | else { | ||
219 | /* make sure the string has at least non-space character */ | ||
220 | if (!string_is_empty(line)) { | ||
221 | uint8_t selfname[MAX_NAME_LENGTH]; | ||
222 | getself_name(m, selfname, sizeof(selfname)); | ||
223 | |||
224 | wattron(ctx->history, COLOR_PAIR(2)); | ||
225 | wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); | ||
226 | wattroff(ctx->history, COLOR_PAIR(2)); | ||
227 | wattron(ctx->history, COLOR_PAIR(1)); | ||
228 | wprintw(ctx->history, "%s: ", selfname); | ||
229 | wattroff(ctx->history, COLOR_PAIR(1)); | ||
230 | wprintw(ctx->history, "%s\n", line); | ||
231 | |||
232 | if (m_sendmessage(m, ctx->friendnum, (uint8_t *) line, strlen(line) + 1) == 0) { | ||
233 | wattron(ctx->history, COLOR_PAIR(3)); | ||
234 | wprintw(ctx->history, " * Failed to send message.\n"); | ||
235 | wattroff(ctx->history, COLOR_PAIR(3)); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | ctx->line[0] = L'\0'; | ||
241 | ctx->pos = 0; | ||
242 | free(line); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | void execute(ToxWindow *self, ChatContext *ctx, Messenger *m, char *cmd) | ||
247 | { | ||
248 | if (!strcmp(cmd, "/clear") || !strcmp(cmd, "/c")) { | ||
249 | wclear(self->window); | ||
250 | wclear(ctx->history); | ||
251 | int x, y; | ||
252 | getmaxyx(self->window, y, x); | ||
253 | (void) x; | ||
254 | wmove(self->window, y - CURS_Y_OFFSET, 0); | ||
255 | } | ||
256 | |||
257 | else if (!strcmp(cmd, "/help") || !strcmp(cmd, "/h")) | ||
258 | print_help(ctx); | ||
259 | |||
260 | else if (!strcmp(cmd, "/quit") || !strcmp(cmd, "/exit") || !strcmp(cmd, "/q")) { | ||
261 | endwin(); | ||
262 | exit(0); | ||
263 | } | ||
264 | |||
265 | else if (!strncmp(cmd, "/me ", strlen("/me "))) { | ||
266 | struct tm *timeinfo = get_time(); | ||
267 | char *action = strchr(cmd, ' '); | ||
268 | |||
269 | if (action == NULL) { | ||
270 | wprintw(self->window, "Invalid syntax.\n"); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | action++; | ||
275 | |||
276 | wattron(ctx->history, COLOR_PAIR(2)); | ||
277 | wprintw(ctx->history, "[%02d:%02d:%02d] ", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec); | ||
278 | wattroff(ctx->history, COLOR_PAIR(2)); | ||
279 | |||
280 | uint8_t selfname[MAX_NAME_LENGTH]; | ||
281 | int len = getself_name(m, selfname, sizeof(selfname)); | ||
282 | char msg[MAX_STR_SIZE - len - 4]; | ||
283 | snprintf(msg, sizeof(msg), "* %s %s\n", (uint8_t *) selfname, action); | ||
284 | |||
285 | wattron(ctx->history, COLOR_PAIR(5)); | ||
286 | wprintw(ctx->history, msg); | ||
287 | wattroff(ctx->history, COLOR_PAIR(5)); | ||
288 | |||
289 | if (m_sendaction(m, ctx->friendnum, (uint8_t *) msg, strlen(msg) + 1) < 0) { | ||
290 | wattron(ctx->history, COLOR_PAIR(3)); | ||
291 | wprintw(ctx->history, " * Failed to send action\n"); | ||
292 | wattroff(ctx->history, COLOR_PAIR(3)); | ||
293 | } | ||
294 | } | ||
295 | |||
296 | else if (!strncmp(cmd, "/status ", strlen("/status "))) { | ||
297 | char *status = strchr(cmd, ' '); | ||
298 | char *msg; | ||
299 | char *status_text; | ||
300 | |||
301 | if (status == NULL) { | ||
302 | wprintw(ctx->history, "Invalid syntax.\n"); | ||
303 | return; | ||
304 | } | ||
305 | |||
306 | status++; | ||
307 | USERSTATUS status_kind; | ||
308 | |||
309 | if (!strncmp(status, "online", strlen("online"))) { | ||
310 | status_kind = USERSTATUS_NONE; | ||
311 | status_text = "ONLINE"; | ||
312 | } | ||
313 | |||
314 | else if (!strncmp(status, "away", strlen("away"))) { | ||
315 | status_kind = USERSTATUS_AWAY; | ||
316 | status_text = "AWAY"; | ||
317 | } | ||
318 | |||
319 | else if (!strncmp(status, "busy", strlen("busy"))) { | ||
320 | status_kind = USERSTATUS_BUSY; | ||
321 | status_text = "BUSY"; | ||
322 | } | ||
323 | |||
324 | else { | ||
325 | wprintw(ctx->history, "Invalid status.\n"); | ||
326 | return; | ||
327 | } | ||
328 | |||
329 | msg = strchr(status, ' '); | ||
330 | |||
331 | if (msg == NULL) { | ||
332 | m_set_userstatus(m, status_kind); | ||
333 | wprintw(ctx->history, "Status set to: %s\n", status_text); | ||
334 | } else { | ||
335 | msg++; | ||
336 | m_set_userstatus(m, status_kind); | ||
337 | m_set_statusmessage(m, ( uint8_t *) msg, strlen(msg) + 1); | ||
338 | wprintw(ctx->history, "Status set to: %s, %s\n", status_text, msg); | ||
339 | } | ||
340 | } | ||
341 | |||
342 | else if (!strncmp(cmd, "/nick ", strlen("/nick "))) { | ||
343 | char *nick; | ||
344 | nick = strchr(cmd, ' '); | ||
345 | |||
346 | if (nick == NULL) { | ||
347 | wprintw(ctx->history, "Invalid syntax.\n"); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | nick++; | ||
352 | setname(m, (uint8_t *) nick, strlen(nick) + 1); | ||
353 | wprintw(ctx->history, "Nickname set to: %s\n", nick); | ||
354 | } | ||
355 | |||
356 | else if (!strcmp(cmd, "/myid")) { | ||
357 | char id[FRIEND_ADDRESS_SIZE * 2 + 1] = {0}; | ||
358 | int i; | ||
359 | uint8_t address[FRIEND_ADDRESS_SIZE]; | ||
360 | getaddress(m, address); | ||
361 | |||
362 | for (i = 0; i < FRIEND_ADDRESS_SIZE; i++) { | ||
363 | char xx[3]; | ||
364 | snprintf(xx, sizeof(xx), "%02X", address[i] & 0xff); | ||
365 | strcat(id, xx); | ||
366 | } | ||
367 | |||
368 | wprintw(ctx->history, "%s\n", id); | ||
369 | } | ||
370 | |||
371 | else if (strcmp(cmd, "/close") == 0) { | ||
372 | int f_num = ctx->friendnum; | ||
373 | delwin(ctx->linewin); | ||
374 | del_window(self); | ||
375 | disable_chatwin(f_num); | ||
376 | } | ||
377 | |||
378 | else | ||
379 | wprintw(ctx->history, "Invalid command.\n"); | ||
380 | } | ||
381 | |||
382 | static void chat_onDraw(ToxWindow *self, Messenger *m) | ||
383 | { | ||
384 | curs_set(1); | ||
385 | int x, y; | ||
386 | getmaxyx(self->window, y, x); | ||
387 | (void) y; | ||
388 | ChatContext *ctx = (ChatContext *) self->x; | ||
389 | mvwhline(ctx->linewin, 0, 0, '_', x); | ||
390 | wrefresh(self->window); | ||
391 | } | ||
392 | |||
393 | static void chat_onInit(ToxWindow *self, Messenger *m) | ||
394 | { | ||
395 | int x, y; | ||
396 | ChatContext *ctx = (ChatContext *) self->x; | ||
397 | getmaxyx(self->window, y, x); | ||
398 | ctx->history = subwin(self->window, y - 4, x, 0, 0); | ||
399 | scrollok(ctx->history, 1); | ||
400 | ctx->linewin = subwin(self->window, 2, x, y - 4, 0); | ||
401 | print_help(ctx); | ||
402 | wmove(self->window, y - CURS_Y_OFFSET, 0); | ||
403 | } | ||
404 | |||
405 | void print_help(ChatContext *self) | ||
406 | { | ||
407 | wattron(self->history, COLOR_PAIR(2) | A_BOLD); | ||
408 | wprintw(self->history, "Commands:\n"); | ||
409 | wattroff(self->history, A_BOLD); | ||
410 | |||
411 | wprintw(self->history, " /status <type> <message> : Set your status\n"); | ||
412 | wprintw(self->history, " /nick <nickname> : Set your nickname\n"); | ||
413 | wprintw(self->history, " /me <action> : Do an action\n"); | ||
414 | wprintw(self->history, " /myid : Print your ID\n"); | ||
415 | wprintw(self->history, " /clear : Clear the screen\n"); | ||
416 | wprintw(self->history, " /close : Close the current chat window\n"); | ||
417 | wprintw(self->history, " /quit or /exit : Exit program\n"); | ||
418 | wprintw(self->history, " /help : Print this message again\n\n"); | ||
419 | |||
420 | wattroff(self->history, COLOR_PAIR(2)); | ||
421 | } | ||
422 | |||
423 | ToxWindow new_chat(Messenger *m, int friendnum) | ||
424 | { | ||
425 | ToxWindow ret; | ||
426 | memset(&ret, 0, sizeof(ret)); | ||
427 | |||
428 | ret.onKey = &chat_onKey; | ||
429 | ret.onDraw = &chat_onDraw; | ||
430 | ret.onInit = &chat_onInit; | ||
431 | ret.onMessage = &chat_onMessage; | ||
432 | ret.onNickChange = &chat_onNickChange; | ||
433 | ret.onStatusChange = &chat_onStatusChange; | ||
434 | ret.onAction = &chat_onAction; | ||
435 | |||
436 | uint8_t nick[MAX_NAME_LENGTH] = {0}; | ||
437 | getname(m, friendnum, (uint8_t *) &nick); | ||
438 | |||
439 | snprintf(ret.title, sizeof(ret.title), "[%s (%d)]", nick, friendnum); | ||
440 | |||
441 | ChatContext *x = calloc(1, sizeof(ChatContext)); | ||
442 | x->friendnum = friendnum; | ||
443 | ret.x = (void *) x; | ||
444 | return ret; | ||
445 | } | ||