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
7  *
8  * see the copyright file, or do a help ircii copyright
9  */
10 
11 
12 #include "irc.h"
13 static char cvsrevision[] = "$Id: funny.c 515 2014-10-29 14:07:05Z keaston $";
14 CVS_REVISION(funny_c)
15 #include "struct.h"
16 
17 #include "ircaux.h"
18 #include "hook.h"
19 #include "vars.h"
20 #include "funny.h"
21 #include "names.h"
22 #include "server.h"
23 #include "lastlog.h"
24 #include "ircterm.h"
25 #include "output.h"
26 #include "numbers.h"
27 #include "parse.h"
28 #include "status.h"
29 #include "misc.h"
30 #include "screen.h"
31 #define MAIN_SOURCE
32 #include "modval.h"
33 
34 static	char	*match_str = NULL;
35 
36 static	int	funny_min;
37 static	int	funny_max;
38 static	int	funny_flags;
39 
funny_match(char * stuff)40 void funny_match(char  *stuff)
41 {
42 	malloc_strcpy(&match_str, stuff);
43 }
44 
set_funny_flags(int min,int max,int flags)45 void set_funny_flags(int min, int max, int flags)
46 {
47 	funny_min = min;
48 	funny_max = max;
49 	funny_flags = flags;
50 }
51 
52 struct	WideListInfoStru
53 {
54 	char	*channel;
55 	int	users;
56 };
57 
58 typedef	struct WideListInfoStru WideList;
59 
60 static	WideList **wide_list = NULL;
61 static	int	wl_size = 0;
62 static	int	wl_elements = 0;
63 
64 static	int	funny_widelist_users (WideList **, WideList **);
65 static	int	funny_widelist_names (WideList **, WideList **);
66 
funny_widelist_users(WideList ** left,WideList ** right)67 static	int funny_widelist_users(WideList **left, WideList **right)
68 {
69 	if ((**left).users > (**right).users)
70 		return -1;
71 	else if ((**right).users > (**left).users)
72 		return 1;
73 	else
74 		return my_stricmp((**left).channel, (**right).channel);
75 }
76 
funny_widelist_names(WideList ** left,WideList ** right)77 static	int funny_widelist_names(WideList **left, WideList **right)
78 {
79 	int	comp;
80 
81 	if (!(comp = my_stricmp((**left).channel, (**right).channel)))
82 		return comp;
83 	else if ((**left).users > (**right).users)
84 		return -1;
85 	else if ((**right).users > (**left).users)
86 		return 1;
87 	else
88 		return 0;
89 }
90 
91 
funny_print_widelist(void)92 void funny_print_widelist(void)
93 {
94 	int	i;
95 	char	buffer1[BIG_BUFFER_SIZE];
96 	char	buffer2[BIG_BUFFER_SIZE];
97 	char	*ptr;
98 
99 	if (!wide_list)
100 		return;
101 
102 	if (funny_flags & FUNNY_NAME)
103 		qsort((void *) wide_list, wl_elements, sizeof(WideList *),
104 		(int (*) (const void *, const void *)) funny_widelist_names);
105 	else if (funny_flags & FUNNY_USERS)
106 		qsort((void *) wide_list, wl_elements, sizeof(WideList *),
107 		(int (*) (const void *, const void *)) funny_widelist_users);
108 
109 	set_display_target(NULL, LOG_CRAP);
110 	*buffer1 = '\0';
111 	for (i = 1; i < wl_elements; i++)
112 	{
113 		snprintf(buffer2, sizeof buffer2, "%s(%d) ", wide_list[i]->channel,
114 				wide_list[i]->users);
115 		ptr = strchr(buffer1, '\0');
116 		if (strlen(buffer1) + strlen(buffer2) > current_term->TI_cols - 5)
117 		{
118 			if (do_hook(WIDELIST_LIST, "%s", buffer1))
119 				put_it("%s", convert_output_format(fget_string_var(FORMAT_WIDELIST_FSET), "%s %s", update_clock(GET_TIME), buffer1));
120 			*buffer1 = 0;
121 			strcat(buffer1, buffer2);
122 		}
123 		else
124 			strcpy(ptr, buffer2);
125 	}
126 	if (*buffer1 && do_hook(WIDELIST_LIST, "%s", buffer1))
127 		put_it("%s", convert_output_format(fget_string_var(FORMAT_WIDELIST_FSET), "%s %s", update_clock(GET_TIME), buffer1));
128 
129 	reset_display_target();
130 	for (i = 0; i < wl_elements; i++)
131 	{
132 		new_free(&wide_list[i]->channel);
133 		new_free((char **)&wide_list[i]);
134 	}
135 	new_free((char **)&wide_list);
136 	wl_elements = wl_size = 0;
137 }
138 
funny_list(char * from,char ** ArgList)139 void funny_list(char *from, char **ArgList)
140 {
141 	char	*channel,
142 		*user_cnt,
143 		*line;
144 	WideList **new_list;
145 	int	cnt;
146 	static	char	format[30];
147 	static	int	last_width = -1;
148 
149 	if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR))
150 	{
151 		if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
152 			snprintf(format, sizeof format, "%%s %%-%u.%us %%-5s %%s", /*thing_ansi,*/
153 				(unsigned char) last_width,
154 				(unsigned char) last_width);
155 		else
156 			snprintf(format, sizeof format, "%%s %%s %%-5s %%s"/*, thing_ansi*/);
157 	}
158 	channel = ArgList[0];
159 	user_cnt = ArgList[1];
160 	line = PasteArgs(ArgList, 2);
161 	if (funny_flags & FUNNY_TOPIC && !(line && *line))
162 			return;
163 	cnt = my_atol(user_cnt);
164 	if (funny_min && (cnt < funny_min))
165 		return;
166 	if (funny_max && (cnt > funny_max))
167 		return;
168 	if ((funny_flags & FUNNY_PRIVATE) && (*channel != '*'))
169 		return;
170 	if ((funny_flags & FUNNY_PUBLIC) && ((*channel == '*') || (*channel == '@')))
171 		return;
172 	if (match_str)
173 	{
174 		if (wild_match(match_str, channel) == 0)
175 			return;
176 	}
177 	if (funny_flags & FUNNY_WIDE)
178 	{
179 		if (wl_elements >= wl_size)
180 		{
181 			new_list = (WideList **) new_malloc(sizeof(WideList *) *
182 			    (wl_size + 50));
183 			memset(new_list, 0, sizeof(WideList *) * (wl_size + 50));
184 			if (wl_size)
185 				memcpy(new_list, wide_list, sizeof(WideList *) * wl_size);
186 			wl_size += 50;
187 			new_free((char **)&wide_list);
188 			wide_list = new_list;
189 		}
190 		wide_list[wl_elements] = (WideList *)
191 			new_malloc(sizeof(WideList));
192 		wide_list[wl_elements]->channel = NULL;
193 		wide_list[wl_elements]->users = cnt;
194 		malloc_strcpy(&wide_list[wl_elements]->channel,
195 				(*channel != '*') ? channel : "Prv");
196 		wl_elements++;
197 		return;
198 	}
199 	set_display_target(channel, LOG_CRAP);
200 	if (do_hook(current_numeric, "%s %s %s %s", from,  channel, user_cnt,
201 	    line) && do_hook(LIST_LIST, "%s %s %s", channel, user_cnt, line))
202 	{
203 		if (channel && user_cnt)
204 			put_it("%s", convert_output_format(fget_string_var(FORMAT_LIST_FSET),"%s %s %s %s", update_clock(GET_TIME), *channel == '*'?"Prv":channel, user_cnt, line));
205 	}
206 	reset_display_target();
207 }
208 
209 /* print_funny_names
210  *
211  * This handles presenting the output of a NAMES reply.  It is a cut-down
212  * version of the /SCAN output formatting.
213  */
print_funny_names(char * line)214 void print_funny_names(char *line)
215 {
216     char *t;
217     int count = 0;
218     char buffer[BIG_BUFFER_SIZE];
219     int cols = get_int_var(NAMES_COLUMNS_VAR);
220 
221 	if (!cols)
222 		cols = 1;
223 
224 	if (line && *line)
225 	{
226 		*buffer = 0;
227 
228 		while ((t = next_arg(line, &line))) {
229             char *nick;
230             char *nick_format;
231             char nick_buffer[BIG_BUFFER_SIZE];
232 
233 			if (!count && fget_string_var(FORMAT_NAMES_BANNER_FSET))
234 				strlcat(buffer, convert_output_format(
235                     fget_string_var(FORMAT_NAMES_BANNER_FSET), NULL, NULL),
236                     sizeof buffer);
237 
238             /* Seperate the nick and the possible status presets that might
239              * preceede it. */
240             nick = t + strspn(t, "@%+~-");
241             nick_format = fget_string_var(isme(nick) ?
242                 FORMAT_NAMES_NICK_ME_FSET : FORMAT_NAMES_NICK_FSET);
243             strlcpy(nick_buffer,
244                 convert_output_format(nick_format, "%s", nick),
245                 sizeof nick_buffer);
246 
247             if (nick != t)
248             {
249                 char special = *t;
250 
251                 if (special == '+')
252 				    strlcat(buffer,
253                         convert_output_format(
254                             fget_string_var(FORMAT_NAMES_USER_VOICE_FSET),
255                             "%c %s", special, nick_buffer), sizeof buffer);
256                 else
257 				    strlcat(buffer,
258                         convert_output_format(
259                             fget_string_var(FORMAT_NAMES_USER_CHANOP_FSET),
260                             "%c %s", special, nick_buffer), sizeof buffer);
261             }
262 			else
263 				strlcat(buffer,
264                     convert_output_format(
265                         fget_string_var(FORMAT_NAMES_USER_FSET), ". %s",
266                         nick_buffer), sizeof buffer);
267 
268 			strlcat(buffer, space, sizeof buffer);
269 
270 			if (++count >= cols)
271 			{
272 				put_it("%s", buffer);
273 				*buffer = 0;
274 				count = 0;
275 			}
276 		}
277 
278 		if (count)
279 			put_it("%s", buffer);
280 	}
281 }
282 
funny_namreply(char * from,char ** Args)283 void funny_namreply(char *from, char **Args)
284 {
285 char	*type,
286 	*channel;
287 static	char	format[40];
288 static	int	last_width = -1;
289 register char	*ptr;
290 register char	*line;
291 int user_count = 0;
292 
293 	PasteArgs(Args, 2);
294 	type = Args[0];
295 	channel = Args[1];
296 	line = Args[2];
297 
298 	/* protocol violation by server */
299 	if (!channel || !line)
300 		return;
301 
302 	ptr = line;
303 	while (*ptr)
304 	{
305 		while (*ptr && (*ptr != ' '))
306 			ptr++;
307 		user_count++;
308 		while (*ptr && (*ptr == ' '))
309 			ptr++;
310 	}
311 
312 	if (in_join_list(channel, from_server))
313 	{
314 		set_display_target(channel, LOG_CRAP);
315 		if (do_hook(current_numeric, "%s %s %s %s", from, type, channel,line)
316 			&& do_hook(NAMES_LIST, "%s %s", channel, line)
317 			&& get_int_var(SHOW_CHANNEL_NAMES_VAR))
318 		{
319 			put_it("%s", convert_output_format(fget_string_var(FORMAT_NAMES_FSET), "%s %s %d %d",update_clock(GET_TIME), channel, user_count, user_count));
320 			print_funny_names(line);
321 		}
322 		if ((user_count == 1) && (*line == '@'))
323 			got_info(channel, from_server, GOTNAMES | GOTNEW);
324 		else
325 			got_info(channel, from_server, GOTNAMES);
326 		reset_display_target();
327 		return;
328 	}
329 	if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR))
330 	{
331 		if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0)
332 			snprintf(format, sizeof format, "%%s: %%-%u.%us %%s",
333 				(unsigned char) last_width,
334 				(unsigned char) last_width);
335 		else
336 			strcpy(format, "%s: %s\t%s");
337 	}
338 	if (funny_min && (user_count < funny_min))
339 		return;
340 	else if (funny_max && (user_count > funny_max))
341 		return;
342 	if ((funny_flags & FUNNY_PRIVATE) && (*type == '='))
343 		return;
344 	if ((funny_flags & FUNNY_PUBLIC) && ((*type == '*') || (*type == '@')))
345 		return;
346 	if (type && channel)
347 	{
348 		if (match_str)
349 		{
350 			if (wild_match(match_str, channel) == 0)
351 				return;
352 		}
353 		if (do_hook(current_numeric, "%s %s %s %s", from, type, channel, line) && do_hook(NAMES_LIST, "%s %s", channel, line))
354 		{
355 			set_display_target(channel, LOG_CRAP);
356 			if (fget_string_var(FORMAT_NAMES_FSET))
357 			{
358 				put_it("%s", convert_output_format(fget_string_var(FORMAT_NAMES_FSET), "%s %s %d %d", update_clock(GET_TIME), channel, user_count, user_count));
359 				print_funny_names(line);
360 			}
361 			else
362 			{
363 				switch (*type)
364 				{
365 				case '=':
366 					if (last_width &&(strlen(channel) > last_width))
367 					{
368 						channel[last_width-1] = '>';
369 						channel[last_width] = (char) 0;
370 					}
371 					put_it(format, "Pub", channel, line);
372 					break;
373 				case '*':
374 					put_it(format, "Prv", channel, line);
375 					break;
376 				case '@':
377 					put_it(format, "Sec", channel, line);
378 					break;
379 				}
380 			}
381 			reset_display_target();
382 		}
383 	}
384 }
385 
funny_mode(char * from,char ** ArgList)386 void funny_mode(char *from, char **ArgList)
387 {
388 	char	*mode, *channel;
389 	ChannelList *chan = NULL;
390 
391 	if (!ArgList[0]) return;
392 
393 	channel = ArgList[0];
394 	mode = ArgList[1];
395 	PasteArgs(ArgList, 1);
396 
397 	if (in_join_list(channel, from_server))
398 	{
399 		update_channel_mode(from, channel, from_server, mode, chan);
400 		update_all_status(current_window, NULL, 0);
401 		got_info(channel, from_server, GOTMODE);
402 	}
403 	else
404 	{
405 		set_display_target(channel, LOG_CRAP);
406 		if (do_hook(current_numeric, "%s %s %s", from, channel, mode))
407 			put_it("%s", convert_output_format(fget_string_var(FORMAT_MODE_CHANNEL_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, *FromUserHost ? FromUserHost:"�", channel, mode));
408 		reset_display_target();
409 	}
410 }
411 
update_user_mode(char * modes)412 void update_user_mode(char *modes)
413 {
414 	int	onoff = 1;
415 	char	*p_umodes = get_possible_umodes(from_server);
416 
417 	for (; *modes; modes++)
418 	{
419 		if (*modes == '-')
420 			onoff = 0;
421 		else if (*modes == '+')
422 			onoff = 1;
423 
424 		else if   ((*modes >= 'a' && *modes <= 'z')
425 			|| (*modes >= 'A' && *modes <= 'Z'))
426 		{
427 			size_t 	idx;
428 			int 	c = *modes;
429 
430 			idx = ccspan(p_umodes, c);
431 			if (p_umodes[idx] == 0)
432 				ircpanic("Invalid user mode referenced");
433 			set_server_flag(from_server, idx, onoff);
434 
435 			if (c == 'o' || c == 'O')
436 				set_server_operator(from_server, onoff);
437 #if 0
438 			char c = tolower(*modes);
439 			size_t idx = (size_t) (strchr(umodes, c) - umodes);
440 
441 			set_server_flag(from_server, USER_MODE << idx, onoff);
442 
443 			if (c == 'o' || c == 'O')
444 				set_server_operator(from_server, onoff);
445 #endif
446 		}
447 	}
448 }
449 
reinstate_user_modes(void)450 void	reinstate_user_modes (void)
451 {
452 	char *modes = get_umode(from_server);
453 	if (modes && *modes)
454 		send_to_server("MODE %s +%s", get_server_nickname(from_server), modes);
455 }
456