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-2000 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 #include "dma.h"
41 IRCII_RCSID("@(#)$Id: notify.c,v 1.34 2000/05/11 03:35:16 mrg Exp $");
42 
43 #include "list.h"
44 #include "notify.h"
45 #include "ircaux.h"
46 #include "whois.h"
47 #include "hook.h"
48 #include "server.h"
49 #include "output.h"
50 #include "vars.h"
51 #include "status.h"
52 
53 #include "ninja.h"
54 #include "friends.h"
55 
56 /* NotifyList: the structure for the notify stuff */
57 typedef	struct	notify_stru
58 {
59 	struct	notify_stru	*next;	/* pointer to next notify person */
60 	u_char	*nick;			/* nickname of person to notify about */
61 	u_char	*user;			/* username of person to notify about */
62 	u_char	*host;			/* hostname of person to notify about */
63 	u_char	*mask;			/* host mask to check of person to notify about */
64 	int	flags;			/* based on the following flags  WAS: 1=person on irc, 0=person not on irc */
65 #define NOTIFY_ONLINE	0x01
66 #define NOTIFY_AWAY	0x01
67 #define NOTIFY_LOG	0x01
68 }	NotifyList;
69 
70 static	NotifyList	*notify_list = (NotifyList *) 0;
71 
72 static	void	free_notify _((NotifyList **));
73 
74 /* Rewritten, -lynx */
75 void
show_notify_list(all)76 show_notify_list(all)
77 	int	all;
78 {
79    NotifyList	*tmp;
80    u_char	*list = (u_char *) 0;
81    int		first = 1;
82 
83    for (tmp = notify_list; tmp; tmp = tmp->next)
84      {
85 	if (tmp->flags & NOTIFY_ONLINE)
86 	  {
87 	     if (first)
88 	       {
89 		  first = 0;
90 		  say("Currently present:");
91 	       }
92 	     put_raw("   %-15s %12s@%s", tmp->nick, tmp->user, tmp->host);
93 	  }
94      }
95    if (all)
96      {
97 	malloc_strcpy(&list, empty_string);
98 	for (tmp = notify_list; tmp; tmp = tmp->next)
99 	  {
100 	     if (!(tmp->flags & NOTIFY_ONLINE))
101 	       {
102 		  malloc_strcat(&list, UP(" "));
103 		  malloc_strcat(&list, tmp->nick);
104 	       }
105 	  }
106 	if (*list) say("Currently absent:%s", list);
107 	new_free(&list);
108      }
109 }
110 
111 /* notify: the NOTIFY command.  Does the whole ball-o-wax */
112 /*ARGSUSED*/
113 void
notify(command,args,subargs)114 notify(command, args, subargs)
115 	u_char	*command,
116 		*args,
117 		*subargs;
118 {
119    u_char	*nick,
120      *list = (u_char *) 0,
121      *ptr;
122    int	no_nicks = 1;
123    int	do_ison = 0;
124    int	old_server = from_server;
125    NotifyList	*new;
126    u_char *mask = UNULL, *tmp = UNULL;
127    int count = 0;
128 
129    malloc_strcpy(&list, empty_string);
130    while ((nick = next_arg(args, &args)) != NULL)
131      {
132 	no_nicks = 0;
133 	while (nick)
134 	  {
135 	     if ((ptr = my_index(nick, ',')) != NULL)
136 	       *ptr++ = '\0';
137 	     if (*nick == '-')
138 	       {
139 		  nick++;
140 		  if (*nick)
141 		    {
142 		       if ((new = (NotifyList *) remove_from_list((List **) &notify_list, nick)) != NULL)
143 			 {
144 			    free_notify(&new);
145 			    say("%s removed from notification list", nick);
146 			 }
147 		       else
148 			 say("%s is not on the notification list", nick);
149 		    }
150 		  else
151 		    {
152 		       while ((new = notify_list))
153 			 {
154 			    notify_list = new->next;
155 			    free_notify(&new);
156 			 }
157 		       say("Notify list cleared");
158 		    }
159 	       }
160 	     else
161 	       {
162 		  /* compatibility */
163 		  if (*nick == '+')
164 		    nick++;
165 		  if (*nick)
166 		    {
167 		       do_ison = 1;
168 		       /* ninja extension, get the mask */
169 		       if (match("*!*@*", nick))
170 			 {
171 			    dma_strcpy(&tmp, nick);
172 			    mask = my_index(tmp, '!');
173 			    *mask++ = '\0';
174 			    nick = tmp;
175 			 }
176 		       if (my_index(nick, '*'))
177 			 say("Wildcards not allowed in NOTIFY nicknames!");
178 		       else
179 			 {
180 
181 			    if ((new = (NotifyList *) remove_from_list((List **) &notify_list, nick)) != NULL)
182 			      free_notify(&new);
183 			    new = (NotifyList *) new_malloc(sizeof(NotifyList));
184 			    /*
185 			     * dma_malloc bzero's
186 			    new->nick = (u_char *) 0;
187 			    new->flag = 0;
188 			     */
189 			    if (*nick == '%')
190 			      {
191 				 new->flags |= NOTIFY_LOG;
192 				 nick++;
193 			      }
194 			    malloc_strcpy(&(new->nick), nick);
195 			    if (mask)
196 			      malloc_strcpy(&(new->mask), mask);
197 			    add_to_list((List **) &notify_list, (List *) new);
198 			    from_server = primary_server;
199 			    if (get_server_2_6_2(from_server))
200 			      {
201 				 if (count == 5)
202 				   {
203 				      add_userhost_to_whois(list, userhost_notify);
204 				      new_free(&list);
205 				      count = 0;
206 				   }
207 				 count++;
208 				 if (list)
209 				   malloc_strcat(&list, UP(" "));
210 				 malloc_strcat(&list, new->nick);
211 			      }
212 			    else
213 			      add_userhost_to_whois(new->nick, userhost_notify);
214 			    say("%s added to the notification list", nick);
215 			    from_server = old_server;
216 			 }
217 		    }
218 		  else
219 		    show_notify_list(0);
220 	       }
221 	     nick = ptr;
222 	  }
223      }
224    if (count && list) {
225       from_server = primary_server;
226       add_userhost_to_whois(list, userhost_notify);
227       from_server = old_server;
228    }
229    new_free(&list);
230    if (no_nicks)
231      show_notify_list(1);
232 }
233 
234 /*
235  * do_notify: This simply goes through the notify list, sending out a WHOIS
236  * for each person on it.  This uses the fancy whois stuff in whois.c to
237  * figure things out.  Look there for more details, if you can figure it out.
238  * I wrote it and I can't figure it out.
239  *
240  * Thank you Michael... leaving me bugs to fix :) Well I fixed them!
241  */
242 void
do_notify()243 do_notify()
244 {
245    int	count = 0,
246      old_server = from_server;
247    u_char	buf[BIG_BUFFER_SIZE+1], *p = buf;
248    u_int	nlen;
249    NotifyList	*tmp;
250 
251    /* ICB doesn't support /notify */
252 #ifdef SUPPORT_ICB
253    if (get_server_version(primary_server) == ServerICB)
254      return;
255 #endif
256    from_server = primary_server;
257    *p = '\0';
258    for (tmp = notify_list; tmp; tmp = tmp->next)
259      {
260 	nlen = strlen(tmp->nick);
261 	if ((sizeof(buf) - (p - buf) < nlen + 2)
262 	    || count == 5)
263 	  {
264 	     /* kludge */
265 	     if (count == 0)
266 	       break;
267 	     /* terminate/add/reset */
268 	     *p = '\0';
269 	     p = buf;
270 	     add_userhost_to_whois(p, userhost_notify);
271 	     *p = '\0';
272 	     count = 0;
273 	  }
274 
275 	/* add one to the list.. */
276 	if (*buf != '\0')
277 	  {
278 	     my_strcat(p, " ");
279 	     p++;
280 	  }
281 	my_strncat(p, tmp->nick, nlen);
282 	p += nlen;
283 	count++;
284      }
285    if (count)
286      {
287 	*p = '\0';
288 	add_userhost_to_whois(buf, userhost_notify);
289      }
290    from_server = old_server;
291 }
292 
293 /*
294  * notify_mark: This marks a given person on the notify list as either on irc
295  * (if flag is 1), or not on irc (if flag is 0).  If the person's status has
296  * changed since the last check, a message is displayed to that effect.  If
297  * the person is not on the notify list, this call is ignored
298  * doit if passed as 0 means it comes from a join, or a msg, etc, not from
299  * an ison reply.  1 is the other..
300  * we also bail out if the primary_server != from_server and the from-server
301  * is valid.
302  *
303  * NOTE:  this function should be called with no particular to_window or other
304  * variables set that would affect what window it would be displayed in.
305  * ideally, a message_from((u_char *) 0, LOG_CURRENT) should be the what is the
306  * current window level.
307  */
308 void
notify_mark(nick,flag,doit,user,host,away)309 notify_mark(nick, flag, doit, user, host, away)
310 	u_char	*nick;
311 	int	flag;
312 	int	doit;
313 	u_char	*user;
314 	u_char	*host;
315 	int	away;
316 {
317    NotifyList	*tmp;
318    u_char	*s = get_string_var(NOTIFY_HANDLER_VAR);
319    int		matched = 1;
320 
321    if (from_server != primary_server && from_server != -1)
322      return;
323    /* if (!s || (!doit && 'O' == *s)) - this broke notify -gkm *//* old notify */
324    if (!doit && 'O' == *s)		/* old notify */
325      return;
326    if ('N' == *s)			/* noisy notify */
327      doit = 1;
328    if ((tmp = (NotifyList *) list_lookup((List **) &notify_list, nick,
329 					 !USE_WILDCARDS, !REMOVE_FROM_LIST)) != NULL)
330      {
331 	if (tmp->mask)
332 	  {
333 	     u_char tbuf[384];
334 	     snprintf(tbuf, sizeof(tbuf)-1, "%s@%s", user, host);
335 	     tbuf[sizeof(tbuf)-1] = '\0';
336 	     matched = match(tmp->mask, tbuf);
337 	  }
338 	if (flag)
339 	  {
340 	     if (!(tmp->flags & NOTIFY_ONLINE))
341 	       {
342 		  u_char *away_str = UP(" (away)");
343 		  if (doit && matched && do_hook(NOTIFY_SIGNON_LIST, "%s %s %s %s", nick, user, host, away ? "G" : "H"))
344 		    say("Notify %s: %s (%s@%s) is now online.%s", update_clock(0, 0, GET_TIME), nick, user, host, away ? away_str : empty_string);
345 		  if ((tmp->flags & NOTIFY_LOG) && doit && matched && server_list[from_server].away_set)
346 		    add_to_awaylog("Notify %s: %s (%s@%s) is now online.%s", update_clock(0, 0, GET_TIME), nick, user, host, away ? away_str : empty_string);
347 		  /*
348 		   * copy the correct case of the nick
349 		   * into our array  ;)
350 		   */
351 		  malloc_strcpy(&(tmp->nick), nick);
352 		  malloc_strcpy(&(tmp->user), user);
353 		  malloc_strcpy(&(tmp->host), host);
354 		  malloc_strcpy(&last_notify_nick, nick);
355 		  tmp->flags |= NOTIFY_ONLINE;
356 
357 		  /* see if we do something for this friend upon notify */
358 		  check_friend_notify(nick, user, host);
359 	       }
360 	  }
361 	else
362 	  {
363 	     if ((tmp->flags & NOTIFY_ONLINE) && doit && matched && do_hook(NOTIFY_SIGNOFF_LIST, "%s %s %s", nick, tmp->user, tmp->host))
364 	       say("Notify %s: %s (%s@%s) has left irc.", update_clock(0, 0, GET_TIME), nick, tmp->user, tmp->host);
365 	     tmp->flags &= ~NOTIFY_ONLINE;
366 	  }
367      }
368 }
369 
370 int
save_notify(fp)371 save_notify(fp)
372 	FILE	*fp;
373 {
374    NotifyList	*tmp;
375    int		count = 0, tc = 0;
376    u_char	*list = UNULL;
377 
378    if (notify_list)
379      {
380 	for (tmp = notify_list; tmp; tmp = tmp->next)
381 	  {
382 	     if (!list)
383 	       malloc_strcat(&list, " ");
384 	     if (tmp->flags & NOTIFY_LOG)
385 	       malloc_strcat(&list, "%");
386 	     malloc_strcat(&list, tmp->nick);
387 	     if (tmp->mask)
388 	       {
389 		  malloc_strcat(&list, "!");
390 		  malloc_strcat(&list, tmp->mask);
391 	       }
392 
393 	     count++;
394 	     tc++;
395 
396 	     if (count == 5)
397 	       {
398 		  fprintf(fp, "NOTIFY %s\n", list);
399 		  new_free(&list);
400 		  count = 0;
401 	       }
402 	  }
403 	if (count > 0 && list)
404 	  {
405 	     fprintf(fp, "NOTIFY %s\n", list);
406 	     new_free(&list);
407 	  }
408      }
409    return tc;
410 }
411 
412 /* I hate broken compilers -mrg */
413 static	char	*vals[] = { "NOISY", "QUIET", "OLD", (char *) 0 };
414 
415 void
set_notify_handler(value)416 set_notify_handler(value)
417 	u_char	*value;
418 {
419    size_t	len;
420    int	i;
421    char	*s;
422 
423    if (!value)
424      value = empty_string;
425    for (i = 0, len = my_strlen(value); (s = vals[i]); i++)
426      if (0 == my_strnicmp(value, UP(s), len))
427        break;
428    set_string_var(NOTIFY_HANDLER_VAR, UP(s));
429    return;
430 }
431 
432 static void
free_notify(nent)433 free_notify(nent)
434     NotifyList **nent;
435 {
436    NotifyList *new = *nent;
437 
438    new_free(&(new->nick));
439    new_free(&(new->user));
440    new_free(&(new->host));
441    new_free(&(new->mask));
442    new_free(&new);
443 }
444