1 /*
2  * notify.c: a few handy routines to notify you when people enter and leave irc
3  *
4  * Written By Michael Sandrof
5  * Copyright(c) 1990
6  * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
7  *
8  * Modified Colten Edwards 96
9  */
10 
11 
12 #include "irc.h"
13 static char cvsrevision[] = "$Id: notify.c 457 2013-11-11 21:29:05Z tcava $";
14 CVS_REVISION(notify_c)
15 #include "struct.h"
16 
17 #include "list.h"
18 #include "notify.h"
19 #include "ircaux.h"
20 #include "who.h"
21 #include "hook.h"
22 #include "server.h"
23 #include "output.h"
24 #include "vars.h"
25 #include "timer.h"
26 #include "misc.h"
27 #include "status.h"
28 #include "userlist.h"
29 #include "hash2.h"
30 #include "cset.h"
31 #include "server.h"
32 #define MAIN_SOURCE
33 #include "modval.h"
34 
35 extern Server *server_list;
36 
37 #define NOTIFY_LIST(s)          (&(server_list[s].notify_list))
38 #define NOTIFY_MAX(s)           (NOTIFY_LIST(s)->max)
39 #define NOTIFY_ITEM(s, i)       (NOTIFY_LIST(s)->list[i])
40 
41 #define WATCH_LIST(s)          (&(server_list[s].watch_list))
42 #define WATCH_MAX(s)           (WATCH_LIST(s)->max)
43 #define WATCH_ITEM(s, i)       (WATCH_LIST(s)->list[i])
44 
45 void batch_notify_userhost (char *);
46 void dispatch_notify_userhosts (void);
47 void notify_userhost_dispatch (UserhostItem *, char *, char *);
48 void notify_userhost_reply (char *, char *);
49 
rebuild_notify_ison(int server)50 void	rebuild_notify_ison (int server)
51 {
52 	char *stuff;
53 	int i;
54 	if (from_server == -1)
55 		return;
56 	stuff = NOTIFY_LIST(from_server)->ison;
57 
58 	if (NOTIFY_LIST(from_server)->ison)
59 		NOTIFY_LIST(from_server)->ison[0] = 0;
60 
61 	for (i = 0; i < NOTIFY_MAX(from_server); i++)
62 	{
63 		m_s3cat(&(NOTIFY_LIST(from_server)->ison),
64 			space, NOTIFY_ITEM(from_server, i)->nick);
65 	}
66 }
67 
rebuild_all_ison(void)68 void	rebuild_all_ison (void)
69 {
70 	int i;
71 	int ofs = from_server;
72 	for (i = 0; i < server_list_size(); i++)
73 	{
74 		from_server = i;
75 		rebuild_notify_ison(i);
76 	}
77 	from_server = ofs;
78 }
79 
80 
81 
ison_notify(char * AskedFor,char * AreOn)82 void ison_notify(char *AskedFor, char *AreOn)
83 {
84 	char	*NextAsked;
85 	char	*NextGot;
86 
87 	NextGot = next_arg(AreOn, &AreOn);
88 	while ((NextAsked = next_arg(AskedFor, &AskedFor)) != NULL)
89 	{
90 		if (NextGot && !my_stricmp(NextAsked, NextGot))
91 		{
92 			notify_mark(NextAsked, NULL, 1, 1);
93 			NextGot = next_arg(AreOn, &AreOn);
94 		}
95 		else
96 			notify_mark(NextAsked, NULL, 0, 1);
97 	}
98         dispatch_notify_userhosts();
99 }
100 
101 
add_to_notify_queue(char * buffer)102 void add_to_notify_queue(char *buffer)
103 {
104 	char *lame = LOCAL_COPY(buffer);
105 	isonbase(lame, ison_notify);
106 }
107 
notify_count(int server,int * on,int * off)108 void notify_count(int server, int *on, int *off)
109 {
110 	NotifyItem *tmp;
111 	int i;
112 	if (server <= -1)
113 		return;
114 
115 	if (on) *on = 0;
116 	if (off) *off = 0;
117 	for (i = 0; i < NOTIFY_MAX(server); i++)
118 	{
119 		tmp = NOTIFY_ITEM(server, i);
120 		if (tmp->flag)
121 		{
122 			if (on) (*on)++;
123 		}
124 		else
125 		{
126 			if (off) (*off)++;
127 		}
128 	}
129 }
130 
131 /* Rewritten, -lynx */
show_notify_list(int all)132 void show_notify_list(int all)
133 {
134 	int count = 0;
135 	int i;
136 	char lastseen[20];
137 	char period[20];
138 	char timeson[20];
139 	NotifyItem *tmp;
140 
141 	if (from_server == -1)
142 		return;
143 
144 	for (i = 0; i < NOTIFY_MAX(from_server); i++)
145 	{
146 		tmp = NOTIFY_ITEM(from_server, i);
147 		if (tmp->flag)
148 		{
149 			if (count == 0)
150 			{
151 				if (do_hook(NOTIFY_HEADER_LIST, "%s", "Online users"))
152 				{
153 					put_it("%s", convert_output_format("$G Online Users", NULL, NULL));
154 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_ON_FSET), "%s %s %s %s %s", "Nick", "UserHost", "Times", "Period", "Last seen"));
155 				}
156 			}
157 			strcpy(period, ltoa(tmp->period));
158 			strcpy(timeson, ltoa(tmp->times));
159 			strcpy(lastseen, ltoa(now - tmp->added));
160 			if (do_hook(NOTIFY_LIST, "%s %s %d %s %s %s", tmp->nick, tmp->host?tmp->host:"unknown@unknown", tmp->flag, timeson, period, lastseen))
161 				put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_ON_FSET), "%s %s %s %s %s", tmp->nick, tmp->host?tmp->host:tmp->looking, timeson, lastseen, "now" ));
162 			count++;
163 		}
164 	}
165 	count = 0;
166 	for (i = 0; i < NOTIFY_MAX(from_server); i++)
167 	{
168 		tmp = NOTIFY_ITEM(from_server, i);
169 		if ((all && !tmp->flag) || (tmp->times && !tmp->flag))
170 		{
171 			if (count == 0)
172 			{
173 				if (do_hook(NOTIFY_HEADER_LIST, "%s", "Offline users"))
174 				{
175 					put_it("%s", convert_output_format("$G Offline Users", NULL, NULL));
176 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_OFF_FSET), "%s %s %s %s %s", "Nick", "UserHost", "Times", "Period", "Last seen"));
177 				}
178 			}
179 			strcpy(period, ltoa(tmp->period));
180 			strcpy(timeson, ltoa(tmp->times));
181 			strcpy(lastseen, ltoa(now - tmp->lastseen));
182 			if (do_hook(NOTIFY_LIST, "%s %s %d %s %s %s", tmp->nick, tmp->host?tmp->host:"unknown@unknown", tmp->flag, timeson, period, lastseen))
183 			{
184 				if (!tmp->times)
185 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_OFF_FSET), "%s %s %s %s %s", tmp->nick, tmp->host?tmp->host:tmp->looking, "never", "none", "n/a"));
186 				else
187 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_OFF_FSET), "%s %s %s %s %s", tmp->nick, tmp->host?tmp->host:tmp->looking, timeson, period, lastseen));
188 			}
189 			count++;
190 		}
191 	}
192 }
193 
194 /* notify: the NOTIFY command.  Does the whole ball-o-wax */
BUILT_IN_COMMAND(notify)195 BUILT_IN_COMMAND(notify)
196 {
197 	char	*nick,
198 		*list = NULL,
199 		*ptr;
200 	int	no_nicks = 1;
201 	int	do_ison = 0;
202 	int	servnum = from_server;
203 	int	shown = 0;
204 	NotifyItem	*new_n;
205 
206 	malloc_strcpy(&list, empty_string);
207 	while ((nick = next_arg(args, &args)))
208 	{
209 		for (no_nicks = 0; nick; nick = ptr)
210 		{
211 			char *host = NULL;
212 			shown = 0;
213 			if ((ptr = strchr(nick, ',')) != NULL)
214 				*ptr++ = 0;
215 			if ((host = strchr(nick, '!')))
216 				*host++ = 0;
217 			else
218 				host = "*@*";
219 
220 			if (*nick == '-')
221 			{
222 				nick++;
223 
224 				if (*nick)
225 				{
226 					for (servnum = 0; servnum < server_list_size(); servnum++)
227 					{
228 						if ((new_n = (NotifyItem *)remove_from_array(
229 							(Array *)NOTIFY_LIST(servnum), nick)))
230 						{
231 							new_free(&new_n->nick);
232 							new_free(&new_n->host);
233 							new_free(&new_n->looking);
234 							new_free((char **)&new_n);
235 
236 							if (!shown)
237 							{
238 								bitchsay("%s!%s removed from notification list", nick, host);
239 								shown = 1;
240 							}
241 						}
242 						else
243 						{
244 							if (!shown)
245 							{
246 								bitchsay("%s!%s is not on the notification list", nick, host);
247 								shown = 1;
248 							}
249 						}
250 					}
251 				}
252 				else
253 				{
254 					for (servnum = 0; servnum < server_list_size(); servnum++)
255 					{
256 						while ((new_n = (NotifyItem *)array_pop(
257 							(Array *)NOTIFY_LIST(servnum), 0)))
258 						{
259 							new_free(&new_n->nick);
260 							new_free(&new_n->host);
261 							new_free(&new_n->looking);
262 							new_free((char **)&new_n);
263 						}
264 					}
265 					bitchsay("Notify list cleared");
266 				}
267 			}
268 			else
269 			{
270 				/* compatibility */
271 				if (*nick == '+')
272 					nick++;
273 
274 				if (*nick)
275 				{
276 					int added = 0;
277 					if (strchr(nick, '*'))
278 						bitchsay("Wildcards not allowed in NOTIFY nicknames!");
279 					else
280 					{
281 						for (servnum = 0; servnum < server_list_size(); servnum++)
282 						{
283 
284 							if ((new_n = (NotifyItem *)array_lookup(
285 								(Array *)NOTIFY_LIST(servnum), nick, 0, 0)))
286 							{
287 								malloc_strcpy(&new_n->looking, host);
288 								new_n->flag = 0;
289 								continue;	/* Already there! */
290 							}
291 
292 							new_n = (NotifyItem *)new_malloc(sizeof(NotifyItem));
293 							new_n->nick = m_strdup(nick);
294 							new_n->looking = m_strdup(host);
295 							new_n->host = NULL;
296 							new_n->flag = 0;
297 							add_to_array((Array *)NOTIFY_LIST(servnum),
298 							     (Array_item *)new_n);
299 							added = 1;
300 						}
301 						if (added)
302 						{
303 							m_s3cat(&list, space, new_n->nick);
304 							do_ison = 1;
305 						}
306 						bitchsay("%s!%s added to the notification list", nick, host);
307 					}
308 				} else
309 					show_notify_list(1);
310 			}
311 		}
312 	}
313 
314 	if (do_ison && get_int_var(NOTIFY_VAR))
315 	{
316 		int ofs = from_server;
317 		for (servnum = 0; servnum < server_list_size(); servnum++)
318 		{
319 			from_server = servnum;
320 			if (is_server_connected(from_server) && list && *list)
321 				add_to_notify_queue(list);
322 		}
323 		from_server = ofs;
324 	}
325 
326 	new_free(&list);
327 	rebuild_all_ison();
328 	if (no_nicks)
329 		show_notify_list(0);
330 }
331 
332 /*
333  * do_notify: This simply goes through the notify list, sending out a WHOIS
334  * for each person on it.  This uses the fancy whois stuff in whois.c to
335  * figure things out.
336  */
do_notify(void)337 void do_notify(void)
338 {
339 	int	old_from_server = from_server;
340 	int	servnum;
341 	static	time_t		last_notify = 0;
342 	int		interval = get_int_var(NOTIFY_INTERVAL_VAR);
343 	time_t current_time = time(NULL);
344 
345 	if (current_time < last_notify)
346 		last_notify = current_time;
347 	else if (!interval || interval > (current_time - last_notify))
348 		return;		/* Not yet */
349 
350 	last_notify = current_time;
351 
352 	if (!server_list_size() || !get_int_var(NOTIFY_VAR))
353 		return;
354 	for (servnum = 0; servnum < server_list_size(); servnum++)
355 	{
356 		if (is_server_connected(servnum) && !get_server_watch(servnum))
357 		{
358 			from_server = servnum;
359 			if (NOTIFY_LIST(servnum)->ison && *NOTIFY_LIST(servnum)->ison)
360 			{
361 				char *lame = LOCAL_COPY(NOTIFY_LIST(servnum)->ison);
362 				isonbase(lame, ison_notify);
363 			}
364 		}
365 	}
366 	from_server = old_from_server;
367 	return;
368 }
369 
check_auto_invite(char * nick,char * userhost)370 void check_auto_invite(char *nick, char *userhost)
371 {
372 #ifdef WANT_USERLIST
373 ChannelList *chan = NULL;
374 UserList *tmp = NULL;
375 	for (chan = get_server_channels(from_server); chan; chan = chan->next)
376 	{
377 		if ((tmp = lookup_userlevelc("*", userhost, chan->channel, NULL)))
378 		{
379 			NickList *n = NULL;
380 			n = find_nicklist_in_channellist(nick, chan, 0);
381 			if (!n && chan->have_op && get_cset_int_var(chan->csets, AINV_CSET) && (tmp->flags & ADD_INVITE) && get_cset_int_var(chan->csets, AINV_CSET))
382 			{
383 				bitchsay("Auto-inviting %s to %s", nick, chan->channel);
384 				send_to_server("NOTICE %s :Auto-invite from %s", nick, get_server_nickname(from_server));
385 				send_to_server("INVITE %s %s%s%s", nick, chan->channel, chan->key?space:empty_string, chan->key?chan->key:empty_string);
386 			}
387 		}
388 		tmp = NULL;
389 	}
390 #endif
391 }
392 
393 
394 
395 
396 static char *batched_notify_userhosts = NULL;
397 static int batched_notifies = 0;
398 
batch_notify_userhost(char * nick)399 void batch_notify_userhost (char *nick)
400 {
401 	m_s3cat(&batched_notify_userhosts, space, nick);
402 	batched_notifies++;
403 }
404 
dispatch_notify_userhosts(void)405 void dispatch_notify_userhosts (void)
406 {
407 	if (batched_notify_userhosts)
408 	{
409 		if (x_debug & DEBUG_NOTIFY)
410 			yell("Dispatching notifies to server [%d], [%s]", from_server, batched_notify_userhosts);
411 		userhostbase(batched_notify_userhosts, notify_userhost_dispatch, 1, NULL);
412 		new_free(&batched_notify_userhosts);
413 		batched_notifies = 0;
414 	}
415 }
416 
notify_userhost_dispatch(UserhostItem * stuff,char * nick,char * text)417 void notify_userhost_dispatch (UserhostItem *stuff, char *nick, char *text)
418 {
419 	char userhost[BIG_BUFFER_SIZE + 1];
420 
421 	snprintf(userhost, sizeof userhost, "%s@%s", stuff->user, stuff->host);
422 	notify_userhost_reply(stuff->nick, userhost);
423 }
424 
425 #if 0
426 <MadHack> #0  0x809a571 in n_malloc_strcpy ()
427 <MadHack> #1  0x80b400e in notify_userhost_reply ()
428 <MadHack> #2  0x80b3f65 in notify_userhost_dispatch ()
429 <MadHack> #3  0x80d2ef0 in userhost_returned ()
430 <MadHack> #4  0x80b61bd in numbered_command ()
431 hard_uh_notify is on
432 #endif
433 
notify_userhost_reply(char * nick,char * userhost)434 void notify_userhost_reply (char *nick, char *userhost)
435 {
436 	NotifyItem *tmp;
437 
438 	if ((tmp = (NotifyItem *)array_lookup(
439 				(Array *)NOTIFY_LIST(from_server), nick, 0, 0)))
440 	{
441 		set_display_target(nick, LOG_CRAP);
442 		malloc_strcpy(&tmp->nick, nick);
443 		if (userhost)
444 		{
445 			malloc_strcpy(&tmp->host, userhost);
446 			if (!wild_match(tmp->looking, userhost))
447 			{
448 				reset_display_target();
449 				return;
450 			}
451 			check_auto_invite(nick, userhost);
452 		}
453 		if ((do_hook(NOTIFY_SIGNON_LIST, "%s %s", tmp->nick, tmp->host?tmp->host:empty_string)))
454 		{
455 			put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_SIGNON_FSET), "%s %s %s",update_clock(GET_TIME),tmp->nick,tmp->host?tmp->host:empty_string));
456                         logmsg(LOG_NOTIFY, tmp->nick,  0, "%s(%s) has logged on", tmp->host ? tmp->host : empty_string, tmp->looking);
457 		}
458 		malloc_strcpy(&last_notify_nick, nick);
459 		reset_display_target();
460 	}
461 }
462 
463 
464 /*
465  * notify_mark: This marks a given person on the notify list as either on irc
466  * (if flag is 1), or not on irc (if flag is 0).  If the person's status has
467  * changed since the last check, a message is displayed to that effect.  If
468  * the person is not on the noTify list, this call is ignored
469  * doit if passed as 0 means it comes from a join, or a msg, etc, not from
470  * an ison reply.  1 is the other..
471  */
notify_mark(char * nick,char * userhost,int flag,int doit)472 void notify_mark(char *nick, char *userhost, int flag, int doit)
473 {
474 	NotifyItem 	*tmp;
475 	int		count = 0;
476 	int		loc = 0;
477 
478 	if ((tmp = (NotifyItem *)find_array_item(
479 				(Array *)NOTIFY_LIST(from_server), nick,
480 				&count, &loc)) && count < 0)
481 	{
482 		if (flag)
483 		{
484 			if (tmp->host && !wild_match(tmp->looking, tmp->host))
485 			{
486 				tmp->flag = 0;
487 				return;
488 			}
489 			if (tmp->flag != 1)
490 			{
491 			        batch_notify_userhost(nick);
492 				tmp->lastseen = 0;
493 				if (!tmp->added)
494 					tmp->added = now;
495 				tmp->times++;
496 			}
497 			tmp->flag = 1;
498 			if (!doit)
499 				dispatch_notify_userhosts();
500 		}
501 		else
502 		{
503 			if (tmp->flag == 1)
504 			{
505 				const char *who = NULL;
506 				unsigned long level = 0;
507 				save_display_target(&who, &level);
508 				set_display_target(nick, LOG_NOTIFY);
509 				check_orig_nick(nick);
510 				if ((do_hook(NOTIFY_SIGNOFF_LIST, "%s %s", tmp->nick, tmp->host?tmp->host:empty_string)) && doit)
511 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_SIGNOFF_FSET), "%s %s %s",update_clock(GET_TIME),tmp->nick,tmp->host?tmp->host:empty_string));
512 				tmp->period += now - tmp->added;
513 				tmp->lastseen = now;
514 	                        logmsg(LOG_NOTIFY, tmp->nick,  0, "%s(%s) has logged off", tmp->host ? tmp->host : empty_string, tmp->looking);
515 				restore_display_target(who, level);
516 			}
517 			tmp->flag = 0;
518 		}
519 	}
520 }
521 
save_notify(FILE * fp)522 void save_notify(FILE *fp)
523 {
524 	int i = 0;
525 	if (server_list_size() && NOTIFY_MAX(0))
526 	{
527 		fprintf(fp, "NOTIFY");
528 		for (i = 0; i < NOTIFY_MAX(0); i++)
529 			fprintf(fp, " %s!%s", NOTIFY_ITEM(0, i)->nick, NOTIFY_ITEM(0, i)->looking);
530 		fprintf(fp, "\n");
531 	}
532 	if (NOTIFY_MAX(0) && do_hook(SAVEFILE_LIST, "Notify %d", NOTIFY_MAX(0)))
533 		bitchsay("Saved %d Notify entries", NOTIFY_MAX(0));
534 }
535 
536 /* I hate broken compilers -mrg */
537 static	char	*vals[] = { "NOISY", "QUIET", "OLD", NULL };
538 
set_notify_handler(Window * win,char * value,int unused)539 void set_notify_handler(Window *win, char *value, int unused)
540 {
541 	int	len;
542 	int	i;
543 	char	*s;
544 
545 	if (!value)
546 		value = empty_string;
547 	for (i = 0, len = strlen(value); (s = vals[i]); i++)
548 		if (0 == my_strnicmp(value, s, len))
549 			break;
550 	set_string_var(NOTIFY_HANDLER_VAR, s);
551 	return;
552 }
553 
make_notify_list(int servnum)554 void make_notify_list (int servnum)
555 {
556 	NotifyItem *tmp;
557 	char *list = NULL;
558 	int i;
559 
560 	server_list[servnum].notify_list.func = (alist_func)global[MY_STRICMP];
561 	server_list[servnum].notify_list.hash = HASH_INSENSITIVE;
562 
563 	if (!get_int_var(NOTIFY_VAR))
564 		return;
565 	for (i = 0; i < NOTIFY_MAX(0); i++)
566 	{
567 		tmp = (NotifyItem *)new_malloc(sizeof(NotifyItem));
568 		tmp->nick = m_strdup(NOTIFY_ITEM(0, i)->nick);
569 		tmp->looking = m_strdup(NOTIFY_ITEM(0, i)->looking);
570 		tmp->flag = 0;
571 
572 		add_to_array ((Array *)NOTIFY_LIST(servnum),
573 			      (Array_item *)tmp);
574 		m_s3cat(&list, space, tmp->nick);
575 	}
576 	if (list)
577 		isonbase(list, ison_notify);
578 	new_free(&list);
579 }
580 
get_notify_nicks(int showserver,int showon,char * nick,int extra)581 char *get_notify_nicks (int showserver, int showon, char *nick, int extra)
582 {
583 	char *list = NULL;
584 	int i = 0;
585 
586 	if (showserver < 0 || showserver >= server_list_size())
587 		return m_strdup(empty_string);
588 
589 	if (nick && *nick)
590 	{
591 		NotifyItem *tmp;
592 		for (i = 0; i < NOTIFY_MAX(showserver); i++)
593 		{
594 			if (my_stricmp(nick, NOTIFY_ITEM(showserver, i)->nick))
595 				continue;
596 			tmp = NOTIFY_ITEM(from_server, i);
597 			m_s3cat(&list, space, tmp->nick);
598 			m_s3cat(&list, space, tmp->host);
599 			m_s3cat(&list, space, ltoa(tmp->flag));
600 			m_s3cat(&list, space, ltoa(tmp->period));
601 			m_s3cat(&list, space, ltoa(tmp->times));
602 			m_s3cat(&list, space, ltoa(tmp->lastseen));
603 			break;
604 		}
605 	}
606 	else
607 	{
608 		for (i = 0; i < NOTIFY_MAX(showserver); i++)
609 		{
610 			if (showon == -1 || showon == NOTIFY_ITEM(showserver, i)->flag)
611 				m_s3cat(&list, space, NOTIFY_ITEM(showserver, i)->nick);
612 		}
613 	}
614 	return list ? list : m_strdup(empty_string);
615 }
616 
617 
get_watch_nicks(int showserver,int showon,char * nick,int extra)618 char *get_watch_nicks (int showserver, int showon, char *nick, int extra)
619 {
620 	char *list = NULL;
621 	int i = 0;
622 
623 	if (showserver < 0 || showserver >= server_list_size())
624 		return m_strdup(empty_string);
625 
626 	if (nick && *nick)
627 	{
628 		NotifyItem *tmp;
629 		for (i = 0; i < WATCH_MAX(showserver); i++)
630 		{
631 			if (my_stricmp(nick, WATCH_ITEM(showserver, i)->nick))
632 				continue;
633 			tmp = WATCH_ITEM(from_server, i);
634 			m_s3cat(&list, space, tmp->nick);
635 			m_s3cat(&list, space, tmp->host);
636 			m_s3cat(&list, space, ltoa(tmp->flag));
637 			m_s3cat(&list, space, ltoa(tmp->period));
638 			m_s3cat(&list, space, ltoa(tmp->times));
639 			m_s3cat(&list, space, ltoa(tmp->lastseen));
640 			break;
641 		}
642 	}
643 	else
644 	{
645 		for (i = 0; i < WATCH_MAX(showserver); i++)
646 		{
647 			if (showon == -1 || showon == WATCH_ITEM(showserver, i)->flag)
648 				m_s3cat(&list, space, WATCH_ITEM(showserver, i)->nick);
649 		}
650 	}
651 	return list ? list : m_strdup(empty_string);
652 }
653 
654 
iswatch(int serv,char * list,int all)655 int iswatch(int serv, char *list, int all)
656 {
657 	if (all)
658 	{
659 		int servnum;
660 		for (servnum = 0; servnum < server_list_size(); servnum++)
661 		{
662 			if (get_server_watch(servnum) && is_server_connected(servnum))
663 				my_send_to_server(servnum, "WATCH %s", list);
664 		}
665 		return 0;
666 	}
667 	if (get_server_watch(serv) && is_server_connected(serv))
668 		my_send_to_server(serv, "WATCH %s", list);
669 	return 0;
670 }
671 
make_watch_list(int servnum)672 void make_watch_list (int servnum)
673 {
674 	NotifyItem *tmp;
675 	char *list = NULL;
676 	int i;
677 
678 	server_list[servnum].watch_list.func = (alist_func)global[MY_STRICMP];
679 	server_list[servnum].watch_list.hash = HASH_INSENSITIVE;
680 
681 	for (i = 0; i < WATCH_MAX(0); i++)
682 	{
683 		if (!(tmp = (NotifyItem *)array_lookup((Array *)WATCH_LIST(servnum), WATCH_ITEM(0, i)->nick, 0, 0)))
684 		{
685 			tmp = (NotifyItem *)new_malloc(sizeof(NotifyItem));
686 			malloc_strcpy(&tmp->nick, WATCH_ITEM(0, i)->nick);
687 			add_to_array ((Array *)WATCH_LIST(servnum), (Array_item *)tmp);
688 		}
689 		tmp->flag = 0;
690 		if (!list)
691 			list = m_opendup(space_plus, tmp->nick, NULL);
692 		else
693 			m_s3cat(&list, space_plus, tmp->nick);
694 	}
695 	if (list)
696 		iswatch(servnum, list, 0);
697 	new_free(&list);
698 }
699 
700 
show_watch_list(int all)701 void show_watch_list(int all)
702 {
703 #if 0
704 int i;
705 char *list = NULL;
706 	if ((server != -1) && server < server_list_size() && WATCH_MAX(server))
707 	{
708 		put_it("Watch List");
709 		for (i = 0; i < WATCH_MAX(server); i++)
710 			m_s3cat(&list, space, WATCH_ITEM(server, i)->nick);
711 		put_it("%s", list);
712 	}
713 	new_free(&list);
714 #endif
715 int i, count = 0;
716 char period[80], timeson[80], lastseen[80];
717 NotifyItem *tmp;
718 
719 	if (from_server == -1)
720 		return;
721 	for (i = 0; i < WATCH_MAX(from_server); i++)
722 	{
723 		tmp = WATCH_ITEM(from_server, i);
724 		if (tmp->flag)
725 		{
726 			strcpy(period, ltoa(tmp->period));
727 			strcpy(timeson, ltoa(tmp->times));
728 			strcpy(lastseen, ltoa(now - tmp->added));
729 			if (do_hook(WATCH_LIST, "%s %s %d %s %s %s", tmp->nick, tmp->host?tmp->host:"unknown@unknown", tmp->flag, timeson, period, lastseen))
730 			{
731 				if (!count)
732 				{
733 					put_it("%s", convert_output_format("$G Online Users", NULL, NULL));
734 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_ON_FSET), "%s %s %s %s %s", "Nick", "UserHost", "Times", "Period", "Last seen"));
735 				}
736 				put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_ON_FSET), "%s %s %s %s %s", tmp->nick, tmp->host?tmp->host:tmp->looking, timeson, lastseen, "now" ));
737 			}
738 			count++;
739 		}
740 	}
741 	count = 0;
742 	for (i = 0; i < WATCH_MAX(from_server); i++)
743 	{
744 		tmp = WATCH_ITEM(from_server, i);
745 		if ((all && !tmp->flag) || (tmp->times && !tmp->flag))
746 		{
747 			strcpy(period, ltoa(tmp->period));
748 			strcpy(timeson, ltoa(tmp->times));
749 			strcpy(lastseen, ltoa(now - tmp->lastseen));
750 			if (do_hook(WATCH_LIST, "%s %s %d %s %s %s", tmp->nick, tmp->host?tmp->host:"unknown@unknown", tmp->flag, timeson, period, lastseen))
751 			{
752 				if (!count)
753 				{
754 					put_it("%s", convert_output_format("$G Offline Users", NULL, NULL));
755 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_OFF_FSET), "%s %s %s %s %s", "Nick", "UserHost", "Times", "Period", "Last seen"));
756 				}
757 
758 				if (!tmp->times)
759 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_OFF_FSET), "%s %s %s %s %s", tmp->nick, tmp->host?tmp->host:tmp->looking, "never", "none", "n/a"));
760 				else
761 					put_it("%s", convert_output_format(fget_string_var(FORMAT_NOTIFY_OFF_FSET), "%s %s %s %s %s", tmp->nick, tmp->host?tmp->host:tmp->looking, timeson, period, lastseen));
762 			}
763 			count++;
764 		}
765 	}
766 
767 }
768 
BUILT_IN_COMMAND(watchcmd)769 BUILT_IN_COMMAND(watchcmd)
770 {
771 char *nick;
772 char *list = NULL;
773 int servnum = 0;
774 	if (args && *args)
775 	{
776 		while ((nick = next_arg(args, &args)))
777 		{
778 			NotifyItem *new_n;
779 			int shown = 0;
780 			if (*nick == '+')
781 			{
782 				int added = 0;
783 				nick++;
784 				if (!*nick)
785 				{
786 					show_watch_list(0);
787 					continue;
788 				}
789 				if (strchr(nick, '*'))
790 					bitchsay("Wildcards not allowed in WATCH nicknames!");
791 				else
792 				{
793 					for (servnum = 0; servnum < server_list_size(); servnum++)
794 					{
795 						if ((new_n = (NotifyItem *)array_lookup(
796 							(Array *)WATCH_LIST(servnum), nick, 0, 0)))
797 						{
798 							new_n->flag = 0;
799 							continue;	/* Already there! */
800 						}
801 						if (WATCH_MAX(servnum) >= (is_server_connected(servnum) ? get_server_watch(servnum) : 128))
802 						{
803 							bitchsay("Too many WATCH entries [%d]", get_server_watch(servnum));
804 							continue;
805 						}
806 						new_n = (NotifyItem *)new_malloc(sizeof(NotifyItem));
807 						new_n->nick = m_strdup(nick);
808 						new_n->flag = 0;
809 						add_to_array((Array *)WATCH_LIST(servnum),
810 						     (Array_item *)new_n);
811 						added = 1;
812 					}
813 					if (added)
814 					{
815 						if (!list)
816 							list = m_opendup(space_plus, new_n->nick, NULL);
817 						else
818 							m_s3cat(&list, space_plus, new_n->nick);
819 					}
820 					bitchsay("%s added to the watch list", nick);
821 				}
822 			}
823 			else if (*nick == '-')
824 			{
825 				nick++;
826 				if (!*nick)
827 					continue;
828 				for (servnum = 0; servnum < server_list_size(); servnum++)
829 				{
830 					if ((new_n = (NotifyItem *)remove_from_array(
831 						(Array *)WATCH_LIST(servnum), nick)))
832 					{
833 						if (!list)
834 							list = m_opendup(space_minus, nick, NULL);
835 						else
836 							m_s3cat(&list, space_minus, nick);
837 						new_free(&new_n->nick);
838 						new_free(&new_n->host);
839 						new_free(&new_n->looking);
840 						new_free((char **)&new_n);
841 						if (!shown)
842 						{
843 							bitchsay("%s removed from watch list", nick);
844 							shown = 1;
845 						}
846 					}
847 					else
848 					{
849 						if (!shown)
850 						{
851 							bitchsay("%s is not on the watch list", nick);
852 							shown = 1;
853 						}
854 					}
855 				}
856 			}
857 			else if (*nick == 'S')
858 				my_send_to_server(from_server, "%s S", command);
859 			else if (*nick == 'L')
860 				my_send_to_server(from_server, "%s L", command);
861 			else if (*nick == 'l')
862 				my_send_to_server(from_server, "%s l", command);
863 			else if (*nick == 'C')
864 			{
865 				for (servnum = 0; servnum < server_list_size(); servnum++)
866 				{
867 					if (!get_server_watch(servnum))
868 						continue;
869 					while ((new_n = (NotifyItem *)array_pop(
870 						(Array *)WATCH_LIST(servnum), 0)))
871 					{
872 						new_free(&new_n->nick);
873 						new_free(&new_n->looking);
874 						new_free(&new_n->host);
875 						new_free((char **)&new_n);
876 					}
877 					if (get_server_watch(servnum) && is_server_connected(servnum))
878 						my_send_to_server(servnum, "%s S", command);
879 				}
880 				bitchsay("Watch list cleared");
881 			}
882 		}
883 		if (list)
884 			iswatch(servnum, list, 1);
885 		new_free(&list);
886 	} else
887 		show_watch_list(1);
888 }
889 
save_watch(FILE * fp)890 void save_watch(FILE *fp)
891 {
892 	int i = 0;
893 	if (server_list_size() && WATCH_MAX(0))
894 	{
895 		fprintf(fp, "WATCH");
896 		for (i = 0; i < WATCH_MAX(0); i++)
897 			fprintf(fp, " +%s", WATCH_ITEM(0, i)->nick);
898 		fprintf(fp, "\n");
899 	}
900 	if (WATCH_MAX(0) && do_hook(SAVEFILE_LIST, "Watch %d", WATCH_MAX(0)))
901 		bitchsay("Saved %d Watch entries", WATCH_MAX(0));
902 }
903 
show_watch_notify(char * from,int online,char ** args)904 void show_watch_notify(char *from, int online, char **args)
905 {
906 NotifyItem *new_n;
907 	if ((new_n = (NotifyItem *)array_lookup((Array *)WATCH_LIST(from_server),
908 		args[0], 0, 0)))
909 	{
910 		if (online)
911 		{
912 			new_free(&new_n->host);
913 			new_n->host = m_opendup(args[1], "@", args[2], NULL);
914 			if (!new_n->flag)
915 			{
916 				new_n->lastseen = 0;
917 				if (!new_n->added)
918 					new_n->added = now;
919 				new_n->times++;
920 	                        logmsg(LOG_NOTIFY, new_n->nick,  0, "%s has logged on", new_n->host ? new_n->host : empty_string);
921 			}
922 			new_n->period = my_atol(args[3]);
923 		}
924 		else
925 		{
926 			if (new_n->flag)
927 			{
928 				new_n->period = now - new_n->added;
929 				new_n->lastseen = now;
930 	                        logmsg(LOG_NOTIFY, new_n->nick,  0, "%s has logged off", new_n->host ? new_n->host : empty_string);
931 			}
932 		}
933 		new_n->flag = online;
934 		put_it("%s", convert_output_format(fget_string_var(online?FORMAT_WATCH_SIGNON_FSET:FORMAT_WATCH_SIGNOFF_FSET), "%s %s %s %s", args[0], args[1], args[2], args[3]));
935 	}
936 }
937 
send_watch(int server)938 void send_watch(int server)
939 {
940 int i;
941 char *list = NULL;
942 NotifyItem *tmp;
943 	for (i = 0; i < WATCH_MAX(server); i++)
944 	{
945 		if (!(tmp = (NotifyItem *)array_lookup((Array *)WATCH_LIST(server), WATCH_ITEM(server, i)->nick, 0, 0)))
946 		{
947 			tmp = (NotifyItem *)new_malloc(sizeof(NotifyItem));
948 			malloc_strcpy(&tmp->nick, WATCH_ITEM(server, i)->nick);
949 			add_to_array ((Array *)WATCH_LIST(server), (Array_item *)tmp);
950 		}
951 		tmp->flag = 0;
952 		if (!list)
953 			list = m_opendup(space_plus, tmp->nick, NULL);
954 		else
955 		{
956 			if ((strlen(list) + strlen(tmp->nick)) > 490)
957 			{
958 				iswatch(server, list, 0);
959 				new_free(&list);
960 				list = m_opendup(space_plus, tmp->nick, NULL);
961 			}
962 			else
963 				m_s3cat(&list, space_plus, tmp->nick);
964 		}
965 	}
966 	if (list)
967 		iswatch(server, list, 0);
968 	new_free(&list);
969 }
970