#pragma once #include #include #include #include #include #include #include #include #include #include #include #define DC_SIMPLEPRINT(w, c, f, ...) do { wattron(w, COLOR_PAIR(c)); wprintw(w, f __VA_OPT__(,) __VA_ARGS__); wrefresh(w); } while (0) /* link with -lncursesw and -lformw */ int dc_ui_print_message (WINDOW * textwin, struct dc_message * msg2do) { char timestring[64]; struct tm timestruct; localtime_r(&msg2do->time, ×truct); strftime(timestring, 64, DC_I18N_MSGTIMEF, ×truct); /* recimo, da je 23 znakov */ DC_SIMPLEPRINT(textwin, 3, "%018.18s %08.8s: %s\n", timestring, msg2do->username, msg2do->content); msg2do->status = 1; return 1; } int dc_ui_processline (struct dc_thread_control * t, char * l, WINDOW * textwin) { struct dc_client * c = t->clients[0]; /* first we trim spaces at the end */ int i, j, k; for (i = strlen(l)-1; i >= 0; i--) if (l[i] == ' ') l[i] = '\0'; else break; if (l[0] == '/') switch (l[1]) { case 'g': case 'G': case 's': case 'S': /* servers */ DC_CRLE(c, c->guilds_lock); for (i = 0; i < c->guilds_sizeof; i++) DC_SIMPLEPRINT(textwin, 4, " %02d. %s\n", i, c->guilds[i]->name); DC_CUE(c, c->guilds_lock); break; case 'c': case 'C': case 'k': case 'K': DC_CRLE(c, c->guilds_lock); if (!strchr(l, ' ') || (j = atoi(strchr(l, ' ')+1)) >= c->guilds_sizeof) { DC_SIMPLEPRINT(textwin, 1, DC_I18N_UI_USAGE ": " DC_I18N_UI_CHANNELS_USAGE "\n", c->guilds_sizeof-1); DC_CUE(c, c->guilds_lock); break; } for (i = 0; i < c->guilds[j]->channels_sizeof; i++) DC_SIMPLEPRINT(textwin, 4, " %02d. %s - %s\n", i, c->guilds[j]->channels[i]->name, c->guilds[j]->channels[i]->topic); DC_CUE(c, c->guilds_lock); break; case 'j': case 'J': case 'p': case 'P': DC_CRLE(c, c->guilds_lock); char * jp; if (!(jp = strchr(l, ' ')) || (j = atoi(jp+1)) >= c->guilds_sizeof) { DC_SIMPLEPRINT(textwin, 1, DC_I18N_UI_USAGE ": " DC_I18N_UI_JOIN_USAGE "\n", c->guilds_sizeof-1, 999); DC_CUE(c, c->guilds_lock); break; } if (!strchr(jp+1, ' ') || (k = atoi(strchr(jp+1, ' ')+1)) >= c->guilds[j]->channels_sizeof) { DC_SIMPLEPRINT(textwin, 1, DC_I18N_UI_USAGE ": " DC_I18N_UI_JOIN_USAGE "\n", c->guilds_sizeof-1, c->guilds[j]->channels_sizeof-1); DC_CUE(c, c->guilds_lock); break; } for (i = c->guilds[j]->channels[k]->messages_sizeof-1; i >= 0; i--) dc_ui_print_message(textwin, c->guilds[j]->channels[k]->messages[i]); c->joinedchannel = c->guilds[j]->channels[k]; DC_CUE(c, c->guilds_lock); break; case 'q': case 'Q': case 'i': case 'I': t->power_api = 2; /* 2 for shutdown */ t->power_ui = 2; break; case 'N': /* api nit (thread) control */ case 'n': if (!strchr(l, ' ')) { DC_SIMPLEPRINT(textwin, 1, "!strchr(l, ' ')\n"); break; } t->power_api = atoi(strchr(l, ' ')+1); DC_SIMPLEPRINT(textwin, 4, "t->power_api = %d\n", atoi(strchr(l, ' ')+1)); break; default: DC_SIMPLEPRINT(textwin, 1, DC_I18N_UI_CNF "\n"); } else { /* send the message, it's not a command */ if (!c->joinedchannel) { DC_SIMPLEPRINT(textwin, 1, "!c->joinedchannel - %s\n", DC_I18N_UI_NOT_JOINED); return -1; } if (!strlen(l)) { DC_SIMPLEPRINT(textwin, 1, "!strlen(l) - %s\n", DC_I18N_UI_EMPTYMSG); return -2; } if (time(NULL) - c->last_sent_message <= c->joinedchannel->slowmode) { DC_SIMPLEPRINT(textwin, 1, DC_I18N_UI_SLOWMODE "\n", c->joinedchannel->slowmode, c->joinedchannel->slowmode-(time(NULL)-c->last_sent_message)); return -3; } c->last_sent_message = time(NULL); /* because the other thread may not update counter before the next message is sent */ /* raise(SIGINT); */ /* To continue from here in GDB: "signal 0". */ DC_CWLE(c, c->sent_messages_lock); c->sent_messages = realloc(c->sent_messages, sizeof(struct dc_message *)*++c->sent_messages_sizeof); #define DC_UISM c->sent_messages[c->sent_messages_sizeof-1] /* ui send messaeg */ DC_UISM = calloc(1, sizeof(struct dc_message)); DC_UISM->content = malloc(strlen(l)+1); strcpy(DC_UISM->content, l); DC_UISM->channel = c->joinedchannel; DC_CUE(c, c->sent_messages_lock); /* DO NOT free it */ } wrefresh(textwin); return 1; } int dc_ui_thread (struct dc_thread_control * t) { while (!t->power_ui) usleep(250000); FIELD * field[2]; /* field[0] je polje z besedilom */ field[1] = NULL; FORM * form; int ret, x, y; wint_t ch; struct dc_client * c = t->clients[0]; initscr(); cbreak(); noecho(); nodelay(stdscr, TRUE); setlocale(LC_ALL, ""); start_color(); init_pair(2, COLOR_YELLOW, COLOR_BLACK); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(3, COLOR_WHITE, COLOR_BLACK); init_pair(4, COLOR_GREEN, COLOR_BLACK); init_pair(5, COLOR_CYAN, COLOR_BLACK); keypad(stdscr, TRUE); getmaxyx(stdscr, y, x); /* to je macro, zato y in x nista kazalca (;: */ WINDOW * textwin = subwin(stdscr, y-3, x, 0, 0); WINDOW * formwin = subwin(stdscr, 2, x, y-2, 0); scrollok(textwin, TRUE); field[0] = new_field(2, x, y-2, 0, 5 /* offscreen rows */, 0); set_field_back(field[0], A_UNDERLINE); field_opts_off(field[0], O_AUTOSKIP); form = new_form(field); set_form_win(form, formwin); post_form(form); int i = 0; wmove(textwin, 0, 0); refresh(); struct dc_channel * prev_joinedchannel = (void *)&i; /* just so we get something that isn't null without warnings (): */ while (t->power_ui != 2) { if (!(rand() % 10)) { /* roughly every 10 cycles we get errors and messages */ assert(!DC_CRLE(c, c->errors_lock)); for (int i = 0; i < c->errors_sizeof; i++) { if (!c->errors[i]->reported) { DC_SIMPLEPRINT(textwin, 1, "[" DC_I18N_ERROR "] %s()@%s:%lu: %s", c->errors[i]->function, c->errors[i]->file, c->errors[i]->line, c->errors[i]->message); c->errors[i]->reported = 1; } } assert(!pthread_rwlock_unlock(c->errors_lock)); /* deadlock if we unlock errors with error reporting, duh */ if (c->joinedchannel) { DC_CRLE(c, c->guilds_lock); for (int i = c->joinedchannel->messages_sizeof-1; i >= 0; i--) { struct dc_message * msg2do = c->joinedchannel->messages[i]; if (!msg2do->status) dc_ui_print_message(textwin, msg2do); } DC_CUE(c, c->guilds_lock); } if (prev_joinedchannel != c->joinedchannel) { curs_set(0); /* too flashy */ attron(COLOR_PAIR(5)); if (c->joinedchannel) { DC_CRLE(c, c->guilds_lock); mvprintw(y-3, 0, "#%s @ %s%s%s ", c->joinedchannel->name, c->joinedchannel->guild->name, strlen(c->joinedchannel->topic) ? " - " : "", c->joinedchannel->topic); DC_CUE(c, c->guilds_lock); } else { attron(COLOR_PAIR(2)); mvprintw(y-3, 0, DC_I18N_UI_LINE_BEFORE_JOIN); } curs_set(1); prev_joinedchannel = c->joinedchannel; } pos_form_cursor(form); } ret = get_wch(&ch); if (ret != ERR) { switch (ch) { case KEY_LEFT: form_driver(form, REQ_PREV_CHAR); break; case KEY_RIGHT: form_driver(form, REQ_NEXT_CHAR); break; case KEY_BACKSPACE: form_driver(form, REQ_DEL_PREV); break; case KEY_DOWN: form_driver(form, REQ_NEXT_LINE); break; case KEY_UP: form_driver(form, REQ_PREV_LINE); break; case KEY_DC: form_driver(form, REQ_DEL_CHAR); break; case KEY_END: form_driver(form, REQ_END_LINE); break; case KEY_HOME: form_driver(form, REQ_BEG_LINE); break; case KEY_SLEFT: form_driver(form, REQ_PREV_WORD); break; case KEY_SRIGHT: form_driver(form, REQ_NEXT_WORD); break; case KEY_SDC: form_driver(form, REQ_CLR_FIELD); break; case KEY_ENTER: case 10: form_driver(form, REQ_NEXT_FIELD); form_driver(form, REQ_PREV_FIELD); if (dc_ui_processline(t, field_buffer(field[0], 0), textwin) > 0) form_driver(form, REQ_CLR_FIELD); pos_form_cursor(form); break; default: form_driver_w(form, ret, ch); break; } wrefresh(formwin); } /* wnoutrefresh(stdscr); wnoutrefresh(textwin); doupdate(); */ i++; usleep(2500); while (t->power_ui == 0) usleep(250000); } unpost_form(form); free_form(form); free_field(field[0]); endwin(); return 1; }