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 **) ¬ify_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 **) ¬ify_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 **) ¬ify_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 **) ¬ify_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