Now inbound_cap_ls() can enable extensions when a bouncer uses a namespace for the...
[rofl0r-ixchat.git] / src / common / notify.c
bloba8319a8143c328c542c5d38ddfff4ab57b39e6c2
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <time.h>
28 #include "xchat.h"
29 #include "notify.h"
30 #include "cfgfiles.h"
31 #include "fe.h"
32 #include "server.h"
33 #include "text.h"
34 #include "util.h"
35 #include "xchatc.h"
38 GSList *notify_list = 0;
39 int notify_tag = 0;
42 static char *
43 despacify_dup (char *str)
45 char *p, *res = malloc (strlen (str) + 1);
47 p = res;
48 while (1)
50 if (*str != ' ')
52 *p = *str;
53 if (*p == 0)
54 return res;
55 p++;
57 str++;
61 static int
62 notify_netcmp (char *str, void *serv)
64 char *net = despacify_dup (server_get_network (serv, TRUE));
66 if (rfc_casecmp (str, net) == 0)
68 free (net);
69 return 0; /* finish & return FALSE from token_foreach() */
72 free (net);
73 return 1; /* keep going... */
76 /* monitor this nick on this particular network? */
78 static gboolean
79 notify_do_network (struct notify *notify, server *serv)
81 if (!notify->networks) /* ALL networks for this nick */
82 return TRUE;
84 if (token_foreach (notify->networks, ',', notify_netcmp, serv))
85 return FALSE; /* network list doesn't contain this one */
87 return TRUE;
90 struct notify_per_server *
91 notify_find_server_entry (struct notify *notify, struct server *serv)
93 GSList *list = notify->server_list;
94 struct notify_per_server *servnot;
96 while (list)
98 servnot = (struct notify_per_server *) list->data;
99 if (servnot->server == serv)
100 return servnot;
101 list = list->next;
104 /* not found, should we add it, or is this not a network where
105 we're monitoring this nick? */
106 if (!notify_do_network (notify, serv))
107 return NULL;
109 servnot = malloc (sizeof (struct notify_per_server));
110 if (servnot)
112 memset (servnot, 0, sizeof (struct notify_per_server));
113 servnot->server = serv;
114 servnot->notify = notify;
115 notify->server_list = g_slist_prepend (notify->server_list, servnot);
117 return servnot;
120 void
121 notify_save (void)
123 int fh;
124 struct notify *notify;
125 GSList *list = notify_list;
127 fh = xchat_open_file ("notify.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
128 if (fh != -1)
130 while (list)
132 notify = (struct notify *) list->data;
133 write (fh, notify->name, strlen (notify->name));
134 if (notify->networks)
136 write (fh, " ", 1);
137 write (fh, notify->networks, strlen (notify->networks));
139 write (fh, "\n", 1);
140 list = list->next;
142 close (fh);
146 void
147 notify_load (void)
149 int fh;
150 char buf[256];
151 char *sep;
153 fh = xchat_open_file ("notify.conf", O_RDONLY, 0, 0);
154 if (fh != -1)
156 while (waitline (fh, buf, sizeof buf, FALSE) != -1)
158 if (buf[0] != '#' && buf[0] != 0)
160 sep = strchr (buf, ' ');
161 if (sep)
163 sep[0] = 0;
164 notify_adduser (buf, sep + 1);
166 else
167 notify_adduser (buf, NULL);
170 close (fh);
174 static struct notify_per_server *
175 notify_find (server *serv, char *nick)
177 GSList *list = notify_list;
178 struct notify_per_server *servnot;
179 struct notify *notify;
181 while (list)
183 notify = (struct notify *) list->data;
185 servnot = notify_find_server_entry (notify, serv);
186 if (!servnot)
188 list = list->next;
189 continue;
192 if (!serv->p_cmp (notify->name, nick))
193 return servnot;
195 list = list->next;
198 return 0;
201 static void
202 notify_announce_offline (server * serv, struct notify_per_server *servnot,
203 char *nick, int quiet)
205 session *sess;
207 sess = serv->front_session;
209 servnot->ison = FALSE;
210 servnot->lastoff = time (0);
211 if (!quiet)
212 EMIT_SIGNAL (XP_TE_NOTIFYOFFLINE, sess, nick, serv->servername,
213 server_get_network (serv, TRUE), NULL, 0);
214 fe_notify_update (nick);
215 fe_notify_update (0);
218 static void
219 notify_announce_online (server * serv, struct notify_per_server *servnot,
220 char *nick)
222 session *sess;
224 sess = serv->front_session;
226 servnot->lastseen = time (0);
227 if (servnot->ison)
228 return;
230 servnot->ison = TRUE;
231 servnot->laston = time (0);
232 EMIT_SIGNAL (XP_TE_NOTIFYONLINE, sess, nick, serv->servername,
233 server_get_network (serv, TRUE), NULL, 0);
234 fe_notify_update (nick);
235 fe_notify_update (0);
237 if (prefs.whois_on_notifyonline)
240 /* Let's do whois with idle time (like in /quote WHOIS %s %s) */
242 char *wii_str = malloc (strlen (nick) * 2 + 2);
243 sprintf (wii_str, "%s %s", nick, nick);
244 serv->p_whois (serv, wii_str);
245 free (wii_str);
249 /* handles numeric 601 */
251 void
252 notify_set_offline (server * serv, char *nick, int quiet)
254 struct notify_per_server *servnot;
256 servnot = notify_find (serv, nick);
257 if (!servnot)
258 return;
260 notify_announce_offline (serv, servnot, nick, quiet);
263 /* handles numeric 604 and 600 */
265 void
266 notify_set_online (server * serv, char *nick)
268 struct notify_per_server *servnot;
270 servnot = notify_find (serv, nick);
271 if (!servnot)
272 return;
274 notify_announce_online (serv, servnot, nick);
277 static void
278 notify_watch (server * serv, char *nick, int add)
280 char tbuf[256];
281 char addchar = '+';
283 if (!add)
284 addchar = '-';
286 if (serv->supports_monitor)
287 snprintf (tbuf, sizeof (tbuf), "MONITOR %c %s", addchar, nick);
288 else if (serv->supports_watch)
289 snprintf (tbuf, sizeof (tbuf), "WATCH %c%s", addchar, nick);
290 else
291 return;
293 serv->p_raw (serv, tbuf);
296 static void
297 notify_watch_all (struct notify *notify, int add)
299 server *serv;
300 GSList *list = serv_list;
301 while (list)
303 serv = list->data;
304 if (serv->connected && serv->end_of_motd && notify_do_network (notify, serv))
305 notify_watch (serv, notify->name, add);
306 list = list->next;
310 static void
311 notify_flush_watches (server * serv, GSList *from, GSList *end)
313 char tbuf[512];
314 GSList *list;
315 struct notify *notify;
317 serv->supports_monitor ? strcpy (tbuf, "MONITOR + ") : strcpy (tbuf, "WATCH");
319 list = from;
320 while (list != end)
322 notify = list->data;
323 serv->supports_monitor ? strcat (tbuf, ",") : strcat (tbuf, " +");
324 strcat (tbuf, notify->name);
325 list = list->next;
327 serv->p_raw (serv, tbuf);
330 /* called when logging in. e.g. when End of motd. */
332 void
333 notify_send_watches (server * serv)
335 struct notify *notify;
336 GSList *list;
337 GSList *point;
338 int len;
340 len = 0;
341 point = list = notify_list;
342 while (list)
344 notify = list->data;
346 if (notify_do_network (notify, serv))
348 len += strlen (notify->name) + serv->supports_monitor ? 1 : 2; /* just , for monitor or + and space for watch */;
349 if (len > 500)
351 notify_flush_watches (serv, point, list);
352 len = strlen (notify->name) + serv->supports_monitor ? 1 : 2;
353 point = list;
357 list = list->next;
360 if (point)
361 notify_flush_watches (serv, point, NULL);
364 /* called when receiving a ISON 303 - should this func go? */
366 void
367 notify_markonline (server *serv, char *word[])
369 struct notify *notify;
370 struct notify_per_server *servnot;
371 GSList *list = notify_list;
372 int i, seen;
374 while (list)
376 notify = (struct notify *) list->data;
377 servnot = notify_find_server_entry (notify, serv);
378 if (!servnot)
380 list = list->next;
381 continue;
383 i = 4;
384 seen = FALSE;
385 while (*word[i])
387 if (!serv->p_cmp (notify->name, word[i]))
389 seen = TRUE;
390 notify_announce_online (serv, servnot, notify->name);
391 break;
393 i++;
394 /* FIXME: word[] is only a 32 element array, limits notify list to
395 about 27 people */
396 if (i > PDIWORDS - 5)
398 /*fprintf (stderr, _("*** XCHAT WARNING: notify list too large.\n"));*/
399 break;
402 if (!seen && servnot->ison)
404 notify_announce_offline (serv, servnot, notify->name, FALSE);
406 list = list->next;
408 fe_notify_update (0);
411 /* yuck! Old routine for ISON notify */
413 static void
414 notify_checklist_for_server (server *serv)
416 char outbuf[512];
417 struct notify *notify;
418 GSList *list = notify_list;
419 int i = 0;
421 strcpy (outbuf, "ISON ");
422 while (list)
424 notify = list->data;
425 if (notify_do_network (notify, serv))
427 i++;
428 strcat (outbuf, notify->name);
429 strcat (outbuf, " ");
430 if (strlen (outbuf) > 460)
432 /* LAME: we can't send more than 512 bytes to the server, but *
433 * if we split it in two packets, our offline detection wouldn't *
434 work */
435 /*fprintf (stderr, _("*** XCHAT WARNING: notify list too large.\n"));*/
436 break;
439 list = list->next;
442 if (i)
443 serv->p_raw (serv, outbuf);
447 notify_checklist (void) /* check ISON list */
449 struct server *serv;
450 GSList *list = serv_list;
452 while (list)
454 serv = list->data;
455 if (serv->connected && serv->end_of_motd && !serv->supports_watch && !serv->supports_monitor)
457 notify_checklist_for_server (serv);
459 list = list->next;
461 return 1;
464 void
465 notify_showlist (struct session *sess)
467 char outbuf[256];
468 struct notify *notify;
469 GSList *list = notify_list;
470 struct notify_per_server *servnot;
471 int i = 0;
473 EMIT_SIGNAL (XP_TE_NOTIFYHEAD, sess, NULL, NULL, NULL, NULL, 0);
474 while (list)
476 i++;
477 notify = (struct notify *) list->data;
478 servnot = notify_find_server_entry (notify, sess->server);
479 if (servnot && servnot->ison)
480 snprintf (outbuf, sizeof (outbuf), _(" %-20s online\n"), notify->name);
481 else
482 snprintf (outbuf, sizeof (outbuf), _(" %-20s offline\n"), notify->name);
483 PrintText (sess, outbuf);
484 list = list->next;
486 if (i)
488 sprintf (outbuf, "%d", i);
489 EMIT_SIGNAL (XP_TE_NOTIFYNUMBER, sess, outbuf, NULL, NULL, NULL, 0);
490 } else
491 EMIT_SIGNAL (XP_TE_NOTIFYEMPTY, sess, NULL, NULL, NULL, NULL, 0);
495 notify_deluser (char *name)
497 struct notify *notify;
498 struct notify_per_server *servnot;
499 GSList *list = notify_list;
501 while (list)
503 notify = (struct notify *) list->data;
504 if (!rfc_casecmp (notify->name, name))
506 fe_notify_update (notify->name);
507 /* Remove the records for each server */
508 while (notify->server_list)
510 servnot = (struct notify_per_server *) notify->server_list->data;
511 notify->server_list =
512 g_slist_remove (notify->server_list, servnot);
513 free (servnot);
515 notify_list = g_slist_remove (notify_list, notify);
516 notify_watch_all (notify, FALSE);
517 if (notify->networks)
518 free (notify->networks);
519 free (notify->name);
520 free (notify);
521 fe_notify_update (0);
522 return 1;
524 list = list->next;
526 return 0;
529 void
530 notify_adduser (char *name, char *networks)
532 struct notify *notify = malloc (sizeof (struct notify));
533 if (notify)
535 memset (notify, 0, sizeof (struct notify));
536 if (strlen (name) >= NICKLEN)
538 notify->name = malloc (NICKLEN);
539 safe_strcpy (notify->name, name, NICKLEN);
540 } else
542 notify->name = strdup (name);
544 if (networks)
545 notify->networks = despacify_dup (networks);
546 notify->server_list = 0;
547 notify_list = g_slist_prepend (notify_list, notify);
548 notify_checklist ();
549 fe_notify_update (notify->name);
550 fe_notify_update (0);
551 notify_watch_all (notify, TRUE);
555 gboolean
556 notify_is_in_list (server *serv, char *name)
558 struct notify *notify;
559 GSList *list = notify_list;
561 while (list)
563 notify = (struct notify *) list->data;
564 if (!serv->p_cmp (notify->name, name))
565 return TRUE;
566 list = list->next;
569 return FALSE;
573 notify_isnotify (struct session *sess, char *name)
575 struct notify *notify;
576 struct notify_per_server *servnot;
577 GSList *list = notify_list;
579 while (list)
581 notify = (struct notify *) list->data;
582 if (!sess->server->p_cmp (notify->name, name))
584 servnot = notify_find_server_entry (notify, sess->server);
585 if (servnot && servnot->ison)
586 return TRUE;
588 list = list->next;
591 return FALSE;
594 void
595 notify_cleanup ()
597 GSList *list = notify_list;
598 GSList *nslist, *srvlist;
599 struct notify *notify;
600 struct notify_per_server *servnot;
601 struct server *serv;
602 int valid;
604 while (list)
606 /* Traverse the list of notify structures */
607 notify = (struct notify *) list->data;
608 nslist = notify->server_list;
609 while (nslist)
611 /* Look at each per-server structure */
612 servnot = (struct notify_per_server *) nslist->data;
614 /* Check the server is valid */
615 valid = FALSE;
616 srvlist = serv_list;
617 while (srvlist)
619 serv = (struct server *) srvlist->data;
620 if (servnot->server == serv)
622 valid = serv->connected; /* Only valid if server is too */
623 break;
625 srvlist = srvlist->next;
627 if (!valid)
629 notify->server_list =
630 g_slist_remove (notify->server_list, servnot);
631 free (servnot);
632 nslist = notify->server_list;
633 } else
635 nslist = nslist->next;
638 list = list->next;
640 fe_notify_update (0);