hirc

[archived] IRC client
git clone https://hhvn.uk/hirc
git clone git://hhvn.uk/hirc
Log | Files | Refs

nick.c (6681B)


      1 /*
      2  * src/nick.c from hirc
      3  *
      4  * Copyright (c) 2021-2022 hhvn <dev@hhvn.uk>
      5  *
      6  * Permission to use, copy, modify, and distribute this software for any
      7  * purpose with or without fee is hereby granted, provided that the above
      8  * copyright notice and this permission notice appear in all copies.
      9  *
     10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     17  *
     18  */
     19 
     20 #include <stdio.h>
     21 #include <ctype.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <limits.h>
     25 #include "hirc.h"
     26 
     27 #define MAX(var1, var2)	(var1 > var2 ? var1 : var2)
     28 #define MIN(var1, var2) (var1 < var2 ? var1 : var2)
     29 #define MAXA(array) MAX(array[0], array[1])
     30 #define MINA(array) MIN(array[0], array[1])
     31 
     32 short
     33 nick_getcolour(struct Nick *nick) {
     34 	unsigned short sum;
     35 	int i;
     36 	long range[2];
     37 	char *s = nick->nick;
     38 
     39 	if (nick->self)
     40 		return config_getl("nickcolour.self");
     41 
     42 	config_getr("nickcolour.range", &range[0], &range[1]);
     43 
     44 	if (range[0] < 0 || range[0] > 99 ||
     45 			range[1] < 0 || range[1] > 99)
     46 		return -1;
     47 
     48 	if (range[0] == range[1])
     49 		return range[0];
     50 
     51 	for (sum=i=0; s && *s; s++, i++) {
     52 		/* don't count certain trailing characters. The following:
     53 		 * hhvn
     54 		 * hhvn_
     55 		 * hhvn2
     56 		 * should all produce the same colour. */
     57 		if ((*s == '_' || isdigit(*s)) && *(s + 1) == '\0')
     58 			break;
     59 
     60 		sum += *s * (i + 1);
     61 		sum ^= *s;
     62 	}
     63 
     64 	return (sum % (MAXA(range) - MINA(range)) + MINA(range) - 1);
     65 }
     66 
     67 void
     68 prefix_tokenize(char *prefix, char **nick, char **ident, char **host) {
     69 	enum { ISNICK, ISIDENT, ISHOST } segment = ISNICK;
     70 	char *p, *dup;
     71 
     72 	p = dup = estrdup(prefix);
     73 
     74 	if (*p == ':')
     75 		p++;
     76 
     77 	if (nick)	*nick = p;
     78 	if (ident)	*ident = NULL;
     79 	if (host)	*host = NULL;
     80 
     81 	for (; p && *p && segment != ISHOST; p++) {
     82 		if (segment == ISNICK && *p == '!') {
     83 			*p = '\0';
     84 			if (ident)
     85 				*ident = p + 1;
     86 			segment = ISIDENT;
     87 		}
     88 		if (segment == ISIDENT && *p == '@') {
     89 			*p = '\0';
     90 			if (host)
     91 				*host = p + 1;
     92 			segment = ISHOST;
     93 		}
     94 	}
     95 
     96 	if (nick && *nick)	*nick = estrdup(*nick);
     97 	if (ident && *ident)	*ident = estrdup(*ident);
     98 	if (host && *host)	*host = estrdup(*host);
     99 	pfree(&dup);
    100 }
    101 
    102 void
    103 nick_free(struct Nick *nick) {
    104 	if (nick) {
    105 		pfree(&nick->prefix);
    106 		pfree(&nick->nick);
    107 		pfree(&nick->ident);
    108 		pfree(&nick->host);
    109 		pfree(&nick);
    110 	}
    111 }
    112 
    113 void
    114 nick_free_list(struct Nick **head) {
    115 	struct Nick *p, *prev;
    116 
    117 	if (!head || !*head)
    118 		return;
    119 
    120 	prev = *head;
    121 	p = prev->next;
    122 	while (prev) {
    123 		nick_free(prev);
    124 		prev = p;
    125 		if (p)
    126 			p = p->next;
    127 	}
    128 	*head = NULL;
    129 }
    130 
    131 struct Nick *
    132 nick_create(char *prefix, char priv, struct Server *server) {
    133 	struct Nick *nick;
    134 
    135 	assert_warn(prefix && priv, NULL);
    136 
    137 	nick = emalloc(sizeof(struct Nick));
    138 	nick->prefix = estrdup(prefix);
    139 	nick->next = nick->prev = NULL;
    140 	nick->priv = priv;
    141 	prefix_tokenize(nick->prefix, &nick->nick, &nick->ident, &nick->host);
    142 	nick->self = nick_isself_server(nick, server);
    143 
    144 	return nick;
    145 }
    146 
    147 int
    148 nick_isself(struct Nick *nick) {
    149 	if (!nick)
    150 		return 0;
    151 
    152 	return nick->self;
    153 }
    154 
    155 int
    156 nick_isself_server(struct Nick *nick, struct Server *server) {
    157 	if (!nick || !server || !nick->nick)
    158 		return 0;
    159 
    160 	if (strcmp_n(server->self->nick, nick->nick) == 0)
    161 		return 1;
    162 	else
    163 		return 0;
    164 }
    165 
    166 struct Nick *
    167 nick_add(struct Nick **head, char *prefix, char priv, struct Server *server) {
    168 	struct Nick *nick;
    169 
    170 	assert_warn(prefix && priv, NULL);
    171 
    172 	nick = nick_create(prefix, priv, server);
    173 	assert_warn(nick, NULL);
    174 
    175 	nick->next = *head;
    176 	nick->prev = NULL;
    177 	if (*head)
    178 		(*head)->prev = nick;
    179 	*head = nick;
    180 
    181 	return nick;
    182 }
    183 
    184 struct Nick *
    185 nick_dup(struct Nick *nick) {
    186 	struct Nick *ret;
    187 	if (!nick)
    188 		return NULL;
    189 	ret = emalloc(sizeof(struct Nick));
    190 	ret->prev = ret->next = NULL;
    191 	ret->priv   = nick->priv;
    192 	ret->prefix = nick->prefix ? strdup(nick->prefix) : NULL;
    193 	ret->nick   = nick->nick ? strdup(nick->nick) : NULL;
    194 	ret->ident  = nick->ident ? strdup(nick->ident) : NULL;
    195 	ret->host   = nick->host ? strdup(nick->host) : NULL;
    196 	ret->self   = nick->self;
    197 	return ret;
    198 }
    199 
    200 struct Nick *
    201 nick_get(struct Nick **head, char *nick) {
    202 	struct Nick *p;
    203 
    204 	p = *head;
    205 	for (; p; p = p->next) {
    206 		if (strcmp_n(p->nick, nick) == 0)
    207 			return p;
    208 	}
    209 
    210 	return NULL;
    211 }
    212 
    213 int
    214 nick_remove(struct Nick **head, char *nick) {
    215 	struct Nick *p;
    216 
    217 	if (!head || !nick)
    218 		return -1;
    219 
    220 	if ((p = nick_get(head, nick)) == NULL)
    221 		return 0;
    222 
    223 	if (*head == p)
    224 		*head = p->next;
    225 	if (p->next)
    226 		p->next->prev = p->prev;
    227 	if (p->prev)
    228 		p->prev->next = p->next;
    229 	nick_free(p);
    230 	return 1;
    231 }
    232 
    233 static inline void
    234 nick_dcpy(struct Nick *dest, struct Nick *origin) {
    235 	dest->priv   = origin->priv;
    236 	dest->prefix = origin->prefix;
    237 	dest->nick   = origin->nick;
    238 	dest->ident  = origin->ident;
    239 	dest->host   = origin->host;
    240 	dest->self   = origin->self;
    241 }
    242 
    243 static inline void
    244 nick_swap(struct Nick *first, struct Nick *second) {
    245 	struct Nick temp;
    246 
    247 	nick_dcpy(&temp, first);
    248 	nick_dcpy(first, second);
    249 	nick_dcpy(second, &temp);
    250 }
    251 
    252 enum {
    253 	S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, S_8, S_9,
    254 	S_a, S_b, S_c, S_d, S_e, S_f, S_g, S_h, S_i,
    255 	S_j, S_k, S_l, S_m, S_n, S_o, S_p, S_q, S_r,
    256 	S_s, S_t, S_u, S_v, S_w, S_x, S_y, S_z,
    257 	S_dash, S_lbrace, S_rbrace, S_pipe, S_grave, S_caret,
    258 	S_null, S_space,
    259 };
    260 
    261 void
    262 nick_sort(struct Nick **head, struct Server *server) {
    263 	char *s[2];
    264 	struct Nick *p, *next;
    265 	int swapped;
    266 	int map[CHAR_MAX] = {
    267 		['\0'] = S_null,
    268 		[' '] = S_space, /* default p->priv */
    269 		['-'] = S_dash,
    270 		['{'] = S_lbrace, ['['] = S_lbrace,
    271 		['}'] = S_rbrace, [']'] = S_rbrace,
    272 		['|'] = S_pipe,  ['\\'] = S_pipe,
    273 		['`'] = S_grave,
    274 		['^'] = S_caret,
    275 		['a'] = S_a, S_b, S_c, S_d, S_e, S_f, S_g, S_h, S_i, S_j,
    276 			S_k, S_l, S_m, S_n, S_o, S_p, S_q, S_r, S_s, S_t,
    277 			S_u, S_v, S_w, S_x, S_y, S_z,
    278 		['A'] = S_a, S_b, S_c, S_d, S_e, S_f, S_g, S_h, S_i, S_j,
    279 			S_k, S_l, S_m, S_n, S_o, S_p, S_q, S_r, S_s, S_t,
    280 			S_u, S_v, S_w, S_x, S_y, S_z,
    281 		['0'] = S_0, S_1, S_2, S_3, S_4, S_5, S_6, S_7, S_8, S_9,
    282 	};
    283 
    284 	if (!head || !*head)
    285 		return;
    286 
    287 	/* TODO: something better than bubblesort */
    288 	do {
    289 		swapped = 0;
    290 		for (p = (*head)->next; p; p = next) {
    291 			next = p->next;
    292 			for (s[0] = p->nick, s[1] = p->prev->nick; s[0] && s[1] && map[*s[0]] == map[*s[1]]; s[0]++, s[1]++);
    293 			if (s[0] && s[1] && map[*s[0]] < map[*s[1]]) {
    294 				nick_swap(p, p->prev);
    295 				swapped = 1;
    296 			}
    297 		}
    298 	} while (swapped);
    299 }