1 /*
2 * funny.c: Well, I put some stuff here and called it funny. So sue me.
3 *
4 * Written by Michael Sandrof
5 *
6 * Copyright (c) 1990 Michael Sandrof.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-2021 Matthew R. Green.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include "irc.h"
36 IRCII_RCSID("@(#)$eterna: funny.c,v 1.58 2021/02/24 10:38:03 mrg Exp $");
37
38 #include "ircaux.h"
39 #include "hook.h"
40 #include "vars.h"
41 #include "funny.h"
42 #include "names.h"
43 #include "server.h"
44 #include "lastlog.h"
45 #include "ircterm.h"
46 #include "output.h"
47 #include "numbers.h"
48 #include "parse.h"
49 #include "screen.h"
50 #include "sl_irc.h"
51
52 static u_char *match_str = NULL;
53
54 static int funny_min;
55 static int funny_max;
56 static int funny_flags;
57
58 void
funny_match(u_char * stuff)59 funny_match(u_char *stuff)
60 {
61 malloc_strcpy(&match_str, stuff);
62 }
63
64 void
set_funny_flags(int min,int max,int flags)65 set_funny_flags(int min, int max, int flags)
66 {
67 funny_min = min;
68 funny_max = max;
69 funny_flags = flags;
70 }
71
72 struct WideListInfoStru
73 {
74 u_char *channel;
75 int users;
76 };
77
78 typedef struct WideListInfoStru WideList;
79
80 static WideList **wide_list = NULL;
81 static int wl_size = 0;
82 static size_t wl_elements = 0;
83
84 static int funny_widelist_users(WideList **, WideList **);
85 static int funny_widelist_names(WideList **, WideList **);
86
87 static int
funny_widelist_users(WideList ** left,WideList ** right)88 funny_widelist_users(WideList **left, WideList **right)
89 {
90 if ((**left).users > (**right).users)
91 return -1;
92 else if ((**right).users > (**left).users)
93 return 1;
94 else
95 return my_stricmp((**left).channel, (**right).channel);
96 }
97
98 static int
funny_widelist_names(WideList ** left,WideList ** right)99 funny_widelist_names(WideList **left, WideList **right)
100 {
101 int comp;
102
103 if ((comp = my_stricmp((**left).channel, (**right).channel)) != 0)
104 return comp;
105 else if ((**left).users > (**right).users)
106 return -1;
107 else if ((**right).users > (**left).users)
108 return 1;
109 else
110 return 0;
111 }
112
113
114 void
funny_print_widelist(void)115 funny_print_widelist(void)
116 {
117 int i;
118 StringList *sl;
119 size_t tlen;
120
121 if (!wide_list)
122 return;
123
124 if (funny_flags & FUNNY_NAME)
125 qsort((void *) wide_list, wl_elements, sizeof(WideList *),
126 (int (*)(const void *, const void *)) funny_widelist_names);
127 else if (funny_flags & FUNNY_USERS)
128 qsort((void *) wide_list, wl_elements, sizeof(WideList *),
129 (int (*)(const void *, const void *)) funny_widelist_users);
130
131 sl = sl_init();
132 tlen = 0;
133 for (i = 0; i < wl_elements; i++)
134 {
135 u_char *entry = NULL;
136 size_t elen;
137
138 malloc_snprintf(&entry, "%s(%d) ", wide_list[i]->channel,
139 wide_list[i]->users);
140 elen = my_strlen(entry);
141 if (tlen + elen > get_co() - 5)
142 {
143 u_char *buffer = sl_concat(sl, empty_string());
144 if (do_hook(WIDELIST_LIST, "%s", buffer))
145 say("%s", buffer);
146 new_free(&buffer);
147 sl_free(sl, 1);
148 sl = sl_init();
149 tlen = 0;
150 }
151 sl_add(sl, CP(entry));
152 tlen += elen;
153 }
154 if (sl_size(sl))
155 {
156 u_char *buffer = sl_concat(sl, empty_string());
157 if (do_hook(WIDELIST_LIST, "%s", buffer))
158 say("%s" , buffer);
159 new_free(&buffer);
160 }
161 sl_free(sl, 1);
162 for (i = 0; i < wl_elements; i++)
163 {
164 new_free(&wide_list[i]->channel);
165 new_free(&wide_list[i]);
166 }
167 new_free(&wide_list);
168 wl_elements = wl_size = 0;
169 }
170
171 void
funny_list(u_char * comm,u_char * from,u_char ** args)172 funny_list(u_char *comm, u_char *from, u_char **args)
173 {
174 u_char *channel,
175 *user_cnt,
176 *line;
177 WideList **new_list;
178 int cnt;
179 static u_char format[25];
180 static int last_width = -1;
181
182 if (check_params(comm, from, 0, args, 3))
183 return;
184
185 if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR))
186 {
187 if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
188 snprintf(CP(format), sizeof format, "*** %%-%u.%us %%-5s %%s",
189 (u_char) last_width,
190 (u_char) last_width);
191 else
192 my_strmcpy(format, "*** %s\t%-5s %s", sizeof format);
193 }
194 channel = args[0];
195 user_cnt = args[1];
196 line = paste_args(args, 2);
197 if (funny_flags & FUNNY_TOPIC && !(line && *line))
198 return;
199 cnt = my_atoi(user_cnt);
200 if (funny_min && (cnt < funny_min))
201 return;
202 if (funny_max && (cnt > funny_max))
203 return;
204 if ((funny_flags & FUNNY_PRIVATE) && (*channel != '*'))
205 return;
206 if ((funny_flags & FUNNY_PUBLIC) && (*channel == '*'))
207 return;
208 if (match_str)
209 {
210 if (wild_match(match_str, channel) == 0)
211 return;
212 }
213 if (funny_flags & FUNNY_WIDE)
214 {
215 if (wl_elements >= wl_size)
216 {
217 const size_t increase = 50;
218 new_list = new_malloc(sizeof(*new_list) * (wl_size + increase));
219 memset(new_list, 0, sizeof(*new_list) * (wl_size + increase));
220 if (wl_size)
221 memmove(new_list, wide_list, sizeof(*new_list) * wl_size);
222 wl_size += increase;
223 new_free(&wide_list);
224 wide_list = new_list;
225 }
226 wide_list[wl_elements] = new_malloc(sizeof **wide_list);
227 wide_list[wl_elements]->users = cnt;
228 wide_list[wl_elements]->channel = NULL;
229 malloc_strcpy(&(wide_list[wl_elements]->channel),
230 (*channel != '*') ? channel : (u_char *) "Prv");
231 wl_elements++;
232 return;
233 }
234 if (do_hook(current_numeric(), "%s %s %s %s",
235 from, channel, user_cnt, line) &&
236 do_hook(LIST_LIST, "%s %s %s", channel, user_cnt, line))
237 {
238 if (channel && user_cnt)
239 {
240 if (*channel == '*')
241 put_it(CP(format), "Prv", user_cnt, line);
242 else
243 put_it(CP(format), channel, user_cnt, line);
244 }
245 }
246 }
247
248 void
funny_namreply(u_char * comm,u_char * from,u_char ** args)249 funny_namreply(u_char *comm, u_char *from, u_char **args)
250 {
251 u_char *type,
252 *nick,
253 *channel;
254 static u_char format[40];
255 static int last_width = -1;
256 int cnt;
257 u_char *ptr;
258 u_char *line;
259
260 if (check_params(comm, from, 0, args, 3))
261 return;
262
263 paste_args(args, 2);
264 type = args[0];
265 channel = args[1];
266 line = args[2];
267 save_message_from();
268 message_from(channel, LOG_CRAP);
269 if (channel_mode_lookup(channel, CHAN_NAMES | CHAN_MODE, CHAN_NAMES))
270 {
271 if (do_hook(current_numeric(), "%s %s %s %s", from, type, channel,
272 line) && get_int_var(SHOW_CHANNEL_NAMES_VAR))
273 say("Users on %s: %s", channel, line);
274 while ((nick = next_arg(line, &line)) != NULL)
275 add_to_channel(channel, nick, parsing_server(), 0, 0);
276 goto out;
277 }
278 if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR))
279 {
280 if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
281 snprintf(CP(format), sizeof format, "%%s: %%-%u.%us %%s",
282 (u_char) last_width,
283 (u_char) last_width);
284 else
285 my_strmcpy(format, "%s: %s\t%s", sizeof format);
286 }
287 ptr = line;
288 for (cnt = -1; ptr; cnt++)
289 {
290 if ((ptr = my_index(ptr, ' ')) != NULL)
291 ptr++;
292 }
293 if (funny_min && (cnt < funny_min))
294 return;
295 else if (funny_max && (cnt > funny_max))
296 return;
297 if ((funny_flags & FUNNY_PRIVATE) && (*type == '='))
298 return;
299 if ((funny_flags & FUNNY_PUBLIC) && (*type == '*'))
300 return;
301 if (type && channel)
302 {
303 if (match_str)
304 {
305 if (wild_match(match_str, channel) == 0)
306 return;
307 }
308 if (do_hook(current_numeric(), "%s %s %s %s", from, type, channel,
309 line) && do_hook(NAMES_LIST, "%s %s", channel, line))
310 {
311 switch (*type)
312 {
313 case '=':
314 if (last_width && (my_strlen(channel) > last_width))
315 {
316 channel[last_width-1] = '>';
317 channel[last_width] = '\0';
318 }
319 put_it(CP(format), "Pub", channel, line);
320 break;
321 case '*':
322 put_it(CP(format), "Prv", channel, line);
323 break;
324 case '@':
325 put_it(CP(format), "Sec", channel, line);
326 break;
327 }
328 }
329 }
330 out:
331 restore_message_from();
332 }
333
334 void
funny_mode(u_char * from,u_char ** args)335 funny_mode(u_char *from, u_char **args)
336 {
337 u_char *mode, *channel;
338
339 if (server_get_version(parsing_server()) < Server2_6)
340 {
341 paste_args(args, 0);
342 channel = NULL;
343 mode = args[0];
344 }
345 else
346 {
347 if (!args[1])
348 return;
349 paste_args(args, 1);
350 channel = args[0];
351 mode = args[1];
352 }
353 /* if (ignore_mode) */
354 if (channel && channel_mode_lookup(channel, CHAN_NAMES | CHAN_MODE, CHAN_MODE))
355 {
356 update_channel_mode(channel, parsing_server(), mode);
357 update_all_status();
358 }
359 else
360 {
361 save_message_from();
362 message_from(channel, LOG_CRAP);
363 if (channel)
364 {
365 if (do_hook(current_numeric(), "%s %s %s", from,
366 channel, mode))
367 put_it("%s Mode for channel %s is \"%s\"",
368 numeric_banner(), channel, mode);
369 }
370 else
371 {
372 if (do_hook(current_numeric(), "%s %s", from, mode))
373 put_it("%s Channel mode is \"%s\"",
374 numeric_banner(), mode);
375 }
376 restore_message_from();
377 }
378 }
379
380 void
update_user_mode(u_char * modes)381 update_user_mode(u_char *modes)
382 {
383 int onoff = 1;
384
385 while (*modes)
386 {
387 switch(*modes++)
388 {
389 case '-':
390 onoff = 0;
391 break;
392 case '+':
393 onoff = 1;
394 break;
395 case 'o':
396 case 'O':
397 server_set_operator(parsing_server(), onoff);
398 break;
399 case 's':
400 case 'S':
401 server_set_flag(parsing_server(), USER_MODE_S, onoff);
402 break;
403 case 'i':
404 case 'I':
405 server_set_flag(parsing_server(), USER_MODE_I, onoff);
406 break;
407 case 'w':
408 case 'W':
409 server_set_flag(parsing_server(), USER_MODE_W, onoff);
410 break;
411 case 'r':
412 server_set_flag(parsing_server(), USER_MODE_R, onoff);
413 break;
414 case 'a':
415 server_set_flag(parsing_server(), USER_MODE_A, onoff);
416 break;
417 case 'z':
418 server_set_flag(parsing_server(), USER_MODE_Z, onoff);
419 break;
420 }
421 }
422 }
423
424 void
reinstate_user_modes(void)425 reinstate_user_modes(void)
426 {
427 u_char modes[10];
428 u_char *c;
429
430 if (server_get_version(parsing_server()) < Server2_7)
431 return;
432 c = modes;
433 if (server_get_flag(parsing_server(), USER_MODE_W))
434 *c++ = 'w';
435 if (server_get_flag(parsing_server(), USER_MODE_S))
436 *c++ = 's';
437 if (server_get_flag(parsing_server(), USER_MODE_I))
438 *c++ = 'i';
439 *c = '\0';
440 if (c != modes)
441 send_to_server("MODE %s +%s",
442 server_get_nickname(parsing_server()),
443 modes);
444 }
445