1# notify.irc: a module to detect the presence of nicknames
2#
3# written by nsx
4#
5# /set variables this script uses:
6#
7#   DO_NOTIFY_IMMEDIATELY -- if set on, the notify system will check for
8#                            signons and signoffs immediately when a
9#                            /notify command has been performed
10#
11#   NOTIFY -- turns notify system on or off
12#
13#   NOTIFY_INTERVAL -- how often (in seconds) to check for signons and signoffs
14#
15#   NOTIFY_USERHOST_AUTOMATIC -- if set on, userhosts will be displayed in
16#                                the signon messages (this can lag you if you
17#                                have a very large notify list)
18#
19#
20# note: this script uses the serial number 556 for its serial hooks
21#
22
23if (word(2 $loadinfo()) != [pf]) { load -pf $word(1 $loadinfo()); return; };
24
25package notify;
26
27load ison;
28
29# global config vars
30@do_notify_immediately = [ON];
31@notify = [ON];
32@notify_interval = 30;
33@notify_userhost_automatic = [ON];
34
35
36# turn off epic's built-in notify system
37on ^set -"NOTIFY *";
38set notify off;
39
40alias change_notify_status (servernum, newstatus, nicklist) {
41	if (newstatus == [online]) {
42		push online_list[$servernum] $nicklist;
43
44		if (NOTIFY_USERHOST_AUTOMATIC == [ON]) {
45			xeval -server $servernum {
46				fe ($nicklist) n1 n2 n3 n4 n5 {
47					userhost $n1 $n2 $n3 $n4 $n5 -cmd {
48						shook notify_signon $0 $3@$4;
49					};
50				};
51			};
52		} else {
53			fe ($nicklist) nickname {
54				shook notify_signon $nickname <EMPTY>;
55			};
56		};
57	} elsif (newstatus == [offline]) {
58		@online_list[$servernum] = remws($nicklist / $online_list[$servernum]));
59
60		fe ($nicklist) nickname {
61			shook notify_signoff $nickname;
62		};
63	};
64};
65
66alias clear_notify_list {
67	@notify_list = [];
68
69	fe ($notify_networks $notify_groups) element {
70		@notify_list[$encode($toupper($element))] = [];
71	};
72
73	@notify_networks = [];
74	@notify_groups = [];
75
76};
77
78alias clear_notify_records {
79	fe ($servernums()) servernum {
80		@np_in_progress[$servernum] = [];
81		@online_list[$servernum] = [];
82	};
83};
84
85alias detect_signons {
86	if (NOTIFY == [OFF]) {
87		return;
88	};
89
90	fe ($servernums()) servernum {
91		if (np_in_progress[$servernum] == 1) {
92			continue;
93		};
94
95		@:groupname = toupper($serverctl(GET $servernum GROUP));
96		@:network = toupper($serverctl(GET $servernum 005 NETWORK));
97		@:ison_send_list = getnick[$servernum];
98
99		push ison_send_list $notify_list;
100		push ison_send_list $notify_list[$encode($toupper($groupname))];
101		push ison_send_list $notify_list[$encode($toupper($network))];
102
103		if (ison_send_list == []) {
104			continue;
105		};
106
107		@np_in_progress[$servernum] = 1;
108
109		ison -oncmd {
110			@observe_online($uniq($*));
111		} -offcmd {
112			@observe_offline($uniq($*));
113		} -end {
114			@np_in_progress[$serverctl(from_server)] = 0;
115		} -server $servernum $ison_send_list;
116	};
117};
118
119alias establish_notify_hooks {
120        ^on #^channel_nick 556 "*" {
121                @observe_offline($1);
122                @observe_online($2);
123        };
124
125        ^on #^channel_signoff 556 "*" {
126                @observe_offline($1);
127        };
128
129        ^on #^join 556 "*" {
130                @observe_online($0);
131        };
132
133        ^on #^msg 556 "*" {
134                @observe_online($0);
135        };
136
137        ^on #^notice 556 "*" {
138                @observe_online($0);
139        };
140
141	^on #^server_lost 556 "*" {
142		@:servernum = [$0];
143
144		@np_in_progress[$servernum] = 0;
145		@online_list[$servernum] = [];
146	};
147
148	^on #^003 556 "*" {
149		@:lserver = serverctl(from_server);
150
151		@np_in_progress[$lserver] = 0;
152		@online_list[$lserver] = [];
153	};
154
155        ^on #^311 556 "*" {
156                @observe_online($1);
157        };
158
159        ^on #^401 556 "*" {
160                @observe_offline($1);
161        };
162
163};
164
165alias getnick (nickname) {
166        if (nickname == []) {
167                @:getnick = getnick[$serverctl(from_server)];
168
169                if (getnick == []) {
170                        xecho -b no getnick for $serverctl(get $serverctl(from_server) itsname) has been set;
171                        xecho;
172                } else {
173                        xecho -b getnick for $serverctl(get $serverctl(from_server) itsname) is: $getnick;
174                        xecho;
175                };
176
177                return;
178        };
179
180        if (nickname == [-]) {
181                @getnick[$serverctl(from_server)] = [];
182
183                xecho -b getnick for $serverctl(get $serverctl(from_server) itsname) has been unset;
184                xecho;
185
186		return;
187        } else {
188                @getnick[$serverctl(from_server)] = nickname;
189
190                xecho -b getnick for $serverctl(get $serverctl(from_server) itsname) set to: $nickname;
191                xecho;
192        };
193
194        @detect_signons();
195};
196
197alias notify (nicklist) {
198	@:lserver = serverctl(from_server);
199	@:lgroup = serverctl(GET $lserver GROUP);
200	@:lnetwork = serverctl(GET $lserver 005 NETWORK);
201	@:online_list = online_list[$lserver];
202	@:offline_list = remws($online_list / $notify_list $notify_list[$encode($toupper($lgroup))] $notify_list[$encode($toupper($lnetwork))]);
203
204	if (functioncall()) {
205		@:notify_list = notify_list;
206
207		if (#nicklist == 0) {
208			fe ($notify_networks) network {
209				fe ($notify_list[$encode($toupper($network))]) nickname {
210					push notify_list $nickname:$network;
211				};
212			};
213
214			fe ($notify_groups) groupname {
215				fe ($notify_list[$encode($toupper($groupname))]) nickname {
216					push notify_list $nickname::$groupname;
217				};
218			};
219
220			return $notify_list;
221		} elsif ((:word = findw(net $nicklist)) > -1) {
222			@:online_list = [];
223			@:network = word(${word + 1} $nicklist);
224			@:list = word(${word - 1} $nicklist) == [] ? word(${word + 2} $nicklist) : word(${word - 1} $nicklist);
225
226			fe ($notify_list[$encode($toupper($network))]) nickname {
227				fe ($servernums()) servernum {
228					if (serverctl(GET $servernum 005 NETWORK) == network && findw($nickname $online_list[$servernum]) > -1) {
229						push online_list $nickname;
230					};
231				};
232			};
233
234			@:online_list = uniq($online_list);
235
236			if (list == [off]) {
237				return $remws($online_list / $notify_list[$encode($toupper($network))]);
238			} else {
239				return $online_list;
240			};
241		} elsif ((:word = findw(group $nicklist)) > -1) {
242			@:online_list = [];
243			@:groupname = word(${word + 1} $nicklist);
244			@:list = word(${word - 1} $nicklist) == [] ? word(${word + 2} $nicklist) : word(${word - 1} $nicklist);
245
246			fe ($notify_list[$encode($toupper($groupname))]) nickname {
247				fe ($servernums()) servernum {
248					if (serverctl(GET $servernum GROUP) == groupname && findw($nickname $online_list[$servernum]) > -1) {
249						push online_list $nickname;
250					};
251				};
252			};
253
254			@:online_list = uniq($online_list);
255
256			if (list == [off]) {
257				return $remws($online_list / $notify_list[$encode($toupper($groupname))]);
258			} else {
259				return $online_list;
260			};
261		} else {
262			if ((:word = findw(serv $nicklist)) > -1) {
263				@:refnum = word(${word + 1} $nicklist);
264				@:list = word(${word - 1} $nicklist) == [] ? word(${word + 2} $nicklist) : word(${word - 1} $nicklist);
265
266			} elsif (#nicklist == 1) {
267				@:lserver = serverctl(from_server);
268				@:list = nicklist;
269			} else {
270				return -1;
271			};
272
273			if (list == [off]) {
274				@:network = serverctl(GET $lserver 005 NETWORK);
275				@:groupname = serverctl(GET $lserver GROUP);
276
277				push notify_list $notify_list[$encode($toupper($network))];
278				push notify_list $notify_list[$encode($toupper($groupname))];
279
280				return $remws($online_list[$lserver] / $notify_list);
281			} else {
282				return $online_list[$lserver];
283			};
284		};
285	};
286
287	if (nicklist == []) {
288		xecho -b -c -- Currently online: $online_list;
289		xecho -b -c -- Currently offline: $offline_list;
290
291		return;
292	};
293
294	if (nicklist == [-]) {
295		@remove_notify_entry();
296
297		xecho -b -c -- the global notify list has been cleared;
298
299		return;
300	};
301
302	if (nicklist == [--]) {
303		@clear_notify_list();
304		@clear_notify_records();
305
306		xecho -b -c -- the global and local notify lists have been cleared;
307		return;
308	};
309
310	fe ($nicklist) nickname {
311		@:separators = count(: $nickname);
312
313		if (left(1 $nickname) == [-]) {
314			@:nickname = rest($nickname);
315
316			if (separators == 1) {
317				@:network = after(: $nickname);
318				@:nickname = before(: $nickname);
319
320				if (nickname == []) {
321					@remove_network_notify_entry($network);
322
323					xecho -b -c -- the notify list for network $network has been cleared;
324
325					continue;
326				};
327
328				if (remove_network_notify_entry($network $nickname) == 1) {
329					xecho -b -c -- $nickname is not in the notify list for network ${network}!;
330				} else {
331					xecho -b -c -- $nickname has been removed from the notify list for network $network;
332				};
333			} elsif (separators >= 2) {
334				@:groupname = after(-1 : $nickname);
335				@:nickname = before(: $nickname);
336				@:refnums = serverctl(GMATCH $groupname);
337
338				if (refnums == []) {
339					xecho -b -c -- server group $groupname does not exist;
340
341					continue;
342				};
343
344				if (nickname == []) {
345					@remove_group_notify_entry($groupname);
346
347					xecho -b -c -- the notify list for server group $groupname has been cleared;
348
349					continue;
350				};
351
352				if (remove_group_notify_entry($groupname $nickname) == 1) {
353					xecho -b -c -- $nickname is not in the notify list for server group ${groupname}!;
354				} else {
355					xecho -b -c -- $nickname has been removed from the notify list for server group ${groupname};
356				};
357			} else {
358				if (nickname == []) {
359					continue;
360				};
361
362				if (remove_notify_entry($nickname) == 1) {
363					xecho -b -c -- $nickname is not in the global notify list!;
364				} else {
365					xecho -b -c -- $nickname has been removed from the global notify list;
366				};
367			};
368		} else {
369			if (left(1 $nickname) == [+]) {
370				@:nickname = rest($nickname);
371			};
372
373			if (separators == 1) {
374				@:network = after(: $nickname);
375				@:nethash = encode($toupper($network));
376				@:nickname = before(: $nickname);
377
378				if (nickname == []) {
379					continue;
380				};
381
382				if (findw($nickname $notify_list[$nethash]) > -1) {
383					xecho -b -c -- $nickname is already in the notify list for network ${network}!;
384
385					continue;
386				};
387
388				if (findw($nickname $notify_list) > -1) {
389					xecho -b -c -- $nickname is already in the global notify list!;
390
391					continue;
392				};
393
394				if (findw($network $notify_networks) == -1) {
395					push notify_networks $network;
396				};
397
398				push notify_list[$nethash] $nickname;
399
400				xecho -b -c -- $nickname has been added to the notify list for network $network;
401			} elsif (separators >= 2) {
402				@:groupname = after(-1 : $nickname);
403				@:grouphash = encode($toupper($groupname));
404				@:nickname = before(: $nickname);
405
406				if (nickname == []) {
407					xecho -b -c -- no nickname provided for server group $groupname;
408					continue;
409				};
410
411
412				if (serverctl(GMATCH $groupname) == []) {
413					xecho -b -c -- server group $groupname does not exist;
414
415					continue;
416				};
417
418				if (findw($nickname $notify_list[$grouphash]) > -1) {
419					xecho -b -- $nickname is already in the notify list for server group ${groupname}!;
420					continue;
421				};
422
423
424				if (findw($nickname $notify_list) > -1) {
425					xecho -b -c -- $nickname is already in the global notify list!;
426
427					continue;
428				};
429
430				if (findw($groupname $notify_groups) == -1) {
431					push notify_groups $groupname;
432				};
433
434				push notify_list[$grouphash] $nickname;
435
436				xecho -b -c -- $nickname has been added to the notify list for server group $groupname;
437			} else {
438				if (nickname == []) {
439					continue;
440				};
441
442				if (findw($nickname $notify_list[$encode($toupper($lgroup))]) > -1) {
443					xecho -b -c -- $nickname is already in the notify list for server group ${lgroup}!;
444
445					continue;
446				};
447
448				if (findw($nickname $notify_list[$encode($toupper($lnetwork))]) > -1) {
449					xecho -b -c -- $nickname is already in the notify list for the network ${lnetwork}!;
450					continue;
451				};
452
453				if (findw($nickname $notify_list) > -1) {
454					xecho -b -c -- $nickname is already in the global notify list!;
455
456					continue;
457				};
458
459				push notify_list $nickname;
460
461				xecho -b -c -- $nickname has been added to the global notify list;
462			};
463		};
464	};
465
466	if (do_notify_immediately == [ON]) {
467		@detect_signons();
468	};
469};
470
471alias observe_offline (nicklist) {
472	@:signoffs = [];
473        @:lserver = serverctl(from_server);
474
475	fe ($nicklist) nickname {
476	        if (getnick[$lserver] != [] && getnick[$lserver] != N && getnick[$lserver] == nickname) {
477			//nick $getnick[$lserver];
478		};
479
480	        if (findw($nickname $online_list[$lserver]) > -1) {
481			push signoffs $nickname;
482		};
483	};
484
485	@change_notify_status($lserver offline $signoffs);
486};
487
488alias observe_online (nicklist) {
489	@:signons = [];
490        @:lserver = serverctl(from_server);
491	@:groupname = serverctl(GET $lserver GROUP);
492	@:network = serverctl(GET $lserver 005 NETWORK);
493        @:offline_list = remws($online_list[$lserver] / $notify_list $notify_list[$encode($toupper($groupname))] $notify_list[$encode($toupper($network))]);
494
495	fe ($nicklist) nickname {
496		if (findw($nickname $offline_list) > -1) {
497			push signons $nickname;
498		};
499	};
500
501	@change_notify_status($lserver online $signons);
502};
503
504alias remove_notify_entry (nickname) {
505	if (nickname == []) {
506		fe ($notify_list) nickname {
507			fe ($servernums()) servernum {
508				@:groupname = serverctl(GET $servernum GROUP);
509				@:network = serverctl(GET $servernum 005 NETWORK);
510
511				if (findw($nickname $notify_list[$encode($toupper($groupname))]) == -1 && findw($nickname $notify_list[$encode($toupper($network))]) == -1) {
512					@online_list[$servernum] = remw($nickname $online_list[$servernum]);
513				};
514			};
515		};
516
517		@notify_list = [];
518
519		return 0;
520	};
521
522	if (findw($nickname $notify_list) == -1) {
523		return 1;
524	} else {
525		@notify_list = remw($nickname $notify_list);
526
527		fe ($servernums()) servernum {
528			@:groupname = serverctl(GET $servernum GROUP);
529			@:network = serverctl(GET $servernum 005 NETWORK);
530
531			if (findw($nickname $notify_list[$encode($toupper($groupname))]) == -1 && findw($nickname $notify_list[$encode($toupper($network))]) == -1) {
532				@online_list[$servernum] = remw($nickname $online_list[$servernum]);
533			};
534		};
535
536		return 0;
537	};
538
539};
540
541alias remove_group_notify_entry (groupname, nickname) {
542	@:grouphash = encode($toupper($groupname));
543
544	if (nickname == []) {
545		fe ($notify_list[$grouphash]) nickname {
546			fe ($servernums()) servernum {
547				if (serverctl(GET $servernum GROUP) == groupname) {
548					@:network = serverctl(GET $servernum 005 NETWORK);
549
550					if (findw($nickname $notify_list[$encode($toupper($network))]) == -1) {
551						@online_list[$servernum] = remw($nickname $online_list[$servernum]);
552					};
553				};
554			};
555		};
556
557		@notify_list[$grouphash] = [];
558		@notify_groups = remw($groupname $notify_groups);
559
560		return 0;
561	};
562
563	if (findw($nickname $notify_list[$grouphash]) == -1) {
564		return 1;
565	} else {
566		@notify_list[$grouphash] = remw($nickname $notify_list[$grouphash]);
567
568		if (notify_list[$grouphash] == []) {
569			@notify_groups = remw($groupname $notify_groups);
570		};
571
572		fe ($servernums()) servernum {
573			if (serverctl(GET $servernum GROUP) == groupname) {
574				@:network = serverctl(GET $servernum 005 NETWORK);
575
576				if (findw($nickname $notify_list[$encode($toupper($network))]) == -1) {
577					@online_list[$servernum] = remw($nickname $online_list[$servernum]);
578				};
579			};
580		};
581
582		return 0;
583	};
584};
585
586alias remove_network_notify_entry (network, nickname) {
587	@:nethash = encode($toupper($network));
588
589	if (nickname == []) {
590		fe ($notify_list[$nethash]) nickname {
591			fe ($servernums()) servernum {
592				if (serverctl(GET $servernum 005 NETWORK) == network) {
593					@:groupname = serverctl(GET $servernum GROUP);
594
595					if (findw($nickname $notify_list[$encode($toupper($groupname))]) == -1) {
596						@online_list[$servernum] = remw($nickname $online_list[$servernum]);
597					};
598				};
599			};
600		};
601
602		@notify_list[$nethash] = [];
603		@notify_networks = remw($network $notify_networks);
604
605		return 0;
606	};
607
608	if (findw($nickname $notify_list[$nethash]) == -1) {
609		return 1;
610	} else {
611		@notify_list[$nethash] = remw($nickname $notify_list[$nethash]);
612
613		if (notify_list[$nethash] == []) {
614			@notify_networks = remw($network $notify_networks);
615		};
616
617		fe ($servernums()) servernum {
618			if (serverctl(GET $servernum 005 NETWORK) == network) {
619				@:groupname = serverctl(GET $servernum GROUP);
620
621				if (findw($nickname $notify_list[$encode($toupper($groupname))]) == -1) {
622					@online_list[$servernum] = remw($nickname $online_list[$servernum]);
623				};
624			};
625		};
626
627		return 0;
628	};
629};
630
631alias remove_notify_hooks {
632	^on #^channel_nick 556 -"*";
633	^on #^channel_signoff 556 -"*";
634	^on #^join 556 -"*";
635	^on #^msg 556 -"*";
636	^on #^notice 556 -"*";
637	^on #^send_to_server 556 -"% % ISON *";
638	^on #^server_lost 556 -"*";
639	^on #^003 556 -"*";
640	^on #^311 556 -"*";
641	^on #^401 556 -"*";
642};
643
644alias servernums {
645	@:refnums = [];
646
647	fe ($serverctl(omatch *)) refnum {
648		if (serverctl(get $refnum connected)) {
649			push refnums $refnum;
650		};
651	};
652
653	return $refnums;
654};
655
656
657on ^notify_signoff "*" {
658	xecho -b -level CRAP -- Signoff by $0 detected;
659};
660
661on ^notify_signon "*" {
662	if (NOTIFY_USERHOST_AUTOMATIC == [ON]) {
663		if ([$1] == [<UNKNOWN>@<UNKNOWN>]) {
664			xecho -b -level CRAP -- Signon by $0 \(\) detected;
665		} else {
666			 xecho -b -level CRAP Signon by $0 \($1\) detected;
667		};
668	} else {
669		xecho -b -level CRAP -- Signon by $0 detected;
670	};
671};
672
673on ^set "DO_NOTIFY_IMMEDIATELY" {
674	if ([$1] == []) {
675		xecho -b Current value of DO_NOTIFY_IMMEDIATELY is $do_notify_immediately;
676	} elsif ([$1] == [off]) {
677		@do_notify_immediately = [off];
678		xecho -b Value of DO_NOTIFY_IMMEDIATELY set to OFF;
679	} elsif ([$1] == [on]) {
680		@do_notify_immediately = [on];
681		xecho -b Value of DO_NOTIFY_IMMEDIATELY set to ON;
682	} else {
683		xecho -b Value of DO_NOTIFY_IMMEDIATELY must be ON or OFF;
684	};
685};
686
687on ^set "NOTIFY *" {
688	if ([$1] == []) {
689		xecho -b Current value of NOTIFY is $notify;
690	} elsif ([$1] == [off]) {
691		@notify = [off];
692
693		^timer -del notcheck;
694		@remove_notify_hooks();
695
696		xecho -b Value of NOTIFY set to OFF;
697	} elsif ([$1] == [on]) {
698		@notify = [on];
699
700		@clear_notify_records();
701		@establish_notify_hooks();
702		^timer -refnum notcheck -rep -1 $notify_interval @detect_signons();
703
704		xecho -b Value of NOTIFY set to ON;
705	} else {
706		xecho -b Value of NOTIFY must be ON or OFF;
707	};
708};
709
710on ^set "NOTIFY_INTERVAL *" {
711	if ([$1] == []) {
712		xecho -b Current value of NOTIFY_INTERVAL is $notify_interval;
713	} elsif (!isnumber($1)) {
714		xecho -b Value of NOTIFY_INTERVAL must be numeric!;
715	} elsif ([$1] < 1) {
716		xecho -b Value of NOTIFY_INTERVAL must be greater than or equal to 1;
717	} else {
718		@notify_interval = [$1];
719
720		^timer -del notcheck;
721		^timer -refnum notcheck -rep -1 $notify_interval @detect_signons();
722
723		xecho -b Value of NOTIFY_INTERVAL set to $notify_interval;
724	};
725};
726
727on ^set "NOTIFY_USERHOST_AUTOMATIC *" {
728	if ([$1] == []) {
729		xecho -b Current value of NOTIFY_USERHOST_AUTOMATIC is $notify_userhost_automatic;
730	} elsif ([$1] == [off]) {
731		@notify_userhost_automatic = [OFF];
732		xecho -b Value of NOTIFY_USERHOST_AUTOMATIC set to OFF;
733	} elsif ([$1] == [on]) {
734		@notify_userhost_automatic = [ON];
735		xecho -b Value of NOTIFY_USERHOST_AUTOMATIC set to ON;
736	} else {
737		xecho -b Value of NOTIFY_USERHOST_AUTOMATIC must be ON or OFF;
738	};
739};
740
741@clear_notify_list();
742@clear_notify_records();
743@establish_notify_hooks();
744@detect_signons();
745timer -refnum notcheck -rep -1 $notify_interval @detect_signons();
746