1 /*
2 notifylist.c : irssi
3
4 Copyright (C) 1999-2000 Timo Sirainen
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "module.h"
22 #include "modules.h"
23 #include "signals.h"
24 #include "settings.h"
25
26 #include "irc.h"
27 #include "irc-channels.h"
28 #include "servers-redirect.h"
29 #include "masks.h"
30 #include "nicklist.h"
31
32 #include "notifylist.h"
33 #include "notify-setup.h"
34
35 GSList *notifies;
36
notifylist_add(const char * mask,const char * ircnets,int away_check)37 NOTIFYLIST_REC *notifylist_add(const char *mask, const char *ircnets,
38 int away_check)
39 {
40 NOTIFYLIST_REC *rec;
41
42 g_return_val_if_fail(mask != NULL, NULL);
43
44 rec = g_new0(NOTIFYLIST_REC, 1);
45 rec->mask = g_strdup(mask);
46 rec->ircnets = ircnets == NULL || *ircnets == '\0' ? NULL :
47 g_strsplit(ircnets, " ", -1);
48 rec->away_check = away_check;
49
50 notifylist_add_config(rec);
51
52 notifies = g_slist_append(notifies, rec);
53 signal_emit("notifylist new", 1, rec);
54 return rec;
55 }
56
notify_destroy(NOTIFYLIST_REC * rec)57 static void notify_destroy(NOTIFYLIST_REC *rec)
58 {
59 if (rec->ircnets != NULL) g_strfreev(rec->ircnets);
60 g_free(rec->mask);
61 g_free(rec);
62 }
63
notifylist_destroy_all(void)64 void notifylist_destroy_all(void)
65 {
66 g_slist_foreach(notifies, (GFunc) notify_destroy, NULL);
67 g_slist_free(notifies);
68
69 notifies = NULL;
70 }
71
notifylist_remove(const char * mask)72 void notifylist_remove(const char *mask)
73 {
74 NOTIFYLIST_REC *rec;
75
76 g_return_if_fail(mask != NULL);
77
78 rec = notifylist_find(mask, "*");
79 if (rec == NULL) return;
80
81 notifylist_remove_config(rec);
82 notifies = g_slist_remove(notifies, rec);
83 signal_emit("notifylist remove", 1, rec);
84
85 notify_destroy(rec);
86 }
87
notifylist_ircnets_match(NOTIFYLIST_REC * rec,const char * ircnet)88 int notifylist_ircnets_match(NOTIFYLIST_REC *rec, const char *ircnet)
89 {
90 char **tmp;
91
92 if (rec->ircnets == NULL) return TRUE;
93 if (ircnet == NULL) return FALSE;
94 if (g_strcmp0(ircnet, "*") == 0) return TRUE;
95
96 for (tmp = rec->ircnets; *tmp != NULL; tmp++) {
97 if (g_ascii_strcasecmp(*tmp, ircnet) == 0)
98 return TRUE;
99 }
100
101 return FALSE;
102 }
103
notifylist_find(const char * mask,const char * ircnet)104 NOTIFYLIST_REC *notifylist_find(const char *mask, const char *ircnet)
105 {
106 NOTIFYLIST_REC *best;
107 GSList *tmp;
108 int len;
109
110 best = NULL;
111 len = strlen(mask);
112 for (tmp = notifies; tmp != NULL; tmp = tmp->next) {
113 NOTIFYLIST_REC *rec = tmp->data;
114
115 /* check mask */
116 if (g_ascii_strncasecmp(rec->mask, mask, len) != 0 ||
117 (rec->mask[len] != '\0' && rec->mask[len] != '!')) continue;
118
119 /* check ircnet */
120 if (rec->ircnets == NULL) {
121 best = rec;
122 continue;
123 }
124
125 if (notifylist_ircnets_match(rec, ircnet))
126 return rec;
127 }
128
129 return best;
130 }
131
notifylist_ison_server(IRC_SERVER_REC * server,const char * nick)132 int notifylist_ison_server(IRC_SERVER_REC *server, const char *nick)
133 {
134 NOTIFY_NICK_REC *rec;
135
136 g_return_val_if_fail(nick != NULL, FALSE);
137 g_return_val_if_fail(IS_IRC_SERVER(server), FALSE);
138
139 rec = notify_nick_find(server, nick);
140 return rec != NULL && rec->host_ok && rec->away_ok;
141 }
142
notifylist_ison_serverlist(const char * nick,const char * taglist)143 static IRC_SERVER_REC *notifylist_ison_serverlist(const char *nick, const char *taglist)
144 {
145 IRC_SERVER_REC *server;
146 char **list, **tmp;
147
148 g_return_val_if_fail(nick != NULL, NULL);
149 g_return_val_if_fail(taglist != NULL, NULL);
150
151 list = g_strsplit(taglist, " ", -1);
152
153 server = NULL;
154 for (tmp = list; *tmp != NULL; tmp++) {
155 server = (IRC_SERVER_REC *) server_find_chatnet(*tmp);
156
157 if (IS_IRC_SERVER(server) &&
158 notifylist_ison_server(server, nick))
159 break;
160 }
161 g_strfreev(list);
162
163 return tmp == NULL ? NULL : server;
164 }
165
notifylist_ison(const char * nick,const char * serverlist)166 IRC_SERVER_REC *notifylist_ison(const char *nick, const char *serverlist)
167 {
168 GSList *tmp;
169
170 g_return_val_if_fail(nick != NULL, FALSE);
171 g_return_val_if_fail(serverlist != NULL, FALSE);
172
173 if (*serverlist != '\0')
174 return notifylist_ison_serverlist(nick, serverlist);
175
176 /* any server.. */
177 for (tmp = servers; tmp != NULL; tmp = tmp->next) {
178 IRC_SERVER_REC *server = tmp->data;
179
180 if (IS_IRC_SERVER(server) &&
181 notifylist_ison_server(server, nick))
182 return tmp->data;
183 }
184
185 return NULL;
186 }
187
notifylist_init_server(IRC_SERVER_REC * server)188 static void notifylist_init_server(IRC_SERVER_REC *server)
189 {
190 MODULE_SERVER_REC *rec;
191
192 g_return_if_fail(server != NULL);
193
194 if (!IS_IRC_SERVER(server))
195 return;
196
197 rec = g_new0(MODULE_SERVER_REC,1 );
198 MODULE_DATA_SET(server, rec);
199 }
200
notifylist_deinit_server(IRC_SERVER_REC * server)201 static void notifylist_deinit_server(IRC_SERVER_REC *server)
202 {
203 MODULE_SERVER_REC *mserver;
204 NOTIFY_NICK_REC *rec;
205
206 g_return_if_fail(server != NULL);
207
208 if (!IS_IRC_SERVER(server))
209 return;
210
211 mserver = MODULE_DATA(server);
212 while (mserver->notify_users != NULL) {
213 rec = mserver->notify_users->data;
214
215 mserver->notify_users = g_slist_remove(mserver->notify_users, rec);
216 notify_nick_destroy(rec);
217 }
218 g_free(mserver);
219 MODULE_DATA_UNSET(server);
220 }
221
notifylist_left(IRC_SERVER_REC * server,NOTIFY_NICK_REC * rec)222 void notifylist_left(IRC_SERVER_REC *server, NOTIFY_NICK_REC *rec)
223 {
224 MODULE_SERVER_REC *mserver;
225
226 mserver = MODULE_DATA(server);
227 mserver->notify_users = g_slist_remove(mserver->notify_users, rec);
228
229 if (rec->host_ok && rec->away_ok) {
230 signal_emit("notifylist left", 6,
231 server, rec->nick,
232 rec->user, rec->host,
233 rec->realname, rec->awaymsg);
234 }
235
236 notify_nick_destroy(rec);
237 }
238
event_quit(IRC_SERVER_REC * server,const char * data,const char * nick)239 static void event_quit(IRC_SERVER_REC *server, const char *data,
240 const char *nick)
241 {
242 NOTIFY_NICK_REC *rec;
243
244 if (*data == ':') data++; /* quit message */
245
246 rec = notify_nick_find(server, nick);
247 if (rec != NULL) notifylist_left(server, rec);
248 }
249
notifylist_check_join(IRC_SERVER_REC * server,const char * nick,const char * userhost,const char * realname,int away)250 static void notifylist_check_join(IRC_SERVER_REC *server, const char *nick,
251 const char *userhost, const char *realname, int away)
252 {
253 NOTIFYLIST_REC *notify;
254 NOTIFY_NICK_REC *rec;
255 char *user, *host;
256
257 if (nick == NULL)
258 return;
259
260 notify = notifylist_find(nick, server->connrec->chatnet);
261 if (notify == NULL) return;
262
263 rec = notify_nick_find(server, nick);
264 if (rec != NULL && rec->join_announced) return;
265 if (rec == NULL) rec = notify_nick_create(server, nick);
266
267 user = g_strdup(userhost == NULL ? "" : userhost);
268 host = strchr(user, '@');
269 if (host != NULL) *host++ = '\0'; else host = "";
270
271 if (!mask_match(SERVER(server), notify->mask, nick, user, host)) {
272 g_free(user);
273 return;
274 }
275
276 if (notify->away_check && away == -1) {
277 /* we need to know if the nick is away */
278 g_free(user);
279 return;
280 }
281
282 g_free_not_null(rec->user);
283 g_free_not_null(rec->host);
284 g_free_not_null(rec->realname);
285 rec->user = g_strdup(user);
286 rec->host = g_strdup(host);
287 rec->realname = realname == NULL || *realname == '\0' ? NULL : g_strdup(realname);
288
289 if (away != -1) rec->away = away;
290 rec->host_ok = TRUE;
291 rec->join_announced = TRUE;
292 rec->away_ok = !notify->away_check || !rec->away;
293
294 signal_emit("notifylist joined", 6,
295 server, rec->nick, rec->user, rec->host, realname, NULL);
296 g_free(user);
297 }
298
event_privmsg(IRC_SERVER_REC * server,const char * data,const char * nick,const char * address)299 static void event_privmsg(IRC_SERVER_REC *server, const char *data,
300 const char *nick, const char *address)
301 {
302 if (nick != NULL) {
303 notifylist_check_join(server, nick, address, "", -1);
304 }
305 }
306
event_join(IRC_SERVER_REC * server,const char * data,const char * nick,const char * address)307 static void event_join(IRC_SERVER_REC *server, const char *data,
308 const char *nick, const char *address)
309 {
310 notifylist_check_join(server, nick, address, "", -1);
311 }
312
sig_channel_wholist(IRC_CHANNEL_REC * channel)313 static void sig_channel_wholist(IRC_CHANNEL_REC *channel)
314 {
315 GSList *nicks, *tmp;
316
317 nicks = nicklist_getnicks(CHANNEL(channel));
318 for (tmp = nicks; tmp != NULL; tmp = tmp->next) {
319 NICK_REC *rec = tmp->data;
320
321 notifylist_check_join(channel->server, rec->nick, rec->host, rec->realname, rec->gone);
322 }
323 g_slist_free(nicks);
324 }
325
irc_notifylist_init(void)326 void irc_notifylist_init(void)
327 {
328 notifylist_read_config();
329
330 notifylist_commands_init();
331 notifylist_ison_init();
332 notifylist_whois_init();
333 signal_add("server connected", (SIGNAL_FUNC) notifylist_init_server);
334 signal_add("server destroyed", (SIGNAL_FUNC) notifylist_deinit_server);
335 signal_add("event quit", (SIGNAL_FUNC) event_quit);
336 signal_add("event privmsg", (SIGNAL_FUNC) event_privmsg);
337 signal_add("event join", (SIGNAL_FUNC) event_join);
338 signal_add("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
339 signal_add("setup reread", (SIGNAL_FUNC) notifylist_read_config);
340
341 settings_check();
342 module_register("notifylist", "irc");
343 }
344
irc_notifylist_deinit(void)345 void irc_notifylist_deinit(void)
346 {
347 notifylist_commands_deinit();
348 notifylist_ison_deinit();
349 notifylist_whois_deinit();
350
351 signal_remove("server connected", (SIGNAL_FUNC) notifylist_init_server);
352 signal_remove("server destroyed", (SIGNAL_FUNC) notifylist_deinit_server);
353 signal_remove("event quit", (SIGNAL_FUNC) event_quit);
354 signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg);
355 signal_remove("event join", (SIGNAL_FUNC) event_join);
356 signal_remove("channel wholist", (SIGNAL_FUNC) sig_channel_wholist);
357 signal_remove("setup reread", (SIGNAL_FUNC) notifylist_read_config);
358
359 notifylist_destroy_all();
360 }
361