1 /*
2  * notify.c: a few handy routines to notify you when people enter and leave irc
3  *
4  * Written By Michael Sandrof
5  *
6  * Copyright (c) 1990 Michael Sandrof.
7  * Copyright (c) 1991, 1992 Troy Rollo.
8  * Copyright (c) 1992-2014 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 /*
36  * Revamped by lynX - Dec '91
37  */
38 
39 #include "irc.h"
40 IRCII_RCSID("@(#)$eterna: notify.c,v 1.55 2017/07/04 03:57:08 mrg Exp $");
41 
42 #include "list.h"
43 #include "notify.h"
44 #include "ircaux.h"
45 #include "whois.h"
46 #include "hook.h"
47 #include "server.h"
48 #include "output.h"
49 #include "vars.h"
50 #include "sl_irc.h"
51 
52 /* NotifyList: the structure for the notify stuff */
53 typedef	struct	notify_stru
54 {
55 	struct	notify_stru	*next;	/* pointer to next notify person */
56 	u_char	*nick;			/* nickname of person to notify about */
57 	int	flag;			/* 1=person on irc, 0=person not on irc */
58 }	NotifyList;
59 
60 static	NotifyList	*notify_list = NULL;
61 static	u_char		*last_notify_nick;	/* last detected nickname */
62 
63 u_char *
get_notify_list(int which)64 get_notify_list(int which)
65 {
66 	u_char	*list = NULL;
67 	NotifyList	*tmp;
68 	int first = 0;
69 
70 	malloc_strcpy(&list, empty_string());
71 	for (tmp = notify_list; tmp; tmp = tmp->next)
72 	{
73 		if ((which & NOTIFY_LIST_ALL) == NOTIFY_LIST_ALL ||
74 		   ((which & NOTIFY_LIST_HERE) && tmp->flag) ||
75 		   ((which & NOTIFY_LIST_GONE) && !tmp->flag))
76 		{
77 			if (first++)
78 				malloc_strcat(&list, UP(" "));
79 			malloc_strcat(&list, tmp->nick);
80 		}
81 	}
82 	return list;
83 }
84 
85 /* Rewritten, -lynx */
86 void
show_notify_list(int all)87 show_notify_list(int all)
88 {
89 	u_char	*list;
90 
91 	list = get_notify_list(NOTIFY_LIST_HERE);
92 	if (*list)
93 		say("Currently present: %s", list);
94 	if (all)
95 	{
96 		new_free(&list);
97 		list = get_notify_list(NOTIFY_LIST_GONE);
98 		if (*list)
99 			say("Currently absent: %s", list);
100 	}
101 	new_free(&list);
102 }
103 
104 /* notify: the NOTIFY command.  Does the whole ball-o-wax */
105 void
notify(u_char * command,u_char * args,u_char * subargs)106 notify(u_char *command, u_char *args, u_char *subargs)
107 {
108 	u_char	*nick,
109 		*list = NULL,
110 		*ptr;
111 	int	no_nicks = 1;
112 	int	do_ison = 0;
113 	int	old_server;
114 	NotifyList	*new;
115 
116 	malloc_strcpy(&list, empty_string());
117 	while ((nick = next_arg(args, &args)) != NULL)
118 	{
119 		no_nicks = 0;
120 		while (nick)
121 		{
122 			if ((ptr = my_index(nick, ',')) != NULL)
123 				*ptr++ = '\0';
124 			if (*nick == '-')
125 			{
126 				nick++;
127 				if (*nick)
128 				{
129 					if ((new = (NotifyList *) remove_from_list((List **)(void *)&notify_list, nick)) != NULL)
130 					{
131 						new_free(&(new->nick));
132 						new_free(&new);
133 						say("%s removed from notification list", nick);
134 					}
135 					else
136 						say("%s is not on the notification list", nick);
137 				}
138 				else
139 				{
140 					while ((new = notify_list))
141 					{
142 						notify_list = new->next;
143 						new_free(&new->nick);
144 						new_free(&new);
145 					}
146 					say("Notify list cleared");
147 				}
148 			}
149 			else
150 			{
151 				/* compatibility */
152 				if (*nick == '+')
153 					nick++;
154 				if (*nick)
155 				{
156 					do_ison = 1;
157 					if (my_index(nick, '*'))
158 						say("Wildcards not allowed in NOTIFY nicknames!");
159 					else
160 					{
161 
162 						if ((new = (NotifyList *) remove_from_list((List **)(void *)&notify_list, nick)) != NULL)
163 						{
164 							new_free(&(new->nick));
165 							new_free(&new);
166 						}
167 						new = new_malloc(sizeof *new);
168 						new->nick = NULL;
169 						malloc_strcpy(&(new->nick), nick);
170 						new->flag = 0;
171 						add_to_list((List **)(void *)&notify_list, (List *) new);
172 						old_server = set_from_server(get_primary_server());
173 						if (server_get_2_6_2(get_from_server()))
174 						{
175 							malloc_strcat(&list, new->nick);
176 							malloc_strcat(&list, UP(" "));
177 						}
178 						else
179 							add_to_whois_queue(new->nick, whois_notify, NULL);
180 						say("%s added to the notification list", nick);
181 						set_from_server(old_server);
182 					}
183 				} else
184 					show_notify_list(0);
185 			}
186 			nick = ptr;
187 		}
188 	}
189 	if (do_ison) {
190 		old_server = set_from_server(get_primary_server());
191 		add_ison_to_whois(list, ison_notify);
192 		set_from_server(old_server);
193 	}
194 	new_free(&list);
195 	if (no_nicks)
196 		show_notify_list(1);
197 }
198 
199 /*
200  * do_notify: This simply goes through the notify list, sending out a WHOIS
201  * for each person on it.  This uses the fancy whois stuff in whois.c to
202  * figure things out.  Look there for more details, if you can figure it out.
203  * I wrote it and I can't figure it out.
204  *
205  * Thank you Michael... leaving me bugs to fix :) Well I fixed them!
206  */
207 void
do_notify(void)208 do_notify(void)
209 {
210 	static	int	location = 0;
211 	int	count,
212 		c2,
213 		old_server;
214 	StringList	*sl;
215 	NotifyList	*tmp;
216 
217 	/* ICB doesn't support /notify */
218 	if (server_get_version(get_primary_server()) == ServerICB)
219 		return;
220 	old_server = set_from_server(get_primary_server());
221 	sl = sl_init();
222 	for (tmp = notify_list, c2 = count = 0; tmp; tmp = tmp->next, count++)
223 	{
224 		if (count >= location && count < location + 40)
225 		{
226 			c2++;
227 			sl_add(sl, CP(tmp->nick));
228 		}
229 	}
230 	if (c2)
231 	{
232 		u_char	*buf = sl_concat(sl, UP(" "));
233 		add_ison_to_whois(buf, ison_notify);
234 		new_free(&buf);
235 	}
236 	sl_free(sl, 0);
237 	if ((location += 40) > count)
238 		location = 0;
239 	set_from_server(old_server);
240 }
241 
242 /*
243  * notify_mark: This marks a given person on the notify list as either on irc
244  * (if flag is 1), or not on irc (if flag is 0).  If the person's status has
245  * changed since the last check, a message is displayed to that effect.  If
246  * the person is not on the notify list, this call is ignored
247  * doit if passed as 0 means it comes from a join, or a msg, etc, not from
248  * an ison reply.  1 is the other..
249  * we also bail out if the get_primary_server() != from_server and the from-server
250  * is valid.
251  *
252  * NOTE:  this function should be called with no particular to_window or other
253  * variables set that would affect what window it would be displayed in.
254  * ideally, a message_from(NULL, LOG_CURRENT) should be the what is the
255  * current window level.
256  */
257 void
notify_mark(u_char * nick,int flag,int doit)258 notify_mark(u_char *nick, int flag, int doit)
259 {
260 	NotifyList	*tmp;
261 	u_char	*s = get_string_var(NOTIFY_HANDLER_VAR);
262 	const	int	from_server = get_from_server();
263 
264 	if (from_server != get_primary_server() && from_server != -1)
265 		return;
266 	/* if (!s || (!doit && 'O' == *s)) - this broke notify -gkm *//* old notify */
267 	if (!doit && 'O' == *s)		/* old notify */
268 		return;
269 	if ('N' == *s)			/* noisy notify */
270 		doit = 1;
271 	if ((tmp = (NotifyList *) list_lookup((List **)(void *)&notify_list, nick,
272 			0, 0)) != NULL)
273 	{
274 		if (flag)
275 		{
276 			if (tmp->flag != 1)
277 			{
278 				if (tmp->flag != -1 && doit && do_hook(NOTIFY_SIGNON_LIST, "%s", nick))
279 					say("Signon by %s detected", nick);
280 				/*
281 				 * copy the correct case of the nick
282 				 * into our array  ;)
283 				 */
284 				malloc_strcpy(&(tmp->nick), nick);
285 				malloc_strcpy(&last_notify_nick, nick);
286 				tmp->flag = 1;
287 			}
288 		}
289 		else
290 		{
291 			if (tmp->flag == 1 && doit && do_hook(NOTIFY_SIGNOFF_LIST, "%s", nick))
292 				say("Signoff by %s detected", nick);
293 			tmp->flag = 0;
294 		}
295 	}
296 }
297 
298 void
save_notify(FILE * fp)299 save_notify(FILE *fp)
300 {
301 	NotifyList	*tmp;
302 
303 	if (notify_list)
304 	{
305 		fprintf(fp, "NOTIFY");
306 		for (tmp = notify_list; tmp; tmp = tmp->next)
307 			fprintf(fp, " %s", tmp->nick);
308 		fprintf(fp, "\n");
309 	}
310 }
311 
312 /* I hate broken compilers -mrg */
313 static	char	*vals[] = { "NOISY", "QUIET", "OLD", NULL };
314 
315 void
set_notify_handler(u_char * value)316 set_notify_handler(u_char *value)
317 {
318 	size_t	len;
319 	int	i;
320 	char	*s;
321 
322 	if (!value)
323 		value = empty_string();
324 	for (i = 0, len = my_strlen(value); (s = vals[i]); i++)
325 		if (0 == my_strnicmp(value, UP(s), len))
326 			break;
327 	set_string_var(NOTIFY_HANDLER_VAR, UP(s));
328 	return;
329 }
330 
331 u_char *
get_last_notify_nick(void)332 get_last_notify_nick(void)
333 {
334 	return last_notify_nick;
335 }
336