regular who doesn't send account
[rofl0r-ixchat.git] / src / common / userlist.c
blob99371668e44682acf41c17b31f509920e3048476
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);
116 void
117 userlist_set_account (struct session *sess, char *nick, char *account)
119 struct User *user;
121 user = userlist_find (sess, nick);
122 if (user)
124 if (user->account)
125 free (user->account);
127 if (strcmp (account, "*") == 0)
128 user->account = NULL;
129 else
130 user->account = strdup (account);
132 /* gui doesnt currently reflect login status, maybe later
133 fe_userlist_rehash (sess, user); */
138 userlist_add_hostname (struct session *sess, char *nick, char *hostname,
139 char *realname, char *servername, char *account, unsigned int away)
141 struct User *user;
143 user = userlist_find (sess, nick);
144 if (user)
146 if (!user->hostname && hostname)
147 user->hostname = strdup (hostname);
148 if (!user->realname && realname)
149 user->realname = strdup (realname);
150 if (!user->servername && servername)
151 user->servername = strdup (servername);
152 if (!user->account && account && strcmp (account, "0") != 0)
153 user->account = strdup (account);
155 if (away != 0xff)
157 if (prefs.showhostname_in_userlist || user->away != away)
159 user->away = away;
160 fe_userlist_rehash (sess, user);
162 user->away = away;
165 fe_userlist_update (sess, user);
167 return 1;
169 return 0;
172 static int
173 free_user (struct User *user, gpointer data)
175 if (user->realname)
176 free (user->realname);
177 if (user->hostname)
178 free (user->hostname);
179 if (user->servername)
180 free (user->servername);
181 if (user->account)
182 free (user->account);
183 free (user);
185 return TRUE;
188 void
189 userlist_free (session *sess)
191 tree_foreach (sess->usertree, (tree_traverse_func *)free_user, NULL);
192 tree_destroy (sess->usertree);
193 tree_destroy (sess->usertree_alpha);
195 sess->usertree = NULL;
196 sess->usertree_alpha = NULL;
197 sess->me = NULL;
199 sess->ops = 0;
200 sess->hops = 0;
201 sess->voices = 0;
202 sess->total = 0;
205 void
206 userlist_clear (session *sess)
208 fe_userlist_clear (sess);
209 userlist_free (sess);
210 fe_userlist_numbers (sess);
213 static int
214 find_cmp (const char *name, struct User *user, server *serv)
216 return serv->p_cmp ((char *)name, user->nick);
219 struct User *
220 userlist_find (struct session *sess, char *name)
222 int pos;
224 if (sess->usertree_alpha)
225 return tree_find (sess->usertree_alpha, name,
226 (tree_cmp_func *)find_cmp, sess->server, &pos);
228 return NULL;
231 struct User *
232 userlist_find_global (struct server *serv, char *name)
234 struct User *user;
235 session *sess;
236 GSList *list = sess_list;
237 while (list)
239 sess = (session *) list->data;
240 if (sess->server == serv)
242 user = userlist_find (sess, name);
243 if (user)
244 return user;
246 list = list->next;
248 return 0;
251 static void
252 update_counts (session *sess, struct User *user, char prefix,
253 int level, int offset)
255 switch (prefix)
257 case '@':
258 user->op = level;
259 sess->ops += offset;
260 break;
261 case '%':
262 user->hop = level;
263 sess->hops += offset;
264 break;
265 case '+':
266 user->voice = level;
267 sess->voices += offset;
268 break;
272 void
273 userlist_update_mode (session *sess, char *name, char mode, char sign)
275 int access;
276 int offset = 0;
277 int level;
278 int pos;
279 char prefix;
280 struct User *user;
282 user = userlist_find (sess, name);
283 if (!user)
284 return;
286 /* remove from binary trees, before we loose track of it */
287 tree_remove (sess->usertree, user, &pos);
288 tree_remove (sess->usertree_alpha, user, &pos);
290 /* which bit number is affected? */
291 access = mode_access (sess->server, mode, &prefix);
293 if (sign == '+')
295 level = TRUE;
296 if (!(user->access & (1 << access)))
298 offset = 1;
299 user->access |= (1 << access);
301 } else
303 level = FALSE;
304 if (user->access & (1 << access))
306 offset = -1;
307 user->access &= ~(1 << access);
311 /* now what is this users highest prefix? e.g. @ for ops */
312 user->prefix[0] = get_nick_prefix (sess->server, user->access);
314 /* update the various counts using the CHANGED prefix only */
315 update_counts (sess, user, prefix, level, offset);
317 /* insert it back into its new place */
318 tree_insert (sess->usertree_alpha, user);
319 pos = tree_insert (sess->usertree, user);
321 /* let GTK move it too */
322 fe_userlist_move (sess, user, pos);
323 fe_userlist_numbers (sess);
327 userlist_change (struct session *sess, char *oldname, char *newname)
329 struct User *user = userlist_find (sess, oldname);
330 int pos;
332 if (user)
334 tree_remove (sess->usertree, user, &pos);
335 tree_remove (sess->usertree_alpha, user, &pos);
337 safe_strcpy (user->nick, newname, NICKLEN);
339 tree_insert (sess->usertree_alpha, user);
341 fe_userlist_move (sess, user, tree_insert (sess->usertree, user));
342 fe_userlist_numbers (sess);
344 return 1;
347 return 0;
351 userlist_remove (struct session *sess, char *name)
353 struct User *user;
355 user = userlist_find (sess, name);
356 if (!user)
357 return FALSE;
359 userlist_remove_user (sess, user);
360 return TRUE;
363 void
364 userlist_remove_user (struct session *sess, struct User *user)
366 int pos;
367 if (user->voice)
368 sess->voices--;
369 if (user->op)
370 sess->ops--;
371 if (user->hop)
372 sess->hops--;
373 sess->total--;
374 fe_userlist_numbers (sess);
375 fe_userlist_remove (sess, user);
377 if (user == sess->me)
378 sess->me = NULL;
380 tree_remove (sess->usertree, user, &pos);
381 tree_remove (sess->usertree_alpha, user, &pos);
382 free_user (user, NULL);
385 void
386 userlist_add (struct session *sess, char *name, char *hostname, char *account, char *realname)
388 struct User *user;
389 int row, prefix_chars;
390 unsigned int acc;
392 acc = nick_access (sess->server, name, &prefix_chars);
394 notify_set_online (sess->server, name + prefix_chars);
396 user = malloc (sizeof (struct User));
397 memset (user, 0, sizeof (struct User));
399 user->access = acc;
401 /* assume first char is the highest level nick prefix */
402 if (prefix_chars)
403 user->prefix[0] = name[0];
405 /* add it to our linked list */
406 if (hostname)
407 user->hostname = strdup (hostname);
408 safe_strcpy (user->nick, name + prefix_chars, NICKLEN);
409 /* is it me? */
410 if (!sess->server->p_cmp (user->nick, sess->server->nick))
411 user->me = TRUE;
412 /* extended join info */
413 if (sess->server->have_extjoin)
415 if (account && strcmp (account, "*") != 0)
416 user->account = strdup (account);
417 if (realname)
418 user->realname = strdup (realname);
421 row = userlist_insertname (sess, user);
423 /* duplicate? some broken servers trigger this */
424 if (row == -1)
426 if (user->hostname)
427 free (user->hostname);
428 if (user->account)
429 free (user->account);
430 if (user->realname)
431 free (user->realname);
432 free (user);
433 return;
436 sess->total++;
438 /* most ircds don't support multiple modechars infront of the nickname
439 for /NAMES - though they should. */
440 while (prefix_chars)
442 update_counts (sess, user, name[0], TRUE, 1);
443 name++;
444 prefix_chars--;
447 if (user->me)
448 sess->me = user;
450 fe_userlist_insert (sess, user, row, FALSE);
451 fe_userlist_numbers (sess);
454 static int
455 rehash_cb (struct User *user, session *sess)
457 fe_userlist_rehash (sess, user);
458 return TRUE;
461 void
462 userlist_rehash (session *sess)
464 tree_foreach (sess->usertree_alpha, (tree_traverse_func *)rehash_cb, sess);
467 static int
468 flat_cb (struct User *user, GSList **list)
470 *list = g_slist_prepend (*list, user);
471 return TRUE;
474 GSList *
475 userlist_flat_list (session *sess)
477 GSList *list = NULL;
479 tree_foreach (sess->usertree_alpha, (tree_traverse_func *)flat_cb, &list);
480 return g_slist_reverse (list);
483 static int
484 double_cb (struct User *user, GList **list)
486 *list = g_list_prepend(*list, user);
487 return TRUE;
490 GList *
491 userlist_double_list(session *sess)
493 GList *list = NULL;
495 tree_foreach (sess->usertree_alpha, (tree_traverse_func *)double_cb, &list);
496 return list;