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-2000 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 * renamed to channels.c and extensively modified by
36 * Joshua J. Drake
37 */
38
39 #include "irc.h"
40 IRCII_RCSID("@(#)$Id: names.c,v 1.81 2000/08/31 12:10:52 mrg Exp $");
41
42 #include "dma.h"
43 #include "ircaux.h"
44 #include "channels.h"
45 #include "window.h"
46 #include "screen.h"
47 #include "server.h"
48 #include "lastlog.h"
49 #include "list.h"
50 #include "output.h"
51 #include "notify.h"
52 #include "vars.h"
53
54 #include "nicks.h"
55 #include "bans.h"
56 #include "ckey.h"
57 #include "friends.h"
58 #include "ninjacmd.h"
59
60 /* channel identifiers */
61 #define STRING_CHANNEL '+'
62 #define MULTI_CHANNEL '#'
63 #define LOCAL_CHANNEL '&'
64 #define SAFE_CHANNEL '!'
65
66 /* from channels.h */
67 static u_char mode_str[] = MODE_STRING;
68
69 static void free_channel _((Channel **));
70 static void show_channel _((Channel *));
71 static void clear_channel _((Channel *));
72 static u_char *recreate_mode _((Channel *));
73 static int decifer_mode _((u_char *, Channel *, u_char *));
74
75 /* ninja extensions */
76 static void clear_channel_nicks _((Channel *));
77 static void clear_channel_bans _((Channel *));
78 static void clear_channel_excepts _((Channel *));
79 static void clear_channel_denys _((Channel *));
80
81 /* clear_channel: erases all entries in a nick list for the given channel */
82 /* in ninja this also removes other channel information */
83 static void
clear_channel(chan)84 clear_channel(chan)
85 Channel *chan;
86 {
87 clear_channel_nicks(chan);
88 clear_channel_bans(chan);
89 clear_channel_excepts(chan);
90 clear_channel_denys(chan);
91 }
92
93 /* clear channel nicks */
94 static void
clear_channel_nicks(chan)95 clear_channel_nicks(chan)
96 Channel *chan;
97 {
98 Nick *tmp, *next;
99
100 for (tmp = chan->nicks; tmp; tmp = next)
101 {
102 next = tmp->next;
103 free_nick(&tmp);
104 }
105 chan->nicks = (Nick *) 0;
106 }
107
108 /* clear channel bans */
109 static void
clear_channel_bans(chan)110 clear_channel_bans(chan)
111 Channel *chan;
112 {
113 Ban *tmp, *next;
114
115 for (tmp = chan->bans; tmp; tmp = next)
116 {
117 next = tmp->next;
118 new_free(&(tmp->ban));
119 new_free(&(tmp->owner));
120 new_free(&tmp);
121 }
122 chan->bans = (Ban *) 0;
123 }
124
125 /* clear channel exceptions */
126 static void
clear_channel_excepts(chan)127 clear_channel_excepts(chan)
128 Channel *chan;
129 {
130 Except *tmp, *next;
131
132 for (tmp = chan->excepts; tmp; tmp = next)
133 {
134 next = tmp->next;
135 new_free(&(tmp->exception));
136 new_free(&(tmp->owner));
137 new_free(&tmp);
138 }
139 chan->excepts = (Except *) 0;
140 }
141
142 /* clear channel deny lines */
143 static void
clear_channel_denys(chan)144 clear_channel_denys(chan)
145 Channel *chan;
146 {
147 Deny *tmp, *next;
148
149 for (tmp = chan->denys; tmp; tmp = next)
150 {
151 next = tmp->next;
152 new_free(&(tmp->regexp));
153 new_free(&(tmp->owner));
154 new_free(&tmp);
155 }
156 chan->denys = (Deny *) 0;
157 }
158
159 /*
160 * we need this to deal with !channels.
161 */
162 int
same_channel(channel,chan2)163 same_channel(channel, chan2)
164 Channel *channel;
165 u_char *chan2;
166 {
167 size_t len, len2;
168
169 /* take the easy way out */
170 if (*channel->channel != '!' && *chan2 != '!')
171 return (!my_stricmp(channel->channel, chan2));
172
173 /*
174 * OK, so what we have is channel = "!fooo" and chan2 = "!JUNKfoo".
175 */
176 len = my_strlen(channel->channel);
177 len2 = my_strlen(chan2);
178
179 /* bail out on known stuff */
180 if (len > len2)
181 return (0);
182 if (len == len2)
183 return (!my_stricmp(channel->channel, chan2));
184
185 /*
186 * replace the channel name if we are the same!
187 */
188 if (!my_stricmp(channel->channel + 1, chan2 + 1 + (len2 - len)))
189 {
190 malloc_strcpy(&channel->channel, chan2);
191 return (1);
192 }
193 return (0);
194 }
195
196 extern Channel *
197 lookup_channel(channel, server, do_unlink)
198 u_char *channel;
199 int server;
200 int do_unlink;
201 {
202 Channel *chan, *last = (Channel *) 0;
203
204 if (server == -1)
205 server = primary_server;
206 if (server < 0 || server >= number_of_servers)
207 return (Channel *) 0;
208 chan = server_list[server].chan_list;
209 while (chan)
210 {
211 if (chan->server == server && same_channel(chan, channel))
212 {
213 if (do_unlink == CHAN_UNLINK)
214 {
215 if (last)
216 last->next = chan->next;
217 else
218 server_list[server].chan_list = chan->next;
219 }
220 break;
221 }
222 last = chan;
223 chan = chan->next;
224 }
225 return chan;
226 }
227
228 /*
229 * add_channel: adds the named channel to the channel list. If the channel
230 * is already in the list, its attributes are modified accordingly with the
231 * connected and copy parameters.
232 */
233 void
add_channel(channel,server,connected,copy)234 add_channel(channel, server, connected, copy)
235 u_char *channel;
236 int server;
237 int connected;
238 Channel *copy;
239 {
240 Channel *new;
241 int do_add = 0;
242 /* u_char *tkey; */
243
244 /*
245 * avoid adding channel "0"
246 */
247 if (channel[0] == '0'&& channel[1] == '\0')
248 return;
249 /* also avoid adding non-channels,
250 * if this is triggered, whatever is calling this is buggy
251 */
252 if (!is_channel(channel))
253 {
254 put_error("add_channel() trying to add channel \"%s\".. notify ninjairc@qoop.org",
255 channel);
256 return;
257 }
258
259 if ((new = lookup_channel(channel, server, CHAN_NOUNLINK)) == (Channel *) 0)
260 {
261 new = (Channel *) new_malloc(sizeof(Channel));
262 /* setting stuff to 0 is pointless because..
263 * dma_Malloc does memset(mem, 0, sizeof(mem))
264 *
265 new->channel = (u_char *) 0;
266 new->status = 0;
267 new->key = (u_char *) 0;
268 new->nicks = (Nick *) 0;
269 new->mode = 0;
270 new->limit = 0;
271 */
272 new->s_mode = empty_string;
273
274 /*
275 * not sure if this is needed..
276 *
277 tkey = get_ckey(channel);
278 if (tkey)
279 {
280 dma_strcpy(&new->key, tkey);
281 // dont do this, let the server do it!
282 // new->mode |= MODE_KEY;
283 }
284 */
285 malloc_strcpy(&new->channel, channel);
286 if ((new->window = is_bound(channel, server)) == (Window *) 0)
287 new->window = curr_scr_win;
288 do_add = 1;
289 add_to_list((List **) &server_list[server].chan_list, (List *) new);
290 }
291 else
292 {
293 if (new->connected != CHAN_LIMBO && new->connected != CHAN_JOINING)
294 yell("--- add_channel: add_channel found channel not CHAN_LIMBO/JOINING: %s", new->channel);
295 }
296
297 if (do_add || (connected == CHAN_JOINED))
298 {
299 #ifdef SHOW_JOIN_TIME
300 gettimeofday(&new->join_time, NULL);
301 #endif
302 new->server = server;
303 clear_channel(new);
304 }
305 if (copy)
306 {
307 new->mode = copy->mode;
308 new->limit = copy->limit;
309 new->window = copy->window;
310 malloc_strcpy(&new->key, copy->key);
311 }
312 new->connected = connected;
313 if ((connected == CHAN_JOINED) && !is_current_channel(channel, server, 0))
314 {
315 int flag = 1;
316 Window *tmp, *expected, *possible = (Window *) 0;
317
318 expected = new->window;
319
320 while ((tmp = traverse_all_windows(&flag)))
321 {
322 if (tmp->server == server)
323 {
324 if (tmp == expected)
325 {
326 set_channel_by_refnum(tmp->refnum, channel);
327 new->window = tmp;
328 update_all_status();
329 return;
330 }
331 else if (!possible)
332 possible = tmp;
333 }
334 }
335 if (possible)
336 {
337 set_channel_by_refnum(possible->refnum, channel);
338 new->window = possible;
339 update_all_status();
340 return;
341 }
342 set_channel_by_refnum(0, channel);
343 new->window = curr_scr_win;
344 }
345 update_all_windows();
346 }
347
348 /*
349 * add_to_channel: adds the given nickname to the given channel. If the
350 * nickname is already on the channel, nothing happens. If the channel is
351 * not on the channel list, nothing happens (although perhaps the channel
352 * should be addded to the list? but this should never happen)
353 *
354 * this will return the channel pointer, if you don't need it cast the call
355 * to void.
356 */
357 Channel *
add_to_channel(channel,nick,server,oper,chop,voice,user,host,real,hops,here,serv_str)358 add_to_channel(channel, nick, server,
359 oper, chop, voice,
360 user, host, real,
361 hops, here, serv_str)
362 u_char *channel;
363 u_char *nick;
364 int server;
365 int oper;
366 int chop;
367 int voice;
368 /* ninja extensions! */
369 u_char *user;
370 u_char *host;
371 u_char *real;
372 int hops;
373 int here;
374 u_char *serv_str;
375 {
376 Nick *new;
377 Channel *chan;
378 int ischop = chop;
379 int hasvoice = voice;
380 int isoper = oper;
381
382 if (!nick)
383 return NULL;
384 if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
385 {
386 /* these two if statements should never
387 * be true with ninja using the WHO command
388 * to cache users instead of names
389 */
390 if (*nick == '+')
391 {
392 hasvoice = 1;
393 nick++;
394 }
395 if (*nick == '@')
396 {
397 nick++;
398 if (!my_stricmp(nick, get_server_nickname(server))
399 && !(chan->status & CHAN_MODE))
400 {
401 u_char *mode = recreate_mode(chan);
402
403 if (*mode)
404 {
405 int old_server = from_server;
406
407 from_server = server;
408 send_to_server("MODE %s %s", chan->channel, mode);
409 from_server = old_server;
410 }
411 chan->status |= CHAN_CHOP;
412 }
413 ischop = 1;
414 }
415
416 if ((new = (Nick *) remove_from_list((List **) &(chan->nicks), nick)))
417 free_nick(&new);
418 new = (Nick *) new_malloc(sizeof(Nick));
419 /* dma_Malloc already bzero's data
420 new->nick = (u_char *) 0;
421 */
422 if (ischop == 1)
423 new->status |= NICK_CHOP;
424 if (hasvoice == 1)
425 new->status |= NICK_VOICE;
426 if (isoper == 1)
427 new->status |= NICK_OPER;
428 if (here == 1)
429 new->status |= NICK_HERE;
430 else if (here == 0)
431 new->status |= NICK_AWAY;
432 new->hops = hops;
433 malloc_strcpy(&(new->nick), nick);
434 malloc_strcpy(&(new->user), user);
435 malloc_strcpy(&(new->host), host);
436 malloc_strcpy(&(new->realname), real);
437 malloc_strcpy(&(new->server), serv_str);
438 add_to_list((List **) &(chan->nicks), (List *) new);
439 }
440 if (here != -1) /* don't do this on names output, wait for who output */
441 notify_mark(nick, NFY_ONLINE, !NFY_FROM_QRY, user, host, (new->status & NICK_AWAY));
442 return chan;
443 }
444
445
446 /*
447 * recreate_mode: converts the bitmap representation of a channels mode into
448 * a string
449 *
450 * there were some possible overflows in here.. fixed by jjd 9/25/01
451 */
452 static u_char *
recreate_mode(chan)453 recreate_mode(chan)
454 Channel *chan;
455 {
456 int mode_pos = 0, mode;
457 static u_char *s;
458 u_char buffer[BIG_BUFFER_SIZE];
459 int len, left;
460
461 memset(buffer, 0, sizeof(buffer)); /* ultra-paranoia */
462 s = buffer;
463 mode = chan->mode;
464 while (mode && (s-buffer) < (sizeof(buffer)-1))
465 {
466 if (mode % 2)
467 *s++ = mode_str[mode_pos];
468 mode /= 2;
469 mode_pos++;
470 }
471 left = sizeof(buffer) - (s - buffer) - 1;
472 if (chan->key
473 && (chan->mode & MODE_KEY)
474 && !get_int_var(HIDE_CHANNEL_KEYS_VAR)
475 && left > 2)
476 {
477 *s++ = ' ';
478 len = my_strlen(chan->key);
479 my_strncpy(s, chan->key, MIN(left, len));
480 s += len;
481 left -= len;
482 }
483 if (chan->limit && left > 1)
484 snprintf(CP(s), left, " %d", chan->limit);
485
486 if (chan->s_mode == empty_string)
487 chan->s_mode = NULL;
488 malloc_strcpy(&chan->s_mode, buffer);
489 return chan->s_mode;
490 }
491
492 /*
493 * decifer_mode: This will figure out the mode string as returned by mode
494 * commands and convert that mode string into a one byte bit map of modes
495 */
496 static int
decifer_mode(mode_string,chan,from)497 decifer_mode(mode_string, chan, from)
498 u_char *mode_string;
499 Channel *chan;
500 u_char *from;
501 {
502 u_char *limit = 0;
503 u_char *person;
504 int add = 0;
505 int limit_set = 0;
506 int limit_reset = 0;
507 u_char *rest, *the_key;
508 Nick *ThisNick;
509 u_long value = 0;
510 u_char *copy, *free_copy = (u_char *) 0;
511 int old_status = 0;
512
513 dma_strcpy(&free_copy, mode_string);
514 copy = free_copy;
515 if (!(copy = next_arg(copy, &rest)))
516 {
517 dma_Free(&free_copy);
518 return -1;
519 }
520 for (; *copy; copy++)
521 {
522 switch (*copy)
523 {
524 case '+':
525 add = 1;
526 value = 0;
527 break;
528 case '-':
529 add = 0;
530 value = 0;
531 break;
532 /*
533 * Ninja supports 2.8-hybird modes for now
534 *
535 case 'a':
536 value = MODE_ANONYMOUS;
537 break;
538 case 'c':
539 value = MODE_COLOURLESS;
540 break;
541 */
542 case 'i':
543 value = MODE_INVITE;
544 break;
545 case 'k':
546 value = MODE_KEY;
547 the_key = next_arg(rest, &rest);
548 if (add)
549 malloc_strcpy(&(chan->key), the_key);
550 else
551 new_free(&(chan->key));
552 add_ckey(chan->channel, chan->key);
553 break;
554 case 'l':
555 value = MODE_LIMIT;
556 if (add)
557 {
558 limit_set = 1;
559 if (!(limit = next_arg(rest, &rest)))
560 limit = empty_string;
561 else if (0 == my_strcmp(limit, zero))
562 limit_reset = 1, limit_set = 0, add = 0;
563 }
564 else
565 limit_reset = 1;
566 break;
567 case 'm':
568 value = MODE_MODERATED;
569 break;
570 case 'o':
571 /* if its me, update my channel status */
572 if ((person = next_arg(rest, &rest)) && !my_stricmp(person, get_server_nickname(from_server))) {
573 old_status = chan->status;
574 if (add)
575 chan->status |= CHAN_CHOP;
576 else
577 chan->status &= ~CHAN_CHOP;
578 }
579 /* the nick */
580 ThisNick = (Nick *) list_lookup((List **) &(chan->nicks), person, !USE_WILDCARDS, !REMOVE_FROM_LIST);
581 if (ThisNick)
582 {
583 if (add)
584 ThisNick->status |= NICK_CHOP;
585 else
586 ThisNick->status &= ~NICK_CHOP;
587 }
588 /* if im getting opped and the channel is sync'd, check friends */
589 if (add
590 && my_stricmp(person, get_server_nickname(from_server)) == 0
591 && old_status != chan->status
592 && ((chan->status & CHAN_MODE)
593 && (chan->status & CHAN_WHO)))
594 friends_channel_sync(chan);
595 break;
596 case 'n':
597 value = MODE_MSGS;
598 break;
599 case 'p':
600 value = MODE_PRIVATE;
601 break;
602 /*
603 case 'q':
604 value = MODE_QUIET;
605 break;
606 case 'r':
607 value = MODE_REOP;
608 break;
609 */
610 case 's':
611 value = MODE_SECRET;
612 break;
613 case 't':
614 value = MODE_TOPIC;
615 break;
616 case 'v':
617 person = next_arg(rest, &rest);
618 ThisNick = (Nick *) list_lookup((List **) &(chan->nicks), person, !USE_WILDCARDS, !REMOVE_FROM_LIST);
619 if (ThisNick)
620 {
621 if (add)
622 ThisNick->status |= NICK_VOICE;
623 else
624 ThisNick->status &= ~NICK_VOICE;
625 }
626 break;
627 /* ban cache */
628 case 'b':
629 person = next_arg(rest, &rest);
630 if (!person || !*person)
631 break;
632 if (add)
633 {
634 u_char tmpstr[32];
635
636 snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", (unsigned long)time(NULL));
637 tmpstr[sizeof(tmpstr)-1] = '\0';
638 add_ban(chan, person, from, tmpstr);
639 }
640 else
641 {
642 Ban *new;
643 if ((new = (Ban *) remove_from_list((List **) &(chan->bans), person)))
644 {
645 dma_Free(&(new->ban));
646 dma_Free(&(new->owner));
647 dma_Free(&new);
648 }
649 }
650 break;
651 /* exception cache */
652 case 'e':
653 person = next_arg(rest, &rest);
654 if (!person || !*person)
655 break;
656 if (add)
657 {
658 u_char tmpstr[32];
659
660 snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", (unsigned long)time(NULL));
661 tmpstr[sizeof(tmpstr)-1] = '\0';
662 /* add_exception(chan, person, from, tmpstr);
663 */
664 }
665 else
666 {
667 Except *new;
668 if ((new = (Except *) remove_from_list((List **) &(chan->excepts), person)))
669 {
670 dma_Free(&(new->exception));
671 dma_Free(&(new->owner));
672 dma_Free(&new);
673 }
674 }
675 break;
676 /* deny cache */
677 case 'd':
678 person = next_arg(rest, &rest);
679 if (!person || !*person)
680 break;
681 if (add)
682 {
683 u_char tmpstr[32];
684
685 snprintf(tmpstr, sizeof(tmpstr)-1, "%lu", (unsigned long)time(NULL));
686 tmpstr[sizeof(tmpstr)-1] = '\0';
687 /* add_deny(chan, person, from, tmpstr);
688 */
689 }
690 else
691 {
692 Deny *new;
693 if ((new = (Deny *) remove_from_list((List **) &(chan->denys), person)))
694 {
695 dma_Free(&(new->regexp));
696 dma_Free(&(new->owner));
697 dma_Free(&new);
698 }
699 }
700 break;
701 /* misc unsupported modes w/arguments */
702 case 'I':
703 case 'O': /* this is a weird special case */
704 (void) next_arg(rest, &rest);
705 break;
706 /*
707 case 'R':
708 value = MODE_REGONLY;
709 break;
710 */
711 }
712 if (add)
713 chan->mode |= value;
714 else
715 chan->mode &= ~value;
716 }
717 if (limit_set)
718 limit_set = my_atoi(limit);
719 else if (limit_reset)
720 limit_set = 0;
721 else
722 limit_set = -1;
723 dma_Free(&free_copy);
724 return limit_set;
725 }
726
727 /*
728 * get_channel_mode: returns the current mode string for the given channel
729 */
730 u_char *
get_channel_mode(channel,server)731 get_channel_mode(channel, server)
732 u_char *channel;
733 int server;
734 {
735 Channel *tmp;
736
737 if ((tmp = lookup_channel(channel, server, CHAN_NOUNLINK)) && (tmp->status & CHAN_MODE))
738 return recreate_mode(tmp);
739 return empty_string;
740 }
741
742 /*
743 * update_channel_mode: This will modify the mode for the given channel
744 * according the the new mode given.
745 */
746 void
update_channel_mode(channel,server,mode,from,chan)747 update_channel_mode(channel, server, mode, from, chan)
748 u_char *channel;
749 int server;
750 u_char *mode;
751 u_char *from;
752 Channel *chan;
753 {
754 Channel *tmp;
755 int limit;
756
757 if (!chan && !channel)
758 return;
759 if (chan && chan->server == server)
760 tmp = chan;
761 else
762 tmp = lookup_channel(channel, server, CHAN_NOUNLINK);
763 if (!tmp)
764 return;
765 limit = decifer_mode(mode, tmp, from);
766 if (limit != -1)
767 tmp->limit = limit;
768 update_all_status();
769
770 /* check friend protection... */
771 check_friend_protection(from, tmp, mode);
772 }
773
774 /*
775 * is_channel_mode: returns the logical AND of the given mode with the
776 * channels mode. Useful for testing a channels mode
777 *
778 */
779 int
is_channel_mode(channel,mode,server_index)780 is_channel_mode(channel, mode, server_index)
781 u_char *channel;
782 int mode;
783 int server_index;
784 {
785 Channel *tmp;
786
787 if ((tmp = lookup_channel(channel, server_index, CHAN_NOUNLINK)))
788 return (tmp->mode & mode);
789 return 0;
790 }
791
792 static void
free_channel(channel)793 free_channel(channel)
794 Channel **channel;
795 {
796 clear_channel(*channel);
797 new_free(&(*channel)->channel);
798 new_free(&(*channel)->key);
799 if ((*channel)->s_mode != empty_string)
800 new_free(&(*channel)->s_mode);
801 new_free(&(*channel));
802 }
803
804 /*
805 * remove_channel: removes the named channel from the
806 * server_list[server].chan_list. If the channel is not on the
807 * server_list[server].chan_list, nothing happens. If the channel was
808 * the current channel, this will select the top of the
809 * server_list[server].chan_list to be the current_channel, or 0 if the
810 * list is empty.
811 */
812 void
remove_channel(channel,server)813 remove_channel(channel, server)
814 u_char *channel;
815 int server;
816 {
817 Channel *tmp;
818
819 if (channel)
820 {
821 int refnum = -1;
822
823 if ((tmp = lookup_channel(channel, server, CHAN_UNLINK)))
824 {
825 if (tmp->window)
826 refnum = tmp->window->refnum;
827 free_channel(&tmp);
828 }
829
830 (void)is_current_channel(channel, server, refnum);
831 }
832 else
833 {
834 Channel *next;
835
836 for (tmp = server_list[server].chan_list; tmp; tmp = next)
837 {
838 next = tmp->next;
839 free_channel(&tmp);
840 }
841 server_list[server].chan_list = (Channel *) 0;
842 }
843 update_all_windows();
844 }
845
846 /*
847 * remove_from_channel: removes the given nickname from the given channel. If
848 * the nickname is not on the channel or the channel doesn't exist, nothing
849 * happens.
850 */
851 void
remove_from_channel(channel,nick,server)852 remove_from_channel(channel, nick, server)
853 u_char *channel;
854 u_char *nick;
855 int server;
856 {
857 Channel *chan;
858 Nick *tmp;
859
860 if (channel)
861 {
862 if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
863 {
864 if ((tmp = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, REMOVE_FROM_LIST)))
865 free_nick(&tmp);
866 }
867 }
868 else
869 {
870 for (chan = server_list[server].chan_list; chan; chan = chan->next)
871 {
872 if ((tmp = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, REMOVE_FROM_LIST)))
873 free_nick(&tmp);
874 }
875 }
876 }
877
878 /*
879 * rename_nick: in response to a changed nickname, this looks up the given
880 * nickname on all you channels and changes it the new_nick
881 */
882 void
rename_nick(old_nick,new_nick,server)883 rename_nick(old_nick, new_nick, server)
884 u_char *old_nick,
885 *new_nick;
886 int server;
887 {
888 Channel *chan;
889 Nick *tmp;
890
891 for (chan = server_list[server].chan_list; chan; chan = chan->next)
892 {
893 if ((chan->server == server))
894 {
895 if ((tmp = (Nick *) list_lookup((List **) &chan->nicks, old_nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)))
896 {
897 /* malloc_strcpy calls free if the pointer is non-null
898 new_free(&tmp->nick);
899 */
900 malloc_strcpy(&tmp->nick, new_nick);
901 }
902 }
903 }
904 }
905
906 /*
907 * is_on_channel: returns true if the given nickname is in the given channel,
908 * false otherwise. Also returns false if the given channel is not on the
909 * channel list.
910 */
911 int
is_on_channel(channel,server,nick)912 is_on_channel(channel, server, nick)
913 u_char *channel;
914 int server;
915 u_char *nick;
916 {
917 Channel *chan;
918
919 chan = lookup_channel(channel, server, CHAN_NOUNLINK);
920 if (chan && (chan->connected == CHAN_JOINED)
921 /* channel may be "surviving" from a server disconnect/reconnect,
922 make sure it's connected -Sol */
923 && list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST))
924 return 1;
925 return 0;
926 }
927
928 int
is_chanop(channel,nick)929 is_chanop(channel, nick)
930 u_char *channel;
931 u_char *nick;
932 {
933 Channel *chan;
934 Nick *tnick;
935
936 if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)) &&
937 (chan->connected == CHAN_JOINED) &&
938 /* channel may be "surviving" from a disconnect/connect
939 check here too -Sol */
940 (tnick = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)) &&
941 (tnick->status & NICK_CHOP))
942 return 1;
943 return 0;
944 }
945
946 int
has_voice(channel,nick)947 has_voice(channel, nick)
948 u_char *channel;
949 u_char *nick;
950 {
951 Channel *chan;
952 Nick *tnick;
953
954 if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK)) &&
955 (chan->connected == CHAN_JOINED) &&
956 /* channel may be "surviving" from a disconnect/connect
957 check here too -Sol */
958 (tnick = (Nick *) list_lookup((List **) &(chan->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)) &&
959 (/* come on, this is for voice, not chanops
960 * (tnick->status & NICK_CHOP) ||
961 */
962 (tnick->status & NICK_VOICE)))
963 return 1;
964 return 0;
965 }
966
967 static void
show_channel(chan)968 show_channel(chan)
969 Channel *chan;
970 {
971 /*
972 Nick *tmp;
973 int buffer_len, len;
974 u_char *nicks = (u_char *) 0;
975 u_char *s;
976 u_char buffer[BIG_BUFFER_SIZE];
977
978 s = recreate_mode(chan);
979 *buffer = (u_char) 0;
980 buffer_len = 0;
981 for (tmp = chan->nicks; tmp; tmp = tmp->next)
982 {
983 len = my_strlen(tmp->nick);
984 if (buffer_len + len >= (BIG_BUFFER_SIZE / 2))
985 {
986 malloc_strcpy(&nicks, buffer);
987 say("\t%s +%s (%s): %s", chan->channel, s, get_server_name(chan->server), nicks);
988 *buffer = (u_char) 0;
989 buffer_len = 0;
990 }
991 my_strmcat(buffer, tmp->nick, BIG_BUFFER_SIZE);
992 my_strmcat(buffer, " ", BIG_BUFFER_SIZE);
993 buffer_len += len + 1;
994 }
995 malloc_strcpy(&nicks, buffer);
996 say("\t%s +%s (%s): %s", chan->channel, s, get_server_name(chan->server), nicks);
997 new_free(&nicks);
998 */
999 ninja_scan("SCAN", chan->channel, NULL);
1000 }
1001
1002 /* list_channels: displays your current channel and your channel list */
1003 void
list_channels()1004 list_channels()
1005 {
1006 Channel *tmp;
1007 int server, no = 1;
1008 int first;
1009
1010 if (connected_to_server < 1)
1011 {
1012 say("You are not connected to a server, use /SERVER to connect.");
1013 return;
1014 }
1015 if (get_channel_by_refnum(0))
1016 say("Current channel %s", get_channel_by_refnum(0));
1017 else
1018 say("No current channel for this window");
1019 first = 1;
1020 for (tmp = server_list[get_window_server(0)].chan_list; tmp; tmp = tmp->next)
1021 {
1022 if (tmp->connected != CHAN_JOINED)
1023 continue;
1024 if (first)
1025 say("You are on the following channels:");
1026 show_channel(tmp);
1027 first = 0;
1028 no = 0;
1029 }
1030
1031 if (connected_to_server > 1)
1032 {
1033 for (server = 0; server < number_of_servers; server++)
1034 {
1035 if (server == get_window_server(0))
1036 continue;
1037 first = 1;
1038 for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1039 {
1040 if (tmp->connected != CHAN_JOINED)
1041 continue;
1042 if (first)
1043 say("Other servers:");
1044 show_channel(tmp);
1045 first = 0;
1046 no = 0;
1047 }
1048 }
1049 }
1050 if (no)
1051 say("You are not on any channels");
1052 }
1053
1054 void
switch_channels(key,ptr)1055 switch_channels(key, ptr)
1056 u_int key;
1057 u_char *ptr;
1058 {
1059 Channel * tmp;
1060 u_char * s;
1061
1062 if (server_list[from_server].chan_list)
1063 {
1064 if (get_channel_by_refnum(0))
1065 {
1066 if ((tmp = lookup_channel(get_channel_by_refnum(0), from_server, CHAN_NOUNLINK)))
1067 {
1068 for (tmp = tmp->next; tmp; tmp = tmp->next)
1069 {
1070 s = tmp->channel;
1071 if (!is_current_channel(s, from_server, 0) && !(is_bound(s, from_server) && curr_scr_win != tmp->window))
1072 {
1073 set_channel_by_refnum(0, s);
1074 update_all_windows();
1075 return;
1076 }
1077 }
1078 }
1079 }
1080 for (tmp = server_list[from_server].chan_list; tmp; tmp = tmp->next)
1081 {
1082 s = tmp->channel;
1083 if (!is_current_channel(s, from_server, 0) && !(is_bound(s, from_server) && curr_scr_win != tmp->window))
1084 {
1085 set_channel_by_refnum(0, s);
1086 update_all_windows();
1087 return;
1088 }
1089 }
1090 }
1091 }
1092
1093 void
change_server_channels(old,new)1094 change_server_channels(old, new)
1095 int old,
1096 new;
1097 {
1098 Channel *tmp;
1099
1100 if (new == old)
1101 return;
1102 if (old > -1)
1103 {
1104 for (tmp = server_list[old].chan_list; tmp ;tmp = tmp->next)
1105 tmp->server = new;
1106 server_list[new].chan_list = server_list[old].chan_list;
1107 }
1108 else
1109 server_list[new].chan_list = (Channel *) 0;
1110 }
1111
1112 void
clear_channel_list(server)1113 clear_channel_list(server)
1114 int server;
1115 {
1116 Channel *tmp, *next;
1117 Window *ptr;
1118 int flag = 1;
1119
1120 while ((ptr = traverse_all_windows(&flag)))
1121 if (ptr->server == server && ptr->current_channel)
1122 new_free(&ptr->current_channel);
1123
1124 for (tmp = server_list[server].chan_list; tmp; tmp = next)
1125 {
1126 next = tmp->next;
1127 free_channel(&tmp);
1128 }
1129 server_list[server].chan_list = (Channel *) 0;
1130 return;
1131 }
1132
1133 /*
1134 * reconnect_all_channels: used after you get disconnected from a server,
1135 * clear each channel nickname list and re-JOINs each channel in the
1136 * channel_list ..
1137 */
1138 void
reconnect_all_channels(server)1139 reconnect_all_channels(server)
1140 int server;
1141 {
1142 Channel *tmp = (Channel *) 0;
1143 u_char *mode, *chan, *key;
1144
1145 for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1146 {
1147 chan = tmp->channel;
1148 if (tmp->key)
1149 key = tmp->key;
1150 else
1151 key = get_ckey(chan);
1152
1153 if (get_server_version(server) >= Server2_8)
1154 send_to_server("JOIN %s%s%s", tmp->channel, key ? " " : "", key ? key : (u_char *) "");
1155 else
1156 {
1157 mode = recreate_mode(tmp);
1158 send_to_server("JOIN %s%s%s", tmp->channel, mode ? " " : "", mode ? mode : (u_char *) "");
1159 }
1160 tmp->connected = CHAN_JOINING;
1161 /* mask off the some of the channel cache flags */
1162 tmp->status = 0;
1163 }
1164 }
1165
1166 u_char *
what_channel(nick,server)1167 what_channel(nick, server)
1168 u_char *nick;
1169 int server;
1170 {
1171 Channel *tmp;
1172
1173 if (curr_scr_win->current_channel && is_on_channel(curr_scr_win->current_channel, curr_scr_win->server, nick))
1174 return curr_scr_win->current_channel;
1175
1176 /* XXX: why are we passing "server" when we just use "from_server" */
1177 for (tmp = server_list[from_server].chan_list; tmp; tmp = tmp->next)
1178 if (list_lookup((List **) &(tmp->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST))
1179 return tmp->channel;
1180
1181 return (u_char *) 0;
1182 }
1183
1184 u_char *
walk_channels(nick,init,server)1185 walk_channels(nick, init, server)
1186 int init;
1187 u_char *nick;
1188 int server;
1189 {
1190 static Channel *tmp = (Channel *) 0;
1191
1192 if (init)
1193 tmp = server_list[server].chan_list;
1194 else if (tmp)
1195 tmp = tmp->next;
1196 /* once again? why from_server ? */
1197 for (;tmp ; tmp = tmp->next)
1198 if ((tmp->server == from_server) && (list_lookup((List **) &(tmp->nicks), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)))
1199 return (tmp->channel);
1200 return (u_char *) 0;
1201 }
1202
1203 int
get_channel_oper(channel,server)1204 get_channel_oper(channel, server)
1205 u_char *channel;
1206 int server;
1207 {
1208 Channel *chan;
1209
1210 if ((chan = lookup_channel(channel, server, CHAN_NOUNLINK)))
1211 return (chan->status & CHAN_CHOP);
1212 else
1213 return 1;
1214 }
1215
1216 extern void
1217 set_channel_window(window, channel, server)
1218 Window *window;
1219 u_char *channel;
1220 int server;
1221 {
1222 Channel *tmp;
1223
1224 if (!channel)
1225 return;
1226 for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1227 if (!my_stricmp(channel, tmp->channel))
1228 {
1229 tmp->window = window;
1230 return;
1231 }
1232 }
1233
1234 extern u_char *
1235 create_channel_list(window)
1236 Window *window;
1237 {
1238 Channel *tmp;
1239 u_char *value = (u_char *) 0;
1240 u_char buffer[BIG_BUFFER_SIZE];
1241
1242 *buffer = '\0';
1243 for (tmp = server_list[window->server].chan_list; tmp; tmp = tmp->next)
1244 {
1245 if (*buffer != '\0')
1246 my_strmcat(buffer, " ", sizeof(buffer)-1);
1247 my_strmcat(buffer, tmp->channel, sizeof(buffer)-1);
1248 }
1249 malloc_strcpy(&value, buffer);
1250
1251 return value;
1252 }
1253
1254 extern void
1255 channel_server_delete(server)
1256 int server;
1257 {
1258 Channel *tmp;
1259 int i;
1260
1261 for (i = server + 1; i < number_of_servers; i++)
1262 for (tmp = server_list[i].chan_list ; tmp; tmp = tmp->next)
1263 if (tmp->server >= server)
1264 tmp->server--;
1265 }
1266
1267 extern int
1268 chan_is_connected(channel, server)
1269 u_char * channel;
1270 int server;
1271 {
1272 Channel * cp = lookup_channel(channel, server, CHAN_NOUNLINK);
1273
1274 if (!cp)
1275 return 0;
1276
1277 return (cp->connected == CHAN_JOINED);
1278 }
1279
1280 void
mark_not_connected(server)1281 mark_not_connected(server)
1282 int server;
1283 {
1284 Channel *tmp;
1285
1286 for (tmp = server_list[server].chan_list; tmp; tmp = tmp->next)
1287 tmp->connected = CHAN_LIMBO;
1288 }
1289
1290 /*
1291 * take the string specified in "chan" and make it into a channel name.
1292 *
1293 * basically, if there's a & or # at the beginning, get out.
1294 * otherwise we prepend a #
1295 *
1296 * uses a static buffer, so multiple calls on the same line won't work properly.
1297 * ie: printf("%s %s\n", make_chan("hi"), make_chan("yo"));
1298 * would print:
1299 * #yo #yo
1300 */
1301 u_char *
make_chan(u_char * chan)1302 make_chan(u_char *chan)
1303 {
1304 static u_char channel[256];
1305
1306 /* this should never happen. */
1307 if (!chan || !*chan)
1308 return channel;
1309
1310 /* this code used to do more, but now it just does this: */
1311 else if (!is_channel(chan))
1312 {
1313 channel[0] = '\0';
1314 my_strmcat(channel, "#", sizeof(channel)-1);
1315 my_strmcat(channel, chan, sizeof(channel)-1);
1316 return channel;
1317 }
1318 return chan;
1319 }
1320
1321 /*
1322 * is the channel cached?
1323 *
1324 * this is only called in one place, then end of nincache.c
1325 *
1326 * it is reponsible for printing the join sync time if needed
1327 */
1328 int
chk_channel_cached(chan)1329 chk_channel_cached(chan)
1330 u_char *chan;
1331 {
1332 Channel *c;
1333
1334 if (!chan)
1335 return 0;
1336 c = lookup_channel(chan, parsing_server_index, CHAN_NOUNLINK);
1337 if (!c)
1338 return 0;
1339 /* if mode, who, or bans isn't cached then neither is the channel..
1340 * there's also CHAN_TIME but i'm not sure what all server support it..
1341 */
1342 if (!(c->status & CHAN_MODE)
1343 || !(c->status & CHAN_WHO)
1344 || !(c->status & CHAN_BANS))
1345 return 0;
1346
1347 /* if the extra channel mode stuff isn't cached, still not!
1348 *
1349 * these aren't implemented yet
1350 *
1351 if ((server_list[chan->server].cmodes
1352 && my_index(server_list[chan->server].cmodes, 'e')
1353 && !(chan->status & CHAN_EXCEPT))
1354 || (server_list[chan->server].cmodes
1355 && my_index(server_list[chan->server].cmodes, 'd')
1356 && !(chan->status & CHAN_DENY)))
1357 return 0;
1358 */
1359 #ifdef SHOW_JOIN_TIME
1360 if (!(c->status & CHAN_SHOWED_TIME))
1361 {
1362 struct timeval tv, td;
1363 gettimeofday(&tv, NULL);
1364 td.tv_sec = tv.tv_sec - c->join_time.tv_sec;
1365 td.tv_usec = tv.tv_usec - c->join_time.tv_usec;
1366 save_message_from();
1367 message_from(c->channel, LOG_CRAP);
1368 put_info("Channel %s cached in %0.3f seconds.",
1369 c->channel,
1370 (double)td.tv_sec + ((double)td.tv_usec / 1000000.0));
1371 restore_message_from();
1372 c->status |= CHAN_SHOWED_TIME;
1373 }
1374 #endif
1375
1376 return 1;
1377 }
1378
1379 /*
1380 * is_channel: determines if the argument is a channel. If it's a number,
1381 * begins with MULTI_CHANNEL and has no '*', or STRING_CHANNEL, then its a
1382 * channel
1383 */
1384 int
is_channel(to)1385 is_channel(to)
1386 u_char *to;
1387 {
1388 int version;
1389
1390 if (to == 0)
1391 return 0;
1392 version = get_server_version(from_server);
1393 return ((version < Server2_7 && (isdigit(*to) || (*to == STRING_CHANNEL)
1394 || *to == '-'))
1395 || (version > Server2_5 && *to == MULTI_CHANNEL)
1396 || (version > Server2_7 && *to == LOCAL_CHANNEL)
1397 || (version > Server2_8 && *to == STRING_CHANNEL)
1398 || (version > Server2_9 && *to == SAFE_CHANNEL)
1399 #ifdef SUPPORT_ICB
1400 || (version == ServerICB && my_stricmp(to, get_server_icbgroup(from_server)) == 0)
1401 #endif
1402 );
1403 }
1404
1405