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 }