1 /*
2 * names.c: This here is used to maintain a list of all the people currently
3 * on your channel. Seems to work
4 *
5 * Written By Michael Sandrof
6 *
7 * Copyright (c) 1990 Michael Sandrof.
8 * Copyright (c) 1991, 1992 Troy Rollo.
9 * Copyright (c) 1992-2017 Matthew R. Green.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "irc.h"
37 IRCII_RCSID("@(#)$eterna: names.c,v 1.145 2018/06/10 00:21:02 mrg Exp $");
38
39 #include "ircaux.h"
40 #include "names.h"
41 #include "window.h"
42 #include "screen.h"
43 #include "server.h"
44 #include "lastlog.h"
45 #include "list.h"
46 #include "output.h"
47 #include "notify.h"
48 #include "vars.h"
49 #include "sl_irc.h"
50
51 /* NickList: structure for the list of nicknames of people on a channel */
52 struct nick_stru
53 {
54 NickList *next; /* pointer to next nickname entry */
55 u_char *nick; /* nickname of person on channel */
56 int chanop; /* True if the given nick has chanop */
57 int hasvoice; /* Has voice? (Notice this is a bit
58 * unreliable if chanop) */
59 };
60
61 /* ChannelList: structure for the list of channels you are current on */
62 struct channel_stru
63 {
64 ChannelList *next; /* pointer to next channel entry */
65 u_char *channel; /* channel name */
66 int server; /* server index for this channel */
67 u_int mode; /* current mode settings for channel */
68 u_char *s_mode; /* string representation of the above */
69 int limit; /* max users for the channel */
70 u_char *key; /* key for this channel */
71 ChanListConnected connected; /* connection status */
72 Window *window; /* the window that the channel is "on" */
73 NickList *nicks; /* pointer to list of nicks on channel */
74 ChanListStatus status; /* different flags */
75 };
76
77 /* from names.h */
78 static u_char mode_str[] = MODE_STRING;
79
80 static int same_channel(ChannelList *, u_char *);
81 static void free_channel(ChannelList **);
82 static void show_channel(ChannelList *);
83 static void clear_channel(ChannelList *);
84 static u_char *recreate_mode(ChannelList *);
85 static int decifer_mode(u_char *, u_int *, ChanListStatus *,
86 NickList **, u_char **);
87 static int switch_channels_backend(ChannelList *);
88
89 /* clear_channel: erases all entries in a nick list for the given channel */
90 static void
clear_channel(ChannelList * chan)91 clear_channel(ChannelList *chan)
92 {
93 NickList *tmp,
94 *next;
95
96 for (tmp = chan->nicks; tmp; tmp = next)
97 {
98 next = tmp->next;
99 new_free(&tmp->nick);
100 new_free(&tmp);
101 }
102 chan->nicks = NULL;
103 chan->status &= ~CHAN_NAMES;
104 }
105
106 /*
107 * we need this to deal with !channels.
108 */
109 static int
same_channel(ChannelList * chan,u_char * channel)110 same_channel(ChannelList *chan, u_char *channel)
111 {
112 size_t len, len2;
113
114 /* take the easy way out */
115 if (*chan->channel != '!' && *channel != '!')
116 return (!my_stricmp(chan->channel, channel));
117
118 /*
119 * OK, so what we have is chan->channel = "!!foo" and
120 * channel = "!JUNKfoo".
121 */
122 len = my_strlen(chan->channel);
123 len2 = my_strlen(channel);
124
125 /* bail out on known stuff */
126 if (len > len2)
127 return (0);
128 if (len == len2)
129 return (!my_stricmp(chan->channel, channel));
130
131 /*
132 * replace the channel name if we are the same!
133 */
134 if (!my_stricmp(chan->channel + 2, channel + 2 + (len2 - len)))
135 {
136 malloc_strcpy(&chan->channel, channel);
137 return 1;
138 }
139 return 0;
140 }
141
142 ChannelList *
lookup_channel(u_char * channel,int server,int do_unlink)143 lookup_channel(u_char *channel, int server, int do_unlink)
144 {
145 ChannelList *chan, *last = NULL;
146
147 if (!channel || !*channel ||
148 (server == -1 && (server = get_primary_server()) == -1))
149 return NULL;
150 chan = server_get_chan_list(server);
151 while (chan)
152 {
153 if (chan->server == server && same_channel(chan, channel))
154 {
155 if (do_unlink == CHAN_UNLINK)
156 {
157 if (last)
158 last->next = chan->next;
159 else
160 server_set_chan_list(server, chan->next);
161 }
162 break;
163 }
164 last = chan;
165 chan = chan->next;
166 }
167 return chan;
168 }
169
170 /*
171 * add_channel: adds the named channel to the channel list. If the channel
172 * is already in the list, its attributes are modified accordingly with the
173 * connected and copy parameters.
174 */
175 void
add_channel(u_char * channel,u_char * key,int server,int connected,ChannelList * copy)176 add_channel(u_char *channel, u_char *key, int server, int connected,
177 ChannelList *copy)
178 {
179 ChannelList *new;
180 int do_add = 0;
181
182 /*
183 * avoid adding channel "0"
184 */
185 if (channel[0] == '0' && channel[1] == '\0')
186 return;
187
188 if ((new = lookup_channel(channel, server, CHAN_NOUNLINK)) == NULL)
189 {
190 ChannelList *full_list;
191
192 new = new_malloc(sizeof *new);
193 new->channel = NULL;
194 new->status = 0;
195 new->key = 0;
196 if (key)
197 malloc_strcpy(&new->key, key);
198 new->nicks = NULL;
199 new->s_mode = empty_string();
200 malloc_strcpy(&new->channel, channel);
201 new->mode = 0;
202 new->limit = 0;
203 do_add = 1;
204 full_list = server_get_chan_list(server);
205 if ((new->window = is_bound(channel, server)) == NULL)
206 new->window = curr_scr_win;
207 add_to_list((List **)(void *)&full_list, (List *) new);
208 server_set_chan_list(server, full_list);
209 }
210 else
211 {
212 if (new->connected != CHAN_LIMBO &&
213 new->connected != CHAN_JOINING)
214 yell("--- add_channel: add_channel found channel "
215 "not CHAN_LIMBO/JOINING: %s", new->channel);
216 }
217 if (do_add || (connected == CHAN_JOINED))
218 {
219 new->server = server;
220 clear_channel(new);
221 }
222 if (copy)
223 {
224 new->mode = copy->mode;
225 new->limit = copy->limit;
226 new->window = copy->window;
227 malloc_strcpy(&new->key, copy->key);
228 }
229 new->connected = connected;
230 if (connected == CHAN_JOINED && !is_current_channel(channel, server, 0))
231 {
232 Win_Trav wt;
233 Window *tmp, *expected,
234 *possible = NULL;
235
236 expected = is_bound(channel, server);
237 if (expected == NULL)
238 expected = new->window;
239
240 wt.init = 1;
241 while ((tmp = window_traverse(&wt)))
242 {
243 if (window_get_server(tmp) == server)
244 {
245 if (tmp == expected)
246 {
247 set_channel_by_refnum(window_get_refnum(tmp),
248 channel);
249 new->window = tmp;
250 update_all_status();
251 return;
252 }
253 else if (!possible)
254 possible = tmp;
255 }
256 }
257 if (possible)
258 {
259 set_channel_by_refnum(window_get_refnum(possible), channel);
260 new->window = possible;
261 update_all_status();
262 return;
263 }
264 set_channel_by_refnum(0, channel);
265 new->window = curr_scr_win;
266 }
267 update_all_windows();
268 }
269
270 void
rename_channel(u_char * oldchan,u_char * newchan,int server)271 rename_channel(u_char *oldchan, u_char *newchan, int server)
272 {
273 ChannelList *new;
274
275 if (!oldchan || !*oldchan || !newchan || !*newchan)
276 return;
277 new = lookup_channel(oldchan, server, CHAN_NOUNLINK);
278 if (!new)
279 return;
280
281 malloc_strcpy(&new->channel, newchan);
282 if (new->window)
283 set_channel_by_refnum(window_get_refnum(new->window), newchan);
284
285 /* are these necessary? */
286 update_all_status();
287 update_all_windows();
288 }
289
290 /*
291 * add_to_channel: adds the given nickname to the given channel. If the
292 * nickname is already on the channel, nothing happens. If the channel is
293 * not on the channel list, nothing happens (although perhaps the channel
294 * should be addded to the list? but this should never happen)
295 */
296 void
add_to_channel(u_char * channel,u_char * nick,int server,int oper,int voice)297 add_to_channel(u_char *channel, u_char *nick, int server, int oper, int voice)
298 {
299 NickList *new;
300 ChannelList *chan;
301 int ischop = oper;
302 int hasvoice = voice;
303
304 if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
305 {
306 if (*nick == '+')
307 {
308 hasvoice = 1;
309 nick++;
310 }
311 if (*nick == '@')
312 {
313 nick++;
314 if (!my_stricmp(nick, server_get_nickname(server))
315 && !((chan->status & CHAN_NAMES)
316 && (chan->status & CHAN_MODE)))
317 {
318 u_char *mode = recreate_mode(chan);
319
320 if (*mode)
321 {
322 int old_server;
323
324 old_server = set_from_server(server);
325 send_to_server("MODE %s %s",
326 chan->channel, mode);
327 set_from_server(old_server);
328 }
329 chan->status |= CHAN_CHOP;
330 }
331 ischop = 1;
332 }
333
334 if ((new = (NickList *)
335 remove_from_list((List **)(void *)&(chan->nicks), nick)))
336 {
337 new_free(&new->nick);
338 new_free(&new);
339 }
340 new = new_malloc(sizeof *new);
341 new->nick = NULL;
342 new->chanop = ischop;
343 new->hasvoice = hasvoice;
344 malloc_strcpy(&(new->nick), nick);
345 add_to_list((List **)(void *)&(chan->nicks), (List *) new);
346 }
347 notify_mark(nick, 1, 0);
348 }
349
350
351 /*
352 * recreate_mode: converts the bitmap representation of a channels mode into
353 * a string
354 */
355 static u_char *
recreate_mode(ChannelList * chan)356 recreate_mode(ChannelList *chan)
357 {
358 u_int mode;
359 int mode_pos = 0,
360 showkey;
361 static u_char *s;
362 u_char modes[33], /* XXX: 32 bit u_int, also limited by mode_str[] */
363 limit[33];
364
365 limit[0] = '\0';
366 s = modes;
367 mode = chan->mode;
368 while (mode)
369 {
370 if (mode % 2)
371 *s++ = mode_str[mode_pos];
372 mode /= 2;
373 mode_pos++;
374 }
375 *s = '\0';
376 showkey = chan->key && *chan->key && !get_int_var(HIDE_CHANNEL_KEYS_VAR);
377 if (chan->limit)
378 snprintf(CP(limit), sizeof limit, " %d", chan->limit);
379
380 malloc_snprintf(&chan->s_mode, "%s%s%s%s",
381 modes,
382 showkey ? UP(" ") : empty_string(),
383 showkey ? chan->key : empty_string(),
384 limit);
385
386 return chan->s_mode;
387 }
388
389 /*
390 * decifer_mode: This will figure out the mode string as returned by mode
391 * commands and convert that mode string into a one byte bit map of modes
392 */
393 static int
decifer_mode(u_char * mode_string,u_int * mode,ChanListStatus * chop,NickList ** nicks,u_char ** key)394 decifer_mode(u_char *mode_string, u_int *mode, ChanListStatus *chop,
395 NickList **nicks, u_char **key)
396 {
397 u_char *limit = 0;
398 u_char *person;
399 int add = 0;
400 int limit_set = 0;
401 int limit_reset = 0;
402 u_char *rest,
403 *the_key;
404 NickList *ThisNick;
405 u_int value = 0;
406
407 if (!(mode_string = next_arg(mode_string, &rest)))
408 return -1;
409 for (; *mode_string; mode_string++)
410 {
411 switch (*mode_string)
412 {
413 case '+':
414 add = 1;
415 value = 0;
416 break;
417 case '-':
418 add = 0;
419 value = 0;
420 break;
421 case 'a':
422 value = MODE_ANONYMOUS;
423 break;
424 case 'c':
425 value = MODE_COLOURLESS;
426 break;
427 case 'i':
428 value = MODE_INVITE;
429 break;
430 case 'k':
431 value = MODE_KEY;
432 the_key = next_arg(rest, &rest);
433 if (add)
434 malloc_strcpy(key, the_key);
435 else
436 new_free(key);
437 break;
438 case 'l':
439 value = MODE_LIMIT;
440 if (add)
441 {
442 limit_set = 1;
443 if (!(limit = next_arg(rest, &rest)))
444 limit = empty_string();
445 else if (0 == my_strncmp(limit, zero(), 1))
446 limit_reset = 1, limit_set = 0, add = 0;
447 }
448 else
449 limit_reset = 1;
450 break;
451 case 'm':
452 value = MODE_MODERATED;
453 break;
454 case 'o':
455 if ((person = next_arg(rest, &rest)) &&
456 !my_stricmp(person,
457 server_get_nickname(get_from_server()))) {
458 if (add)
459 *chop |= CHAN_CHOP;
460 else
461 *chop &= ~CHAN_CHOP;
462 }
463 ThisNick = (NickList *)
464 list_lookup((List **)(void *)nicks, person,
465 0, 0);
466 if (ThisNick)
467 ThisNick->chanop = add;
468 break;
469 case 'n':
470 value = MODE_MSGS;
471 break;
472 case 'p':
473 value = MODE_PRIVATE;
474 break;
475 case 'q':
476 value = MODE_QUIET;
477 break;
478 case 'r':
479 value = MODE_REOP;
480 break;
481 case 's':
482 value = MODE_SECRET;
483 break;
484 case 't':
485 value = MODE_TOPIC;
486 break;
487 case 'v':
488 person = next_arg(rest, &rest);
489 ThisNick = (NickList *)
490 list_lookup((List **) nicks, person,
491 0, 0);
492 if (ThisNick)
493 ThisNick->hasvoice = add;
494 break;
495 case 'b':
496 case 'e':
497 case 'I':
498 case 'O': /* this is a weird special case */
499 (void) next_arg(rest, &rest);
500 break;
501 case 'R':
502 value = MODE_REGONLY;
503 break;
504 }
505 if (add)
506 *mode |= value;
507 else
508 *mode &= ~value;
509 }
510 if (limit_set)
511 return (my_atoi(limit));
512 else if (limit_reset)
513 return(0);
514 else
515 return(-1);
516 }
517
518 /*
519 * get_channel_mode: returns the current mode string for the given channel
520 */
521 u_char *
get_channel_mode(u_char * channel,int server)522 get_channel_mode(u_char *channel, int server)
523 {
524 ChannelList *tmp;
525
526 if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)) &&
527 (tmp->status & CHAN_MODE))
528 return recreate_mode(tmp);
529 return empty_string();
530 }
531
532 /*
533 * update_channel_mode: This will modify the mode for the given channel
534 * according the the new mode given.
535 */
536 void
update_channel_mode(u_char * channel,int server,u_char * mode)537 update_channel_mode(u_char *channel, int server, u_char *mode)
538 {
539 ChannelList *tmp;
540 int limit;
541
542 if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)) &&
543 (limit = decifer_mode(mode, &tmp->mode, &tmp->status,
544 &tmp->nicks, &tmp->key)) != -1)
545 tmp->limit = limit;
546 }
547
548 /*
549 * is_channel_mode: returns the logical AND of the given mode with the
550 * channels mode. Useful for testing a channels mode
551 */
552 int
is_channel_mode(u_char * channel,u_int mode,int server_index)553 is_channel_mode(u_char *channel, u_int mode, int server_index)
554 {
555 ChannelList *tmp;
556
557 if ((tmp = lookup_channel(channel, server_index, CHAN_NOUNLINK)))
558 return (tmp->mode & mode);
559 return 0;
560 }
561
562 static void
free_channel(ChannelList ** channel)563 free_channel(ChannelList **channel)
564 {
565 clear_channel(*channel);
566 new_free(&(*channel)->channel);
567 new_free(&(*channel)->key);
568 new_free(&(*channel)->s_mode);
569 new_free(&(*channel));
570 }
571
572 /*
573 * remove_channel: removes the named channel from the specified
574 * server's channel list.
575 * If the channel is not on the this list, nothing happens.
576 * If the channel was the current channel, this will select the top of
577 * the channel list to be the current_channel, or 0 if the list is empty.
578 */
579 void
remove_channel(u_char * channel,int server)580 remove_channel(u_char *channel, int server)
581 {
582 ChannelList *tmp;
583
584 if (channel)
585 {
586 int refnum = -1;
587
588 tmp = lookup_channel(channel, server, CHAN_UNLINK);
589 if (tmp)
590 {
591 if (tmp->window)
592 refnum = window_get_refnum(tmp->window);
593 free_channel(&tmp);
594 }
595
596 (void)is_current_channel(channel, server, refnum);
597 }
598 else
599 {
600 ChannelList *next;
601
602 for (tmp = server_get_chan_list(server); tmp; tmp = next)
603 {
604 next = tmp->next;
605 free_channel(&tmp);
606 }
607 server_set_chan_list(server, NULL);
608 }
609 update_all_windows();
610 }
611
612 /*
613 * remove_from_channel: removes the given nickname from the given channel. If
614 * the nickname is not on the channel or the channel doesn't exist, nothing
615 * happens.
616 */
617 void
remove_from_channel(u_char * channel,u_char * nick,int server)618 remove_from_channel(u_char *channel, u_char *nick, int server)
619 {
620 ChannelList *chan;
621 NickList *tmp;
622
623 if (channel)
624 {
625 if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
626 {
627 if ((tmp = (NickList *)
628 list_lookup((List **)(void *)&chan->nicks, nick,
629 0, REMOVE_FROM_LIST)))
630 {
631 new_free(&tmp->nick);
632 new_free(&tmp);
633 }
634 }
635 }
636 else
637 {
638 for (chan = server_get_chan_list(server); chan; chan = chan->next)
639 {
640 if ((tmp = (NickList *)
641 list_lookup((List **)(void *)&chan->nicks, nick,
642 0, REMOVE_FROM_LIST)))
643 {
644 new_free(&tmp->nick);
645 new_free(&tmp);
646 }
647 }
648 }
649 }
650
651 /*
652 * rename_nick: in response to a changed nickname, this looks up the given
653 * nickname on all you channels and changes it the new_nick
654 */
655 void
rename_nick(u_char * old_nick,u_char * new_nick,int server)656 rename_nick(u_char *old_nick, u_char *new_nick, int server)
657 {
658 ChannelList *chan;
659 NickList *tmp;
660
661 for (chan = server_get_chan_list(server); chan; chan = chan->next)
662 {
663 if ((chan->server == server) != 0)
664 {
665 if ((tmp = (NickList *)
666 list_lookup((List **)(void *)&chan->nicks,
667 old_nick, 0, 0)))
668 {
669 new_free(&tmp->nick);
670 malloc_strcpy(&tmp->nick, new_nick);
671 }
672 }
673 }
674 }
675
676 /*
677 * is_on_channel: returns true if the given nickname is in the given channel,
678 * false otherwise. Also returns false if the given channel is not on the
679 * channel list.
680 */
681 int
is_on_channel(u_char * channel,int server,u_char * nick)682 is_on_channel(u_char *channel, int server, u_char *nick)
683 {
684 ChannelList *chan;
685
686 chan = lookup_channel(channel, server, CHAN_NOUNLINK);
687 if (chan && (chan->connected == CHAN_JOINED)
688 && list_lookup((List **)(void *)&(chan->nicks), nick, 0, 0))
689 return 1;
690 return 0;
691 }
692
693 int
is_chanop(u_char * channel,u_char * nick)694 is_chanop(u_char *channel, u_char *nick)
695 {
696 ChannelList *chan;
697 NickList *Nick;
698
699 if ((chan = lookup_channel(channel, get_from_server(), CHAN_NOUNLINK)) &&
700 chan->connected == CHAN_JOINED &&
701 /* channel may be "surviving" from a disconnect/connect
702 check here too -Sol */
703 (Nick = (NickList *) list_lookup((List **)(void *)&(chan->nicks),
704 nick, 0, 0)) &&
705 Nick->chanop)
706 return 1;
707 return 0;
708 }
709
710 int
has_voice(u_char * channel,u_char * nick,int server)711 has_voice(u_char *channel, u_char *nick, int server)
712 {
713 ChannelList *chan;
714 NickList *Nick;
715
716 if (channel && *channel &&
717 (chan = lookup_channel(channel, server, CHAN_NOUNLINK)) &&
718 chan->connected == CHAN_JOINED &&
719 /* channel may be "surviving" from a disconnect/connect
720 check here too -Sol */
721 (Nick = (NickList *) list_lookup((List **)(void *)&(chan->nicks), nick,
722 0, 0)) &&
723 (Nick->chanop || Nick->hasvoice))
724 return 1;
725 return 0;
726 }
727
728 static void
show_channel(ChannelList * chan)729 show_channel(ChannelList *chan)
730 {
731 NickList *tmp;
732 size_t buffer_len,
733 len;
734 u_char *mode;
735 StringList *sl;
736
737 mode = recreate_mode(chan);
738 sl = sl_init();
739 buffer_len = 0;
740 for (tmp = chan->nicks; tmp; tmp = tmp->next)
741 {
742 len = my_strlen(tmp->nick);
743 if (buffer_len + len >= get_co() - 5)
744 {
745 u_char *buffer = sl_concat(sl, UP(" "));
746 say("\t%s +%s (%s): %s", chan->channel, mode,
747 server_get_name(chan->server), buffer);
748 new_free(&buffer);
749 sl_free(sl, 0);
750 sl = sl_init();
751 buffer_len = 0;
752 }
753 sl_add(sl, CP(tmp->nick));
754 buffer_len += len + 1;
755 }
756 if (sl_size(sl))
757 {
758 u_char *buffer = sl_concat(sl, UP(" "));
759 say("\t%s +%s (%s): %s", chan->channel, mode,
760 server_get_name(chan->server), buffer);
761 new_free(&buffer);
762 }
763 sl_free(sl, 0);
764 }
765
766 /* list_channels: displays your current channel and your channel list */
767 void
list_channels(void)768 list_channels(void)
769 {
770 ChannelList *tmp;
771 int server,
772 no = 1;
773 int first;
774
775 if (connected_to_server() < 1)
776 {
777 say("You are not connected to a server, use /SERVER to connect.");
778 return;
779 }
780 if (get_channel_by_refnum(0))
781 say("Current channel %s", get_channel_by_refnum(0));
782 else
783 say("No current channel for this window");
784 first = 1;
785 for (tmp = server_get_chan_list(get_window_server(0));
786 tmp; tmp = tmp->next)
787 {
788 if (tmp->connected != CHAN_JOINED)
789 continue;
790 if (first)
791 say("You are on the following channels:");
792 show_channel(tmp);
793 first = 0;
794 no = 0;
795 }
796
797 if (connected_to_server() > 1)
798 {
799 for (server = 0; server < number_of_servers(); server++)
800 {
801 if (server == get_window_server(0))
802 continue;
803 first = 1;
804 for (tmp = server_get_chan_list(server);
805 tmp; tmp = tmp->next)
806 {
807 if (tmp->connected != CHAN_JOINED)
808 continue;
809 if (first)
810 say("Other servers:");
811 show_channel(tmp);
812 first = 0;
813 no = 0;
814 }
815 }
816 }
817 if (no)
818 say("You are not on any channels");
819 }
820
821 /*
822 * backend of switch_channels().
823 */
824 static int
switch_channels_backend(ChannelList * chan)825 switch_channels_backend(ChannelList * chan)
826 {
827 u_char *newchan;
828 const int from_server = get_from_server();
829
830 for (; chan; chan = chan->next)
831 {
832 newchan = chan->channel;
833 if (!is_current_channel(newchan, from_server, 0)
834 && !(is_bound(newchan, from_server)
835 && curr_scr_win != chan->window)
836 && (get_int_var(SWITCH_TO_QUIET_CHANNELS)
837 || !(chan->mode & MODE_QUIET)))
838 {
839 set_channel_by_refnum(0, newchan);
840 update_all_windows();
841 return 0;
842 }
843 }
844 return 1;
845 }
846
847 void
switch_channels(u_int key,u_char * ptr)848 switch_channels(u_int key, u_char *ptr)
849 {
850 ChannelList * tmp;
851 const int from_server = get_from_server();
852
853 if (server_get_chan_list(from_server) &&
854 get_channel_by_refnum(0) &&
855 (tmp = lookup_channel(get_channel_by_refnum(0), from_server,
856 CHAN_NOUNLINK)) &&
857 switch_channels_backend(tmp->next))
858 switch_channels_backend(server_get_chan_list(from_server));
859 }
860
861 void
change_server_channels(int old,int new)862 change_server_channels(int old, int new)
863 {
864 ChannelList *tmp;
865
866 if (new == old)
867 return;
868 if (old > -1)
869 {
870 for (tmp = server_get_chan_list(old); tmp ;tmp = tmp->next)
871 tmp->server = new;
872 server_set_chan_list(new, server_get_chan_list(old));
873 }
874 else
875 server_set_chan_list(new, NULL);
876 }
877
878 void
clear_channel_list(int server)879 clear_channel_list(int server)
880 {
881 ChannelList *tmp, *next;
882 Window *ptr;
883 Win_Trav wt;
884
885 wt.init = 1;
886 while ((ptr = window_traverse(&wt)))
887 if (window_get_server(ptr) == server && window_get_current_channel(ptr))
888 window_set_current_channel(ptr, NULL);
889
890 for (tmp = server_get_chan_list(server); tmp; tmp = next)
891 {
892 next = tmp->next;
893 free_channel(&tmp);
894 }
895 server_set_chan_list(server, NULL);
896 return;
897 }
898
899 /*
900 * reconnect_all_channels: used after you get disconnected from a server,
901 * clear each channel nickname list and re-JOINs each channel in the
902 * channel_list ..
903 */
904 void
reconnect_all_channels(int server)905 reconnect_all_channels(int server)
906 {
907 ChannelList *tmp = NULL;
908 u_char *mode, *chan;
909
910 for (tmp = server_get_chan_list(server); tmp; tmp = tmp->next)
911 {
912 mode = recreate_mode(tmp);
913 chan = tmp->channel;
914 if (server_get_version(server) >= Server2_8)
915 send_to_server("JOIN %s%s%s", chan, tmp->key ? " " : "",
916 tmp->key ? tmp->key : (u_char *) "");
917 else
918 send_to_server("JOIN %s%s%s", chan, mode ? " " : "",
919 mode ? mode : (u_char *) "");
920 tmp->connected = CHAN_JOINING;
921 }
922 }
923
924 u_char *
what_channel(u_char * nick,int server)925 what_channel(u_char *nick, int server)
926 {
927 ChannelList *tmp;
928 u_char *channel = window_get_current_channel(curr_scr_win);
929
930 if (channel && is_on_channel(channel, window_get_server(curr_scr_win),
931 nick))
932 return channel;
933
934 for (tmp = server_get_chan_list(get_from_server()); tmp; tmp = tmp->next)
935 if (list_lookup((List **)(void *)&(tmp->nicks), nick,
936 0, 0))
937 return tmp->channel;
938
939 return NULL;
940 }
941
942 u_char *
walk_channels(u_char * nick,int init,int server)943 walk_channels(u_char *nick, int init, int server)
944 {
945 static ChannelList *tmp = NULL;
946
947 if (server < 0)
948 server = get_from_server();
949 if (init)
950 tmp = server_get_chan_list(server);
951 else if (tmp)
952 tmp = tmp->next;
953 for (;tmp ; tmp = tmp->next)
954 if (tmp->server == server &&
955 list_lookup((List **)(void *)&(tmp->nicks), nick,
956 0, 0))
957 return (tmp->channel);
958 return NULL;
959 }
960
961 int
get_channel_oper(u_char * channel,int server)962 get_channel_oper(u_char *channel, int server)
963 {
964 ChannelList *chan;
965
966 if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
967 return (chan->status & CHAN_CHOP);
968 else
969 return 1;
970 }
971
972 void
set_channel_window(Window * window,u_char * channel,int server)973 set_channel_window(Window *window, u_char *channel, int server)
974 {
975 ChannelList *tmp;
976
977 if (!channel || server < 0)
978 return;
979 for (tmp = server_get_chan_list(server); tmp; tmp = tmp->next)
980 if (!my_stricmp(channel, tmp->channel))
981 {
982 tmp->window = window;
983 return;
984 }
985 }
986
987 u_char *
create_channel_list(Window * window)988 create_channel_list(Window *window)
989 {
990 ChannelList *tmp;
991 u_char *value = NULL;
992 StringList *sl;
993
994 if (window_get_server(window) < 0)
995 malloc_strcpy(&value, empty_string());
996 else
997 {
998 sl = sl_init();
999 for (tmp = server_get_chan_list(window_get_server(window));
1000 tmp; tmp = tmp->next)
1001 {
1002 sl_add(sl, CP(tmp->channel));
1003 }
1004 value = sl_concat(sl, UP(" "));
1005 sl_free(sl, 0);
1006 }
1007
1008 return value;
1009 }
1010
1011 void
channel_server_delete(int server)1012 channel_server_delete(int server)
1013 {
1014 ChannelList *tmp;
1015 int i;
1016
1017 for (i = server + 1; i < number_of_servers(); i++)
1018 for (tmp = server_get_chan_list(i); tmp; tmp = tmp->next)
1019 if (tmp->server >= server)
1020 tmp->server--;
1021 }
1022
1023 int
chan_is_connected(u_char * channel,int server)1024 chan_is_connected(u_char *channel, int server)
1025 {
1026 ChannelList * cp = lookup_channel(channel, server, CHAN_NOUNLINK);
1027
1028 if (!cp)
1029 return 0;
1030
1031 return (cp->connected == CHAN_JOINED);
1032 }
1033
1034 void
mark_not_connected(int server)1035 mark_not_connected(int server)
1036 {
1037 ChannelList *tmp;
1038
1039 if (server >= 0)
1040 for (tmp = server_get_chan_list(server); tmp; tmp = tmp->next)
1041 {
1042 tmp->status = 0;
1043 tmp->connected = CHAN_LIMBO;
1044 }
1045 }
1046
1047 void
free_nicks(Window * window)1048 free_nicks(Window *window)
1049 {
1050 NickList *nicks = *window_get_nicks(window);
1051 NickList *tmp, *next;
1052
1053 for (tmp = nicks; tmp; tmp = next)
1054 {
1055 next = tmp->next;
1056 new_free(&tmp->nick);
1057 new_free(&tmp);
1058 }
1059 }
1060
1061 void
display_nicks_info(Window * window)1062 display_nicks_info(Window *window)
1063 {
1064 NickList *nicks = *window_get_nicks(window);
1065
1066 if (nicks)
1067 {
1068 say("\tName list:");
1069 for (; nicks; nicks = nicks->next)
1070 say("\t %s", nicks->nick);
1071 }
1072 }
1073
1074 int
nicks_add_to_window(Window * window,u_char * nick)1075 nicks_add_to_window(Window *window, u_char *nick)
1076 {
1077 NickList **nicks = window_get_nicks(window);
1078
1079 if (!find_in_list((List **)(void *)nicks, nick, 0))
1080 {
1081 NickList *new = new_malloc(sizeof *new);
1082 new->nick = NULL;
1083 malloc_strcpy(&new->nick, nick);
1084 add_to_list((List **)(void *)nicks, (List *) new);
1085 return 1;
1086 }
1087 return 0;
1088 }
1089
1090 int
nicks_remove_from_window(Window * window,u_char * nick)1091 nicks_remove_from_window(Window *window, u_char *nick)
1092 {
1093 NickList **nicks = window_get_nicks(window);
1094 NickList *new;
1095
1096 if ((new = (NickList *)
1097 remove_from_list((List **)(void *)nicks, nick)) != NULL)
1098 {
1099 new_free(&new->nick);
1100 new_free(&new);
1101 return 1;
1102 }
1103 return 0;
1104 }
1105
1106 u_char *
function_chanusers(u_char * input)1107 function_chanusers(u_char *input)
1108 {
1109 ChannelList *chan;
1110 NickList *nicks;
1111 u_char *result = NULL;
1112 int len = 0;
1113 int notfirst = 0;
1114
1115 chan = lookup_channel(input, get_from_server(), CHAN_NOUNLINK);
1116 if (NULL == chan)
1117 return NULL;
1118
1119 for (nicks = chan->nicks; nicks; nicks = nicks->next)
1120 len += (my_strlen(nicks->nick) + 1);
1121 result = new_malloc(len + 1);
1122 *result = '\0';
1123
1124 for (nicks = chan->nicks; nicks; nicks = nicks->next)
1125 {
1126 if (notfirst)
1127 my_strmcat(result, " ", len);
1128 else
1129 notfirst = 1;
1130 my_strmcat(result, nicks->nick, len);
1131 }
1132
1133 return (result);
1134 }
1135
1136 int
channel_mode_lookup(u_char * channel,int check_modes,int set_modes)1137 channel_mode_lookup(u_char *channel, int check_modes, int set_modes)
1138 {
1139 ChannelList *tmp;
1140
1141 tmp = lookup_channel(channel, parsing_server(), CHAN_NOUNLINK);
1142 if (tmp && (tmp->status & check_modes) != check_modes) {
1143 tmp->status |= set_modes;
1144 return 1;
1145 }
1146 return 0;
1147 }
1148
1149 /*
1150 * given a server and a channel, look up a window it belongs to.
1151 * NULL means the channel was not found.
1152 */
1153 Window *
channel_window(u_char * channel,int server)1154 channel_window(u_char *channel, int server)
1155 {
1156 ChannelList *chan;
1157
1158 chan = lookup_channel(channel, server, CHAN_NOUNLINK);
1159 if (!chan)
1160 return NULL;
1161 return chan->window ? chan->window : curr_scr_win;
1162 }
1163
1164 int
channel_is_current_window(u_char * channel,int server)1165 channel_is_current_window(u_char *channel, int server)
1166 {
1167 ChannelList *chan;
1168
1169 chan = lookup_channel(channel, server, CHAN_NOUNLINK);
1170
1171 return chan && chan->window != curr_scr_win;
1172 }
1173
1174 /*
1175 * backend for is_current_channel() that interrogates the channel
1176 * list for each server.
1177 */
1178 int
channel_is_on_window(u_char * channel,int server,Window * found_window,int refnum)1179 channel_is_on_window(u_char *channel, int server, Window *found_window,
1180 int refnum)
1181 {
1182 Window *tmp;
1183 ChannelList *chan;
1184 ChannelList *possible = NULL;
1185 int found = 0;
1186
1187 for (chan = server_get_chan_list(server); chan; chan = chan->next)
1188 {
1189 if (!my_stricmp(chan->channel, channel))
1190 continue;
1191 if (chan->window == found_window)
1192 {
1193 set_channel_by_refnum(window_get_refnum(found_window),
1194 chan->channel);
1195 return 1;
1196 }
1197 if (!get_int_var(SAME_WINDOW_ONLY_VAR) &&
1198 !is_bound(chan->channel, server) &&
1199 chan->window != found_window)
1200 {
1201 int is_current = 0;
1202 Win_Trav wt;
1203
1204 wt.init = 1;
1205 while ((tmp = window_traverse(&wt)))
1206 {
1207 if (window_get_server(tmp) != server)
1208 continue;
1209 if (window_get_current_channel(tmp) &&
1210 !my_stricmp(chan->channel,
1211 window_get_current_channel(tmp)))
1212 is_current = 1;
1213 }
1214 if (!is_current)
1215 possible = chan;
1216 }
1217 }
1218 if (!get_int_var(SAME_WINDOW_ONLY_VAR))
1219 {
1220 u_char *delete_channel;
1221
1222 if (possible)
1223 {
1224 set_channel_by_refnum(window_get_refnum(found_window),
1225 possible->channel);
1226 return 1;
1227 }
1228 delete_channel = get_channel_by_refnum((u_int)refnum);
1229 if (delete_channel &&
1230 !(is_bound(delete_channel, server) &&
1231 window_get_refnum(found_window) != refnum))
1232 set_channel_by_refnum(window_get_refnum(found_window),
1233 get_channel_by_refnum((u_int)refnum));
1234 }
1235 return found;
1236 }
1237
1238 int
channels_move_server_simple(int old_serv,int server)1239 channels_move_server_simple(int old_serv, int server)
1240 {
1241 ChannelList *tmp;
1242 int moved = 0;
1243
1244 for (tmp = server_get_chan_list(old_serv); tmp; tmp = tmp->next)
1245 {
1246 if (!moved) /* If we're here, it means
1247 we're going to transfer
1248 channels to the new server,
1249 so we dump old channels
1250 first, but only once -Sol */
1251 {
1252 moved++;
1253 clear_channel_list(server);
1254 }
1255 add_channel(tmp->channel, 0, server, CHAN_LIMBO, tmp);
1256 }
1257 return moved;
1258 }
1259
1260 void
channels_move_server_complex(Window * window,Window * new_win,int old_serv,int server,int misc,int moved)1261 channels_move_server_complex(Window *window, Window *new_win, int old_serv,
1262 int server, int misc, int moved)
1263 {
1264 ChannelList *tmp;
1265
1266 for (tmp = server_get_chan_list(old_serv); tmp; tmp = tmp->next)
1267 {
1268 if (tmp->window == NULL ||
1269 (tmp->window != window &&
1270 (!window_get_server_group(window) ||
1271 window_get_server_group(tmp->window) !=
1272 window_get_server_group(window))))
1273 continue;
1274
1275 /* Found a channel to be relocated -Sol */
1276 if (window_get_sticky(tmp->window) || (misc & WIN_FORCE))
1277 { /* This channel moves -Sol */
1278 int old;
1279
1280 if (!moved)
1281 {
1282 moved++;
1283 clear_channel_list(server);
1284 }
1285 /* Copy it -Sol */
1286 add_channel(tmp->channel, 0, server, CHAN_LIMBO, tmp);
1287 /* On old_serv, leave it -Sol */
1288 old = set_from_server(old_serv);
1289 send_to_server("PART %s", tmp->channel);
1290 set_from_server(old);
1291 remove_channel(tmp->channel, old_serv);
1292 }
1293 else
1294 tmp->window = new_win;
1295 }
1296 }
1297
1298
1299 void
window_list_channels(Window * window)1300 window_list_channels(Window *window)
1301 {
1302 ChannelList *tmp;
1303 int print_one = 0;
1304
1305 if (!window)
1306 return;
1307
1308 for (tmp = server_get_chan_list(window_get_server(window));
1309 tmp; tmp = tmp->next)
1310 if (tmp->window == window)
1311 {
1312 if (!print_one)
1313 {
1314 say("Channels currently in this window:");
1315 print_one++;
1316 }
1317 say("\t%s", tmp->channel);
1318 }
1319 if (!print_one)
1320 say("There are no channels in this window");
1321 }
1322
1323 /*
1324 * realloc_channels: Attempts to reallocate a channel to a window of the
1325 * same server
1326 *
1327 * XXX mrg this looks broken to me but i'm not sure. blah.
1328 */
1329 void
realloc_channels(Window * window)1330 realloc_channels(Window *window)
1331 {
1332 Window *tmp;
1333 Win_Trav wt;
1334 ChannelList *chan;
1335 int server = window_get_server(window);
1336
1337 wt.init = 1;
1338 while ((tmp = window_traverse(&wt)))
1339 {
1340 if (window != tmp && window_get_server(tmp) == server)
1341 {
1342 for (chan = server_get_chan_list(server);
1343 chan; chan = chan->next)
1344 if (chan->window == window)
1345 {
1346 chan->window = tmp;
1347 if (!window_get_current_channel(tmp))
1348 set_channel_by_refnum(window_get_refnum(tmp), chan->channel);
1349 }
1350 return;
1351 }
1352 }
1353
1354 for (chan = server_get_chan_list(server); chan; chan = chan->next)
1355 {
1356 chan->window = NULL;
1357 }
1358 }
1359
1360 /* swap_channels_win_ptr: must be called because swap_window modifies the
1361 * content of *v_window and *window instead of swapping pointers
1362 */
1363 void
channel_swap_win_ptr(Window * v_window,Window * window)1364 channel_swap_win_ptr(Window *v_window, Window *window)
1365 {
1366 ChannelList *chan;
1367 int server = window_get_server(window);
1368 int v_server = window_get_server(v_window);
1369
1370 if (v_server != -1)
1371 {
1372 for (chan = server_get_chan_list(v_server);
1373 chan; chan = chan->next)
1374 if (chan->window == v_window)
1375 chan->window = window;
1376 else if (chan->window == window)
1377 chan->window = v_window;
1378 }
1379 if (server == v_server)
1380 return;
1381 if (server != -1)
1382 for (chan = server_get_chan_list(server);
1383 chan; chan = chan->next)
1384 if (chan->window == window)
1385 chan->window = v_window;
1386 }
1387
1388 int
nicks_has_who_from(NickList ** nicks)1389 nicks_has_who_from(NickList **nicks)
1390 {
1391 return find_in_list((List **)(void *)nicks, current_who_from(), 0) != NULL;
1392 }
1393