aboutsummaryrefslogtreecommitdiffstats
path: root/kirc.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--kirc.c1186
1 files changed, 781 insertions, 405 deletions
diff --git a/kirc.c b/kirc.c
index f9c6e2d..5460cf6 100644
--- a/kirc.c
+++ b/kirc.c
@@ -1,19 +1,20 @@
-#include "kirc.h"
-
/*
* SPDX-License-Identifier: MIT
* Copyright (C) 2023 Michael Czigler
*/
+#include "kirc.h"
+
static void free_history(void)
{
- if (history) {
- int j;
- for (j = 0; j < history_len; j++) {
- free(history[j]);
- }
- free(history);
+ if (!history) {
+ return;
}
+ int j;
+ for (j = 0; j < history_len; j++) {
+ free(history[j]);
+ }
+ free(history);
}
static void disable_raw_mode(void)
@@ -83,89 +84,68 @@ static int get_cursor_position(int ifd, int ofd)
static int get_columns(int ifd, int ofd)
{
struct winsize ws;
- if (ioctl(1, TIOCGWINSZ, &ws) == -1 || ws.ws_col == 0) {
- int start = get_cursor_position(ifd, ofd);
- if (start == -1) {
- return 80;
- }
- if (write(ofd, "\x1b[999C", 6) != 6) {
- return 80;
- }
- int cols = get_cursor_position(ifd, ofd);
- if (cols == -1) {
- return 80;
- }
- if (cols > start) {
- char seq[32];
- snprintf(seq, sizeof(seq), "\x1b[%dD", cols - start);
- if (write(ofd, seq, strnlen(seq, MSG_MAX)) == -1) {
- }
- }
- return cols;
- } else {
+ if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col != 0) {
return ws.ws_col;
}
-}
-
-static void
-buffer_position_move(state l, ssize_t dest, ssize_t src, size_t size)
-{
- memmove(l->buf + l->posb + dest, l->buf + l->posb + src, size);
-}
-
-static void buffer_position_move_end(state l, ssize_t dest, ssize_t src)
-{
- buffer_position_move(l, dest, src, l->lenb - (l->posb + src) + 1);
-}
-
-static int u8_character_start(char c)
-{
- int ret = 1;
- if (isu8 != 0) {
- ret = (c & 0x80) == 0x00 || (c & 0xC0) == 0xC0;
+ int start = get_cursor_position(ifd, ofd);
+ if (start == -1) {
+ return 80;
+ }
+ if (write(ofd, "\x1b[999C", 6) != 6) {
+ return 80;
+ }
+ int cols = get_cursor_position(ifd, ofd);
+ if (cols == -1) {
+ return 80;
}
- return ret;
+ if (cols <= start) {
+ return cols;
+ }
+ char seq[32];
+ snprintf(seq, sizeof(seq), "\x1b[%dD", cols - start);
+ (void)write(ofd, seq, strnlen(seq, 32));
+ return cols;
}
static int u8_character_size(char c)
{
- int ret = 1;
- if (isu8 != 0) {
- int size = 0;
- while (c & (0x80 >> size)) {
- size++;
- }
- ret = (size != 0) ? size : 1;
+ if (isu8 == 0){
+ return 1;
}
- return ret;
+ int size = 0;
+ while (c & (0x80 >> size++));
+ return size ? size : 1;
}
static size_t u8_length(const char *s)
{
size_t lenu8 = 0;
while (*s != '\0') {
- lenu8 += u8_character_start(*(s++));
+ lenu8 += u8_character_start(*s);
+ s++;
}
return lenu8;
}
static size_t u8_previous(const char *s, size_t posb)
{
- if (posb != 0) {
- do {
- posb--;
- } while ((posb > 0) && !u8_character_start(s[posb]));
+ if (posb == 0) {
+ return 0;
}
+ do {
+ posb--;
+ } while ((posb > 0) && !u8_character_start(s[posb]));
return posb;
}
static size_t u8_next(const char *s, size_t posb)
{
- if (s[posb] != '\0') {
- do {
- posb++;
- } while ((s[posb] != '\0') && !u8_character_start(s[posb]));
+ if (s[posb] == '\0') {
+ return posb;
}
+ do {
+ posb++;
+ } while ((s[posb] != '\0') && !u8_character_start(s[posb]));
return posb;
}
@@ -180,40 +160,28 @@ static int setIsu8_C(int ifd, int ofd)
if (get_cursor_position(ifd, ofd) != 1) {
return -1;
}
- const char *testChars[] = {
- "\xe1\xbb\xa4",
- NULL
- };
- for (const char **it = testChars; *it; it++) {
- if (write(ofd, *it, strlen(*it)) != (ssize_t) strlen(*it)) {
- return -1;
- }
- int pos = get_cursor_position(ifd, ofd);
- if (write(ofd, "\r", 1) != 1) {
- return -1;
- }
- for (int i = 1; i < pos; i++) {
- if (write(ofd, " ", 1) != 1) {
- return -1;
- }
- }
- if (write(ofd, "\r", 1) != 1) {
+ if (write(ofd, TESTCHARS, sizeof(TESTCHARS) - 1) != sizeof(TESTCHARS) - 1) {
+ return -1;
+ }
+ int pos = get_cursor_position(ifd, ofd);
+ if (write(ofd, "\r", 1) != 1) {
+ return -1;
+ }
+ for (int i = 1; i < pos; i++) {
+ if (write(ofd, " ", 1) != 1) {
return -1;
}
- if (pos != 2) {
- return 0;
- }
+ }
+ if (write(ofd, "\r", 1) != 1) {
+ return -1;
+ }
+ if (pos != 2) {
+ return 0;
}
isu8 = 1;
return 0;
}
-static void ab_initialize(struct abuf *ab)
-{
- ab->b = NULL;
- ab->len = 0;
-}
-
static void ab_append(struct abuf *ab, const char *s, int len)
{
char *new = realloc(ab->b, ab->len + len);
@@ -225,16 +193,9 @@ static void ab_append(struct abuf *ab, const char *s, int len)
ab->len += len;
}
-static void ab_free(struct abuf *ab)
-{
- free(ab->b);
-}
-
static void refresh_line(state l)
{
- char seq[64];
size_t plenu8 = l->plenu8 + 2;
- int fd = STDOUT_FILENO;
char *buf = l->buf;
size_t lenb = l->lenb;
size_t posu8 = l->posu8;
@@ -245,115 +206,123 @@ static void refresh_line(state l)
buf += u8_next(buf, 0);
posu8--;
}
- while (txtlenb < lenb && ch++ < l->cols)
+ while (txtlenb < lenb && ch++ < l->cols) {
txtlenb += u8_next(buf + txtlenb, 0);
- ab_initialize(&ab);
- snprintf(seq, sizeof(seq), "\r");
- ab_append(&ab, seq, strnlen(seq, MSG_MAX));
- ab_append(&ab, l->prompt, l->plenb);
- ab_append(&ab, "> ", 2);
+ }
+ ab.b = NULL;
+ ab.len = 0;
+ ab_append(&ab, "\r", sizeof("\r") - 1);
+ ab_append(&ab, chan, l->plenb);
+ ab_append(&ab, "> ", sizeof("> ") - 1);
ab_append(&ab, buf, txtlenb);
- snprintf(seq, sizeof(seq), "\x1b[0K");
- ab_append(&ab, seq, strnlen(seq, MSG_MAX));
+ ab_append(&ab, "\x1b[0K", sizeof("\x1b[0K") - 1);
if (posu8 + plenu8) {
+ char seq[32];
snprintf(seq, sizeof(seq), "\r\x1b[%dC", (int)(posu8 + plenu8));
+ ab_append(&ab, seq, strnlen(seq, 32));
} else {
- snprintf(seq, sizeof(seq), "\r");
+ ab_append(&ab, "\r", sizeof("\r") - 1);
}
- ab_append(&ab, seq, strnlen(seq, MSG_MAX));
- if (write(fd, ab.b, ab.len) == -1) {
+ if (write(STDOUT_FILENO, ab.b, ab.len) == -1) {
}
- ab_free(&ab);
+ free(ab.b);
}
static int edit_insert(state l, char *c)
{
size_t clenb = strlen(c);
- if ((l->lenb + clenb) < l->buflen) {
- if (l->lenu8 == l->posu8) {
- strcpy(l->buf + l->posb, c);
- l->posu8++;
- l->lenu8++;
- l->posb += clenb;
- l->lenb += clenb;
- if ((l->plenu8 + l->lenu8) < l->cols) {
- if (write(STDOUT_FILENO, c, clenb) == -1) {
- return -1;
- }
- } else {
- refresh_line(l);
- }
- } else {
- buffer_position_move_end(l, clenb, 0);
- memmove(l->buf + l->posb, c, clenb);
- l->posu8++;
- l->lenu8++;
- l->posb += clenb;
- l->lenb += clenb;
- refresh_line(l);
- }
+ if ((l->lenb + clenb) >= l->buflen) {
+ return 0;
+ }
+ if (l->lenu8 != l->posu8) {
+ buffer_position_move_end(l, clenb, 0);
+ memmove(l->buf + l->posb, c, clenb);
+ l->posu8++;
+ l->lenu8++;
+ l->posb += clenb;
+ l->lenb += clenb;
+ refresh_line(l);
+ return 0;
+ }
+ strcpy(l->buf + l->posb, c);
+ l->posu8++;
+ l->lenu8++;
+ l->posb += clenb;
+ l->lenb += clenb;
+ if ((l->plenu8 + l->lenu8) >= l->cols) {
+ refresh_line(l);
+ return 0;
+ }
+ if (write(STDOUT_FILENO, c, clenb) == -1) {
+ return -1;
}
return 0;
}
static void edit_move_left(state l)
{
- if (l->posb > 0) {
- l->posb = u8_previous(l->buf, l->posb);
- l->posu8--;
- refresh_line(l);
+ if (l->posb == 0){
+ return;
}
+ l->posb = u8_previous(l->buf, l->posb);
+ l->posu8--;
+ refresh_line(l);
}
static void edit_move_right(state l)
{
- if (l->posu8 != l->lenu8) {
- l->posb = u8_next(l->buf, l->posb);
- l->posu8++;
- refresh_line(l);
+ if (l->posu8 == l->lenu8) {
+ return;
}
+ l->posb = u8_next(l->buf, l->posb);
+ l->posu8++;
+ refresh_line(l);
}
static void edit_move_home(state l)
{
- if (l->posb != 0) {
- l->posb = 0;
- l->posu8 = 0;
- refresh_line(l);
+ if (l->posb == 0) {
+ return;
}
+ l->posb = 0;
+ l->posu8 = 0;
+ refresh_line(l);
}
static void edit_move_end(state l)
{
- if (l->posu8 != l->lenu8) {
- l->posb = l->lenb;
- l->posu8 = l->lenu8;
- refresh_line(l);
+ if (l->posu8 == l->lenu8) {
+ return;
}
+ l->posb = l->lenb;
+ l->posu8 = l->lenu8;
+ refresh_line(l);
}
static void edit_delete(state l)
{
- if ((l->lenu8 > 0) && (l->posu8 < l->lenu8)) {
- size_t this_size = u8_next(l->buf, l->posb) - l->posb;
- buffer_position_move_end(l, 0, this_size);
- l->lenb -= this_size;
- l->lenu8--;
- refresh_line(l);
+ if ((l->lenu8 == 0) || (l->posu8 >= l->lenu8)) {
+ return;
}
+ size_t this_size = u8_next(l->buf, l->posb) - l->posb;
+ buffer_position_move_end(l, 0, this_size);
+ l->lenb -= this_size;
+ l->lenu8--;
+ refresh_line(l);
}
static void edit_backspace(state l)
{
- if ((l->posu8 > 0) && (l->lenu8 > 0)) {
- size_t prev_size = l->posb - u8_previous(l->buf, l->posb);
- buffer_position_move_end(l, (ssize_t) - prev_size, 0);
- l->posb -= prev_size;
- l->lenb -= prev_size;
- l->posu8--;
- l->lenu8--;
- refresh_line(l);
+ if ((l->posu8 == 0) || (l->lenu8 == 0)) {
+ return;
}
+ size_t prev_size = l->posb - u8_previous(l->buf, l->posb);
+ buffer_position_move_end(l, (ssize_t) - prev_size, 0);
+ l->posb -= prev_size;
+ l->lenb -= prev_size;
+ l->posu8--;
+ l->lenu8--;
+ refresh_line(l);
}
static void edit_delete_previous_word(state l)
@@ -378,14 +347,14 @@ static void edit_delete_previous_word(state l)
refresh_line(l);
}
-static void edit_delete_whole_line(state l)
+static inline void edit_delete_whole_line(state l)
{
l->buf[0] = '\0';
l->posb = l->lenb = l->posu8 = l->lenu8 = 0;
refresh_line(l);
}
-static void edit_delete_line_to_end(state l)
+static inline void edit_delete_line_to_end(state l)
{
l->buf[l->posb] = '\0';
l->lenb = l->posb;
@@ -395,55 +364,54 @@ static void edit_delete_line_to_end(state l)
static void edit_swap_character_w_previous(state l)
{
- if (l->posu8 > 0 && l->posu8 < l->lenu8) {
- char aux[8];
- ssize_t prev_size = l->posb - u8_previous(l->buf, l->posb);
- ssize_t this_size = u8_next(l->buf, l->posb) - l->posb;
- memmove(aux, l->buf + l->posb, this_size);
- buffer_position_move(l, -prev_size + this_size, -prev_size, prev_size);
- memmove(l->buf + l->posb - prev_size, aux, this_size);
- if (l->posu8 != l->lenu8 - 1) {
- l->posu8++;
- l->posb += this_size;
- }
- refresh_line(l);
+ if (l->posu8 == 0 || l->posu8 >= l->lenu8) {
+ return;
+ }
+ char aux[8];
+ ssize_t prev_size = l->posb - u8_previous(l->buf, l->posb);
+ ssize_t this_size = u8_next(l->buf, l->posb) - l->posb;
+ memmove(aux, l->buf + l->posb, this_size);
+ buffer_position_move(l, -prev_size + this_size, -prev_size, prev_size);
+ memmove(l->buf + l->posb - prev_size, aux, this_size);
+ if (l->posu8 != l->lenu8 - 1) {
+ l->posu8++;
+ l->posb += this_size;
}
+ refresh_line(l);
}
static void edit_history(state l, int dir)
{
- if (history_len > 1) {
- free(history[history_len - (1 + l->history_index)]);
- history[history_len - (1 + l->history_index)] = strdup(l->buf);
- l->history_index += (dir == 1) ? 1 : -1;
- if (l->history_index < 0) {
- l->history_index = 0;
- return;
- } else if (l->history_index >= history_len) {
- l->history_index = history_len - 1;
- return;
- }
- strncpy(l->buf, history[history_len - (1 + l->history_index)],
- l->buflen);
- l->buf[l->buflen - 1] = '\0';
- l->lenb = l->posb = strnlen(l->buf, MSG_MAX);
- l->lenu8 = l->posu8 = u8_length(l->buf);
- refresh_line(l);
+ if (history_len <= 1) {
+ return;
+ }
+ free(history[history_len - (1 + l->history_index)]);
+ history[history_len - (1 + l->history_index)] = strdup(l->buf);
+ l->history_index += (dir == 1) ? 1 : -1;
+ if (l->history_index < 0) {
+ l->history_index = 0;
+ return;
+ }
+ if (l->history_index >= history_len) {
+ l->history_index = history_len - 1;
+ return;
}
+ strcpy(l->buf, history[history_len - (1 + l->history_index)]);
+ l->buf[l->buflen - 1] = '\0';
+ l->lenb = l->posb = strnlen(l->buf, MSG_MAX);
+ l->lenu8 = l->posu8 = u8_length(l->buf);
+ refresh_line(l);
}
static int history_add(const char *line)
{
char *linecopy;
- if (history_max_len == 0) {
- return 0;
- }
if (history == NULL) {
- history = malloc(sizeof(char *) * history_max_len);
+ history = malloc(sizeof(char *) * HIS_MAX);
if (history == NULL) {
return 0;
}
- memset(history, 0, (sizeof(char *) * history_max_len));
+ memset(history, 0, (sizeof(char *) * HIS_MAX));
}
if (history_len && !strcmp(history[history_len - 1], line)) {
return 0;
@@ -452,9 +420,9 @@ static int history_add(const char *line)
if (!linecopy) {
return 0;
}
- if (history_len == history_max_len) {
+ if (history_len == HIS_MAX) {
free(history[0]);
- memmove(history, history + 1, sizeof(char *) * (history_max_len - 1));
+ memmove(history, history + 1, sizeof(char *) * (HIS_MAX - 1));
history_len--;
}
history[history_len] = linecopy;
@@ -462,7 +430,7 @@ static int history_add(const char *line)
return 1;
}
-static void edit_enter(void)
+static inline void edit_enter(void)
{
history_len--;
free(history[history_len]);
@@ -470,140 +438,143 @@ static void edit_enter(void)
static void edit_escape_sequence(state l, char seq[3])
{
- if (read(ttyinfd, seq, 1) == -1)
+ if (read(ttyinfd, seq, 1) == -1) {
return;
- if (read(ttyinfd, seq + 1, 1) == -1)
+ }
+ if (read(ttyinfd, seq + 1, 1) == -1) {
return;
- if (seq[0] == '[') { /* ESC [ sequences. */
- if ((seq[1] >= '0') && (seq[1] <= '9')) {
- /* Extended escape, read additional byte. */
- if (read(ttyinfd, seq + 2, 1) == -1) {
- return;
- }
- if ((seq[2] == '~') && (seq[1] == 3)) {
- edit_delete(l); /* Delete key. */
- }
- } else {
- switch (seq[1]) {
- case 'A':
- edit_history(l, 1);
- break; /* Up */
- case 'B':
- edit_history(l, 0);
- break; /* Down */
- case 'C':
- edit_move_right(l);
- break; /* Right */
- case 'D':
- edit_move_left(l);
- break; /* Left */
- case 'H':
- edit_move_home(l);
- break; /* Home */
- case 'F':
- edit_move_end(l);
- break; /* End */
- }
+ }
+ if (seq[0] != '[') { /* ESC [ sequences. */
+ if (seq[0] != 'O') { /* ESC O sequences. */
+ return;
}
- } else if (seq[0] == 'O') { /* ESC O sequences. */
switch (seq[1]) {
case 'H':
edit_move_home(l);
- break; /* Home */
+ return; /* Home */
case 'F':
edit_move_end(l);
- break; /* End */
+ return; /* End */
}
+ return;
+ }
+ if ((seq[1] >= '0') && (seq[1] <= '9')) {
+ /* Extended escape, read additional byte. */
+ if (read(ttyinfd, seq + 2, 1) == -1) {
+ return;
+ }
+ if ((seq[2] == '~') && (seq[1] == 3)) {
+ edit_delete(l); /* Delete key. */
+ }
+ return;
+ }
+ switch (seq[1]) {
+ case 'A':
+ edit_history(l, 1);
+ return; /* Up */
+ case 'B':
+ edit_history(l, 0);
+ return; /* Down */
+ case 'C':
+ edit_move_right(l);
+ return; /* Right */
+ case 'D':
+ edit_move_left(l);
+ return; /* Left */
+ case 'H':
+ edit_move_home(l);
+ return; /* Home */
+ case 'F':
+ edit_move_end(l);
+ return; /* End */
}
}
-
static int edit(state l)
{
- char c, seq[3];
- int ret = 0;
- ssize_t nread = read(ttyinfd, &c, 1);
- if (nread <= 0) {
- ret = 1;
- } else {
- switch (c) {
- case 13:
- edit_enter();
- return 1; /* enter */
- case 3:
- errno = EAGAIN;
- return -1; /* ctrl-c */
- case 127: /* backspace */
- case 8:
- edit_backspace(l);
- break; /* ctrl-h */
- case 2:
- edit_move_left(l);
- break; /* ctrl-b */
- case 6:
- edit_move_right(l);
- break; /* ctrl-f */
- case 1:
- edit_move_home(l);
- break; /* Ctrl+a */
- case 5:
- edit_move_end(l);
- break; /* ctrl+e */
- case 23:
- edit_delete_previous_word(l);
- break; /* ctrl+w */
- case 21:
- edit_delete_whole_line(l);
- break; /* Ctrl+u */
- case 11:
- edit_delete_line_to_end(l);
- break; /* Ctrl+k */
- case 14:
- edit_history(l, 0);
- break; /* Ctrl+n */
- case 16:
- edit_history(l, 1);
- break; /* Ctrl+p */
- case 20:
- edit_swap_character_w_previous(l);
- break; /* ctrl-t */
- case 27:
- edit_escape_sequence(l, seq);
- break; /* escape sequence */
- case 4: /* ctrl-d */
- if (l->lenu8 > 0) {
- edit_delete(l);
- } else {
- history_len--;
- free(history[history_len]);
- ret = -1;
- }
+ char c;
+ if (read(ttyinfd, &c, 1) <= 0) {
+ return 1;
+ }
+ char seq[3];
+ switch (c) {
+ case 13:
+ edit_enter();
+ return 1; /* enter */
+ case 3:
+ errno = EAGAIN;
+ return -1; /* ctrl-c */
+ case 127: /* backspace */
+ case 8:
+ edit_backspace(l);
+ return 0; /* ctrl-h */
+ case 2:
+ edit_move_left(l);
+ return 0; /* ctrl-b */
+ case 6:
+ edit_move_right(l);
+ return 0; /* ctrl-f */
+ case 1:
+ edit_move_home(l);
+ return 0; /* Ctrl+a */
+ case 5:
+ edit_move_end(l);
+ return 0; /* ctrl+e */
+ case 23:
+ edit_delete_previous_word(l);
+ return 0; /* ctrl+w */
+ case 21:
+ edit_delete_whole_line(l);
+ return 0; /* Ctrl+u */
+ case 11:
+ edit_delete_line_to_end(l);
+ return 0; /* Ctrl+k */
+ case 14:
+ edit_history(l, 0);
+ return 0; /* Ctrl+n */
+ case 16:
+ edit_history(l, 1);
+ return 0; /* Ctrl+p */
+ case 20:
+ edit_swap_character_w_previous(l);
+ return 0; /* ctrl-t */
+ case 27:
+ edit_escape_sequence(l, seq);
+ return 0; /* escape sequence */
+ case 4: /* ctrl-d */
+ if (l->lenu8 == 0) {
+ history_len--;
+ free(history[history_len]);
+ return -1;
+ }
+ edit_delete(l);
+ return 0;
+ }
+ if (!u8_character_start(c)) {
+ return 0;
+ }
+ char aux[8];
+ aux[0] = c;
+ int size = u8_character_size(c);
+ for (int i = 1; i < size; i++) {
+ if(read(ttyinfd, aux + i, 1) == -1){
break;
- default:
- if (u8_character_start(c)) {
- char aux[8];
- aux[0] = c;
- int size = u8_character_size(c);
- for (int i = 1; i < size; i++) {
- nread = read(ttyinfd, aux + i, 1);
- if ((aux[i] & 0xC0) != 0x80) {
- break;
- }
- }
- aux[size] = '\0';
- if (edit_insert(l, aux)) {
- ret = -1;
- }
- }
+ }
+ if ((aux[i] & 0xC0) != 0x80) {
break;
}
}
- return ret;
+ aux[size] = '\0';
+ if (edit_insert(l, aux)) {
+ return -1;
+ }
+ return 0;
}
-static void state_reset(state l)
+
+static inline void state_reset(state l)
{
- l->plenb = strnlen(l->prompt, MSG_MAX);
- l->plenu8 = u8_length(l->prompt);
+ l->plenb = strnlen(chan, MSG_MAX);
+ l->plenu8 = u8_length(chan);
l->oldposb = l->posb = l->oldposu8 = l->posu8 = l->lenb = l->lenu8 = 0;
l->history_index = 0;
l->buf[0] = '\0';
@@ -631,16 +602,16 @@ static void log_append(char *str, char *path)
exit(1);
}
ctime_now(buf);
- fprintf(out, "%s:", buf, str);
+ fprintf(out, "%s:", buf);
while (*str != '\0') {
if (*str >= 32 && *str < 127) {
fwrite(str, sizeof(char), 1, out);
} else if (*str == 3 || *str == 4) {
- *str++;
+ str++;
} else if (*str == '\n') {
fwrite("\n", sizeof(char), 1, out);
}
- *str++;
+ str++;
};
fclose(out);
}
@@ -711,9 +682,9 @@ static void message_wrap(param p)
return;
}
char *tok;
- size_t wordwidth, spacewidth = 1;
size_t spaceleft = p->maxcols - (p->nicklen + p->offset);
for (tok = strtok(p->message, " "); tok != NULL; tok = strtok(NULL, " ")) {
+ size_t wordwidth, spacewidth = 1;
wordwidth = strnlen(tok, MSG_MAX);
if ((wordwidth + spacewidth) > spaceleft) {
printf("\r\n%*.s%s ", (int)p->nicklen + 1, " ", tok);
@@ -725,7 +696,7 @@ static void message_wrap(param p)
}
}
-static void param_print_nick(param p)
+static inline void param_print_nick(param p)
{
printf("\x1b[35;1m%*s\x1b[0m ", p->nicklen - 4, p->nickname);
printf("--> \x1b[35;1m%s\x1b[0m", p->message);
@@ -734,12 +705,12 @@ static void param_print_nick(param p)
static void param_print_part(param p)
{
printf("%*s<-- \x1b[34;1m%s\x1b[0m", p->nicklen - 3, "", p->nickname);
- if (p->channel != NULL && strcmp(p->channel + 1, cdef)) {
+ if (p->channel != NULL && strcmp(p->channel + 1, chan)) {
printf(" [\x1b[33m%s\x1b[0m] ", p->channel);
}
}
-static void param_print_quit(param p)
+static inline void param_print_quit(param p)
{
printf("%*s<<< \x1b[34;1m%s\x1b[0m", p->nicklen - 3, "", p->nickname);
}
@@ -747,41 +718,272 @@ static void param_print_quit(param p)
static void param_print_join(param p)
{
printf("%*s--> \x1b[32;1m%s\x1b[0m", p->nicklen - 3, "", p->nickname);
- if (p->channel != NULL && strcmp(p->channel + 1, cdef)) {
+ if (p->channel != NULL && strcmp(p->channel + 1, chan)) {
printf(" [\x1b[33m%s\x1b[0m] ", p->channel);
}
}
-static void handle_ctcp(const char *nickname, char *message)
+static void print_error(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ printf("\r\x1b[31merror: ");
+ vprintf(fmt, ap);
+ printf("\x1b[0m\r\n");
+ va_end(ap);
+}
+
+static short parse_dcc_send_message(const char *message, char *filename, unsigned int *ip_addr, char *ipv6_addr, unsigned short *port, size_t *file_size)
+{
+ /* TODO: Fix horrible hacks */
+
+ char ipv6 = 0;
+
+ if (sscanf(message, "SEND \"%" STR(FNM_MAX) "[^\"]\" %41s %hu %zu", filename, ipv6_addr, port, file_size) == 4) {
+ ipv6 = !!(ipv6_addr[15]);
+ if (ipv6 == 1) {
+ return 1;
+ }
+ }
+ if (sscanf(message, "SEND %" STR(FNM_MAX) "s %41s %hu %zu", filename, ipv6_addr, port, file_size) == 4) {
+ ipv6 = !!(ipv6_addr[15]);
+ if (ipv6 == 1) {
+ return 1;
+ }
+ }
+ if (sscanf(message, "SEND \"%" STR(FNM_MAX) "[^\"]\" %u %hu %zu", filename, ip_addr, port, file_size) == 4) {
+ return 0;
+ }
+ if (sscanf(message, "SEND %" STR(FNM_MAX) "s %u %hu %zu", filename, ip_addr, port, file_size) == 4) {
+ return 0;
+ }
+ print_error("unable to parse DCC message '%s'", message);
+ return -1;
+}
+
+static short parse_dcc_accept_message(const char *message, char *filename, unsigned short *port, size_t *file_size)
{
- if (message[0] != '\001' && strncmp(message, "ACTION", 6)) {
+ if (sscanf(message, "ACCEPT \"%" STR(FNM_MAX) "[^\"]\" %hu %zu", filename, port, file_size) == 3) {
+ return 0;
+ }
+ if (sscanf(message, "ACCEPT %" STR(FNM_MAX) "s %hu %zu", filename, port, file_size) == 3) {
+ return 0;
+ }
+ print_error("unable to parse DCC message '%s'", message);
+ return 1;
+}
+
+static void open_socket(int slot, int *file_fd)
+{
+ int sock_fd;
+ if(!ipv6) {
+ sock_fd = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in sockaddr = dcc_sessions.slots[slot].sin;
+ if (connect(sock_fd, (const struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
+ close(sock_fd);
+ close(*file_fd);
+ perror("connect");
+ return;
+ }
+ }
+ else {
+ sock_fd = socket(AF_INET6, SOCK_STREAM, 0);
+ struct sockaddr_in6 sockaddr = dcc_sessions.slots[slot].sin6;
+ if (connect(sock_fd, (const struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) {
+ close(sock_fd);
+ close(*file_fd);
+ perror("connect");
+ return;
+ }
+ }
+ if (sock_fd < 0) {
+ close(*file_fd);
+ perror("socket");
+ return;
+ }
+ int flags = fcntl(sock_fd, F_GETFL, 0) | O_NONBLOCK;
+ if (flags < 0 || fcntl(sock_fd, F_SETFL, flags) < 0) {
+ close(sock_fd);
+ close(*file_fd);
+ perror("fcntl");
+ return;
+ }
+ dcc_sessions.sock_fds[slot].fd = sock_fd;
+}
+
+/* TODO: since we don't have config files how do we configure a download directory? */
+static void handle_dcc(param p)
+{
+ const char *message = p->message + 5;
+ char filename[FNM_MAX + 1];
+ size_t file_size = 0;
+ unsigned int ip_addr = 0;
+ unsigned short port = 0;
+ char ipv6_addr[42];
+
+ int slot = -1;
+ int file_fd;
+
+ if (!strncmp(message, "SEND", 4)) {
+ while(++slot < CON_MAX && dcc_sessions.slots[slot].file_fd >= 0);
+
+ if (slot == CON_MAX) {
+ raw("PRIVMSG %s :XDCC CANCEL\r\n", p->nickname);
+ return;
+ }
+
+ /* TODO: the file size parameter is optional so this isn't strictly correct. */
+
+ ipv6 = parse_dcc_send_message(message, filename, &ip_addr, ipv6_addr, &port, &file_size);
+ if(ipv6 == -1) {
+ return;
+ }
+
+ /* TODO: at this point we should make sure that the filename is actually a filename
+ and not a file path. furthermore, it would be helpful to give the user
+ the option to rename to the file.
+ */
+
+ int file_resume = 0;
+ size_t bytes_read = 0;
+ file_fd = open(filename, DCC_FLAGS);
+
+ if (file_fd > 0) {
+ struct stat statbuf = {0};
+ if (fstat(file_fd, &statbuf)) {
+ close(file_fd);
+ }
+ bytes_read = statbuf.st_size;
+ file_resume = 1;
+ }
+
+ if (!file_resume) {
+ file_fd = open(filename, DCC_FLAGS | O_CREAT, DCC_MODE);
+ }
+
+ if (file_fd < 0) {
+ perror("open");
+ exit(1);
+ }
+
+ if (file_size == bytes_read) {
+ close(file_fd);
+ return;
+ }
+
+ dcc_sessions.slots[slot] = (struct dcc_connection) {
+ .bytes_read = bytes_read,
+ .file_size = file_size,
+ .file_fd = file_fd,
+ };
+ strcpy(dcc_sessions.slots[slot].filename, filename);
+ if(!ipv6) {
+ dcc_sessions.slots[slot].sin = (struct sockaddr_in){
+ .sin_family = AF_INET,
+ .sin_addr = (struct in_addr){htonl(ip_addr)},
+ .sin_port = htons(port),
+ };
+ goto check_resume;
+ }
+ struct in6_addr result;
+ if (inet_pton(AF_INET6, ipv6_addr, &result) != 1){
+ close(file_fd);
+ }
+ dcc_sessions.slots[slot].sin6 = (struct sockaddr_in6){
+ .sin6_family = AF_INET6,
+ .sin6_addr = result,
+ .sin6_port = htons(port),
+ };
+
+check_resume:
+ if (file_resume) {
+ raw("PRIVMSG %s :\001DCC RESUME \"%s\" %hu %zu\001\r\n",
+ p->nickname, filename, port, bytes_read);
+ return;
+ }
+ open_socket(slot, &file_fd);
return;
}
- message++;
+ if (!strncmp(message, "ACCEPT", 6)) {
+ if(parse_dcc_accept_message(message, filename, &port, &file_size)) {
+ return;
+ }
+
+ while(++slot < CON_MAX && strncmp(dcc_sessions.slots[slot].filename, filename, FNM_MAX));
+
+ if (slot == CON_MAX) {
+ return;
+ }
+
+ file_fd = dcc_sessions.slots[slot].file_fd;
+ open_socket(slot, &file_fd);
+ return;
+ }
+}
+
+static void handle_ctcp(param p)
+{
+ if (p->message[0] != '\001' && strncmp(p->message, "ACTION", 6)) {
+ return;
+ }
+ const char *message = p->message + 1;
if (!strncmp(message, "VERSION", 7)) {
- raw("NOTICE %s :\001VERSION kirc " VERSION "\001\r\n", nickname);
- } else if (!strncmp(message, "TIME", 7)) {
+ raw("NOTICE %s :\001VERSION kirc " VERSION "\001\r\n", p->nickname);
+ return;
+ }
+ if (!strncmp(message, "TIME", 7)) {
char buf[26];
if (!ctime_now(buf)) {
- raw("NOTICE %s :\001TIME %s\001\r\n", nickname, buf);
+ raw("NOTICE %s :\001TIME %s\001\r\n", p->nickname, buf);
}
- } else if (!strncmp(message, "CLIENTINFO", 10)) {
- raw("NOTICE %s :\001CLIENTINFO " CTCP_CMDS "\001\r\n", nickname);
- } else if (!strncmp(message, "PING", 4)) {
- raw("NOTICE %s :\001%s\r\n", nickname, message);
+ return;
+ }
+ if (!strncmp(message, "CLIENTINFO", 10)) {
+ raw("NOTICE %s :\001CLIENTINFO " CTCP_CMDS "\001\r\n", p->nickname);
+ return;
+ }if (!strncmp(message, "PING", 4)) {
+ raw("NOTICE %s :\001%s\r\n", p->nickname, message);
+ return;
+ }
+ if (!strncmp(message, "DCC", 3)) {
+ handle_dcc(p);
+ return;
}
}
static void param_print_private(param p)
{
+ time_t rawtime;
+ struct tm *timeinfo;
+ time ( &rawtime );
+ timeinfo = localtime ( &rawtime );
+ char timestamp[9];
+ if (!small_screen) {
+ if (strnlen(p->nickname, p->nicklen) > (size_t)p->nicklen - 8) {
+ *(p->nickname + p->nicklen - 8) = '\0';
+ }
+ strcpy(timestamp, "[");
+ char buf[5];
+ if (timeinfo->tm_hour < 10) {
+ strcat(timestamp, "0");
+ }
+ snprintf(buf, sizeof(buf), "%d:", timeinfo->tm_hour);
+ strcat(timestamp, buf);
+ if (timeinfo->tm_min < 10) {
+ strcat(timestamp, "0");
+ }
+ snprintf(buf, sizeof(buf), "%d] ", timeinfo->tm_min);
+ strcat(timestamp, buf);
+ printf("%s", timestamp);
+ }
int s = 0;
- if (strnlen(p->nickname, MSG_MAX) <= (size_t)p->nicklen) {
- s = p->nicklen - strnlen(p->nickname, MSG_MAX);
+ if (strnlen(p->nickname, MSG_MAX) <= (size_t)p->nicklen + strnlen(timestamp, sizeof(timestamp))) {
+ s = p->nicklen - strnlen(p->nickname, MSG_MAX) - strnlen(timestamp, sizeof(timestamp));
}
if (p->channel != NULL && (strcmp(p->channel, nick) == 0)) {
- handle_ctcp(p->nickname, p->message);
- printf("%*s\x1b[33;1m%-.*s\x1b[36m ", s, "", p->nicklen, p->nickname);
- } else if (p->channel != NULL && strcmp(p->channel + 1, cdef)) {
+ handle_ctcp(p);
+ printf("%*s\x1b[33;1m%-.*s [PRIVMSG]\x1b[36m ", s, "", p->nicklen, p->nickname);
+ } else if (p->channel != NULL && strcmp(p->channel + 1, chan)) {
printf("%*s\x1b[33;1m%-.*s\x1b[0m", s, "", p->nicklen, p->nickname);
printf(" [\x1b[33m%s\x1b[0m] ", p->channel);
p->offset += 12 + strnlen(p->channel, CHA_MAX);
@@ -825,7 +1027,6 @@ static void raw_parser(char *string)
if (olog) {
log_append(string, olog);
}
- char *tok;
param_t p = {
.prefix = strtok(string, " ") + 1,
.suffix = strtok(NULL, ":"),
@@ -835,30 +1036,48 @@ static void raw_parser(char *string)
.channel = strtok(NULL, " \r"),
.params = strtok(NULL, ":\r"),
.maxcols = get_columns(ttyinfd, STDOUT_FILENO),
- .nicklen = (p.maxcols / 3 > NIC_MAX ? NIC_MAX : p.maxcols / 3),
.offset = 0
};
- if (!strncmp(p.command, "001", 3) && chan != NULL) {
+ if (WRAP_LEN > p.maxcols / 3) {
+ small_screen = 1;
+ p.nicklen = p.maxcols / 3;
+ }
+ else {
+ small_screen = 0;
+ p.nicklen = WRAP_LEN;
+ }
+ if (!strncmp(p.command, "001", 3) && *chan != '\0') {
+ char *tok;
for (tok = strtok(chan, ",|"); tok != NULL; tok = strtok(NULL, ",|")) {
- strcpy(cdef, tok);
+ strcpy(chan, tok);
raw("JOIN #%s\r\n", tok);
}
return;
- } else if (!strncmp(p.command, "QUIT", 4)) {
+ }
+ if (!strncmp(p.command, "QUIT", 4)) {
param_print_quit(&p);
- } else if (!strncmp(p.command, "PART", 4)) {
+ printf("\x1b[0m\r\n");
+ return;
+ }if (!strncmp(p.command, "PART", 4)) {
param_print_part(&p);
- } else if (!strncmp(p.command, "JOIN", 4)) {
+ printf("\x1b[0m\r\n");
+ return;
+ }if (!strncmp(p.command, "JOIN", 4)) {
param_print_join(&p);
- } else if (!strncmp(p.command, "NICK", 4)) {
+ printf("\x1b[0m\r\n");
+ return;
+ }if (!strncmp(p.command, "NICK", 4)) {
param_print_nick(&p);
- } else if (!strncmp(p.command, "PRIVMSG", 7)) {
+ printf("\x1b[0m\r\n");
+ return;
+ }if (!strncmp(p.command, "PRIVMSG", 7)) {
param_print_private(&p);
message_wrap(&p);
- } else {
- param_print_channel(&p);
- message_wrap(&p);
+ printf("\x1b[0m\r\n");
+ return;
}
+ param_print_channel(&p);
+ message_wrap(&p);
printf("\x1b[0m\r\n");
}
@@ -873,10 +1092,9 @@ static int handle_server_message(void)
if (nread == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0;
- } else {
- perror("read");
- return -2;
}
+ perror("read");
+ return -2;
}
if (nread == 0) {
fputs("\rconnection closed", stderr);
@@ -892,8 +1110,7 @@ static int handle_server_message(void)
message_buffer[i + 1] = '\0';
raw_parser(message_buffer);
message_buffer[i + 1] = saved_char;
- memmove(&message_buffer, &message_buffer[i + 1],
- message_end - i - 1);
+ memmove(&message_buffer, &message_buffer[i + 1], message_end - i - 1);
message_end = message_end - i - 1;
i = 0;
}
@@ -904,9 +1121,88 @@ static int handle_server_message(void)
}
}
+static void join_command(state l)
+{
+ if (!strchr(l->buf, '#')){
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ printf("\x1b[35mIllegal channel!\x1b[0m\r\n");
+ return;
+ }
+ *stpncpy(chan, strchr(l->buf, '#') + 1, MSG_MAX - 1) = '\0';
+ raw("join #%s\r\n", chan);
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ printf("\x1b[35mJoined #%s!\x1b[0m\r\n", chan);
+}
+
+static void part_command(state l)
+{
+ char *tok;
+ tok = strchr(l->buf, '#');
+ if (tok){
+ raw("part %s\r\n", tok);
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ printf("\x1b[35mLeft %s!\r\n", tok);
+ printf("\x1b[35mYou need to use /join or /# to speak in a channel!\x1b[0m\r\n");
+ strcpy(chan, "");
+ return;
+ }
+ tok = l->buf + 5;
+ while (*tok == ' ') {
+ tok++;
+ }
+ if (*tok == '#' || *tok == '\0') {
+ raw("part #%s\r\n", chan);
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ printf("\x1b[35mLeft #%s!\r\n", chan);
+ printf("\x1b[35mYou need to use /join or /# to speak in a channel!\x1b[0m\r\n");
+ strcpy(chan, "");
+ return;
+ }
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ printf("\x1b[35mIllegal channel!\x1b[0m\r\n");
+}
+
+static void msg_command(state l)
+{
+ char *tok;
+ strtok_r(l->buf + 4, " ", &tok);
+ int offset = 0;
+ while (*(l->buf + 4 + offset) == ' ') {
+ offset ++;
+ }
+ raw("privmsg %s :%s\r\n", l->buf + 4 + offset, tok);
+ if (strncmp(l->buf + 4 + offset, "NickServ", 8)) {
+ printf("\x1b[35mprivmsg %s :%s\x1b[0m\r\n", l->buf + 4 + offset, tok);
+ }
+}
+
+static void action_command(state l)
+{
+ char *tok;
+ strtok_r(l->buf + 7, " ", &tok);
+ int offset = 0;
+ while (*(l->buf + 7 + offset) == ' ') {
+ offset ++;
+ }
+ raw("privmsg #%s :\001ACTION %s\001\r\n", chan, l->buf + 7 + offset);
+ printf("\x1b[35mprivmsg #%s :ACTION %s\x1b[0m\r\n", chan, l->buf + 7 + offset);
+}
+
+static void nick_command(state l)
+{
+ char *tok;
+ raw("%s\r\n", l->buf + 1);
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ tok = l->buf + 5;
+ while (*tok == ' ') {
+ tok ++;
+ }
+ strcpy(nick, tok);
+}
+
static void handle_user_input(state l)
{
- if (l->buf == NULL) {
+ if (*l->buf == '\0') {
return;
}
char *tok;
@@ -916,62 +1212,141 @@ static void handle_user_input(state l)
}
printf("\r\x1b[0K");
switch (l->buf[0]) {
- case '/': /* send system command */
+ case '/': /* send system command */
+ if (!strncmp(l->buf + 1, "JOIN", 4) || !strncmp(l->buf + 1, "join", 4)) {
+ join_command(l);
+ return;
+ }
+ if (!strncmp(l->buf + 1, "PART", 4) || !strncmp(l->buf + 1, "part", 4)) {
+ part_command(l);
+ return;
+ }
+ if (l->buf[1] == '/') {
+ raw("privmsg #%s :%s\r\n", chan, l->buf + 2);
+ printf("\x1b[35mprivmsg #%s :%s\x1b[0m\r\n", chan, l->buf + 2);
+ return;
+ }
+ if (!strncmp(l->buf + 1, "MSG", 3) || !strncmp(l->buf + 1, "msg", 3)) {
+ msg_command(l);
+ return;
+ }
+ if (!strncmp(l->buf + 1, "NICK", 4) || !strncmp(l->buf + 1, "nick", 4)) {
+ nick_command(l);
+ return;
+ }
+ if (!strncmp(l->buf + 1, "ACTION", 6) || !strncmp(l->buf + 1, "action", 6)) {
+ action_command(l);
+ return;
+ }
if (l->buf[1] == '#') {
- strcpy(cdef, l->buf + 2);
- printf("\x1b[35mnew channel: #%s\x1b[0m\r\n", cdef);
- } else {
- raw("%s\r\n", l->buf + 1);
- printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ strcpy(chan, l->buf + 2);
+ printf("\x1b[35mnew channel: #%s\x1b[0m\r\n", chan);
+ return;
}
- break;
- case '@': /* send private message to target channel or user */
+ raw("%s\r\n", l->buf + 1);
+ printf("\x1b[35m%s\x1b[0m\r\n", l->buf);
+ return;
+ case '@': /* send private message to target channel or user */
strtok_r(l->buf, " ", &tok);
- if (l->buf[1] == '@') {
- if (l->buf[2] == '\0') {
- raw("privmsg #%s :\001ACTION %s\001\r\n", cdef, tok);
- printf("\x1b[35mprivmsg #%s :ACTION %s\x1b[0m\r\n", cdef, tok);
- } else {
- raw("privmsg %s :\001ACTION %s\001\r\n", l->buf + 2, tok);
- printf("\x1b[35mprivmsg %s :ACTION %s\x1b[0m\r\n", l->buf + 2,
- tok);
- }
- } else {
+ if (l->buf[1] != '@') {
raw("privmsg %s :%s\r\n", l->buf + 1, tok);
printf("\x1b[35mprivmsg %s :%s\x1b[0m\r\n", l->buf + 1, tok);
+ return;
}
- break;
- default: /* send private message to default channel */
- raw("privmsg #%s :%s\r\n", cdef, l->buf);
- printf("\x1b[35mprivmsg #%s :%s\x1b[0m\r\n", cdef, l->buf);
+ raw("privmsg %s :\001ACTION %s\001\r\n", l->buf + 2, tok);
+ printf("\x1b[35mprivmsg %s :ACTION %s\x1b[0m\r\n", l->buf + 2, tok);
+ return;
+ default: /* send private message to default channel */
+ raw("privmsg #%s :%s\r\n", chan, l->buf);
+ printf("\x1b[35mprivmsg #%s :%s\x1b[0m\r\n", chan, l->buf);
+ return;
}
}
-static void usage(void)
+static inline void usage(void)
{
fputs("kirc [-s host] [-p port] [-c channel] [-n nick] [-r realname] \
[-u username] [-k password] [-a token] [-o path] [-e] [-x] [-v] [-V]\n", stderr);
exit(2);
}
-static void version(void)
+static inline void version(void)
{
fputs("kirc-" VERSION " Copyright © 2022 Michael Czigler, MIT License\n",
stdout);
exit(0);
}
-static void open_tty()
-{
- if ((ttyinfd = open("/dev/tty", 0)) == -1) {
- perror("failed to open /dev/tty");
- exit(1);
+static inline void slot_clear(size_t i) {
+ memset(dcc_sessions.slots[i].filename, 0, FNM_MAX);
+ dcc_sessions.sock_fds[i] = (struct pollfd){.fd = -1, .events = POLLIN | POLLOUT};
+ dcc_sessions.slots[i] = (struct dcc_connection){.file_fd = -1};
+}
+
+/* TODO: implicitly assumes that the size reported was the correct size */
+/* TODO: should we just close the file and keep on running if we get
+ an error we can recover from? */
+static void slot_process(state l, char *buf, size_t buf_len, size_t i) {
+ const char *err_str;
+ int sock_fd = dcc_sessions.sock_fds[i].fd;
+ int file_fd = dcc_sessions.slots[i].file_fd;
+
+ if (~dcc_sessions.sock_fds[i].revents & POLLIN) {
+ return;
+ }
+
+ int n = read(sock_fd, buf, buf_len);
+ if (n == -1) {
+ err_str = "read";
+ goto handle_err;
+ }
+
+ dcc_sessions.slots[i].bytes_read += n;
+ if (write(file_fd, buf, n) < 0) {
+ err_str = "write";
+ goto handle_err;
+ }
+
+ if (!(dcc_sessions.sock_fds[i].revents & POLLOUT)) {
+ refresh_line(l);
+ return;
+ }
+ size_t file_size = dcc_sessions.slots[i].file_size;
+ size_t bytes_read = dcc_sessions.slots[i].bytes_read;
+ unsigned ack_is_64 = file_size > UINT_MAX;
+ unsigned ack_shift = (1 - ack_is_64) * 32;
+ unsigned long long ack = htonll(bytes_read << ack_shift);
+ if (write(sock_fd, &ack, ack_is_64 ? 8 : 4) < 0) {
+ err_str = "write";
+ goto handle_err;
+ }
+ if (bytes_read == file_size) {
+ shutdown(sock_fd, SHUT_RDWR);
+ close(sock_fd);
+ close(file_fd);
+ slot_clear(i);
+ }
+ refresh_line(l);
+ return;
+handle_err:
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ return;
+ }
+ if (errno == ECONNRESET) {
+ shutdown(sock_fd, SHUT_RDWR);
+ close(sock_fd);
+ close(file_fd);
+ slot_clear(i);
+ return;
+ } else {
+ perror(err_str);
+ return;
}
}
int main(int argc, char **argv)
{
- open_tty();
+ char buf[BUFSIZ];
int cval;
while ((cval = getopt(argc, argv, "s:p:o:n:k:c:u:r:a:exvV")) != -1) {
switch (cval) {
@@ -1009,7 +1384,7 @@ int main(int argc, char **argv)
pass = optarg;
break;
case 'c':
- chan = optarg;
+ strcpy(chan, optarg);
break;
case 'x':
cmds = 1;
@@ -1053,16 +1428,13 @@ int main(int argc, char **argv)
raw("%s\r\n", inic);
}
}
- struct pollfd fds[2] = {
- {.fd = ttyinfd,.events = POLLIN},
- {.fd = conn,.events = POLLIN}
- };
- char usrin[MSG_MAX];
- state_t l = {
- .buf = usrin,
- .buflen = MSG_MAX,
- .prompt = cdef
- };
+ for (int i = 0; i < CON_MAX; i++) {
+ slot_clear(i);
+ }
+ dcc_sessions.sock_fds[CON_MAX] = (struct pollfd){.fd = ttyinfd,.events = POLLIN};
+ dcc_sessions.sock_fds[CON_MAX + 1] = (struct pollfd){.fd = conn,.events = POLLIN};
+ state_t l;
+ l.buflen = MSG_MAX;
state_reset(&l);
int rc, editReturnFlag = 0;
if (enable_raw_mode(ttyinfd) == -1) {
@@ -1072,8 +1444,8 @@ int main(int argc, char **argv)
return 1;
}
for (;;) {
- if (poll(fds, 2, -1) != -1) {
- if (fds[0].revents & POLLIN) {
+ if (poll(dcc_sessions.sock_fds, CON_MAX + 2, -1) != -1) {
+ if (dcc_sessions.sock_fds[CON_MAX + 0].revents & POLLIN) {
editReturnFlag = edit(&l);
if (editReturnFlag > 0) {
history_add(l.buf);
@@ -1085,18 +1457,22 @@ int main(int argc, char **argv)
}
refresh_line(&l);
}
- if (fds[1].revents & POLLIN) {
+ if (dcc_sessions.sock_fds[CON_MAX + 1].revents & POLLIN) {
rc = handle_server_message();
+ if (rc == -2) {
+ return 1;
+ }
if (rc != 0) {
- if (rc == -2) {
- return 1;
- }
return 0;
}
refresh_line(&l);
}
+
+ for (int i = 0; i < CON_MAX; i++) {
+ slot_process(&l, buf, sizeof(buf), i);
+ }
} else {
- if (errno == EAGAIN) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
continue;
}
perror("poll");