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