hirc

IRC client
Log | Files | Refs

commit 81822db61acc0b67bb48ce44a2e2a6930e5093d9
parent 2c44097439323618f6df8277b348bb597a0df756
Author: hhvn <dev@hhvn.uk>
Date:   Thu, 11 Nov 2021 19:48:11 +0000

config.{c,h} Makefile {commands,handle,hist,main,nick,serv,ui}.c {hirc,struct}.h: /set

Diffstat:
MMakefile | 5+++--
Mcommands.c | 17+++++++++++++----
Mconfig.c | 285+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Dconfig.h | 155-------------------------------------------------------------------------------
Mhandle.c | 2+-
Mhirc.h | 22+++++++++++++++++++++-
Mhist.c | 9++++++++-
Mmain.c | 30++++++++++++++++++++++++++++--
Mnick.c | 15+++++++++++----
Mserv.c | 8++++----
Mstruct.h | 28+++++++++++++++++++---------
Mui.c | 42++++++++++++++++++++++++++++++++----------
12 files changed, 347 insertions(+), 271 deletions(-)

diff --git a/Makefile b/Makefile @@ -2,7 +2,8 @@ PREFIX = /usr/local BINDIR = $(PREFIX)/bin BIN = hirc OBJ = main.o handle.o hist.o nick.o \ - chan.o serv.o ui.o commands.o + chan.o serv.o ui.o commands.o \ + config.o # Comment to disable TLS LDTLS = -ltls @@ -20,4 +21,4 @@ clean: .c.o: $(CC) $(CFLAGS) -c $< -$(OBJ): config.h +$(OBJ): diff --git a/commands.c b/commands.c @@ -18,12 +18,13 @@ static struct Command commands[] = { {"quit", command_quit}, {"connect", command_connect}, {"select", command_select}, + {"set", command_set}, {NULL, NULL}, }; void command_quit(char *str) { - cleanup(str ? str : quitmessage); + cleanup(str ? str : config_gets("misc.quitmessage")); exit(EXIT_SUCCESS); } @@ -33,9 +34,9 @@ command_connect(char *str) { char *network = NULL; char *host = NULL; char *port = NULL; - char *nick = NULL; - char *username = NULL; - char *realname = NULL; + char *nick = config_gets("def.nick"); + char *username = config_gets("def.user"); + char *realname = config_gets("def.real"); int tls = 0, tls_verify = 0; int ret; struct passwd *user; @@ -189,6 +190,14 @@ command_select(char *str) { } } +void +command_set(char *str) { + char *name, *val; + + name = strtok_r(str, " ", &val); + config_set(name, val); +} + int command_getopt(char **str, struct CommandOpts *opts) { char *opt; diff --git a/config.c b/config.c @@ -1,19 +1,29 @@ +#include <ncurses.h> #include <string.h> #include <stdlib.h> #include "hirc.h" +char *valname[] = { + [Val_string] = "a string", + [Val_bool] = "boolean", + [Val_signed] = "a numeric value", + [Val_unsigned] = "positive", + [Val_nzunsigned] = "greater than zero", + [Val_range] = "a range", +}; + struct Config config[] = { {"log.dir", 1, Val_string, .str = "~/.local/hirc", .strhandle = NULL, .description = - "Directory for hirc to log to." - "Can contain ~ to refer to $HOME"}, + "Directory for hirc to log to.\n" + "Can contain ~ to refer to $HOME\n"}, {"log.toggle", 1, Val_bool, .num = 1, .numhandle = NULL, .description = - "Simple: to log, or not to log"}, + "Simple: to log, or not to log\n"}, {"def.nick", 1, Val_string, .str = NULL, .strhandle = NULL, @@ -23,100 +33,100 @@ struct Config config[] = { .str = NULL, .strhandle = NULL, .description = - "Default username (nick!..here..@host), " - "may be replaced by identd response"}, + "Default username (nick!..here..@host), \n" + "may be replaced by identd response\n"}, {"def.real", 1, Val_string, .str = NULL, .strhandle = NULL, .description = - "Default \"realname\", seen in /whois"}, + "Default \"realname\", seen in /whois\n"}, {"def.chantypes", 1, Val_string, .str = "#&!+", .strhandle = NULL, .description = - "You most likely don't want to touch this." - "If a server does not supply this in RPL_ISUPPORT," - "hirc assumes it will use these channel types."}, + "You most likely don't want to touch this.\n" + "If a server does not supply this in RPL_ISUPPORT,\n" + "hirc assumes it will use these channel types.\n"}, {"def.prefixes", 1, Val_string, .str = "(ov)@+", .strhandle = NULL, .description = - "You most likely don't want to touch this." - "If a server doesn't supply this in the nonstandard" - "RPL_ISUPPORT, it likely won't support nonstandard" - "prefixes."}, + "You most likely don't want to touch this.\n" + "If a server doesn't supply this in the nonstandard\n" + "RPL_ISUPPORT, it likely won't support nonstandard\n" + "prefixes.\n"}, {"reconnect.interval", 1, Val_nzunsigned, .num = 10, .numhandle = NULL, .description = - "Starting reconnect interval in seconds." - "In reality, for each attempt this will be multipled" - "by the number of failed attemps until it reaches" - "reconnect.maxinterval"}, + "Starting reconnect interval in seconds.\n" + "In reality, for each attempt this will be multipled\n" + "by the number of failed attemps until it reaches\n" + "reconnect.maxinterval\n"}, {"reconnect.maxinterval", 1, Val_nzunsigned, .num = 600, .numhandle = NULL, .description = - "Maximum reconnect interval in seconds." - "See reconnect.interval"}, + "Maximum reconnect interval in seconds.\n" + "See reconnect.interval\n"}, {"nickcolour.self", 1, Val_nzunsigned, .num = 90, .numhandle = config_colour_self, .description = - "Colour to use for onself." - "Must be 0, 99 or anywhere between. 99 is no colours."}, + "Colour to use for onself.\n" + "Must be 0, 99 or anywhere between. 99 is no colours.\n"}, {"nickcolour.range", 1, Val_range, .range = {28, 63}, .rangehandle = config_colour_range, .description = - "Range of (mirc extended) colours used to colour nicks" - "Must be 0, 99 or anywhere between. 99 is no colour" - "Giving a single value or two identical values will" - "use that colour only"}, + "Range of (mirc extended) colours used to colour nicks\n" + "Must be 0, 99 or anywhere between. 99 is no colour\n" + "Giving a single value or two identical values will\n" + "use that colour only\n"}, {"nicklist.location", 1, Val_unsigned, .num = RIGHT, .numhandle = config_nicklist_location, .description = - "Location of nicklist. May be:" - " - Hidden (0)" - " - Left (1)" - " - Right (2)"}, + "Location of nicklist. May be:\n" + " 0 - Hidden\n" + " 1 - Left\n" + " 2 - Right\n"}, {"nicklist.width", 1, Val_nzunsigned, .num = 15, .numhandle = config_nicklist_width, .description = - "Number of columns nicklist will take up."}, + "Number of columns nicklist will take up.\n"}, {"buflist.location", 1, Val_unsigned, .num = LEFT, .numhandle = config_buflist_location, .description = - "Location of nicklist. May be:" - " - Hidden (0)" - " - Left (1)" - " - Right (2)"}, + "Location of nicklist. May be:\n" + " 0 - Hidden\n" + " 1 - Left\n" + " 2 - Right\n"}, {"buflist.width", 1, Val_nzunsigned, .num = 25, .numhandle = config_buflist_width, .description = - "Number of columns buflist will take up."}, + "Number of columns buflist will take up.\n"}, {"misc.pingtime", 1, Val_nzunsigned, .num = 200, .numhandle = NULL, .description = - "Wait this many seconds since last received message" - "from server to send PING. If ping.wait seconds" - "elapses since sending a PING, hirc will consider" - "the server disconnected."}, + "Wait this many seconds since last received message\n" + "from server to send PING. If ping.wait seconds\n" + "elapses since sending a PING, hirc will consider\n" + "the server disconnected.\n"}, {"misc.quitmessage", 1, Val_string, .str = "pain is temporary", .strhandle = NULL, .description = - "Message to send on /quit"}, + "Message to send on /quit\n"}, {"misc.partmessage", 1, Val_string, .str = "pain is temporary", .strhandle = NULL, .description = - "Message to send on /part"}, + "Message to send on /part\n"}, {NULL}, }; @@ -136,6 +146,28 @@ config_getl(char *name) { return 0; } +void +config_get_print(char *name) { + int i; + + for (i=0; config[i].name; i++) { + if (strcmp(config[i].name, name) == 0) { + if (config[i].valtype == Val_string) + hist_format(main_buf, Activity_status, HIST_SHOW, "%s: %s", + name, config[i].str); + else if (config[i].valtype == Val_range) + hist_format(main_buf, Activity_status, HIST_SHOW, "%s: {%ld, %ld}", + name, config[i].range[0], config[i].range[1]); + else + hist_format(main_buf, Activity_status, HIST_SHOW, "%s: %ld", + name, config[i].num); + return; + } + } + + ui_error("no such configuration variable: '%s'", name); +} + char * config_gets(char *name) { int i; @@ -168,20 +200,24 @@ config_setl(char *name, long num) { int i; for (i=0; config[i].name; i++) { - if (strcmp(config[i].name, name) == 0 && ( - config[i].valtype == Val_bool || - config[i].valtype == Val_signed || - config[i].valtype == Val_unsigned || - config[i].valtype == Val_nzunsigned)) { - if (config[i].numhandle) { - config[i].numhandle(num); - } else { + if (strcmp(config[i].name, name) == 0) { + if ((config[i].valtype == Val_bool && (num == 1 || num == 0)) || + (config[i].valtype == Val_signed) || + (config[i].valtype == Val_unsigned && num >= 0) || + (config[i].valtype == Val_nzunsigned && num > 0)) { + if (config[i].numhandle) + if (!config[i].numhandle(num)) + return; config[i].isdef = 0; config[i].num = num; + } else { + ui_error("%s must be %s", name, valname[config[i].valtype]); } return; } } + + ui_error("no such configuration variable: '%s'", name); } void @@ -189,20 +225,24 @@ config_sets(char *name, char *str) { int i; for (i=0; config[i].name; i++) { - if (strcmp(config[i].name, name) == 0 && - config[i].valtype == Val_string) { - if (config[i].strhandle) { - config[i].strhandle(str); - } else { - if (!config[i].isdef) - free(config[i].str); - else - config[i].isdef = 0; - config[i].str = estrdup(str); + if (strcmp(config[i].name, name) == 0) { + if (config[i].valtype != Val_string) { + ui_error("%s must be %s", name, valname[config[i].valtype]); + return; } + if (config[i].strhandle) + if (!config[i].strhandle(str)) + return; + if (!config[i].isdef) + free(config[i].str); + else + config[i].isdef = 0; + config[i].str = estrdup(str); return; } } + + ui_error("no such configuration variable: '%s'", name); } void @@ -210,41 +250,130 @@ config_setr(char *name, long a, long b) { int i; for (i=0; config[i].name; i++) { - if (strcmp(config[i].name, name) == 0 && - config[i].valtype == Val_range) { - if (config[i].strhandle) { - config[i].rangehandle(a, b); - } else { - config[i].isdef = 0; - config[i].range[0] = a; - config[i].range[1] = b; + if (strcmp(config[i].name, name) == 0 ) { + if (config[i].valtype != Val_range) { + ui_error("%s must be %s", name, valname[config[i].valtype]); + return; } + if (config[i].rangehandle) + if (!config[i].rangehandle(a, b)) + return; + config[i].isdef = 0; + config[i].range[0] = a; + config[i].range[1] = b; return; } } + + ui_error("no such configuration variable: '%s'", name); } void +config_set(char *name, char *val) { + char *str = val ? strdup(val) : NULL; + char *tok[3], *save, *p; + + tok[0] = strtok_r(val, " ", &save); + tok[1] = strtok_r(NULL, " ", &save); + tok[2] = strtok_r(NULL, " ", &save); + + if (strisnum(tok[0]) && strisnum(tok[1]) && !tok[2]) + config_setr(name, strtol(tok[0], NULL, 10), strtol(tok[1], NULL, 10)); + else if (strisnum(tok[0]) && !tok[1]) + config_setl(name, strtol(tok[0], NULL, 10)); + else if (tok[0]) + config_sets(name, str); + else + config_get_print(name); + + free(str); +} + +int config_colour_self(long num) { - return; + if (num >= 0 && num <= 99) + return 1; + + ui_error("nickcolour.self must be between 0 and 99 (including both)", NULL); + return 0; } -void + +int config_colour_range(long a, long b) { - return; + if (a >= 0 && a <= 0 && + b >= 0 && b <= 0) + return 1; + + ui_error("nickcolour.range must have numbers between 0 and 99 (including both)", NULL); } -void + +int config_nicklist_location(long num) { - return; + int i; + + if (num != HIDDEN && num != LEFT && num != RIGHT) { + ui_error("nicklist.location must be 0, 1 or 2", NULL); + return 0; + } + + if (num == windows[Win_buflist].location != HIDDEN) + windows[Win_buflist].location = num == LEFT ? RIGHT : LEFT; + windows[Win_nicklist].location = num; + + ui_redraw(); + + for (i=0; config[i].name; i++) { + if (strcmp(config[i].name, "nicklist.location") == 0) + config[i].num = num; + if (strcmp(config[i].name, "buflist.location") == 0) + config[i].num = windows[Win_buflist].location; + } + + return 0; } -void + +int config_nicklist_width(long num) { - return; + if (num <= COLS - (windows[Win_buflist].location ? windows[Win_buflist].w : 0) - 2) { + uineedredraw = 1; + return 1; + } + + ui_error("nicklist will be too big", NULL); + return 0; } -void + +int config_buflist_location(long num) { - return; + int i; + + if (num != HIDDEN && num != LEFT && num != RIGHT) { + ui_error("buflist.location must be 0, 1 or 2", NULL); + return 0; + } + + if (num == windows[Win_buflist].location != HIDDEN) + windows[Win_nicklist].location = num == LEFT ? RIGHT : LEFT; + windows[Win_buflist].location = num; + + ui_redraw(); + + for (i=0; config[i].name; i++) { + if (strcmp(config[i].name, "buflist.location") == 0) + config[i].num = num; + if (strcmp(config[i].name, "nicklist.location") == 0) + config[i].num = windows[Win_nicklist].location; + } + + return 0; } -void +int config_buflist_width(long num) { - return; + if (num <= COLS - (windows[Win_nicklist].location ? windows[Win_nicklist].w : 0) - 2) { + uineedredraw = 1; + return 1; + } + + ui_error("buflist will be too big", NULL); + return 0; } diff --git a/config.h b/config.h @@ -1,155 +0,0 @@ -#ifndef H_CONFIG -#define H_CONFIG - -#include "struct.h" - -#define MAIN_NICK "hhvn" -#define MAIN_USERNAME "Fanatic" -#define MAIN_REALNAME "gopher://hhvn.uk" - -static char *logdir = "~/.local/hirc"; -static struct Netconfig netconfig[] = { - { - .name = "test", - .host = "localhost", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { "#test", "#test2", NULL }, - .tls = 0, - .tls_verify = 0, - }, - /* - { - .name = "hlircnet", - .host = "irc.hhvn.uk", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { - "#hlircnet", "#help", "#gopher", "#vhosts", - "#hlfm", "#cgo", "#distrotube", NULL - }, - }, - { - .name = "dataswamp", - .host = "irc.dataswamp.org", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { "#dataswamp", NULL }, - }, - { - .name = "efnet", - .host = "efnet.port80.se", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { "#asciiart", "#LRH", "#thepiratebay.org", NULL }, - }, - { - .name = "ikteam", - .host = "irc.nk.ax", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { "#chat", NULL }, - }, - { - .name = "nebulacentre", - .host = "irc.nebulacentre.net", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { "#general", NULL }, - }, - { - .name = "sdf", - .host = "irc.sdf.org", - .port = "6667", - .nick = MAIN_NICK, - .user = MAIN_USERNAME, - .real = MAIN_REALNAME, - .join = { "#sdf", "#gopher", "#helpdesk", NULL }, - } - */ -}; - -/* real maximum = MAX_HISTORY * (channels + servers + queries) */ -#define MAX_HISTORY 1024 - -#define HIRC_COLOURS 100 -static unsigned short colourmap[HIRC_COLOURS] = { - /* original 16 mirc colours - * some clients use the first 16 ansi colours for this, - * but here I use the 256 colours to ensure terminal-agnosticism */ - [0] = 255, 16, 19, 46, 124, 88, 127, 184, - [8] = 208, 46, 45, 51, 21, 201, 240, 255, - - /* extended */ - [16] = 52, 94, 100, 58, 22, 29, 23, 24, 17, 54, 53, 89, - [28] = 88, 130, 142, 64, 28, 35, 30, 25, 18, 91, 90, 125, - [40] = 124, 166, 184, 106, 34, 49, 37, 33, 19, 129, 127, 161, - [52] = 196, 208, 226, 154, 46, 86, 51, 75, 21, 171, 201, 198, - [64] = 203, 215, 227, 191, 83, 122, 87, 111, 63, 177, 207, 205, - [76] = 217, 223, 229, 193, 157, 158, 159, 153, 147, 183, 219, 212, - [88] = 16, 233, 235, 237, 239, 241, 244, 247, 250, 254, 231, - - /* transparency */ - [99] = -1 -}; - -/* (mIRC) colour for any messages sent by oneself */ -static unsigned short selfcolour = 90; - -/* (mIRC) inclusive colour range for any messages sent - * by others. Use same number twice for constant colour */ -static unsigned short othercolour[2] = {28, 63}; - -/* default channel types */ -static char *default_chantypes = "#&!+"; - -/* default prefixes/priveledges, (symbols)modes */ -static char *default_prefixes = "(ov)@+"; - -/* send ping to server after n seconds of inactivity */ -static int pinginact = 200; - -/* max seconds to wait between reconnects */ -static long maxreconnectinterval = 600; - -/* number of seconds between reconnects, - * multiplied by amount of failed reconnects. - * Example: reconnectinterval = 10, maxreconnectinterval = 600 - * 1st: 0 * 10 = 0 - * 2nd: 1 * 10 = 10 - * 3rd: 2 * 10 = 20 - * 10th: 10 * 10 = 100 - * 60th: 60 * 10 = 600 - * 61st: 600, maxreconnectinterval reached */ -static long reconnectinterval = 10; - -/* nicklist location: - * HIDDEN, LEFT, RIGHT */ -static short nicklistlocation = RIGHT; - -/* width of nicklist in columns */ -static int nicklistwidth = 15; - -/* buffer list location: - * HIDDEN, LEFT, RIGHT */ -static short buflistlocation = LEFT; - -/* width of buffer list in columns */ -static int buflistwidth = 25; - -/* default quit message */ -static char *quitmessage = "pain is temporary"; - -#endif /* H_CONFIG */ diff --git a/handle.c b/handle.c @@ -297,7 +297,7 @@ handle(int rfd, struct Server *server) { if (!read_line(rfd, buf, sizeof(buf))) { if (buf[0] == EOF || buf[0] == 3 || buf[0] == 4) { - serv_disconnect(server, 1); + serv_disconnect(server, 1, "EOF"); hist_format(server->history, Activity_error, HIST_SHOW, "SELF_CONNECTLOST %s %s %s :EOF received", server->name, server->host, server->port); diff --git a/hirc.h b/hirc.h @@ -2,12 +2,13 @@ #define H_HIRC #include "struct.h" -#include "config.h" #define PARAM_MAX 64 #define INPUT_MAX 8192 #define COMMANDARG_MAX (INPUT_MAX / 5) /* Theoretical max: -a o -b o -c o * * 12345 */ +#define MAX_HISTORY 8192 + /* real maximum = MAX_HISTORY * (channels + servers + queries) */ /* main.c */ void * emalloc(size_t size); @@ -21,6 +22,7 @@ int ircprintf(struct Server *server, char *format, ...); char * homepath(char *path); char chrcmp(char c, char *s); char * struntil(char *str, char until); +int strisnum(char *str); /* chan.c */ void chan_free(struct Channel *channel); @@ -127,6 +129,23 @@ int command_getopt(char **str, struct CommandOpts *opts); void command_quit(char *str); void command_connect(char *str); void command_select(char *str); +void command_set(char *str); + +/* config.h */ +void config_get_print(char *name); +long config_getl(char *name); +char * config_gets(char *name); +void config_getr(char *name, long *a, long *b); +void config_set(char *name, char *str); +void config_setl(char *name, long num); +void config_sets(char *name, char *str); +void config_setr(char *name, long a, long b); +int config_colour_self(long num); +int config_colour_range(long a, long b); +int config_nicklist_location(long num); +int config_nicklist_width(long num); +int config_buflist_location(long num); +int config_buflist_width(long num); /* main.c */ extern struct Server *servers; @@ -135,5 +154,6 @@ extern struct HistInfo *main_buf; /* ui.c */ extern struct Selected selected; extern struct Window windows[Win_last]; +extern int uineedredraw; #endif /* H_HIRC */ diff --git a/hist.c b/hist.c @@ -128,8 +128,15 @@ hist_format(struct HistInfo *histinfo, enum Activity activity, enum HistOpt opti int hist_log(char *msg, struct Nick *from, time_t timestamp, struct Server *server) { char filename[2048]; + char *logdir; int ret, serrno; + if (!config_getl("log.toggle")) + return -2; + + if ((logdir = config_gets("log.dir")) == NULL) + return -3; + if (*msg == ':' && strchr(msg, ' ')) msg = strchr(msg, ' ') + 1; @@ -157,7 +164,7 @@ hist_log(char *msg, struct Nick *from, time_t timestamp, struct Server *server) ui_error("Failed to write to log of server '%s': %s", server->name, strerror(errno)); return -1; } - + return 1; } diff --git a/main.c b/main.c @@ -137,7 +137,7 @@ ircprintf(struct Server *server, char *format, ...) { ret = write(server->wfd, msg, strlen(msg)); if (ret == -1 && server->status == ConnStatus_connected) { - serv_disconnect(server, 1); + serv_disconnect(server, 1, "Eead Rrror"); hist_format(server->history, Activity_error, HIST_SHOW, "SELF_CONNECTLOST %s %s %s :%s", server->name, server->host, server->port, strerror(errno)); @@ -182,6 +182,20 @@ struntil(char *str, char until) { return ret; } +int +strisnum(char *str) { + if (!str) + return 0; + + if (*str == '-' || *str == '+') + str += 1; + + for (; *str; str++) + if (*str > '9' || *str < '0') + return 0; + return 1; +} + void sighandler(int signal) { return; @@ -193,6 +207,7 @@ main(int argc, char **argv) { struct Server *sp; FILE *file; int i, refreshed, inputrefreshed; + long pinginact, reconnectinterval, maxreconnectinterval; struct pollfd fds[] = { { .fd = fileno(stdin), .events = POLLIN }, }; @@ -216,6 +231,9 @@ main(int argc, char **argv) { exit(EXIT_FAILURE); } + pinginact = config_getl("misc.pingtime"); + reconnectinterval = config_getl("reconnect.interval"); + maxreconnectinterval = config_getl("reconnect.maxinterval"); for (sp = servers; sp; sp = sp->next) { if (sp->rpollfd->revents) { /* received an event */ @@ -230,7 +248,7 @@ main(int argc, char **argv) { } else if (sp->pingsent && (time(NULL) - sp->pingsent) >= pinginact) { /* haven't gotten a response in pinginact seconds since * sending ping, this connexion is probably dead now */ - serv_disconnect(sp, 1); + serv_disconnect(sp, 1, "Eead Rror"); hist_format(sp->history, Activity_error, HIST_SHOW, "SELF_CONNECTLOST %s %s %s :No ping reply in %d seconds", sp->name, sp->host, sp->port, pinginact); @@ -256,6 +274,14 @@ main(int argc, char **argv) { oldselected.history = selected.history; oldselected.name = selected.name; + if (uineedredraw) { + uineedredraw = 0; + ui_redraw(); + for (i=0; i < Win_last; i++) + windows[i].redraw = 0; + continue; + } + refreshed = inputrefreshed = 0; for (i=0; i < Win_last; i++) { if (windows[i].redraw) { diff --git a/nick.c b/nick.c @@ -10,13 +10,20 @@ #define MAXA(array) MAX(array[0], array[1]) #define MINA(array) MIN(array[0], array[1]) -unsigned short +short nick_getcolour(char *nick) { unsigned short ret, sum; int i; + long range[2]; - if (othercolour[0] == othercolour[1]) - return othercolour[0]; + config_getr("nickcolour.range", &range[0], &range[1]); + + if (range[0] < 0 || range[0] > 99 || + range[1] < 0 || range[1] > 99) + return -1; + + if (range[0] == range[1]) + return range[0]; for (sum=i=0; nick && *nick; nick++, i++) { /* don't count certain trailing characters. The following: @@ -31,7 +38,7 @@ nick_getcolour(char *nick) { sum ^= *nick; } - return (sum % (MAXA(othercolour) - MINA(othercolour)) + MINA(othercolour) - 1); + return (sum % (MAXA(range) - MINA(range)) + MINA(range) - 1); } void diff --git a/serv.c b/serv.c @@ -63,8 +63,8 @@ serv_create(char *name, char *host, char *port, char *nick, server->host = estrdup(host); server->port = estrdup(port); server->supports = NULL; - support_set(server, "CHANTYPES", default_chantypes); - support_set(server, "PREFIX", default_prefixes); + support_set(server, "CHANTYPES", config_gets("def.chantypes")); + support_set(server, "PREFIX", config_gets("def.prefixes")); server->self = nick_create(nick, ' ', NULL); server->self->self = 1; server->history = emalloc(sizeof(struct HistInfo)); @@ -229,8 +229,8 @@ serv_connect(struct Server *server) { return; fail: - serv_disconnect(server, 1); - if (server->connectfail * reconnectinterval < maxreconnectinterval) + serv_disconnect(server, 1, "Eead Rrror"); + if (server->connectfail * config_getl("reconnect.interval") < config_getl("reconnect.maxinterval")) server->connectfail += 1; freeaddrinfo(ai); } diff --git a/struct.h b/struct.h @@ -130,16 +130,26 @@ struct CommandOpts { int ret; }; -struct Netconfig { +enum Valtype { + Val_string, + Val_bool, + Val_signed, + Val_unsigned, + Val_nzunsigned, + Val_range, +}; + +struct Config { char *name; - char *host; - char *port; - char *nick; - char *user; - char *real; - char *join[64]; - int tls; - int tls_verify; + int isdef; + enum Valtype valtype; + char *description; + char *str; + long num; + long range[2]; + int (*strhandle)(char *string); + int (*numhandle)(long num); + int (*rangehandle)(long a, long b); }; enum WindowLocation { diff --git a/ui.c b/ui.c @@ -10,6 +10,29 @@ #endif /* TLS */ #include "hirc.h" +int uineedredraw = 0; + +#define HIRC_COLOURS 100 +static unsigned short colourmap[HIRC_COLOURS] = { + /* original 16 mirc colours + * some clients use the first 16 ansi colours for this, + * but here I use the 256 colours to ensure terminal-agnosticism */ + [0] = 255, 16, 19, 46, 124, 88, 127, 184, + [8] = 208, 46, 45, 51, 21, 201, 240, 255, + + /* extended */ + [16] = 52, 94, 100, 58, 22, 29, 23, 24, 17, 54, 53, 89, + [28] = 88, 130, 142, 64, 28, 35, 30, 25, 18, 91, 90, 125, + [40] = 124, 166, 184, 106, 34, 49, 37, 33, 19, 129, 127, 161, + [52] = 196, 208, 226, 154, 46, 86, 51, 75, 21, 171, 201, 198, + [64] = 203, 215, 227, 191, 83, 122, 87, 111, 63, 177, 207, 205, + [76] = 217, 223, 229, 193, 157, 158, 159, 153, 147, 183, 219, 212, + [88] = 16, 233, 235, 237, 239, 241, 244, 247, 250, 254, 231, + + /* transparency */ + [99] = -1 +}; + struct Window windows[Win_last] = { [Win_main] = {.handler = ui_draw_main}, [Win_input] = {.handler = ui_draw_input}, @@ -72,14 +95,8 @@ ui_init(void) { memset(input.string, '\0', sizeof(input.string)); input.counter = 0; - if (nicklistlocation != 0 && nicklistlocation == buflistlocation) { - ui_error("nicklist and buflist can't be set to same location in config.h", NULL); - windows[Win_buflist].location = LEFT; - windows[Win_nicklist].location = RIGHT; - } else { - windows[Win_buflist].location = buflistlocation; - windows[Win_nicklist].location = nicklistlocation; - } + windows[Win_nicklist].location = config_getl("nicklist.location"); + windows[Win_buflist].location = config_getl("buflist.location"); windows[Win_main].window = newwin(0, 0, 0, 0); windows[Win_input].window = newwin(0, 0, 0, 0); @@ -152,8 +169,8 @@ ui_read(void) { needredraw = 0; } return; - case KEY_RESIZE: - ui_redraw(); + case KEY_RESIZE: + ui_redraw(); return; case KEY_BACKSPACE: if (input.counter) { @@ -239,9 +256,14 @@ ui_input_delete(int num, int counter) { void ui_redraw(void) { + long nicklistwidth, buflistwidth; int x = 0, rx = 0; int i; + nicklistwidth = config_getl("nicklist.width"); + buflistwidth = config_getl("buflist.width"); + + /* TODO: what if nicklistwidth or buflistwidth is too big? */ if (windows[Win_buflist].location == LEFT) { windows[Win_buflist].x = windows[Win_buflist].y = 0; windows[Win_buflist].h = LINES;