configure: add stuff for spell checking
[rofl0r-ixchat.git] / src / common / userlist.c
bloba18485b1173284d7f162fe1d1f00fa5aed421d03
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
23 #include "xchat.h"
24 #include "modes.h"
25 #include "fe.h"
26 #include "notify.h"
27 #include "tree.h"
28 #include "xchatc.h"
29 #include "util.h"
32 static int
33 nick_cmp_az_ops (server *serv, struct User *user1, struct User *user2)
35 unsigned int access1 = user1->access;
36 unsigned int access2 = user2->access;
37 int pos;
39 if (access1 != access2)
41 for (pos = 0; pos < USERACCESS_SIZE; pos++)
43 if ((access1&(1<<pos)) && (access2&(1<<pos)))
44 break;
45 if ((access1&(1<<pos)) && !(access2&(1<<pos)))
46 return -1;
47 if (!(access1&(1<<pos)) && (access2&(1<<pos)))
48 return 1;
52 return serv->p_cmp (user1->nick, user2->nick);
55 static int
56 nick_cmp_alpha (struct User *user1, struct User *user2, server *serv)
58 return serv->p_cmp (user1->nick, user2->nick);
61 static int
62 nick_cmp (struct User *user1, struct User *user2, server *serv)
64 switch (prefs.userlist_sort)
66 case 0:
67 return nick_cmp_az_ops (serv, user1, user2);
68 case 1:
69 return serv->p_cmp (user1->nick, user2->nick);
70 case 2:
71 return -1 * nick_cmp_az_ops (serv, user1, user2);
72 case 3:
73 return -1 * serv->p_cmp (user1->nick, user2->nick);
74 default:
75 return -1;
80 insert name in appropriate place in linked list. Returns row number or:
81 -1: duplicate
84 static int
85 userlist_insertname (session *sess, struct User *newuser)
87 if (!sess->usertree)
89 sess->usertree = tree_new ((tree_cmp_func *)nick_cmp, sess->server);
90 sess->usertree_alpha = tree_new ((tree_cmp_func *)nick_cmp_alpha, sess->server);
93 tree_insert (sess->usertree_alpha, newuser);
94 return tree_insert (sess->usertree, newuser);
97 void
98 userlist_set_away (struct session *sess, char *nick, unsigned int away)
100 struct User *user;
102 user = userlist_find (sess, nick);
103 if (user)
105 if (user->away != away)
107 user->away = away;
108 /* rehash GUI */
109 fe_userlist_rehash (sess, user);
110 if (away)
111 fe_userlist_update (sess, user);
117 userlist_add_hostname (struct session *sess, char *nick, char *hostname,
118 char *realname, char *servername, unsigned int away)
120 struct User *user;
122 user = userlist_find (sess, nick);
123 if (user)
125 if (!user->hostname && hostname)
126 user->hostname = strdup (hostname);
127 if (!user->realname && realname)
128 user->realname = strdup (realname);
129 if (!user->servername && servername)
130 user->servername = strdup (servername);
132 if (away != 0xff)
134 if (prefs.showhostname_in_userlist || user->away != away)
136 user->away = away;
137 fe_userlist_rehash (sess, user);
139 user->away = away;
142 fe_userlist_update (sess, user);
144 return 1;
146 return 0;
149 static int
150 free_user (struct User *user, gpointer data)
152 if (user->realname)
153 free (user->realname);
154 if (user->hostname)
155 free (user->hostname);
156 if (user->servername)
157 free (user->servername);
158 free (user);
160 return TRUE;
163 void
164 userlist_free (session *sess)
166 tree_foreach (sess->usertree, (tree_traverse_func *)free_user, NULL);
167 tree_destroy (sess->usertree);
168 tree_destroy (sess->usertree_alpha);
170 sess->usertree = NULL;
171 sess->usertree_alpha = NULL;
172 sess->me = NULL;
174 sess->ops = 0;
175 sess->hops = 0;
176 sess->voices = 0;
177 sess->total = 0;
180 void
181 userlist_clear (session *sess)
183 fe_userlist_clear (sess);
184 userlist_free (sess);
185 fe_userlist_numbers (sess);
188 static int
189 find_cmp (const char *name, struct User *user, server *serv)
191 return serv->p_cmp ((char *)name, user->nick);
194 struct User *
195 userlist_find (struct session *sess, char *name)
197 int pos;
199 if (sess->usertree_alpha)
200 return tree_find (sess->usertree_alpha, name,
201 (tree_cmp_func *)find_cmp, sess->server, &pos);
203 return NULL;
206 struct User *
207 userlist_find_global (struct server *serv, char *name)
209 struct User *user;
210 session *sess;
211 GSList *list = sess_list;
212 while (list)
214 sess = (session *) list->data;
215 if (sess->server == serv)
217 user = userlist_find (sess, name);
218 if (user)
219 return user;
221 list = list->next;
223 return 0;
226 static void
227 update_counts (session *sess, struct User *user, char prefix,
228 int level, int offset)
230 switch (prefix)
232 case '@':
233 user->op = level;
234 sess->ops += offset;
235 break;
236 case '%':
237 user->hop = level;
238 sess->hops += offset;
239 break;
240 case '+':
241 user->voice = level;
242 sess->voices += offset;
243 break;
247 void
248 userlist_update_mode (session *sess, char *name, char mode, char sign)
250 int access;
251 int offset = 0;
252 int level;
253 int pos;
254 char prefix;
255 struct User *user;
257 user = userlist_find (sess, name);
258 if (!user)
259 return;
261 /* remove from binary trees, before we loose track of it */
262 tree_remove (sess->usertree, user, &pos);
263 tree_remove (sess->usertree_alpha, user, &pos);
265 /* which bit number is affected? */
266 access = mode_access (sess->server, mode, &prefix);
268 if (sign == '+')
270 level = TRUE;
271 if (!(user->access & (1 << access)))
273 offset = 1;
274 user->access |= (1 << access);
276 } else
278 level = FALSE;
279 if (user->access & (1 << access))
281 offset = -1;
282 user->access &= ~(1 << access);
286 /* now what is this users highest prefix? e.g. @ for ops */
287 user->prefix[0] = get_nick_prefix (sess->server, user->access);
289 /* update the various counts using the CHANGED prefix only */
290 update_counts (sess, user, prefix, level, offset);
292 /* insert it back into its new place */
293 tree_insert (sess->usertree_alpha, user);
294 pos = tree_insert (sess->usertree, user);
296 /* let GTK move it too */
297 fe_userlist_move (sess, user, pos);
298 fe_userlist_numbers (sess);
302 userlist_change (struct session *sess, char *oldname, char *newname)
304 struct User *user = userlist_find (sess, oldname);
305 int pos;
307 if (user)
309 tree_remove (sess->usertree, user, &pos);
310 tree_remove (sess->usertree_alpha, user, &pos);
312 safe_strcpy (user->nick, newname, NICKLEN);
314 tree_insert (sess->usertree_alpha, user);
316 fe_userlist_move (sess, user, tree_insert (sess->usertree, user));
317 fe_userlist_numbers (sess);
319 return 1;
322 return 0;
326 userlist_remove (struct session *sess, char *name)
328 struct User *user;
330 user = userlist_find (sess, name);
331 if (!user)
332 return FALSE;
334 userlist_remove_user (sess, user);
335 return TRUE;
338 void
339 userlist_remove_user (struct session *sess, struct User *user)
341 int pos;
342 if (user->voice)
343 sess->voices--;
344 if (user->op)
345 sess->ops--;
346 if (user->hop)
347 sess->hops--;
348 sess->total--;
349 fe_userlist_numbers (sess);
350 fe_userlist_remove (sess, user);
352 if (user == sess->me)
353 sess->me = NULL;
355 tree_remove (sess->usertree, user, &pos);
356 tree_remove (sess->usertree_alpha, user, &pos);
357 free_user (user, NULL);
360 void
361 userlist_add (struct session *sess, char *name, char *hostname)
363 struct User *user;
364 int row, prefix_chars;
365 unsigned int acc;
367 acc = nick_access (sess->server, name, &prefix_chars);
369 notify_set_online (sess->server, name + prefix_chars);
371 user = malloc (sizeof (struct User));
372 memset (user, 0, sizeof (struct User));
374 user->access = acc;
376 /* assume first char is the highest level nick prefix */
377 if (prefix_chars)
378 user->prefix[0] = name[0];
380 /* add it to our linked list */
381 if (hostname)
382 user->hostname = strdup (hostname);
383 safe_strcpy (user->nick, name + prefix_chars, NICKLEN);
384 /* is it me? */
385 if (!sess->server->p_cmp (user->nick, sess->server->nick))
386 user->me = TRUE;
387 row = userlist_insertname (sess, user);
389 /* duplicate? some broken servers trigger this */
390 if (row == -1)
392 if (user->hostname)
393 free (user->hostname);
394 free (user);
395 return;
398 sess->total++;
400 /* most ircds don't support multiple modechars infront of the nickname
401 for /NAMES - though they should. */
402 while (prefix_chars)
404 update_counts (sess, user, name[0], TRUE, 1);
405 name++;
406 prefix_chars--;
409 if (user->me)
410 sess->me = user;
412 fe_userlist_insert (sess, user, row, FALSE);
413 fe_userlist_numbers (sess);
416 static int
417 rehash_cb (struct User *user, session *sess)
419 fe_userlist_rehash (sess, user);
420 return TRUE;
423 void
424 userlist_rehash (session *sess)
426 tree_foreach (sess->usertree_alpha, (tree_traverse_func *)rehash_cb, sess);
429 static int
430 flat_cb (struct User *user, GSList **list)
432 *list = g_slist_prepend (*list, user);
433 return TRUE;
436 GSList *
437 userlist_flat_list (session *sess)
439 GSList *list = NULL;
441 tree_foreach (sess->usertree_alpha, (tree_traverse_func *)flat_cb, &list);
442 return g_slist_reverse (list);
445 static int
446 double_cb (struct User *user, GList **list)
448 *list = g_list_prepend(*list, user);
449 return TRUE;
452 GList *
453 userlist_double_list(session *sess)
455 GList *list = NULL;
457 tree_foreach (sess->usertree_alpha, (tree_traverse_func *)double_cb, &list);
458 return list;