summary refs log blame commit diff stats
path: root/.gitignore
blob: 7b4fcb280757cbdf9872b759afd5a92bd4ac929a (plain) (tree)
1
2
3
4
5
6
7
8
9
79
80
81
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/* X-Chat
 * Copyright (C) 1998 Peter Zelezny.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>

#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif

#include "hexchat.h"
#include "notify.h"
#include "cfgfiles.h"
#include "fe.h"
#include "server.h"
#include "text.h"
#include "util.h"
#include "hexchatc.h"


GSList *notify_list = 0;
int notify_tag = 0;


static char *
despacify_dup (char *str)
{
	char *p, *res = malloc (strlen (str) + 1);

	p = res;
	while (1)
	{
		if (*str != ' ')
		{
			*p = *str;
			if (*p == 0)
				return res;
			p++;
		}
		str++;
	}
}

static int
notify_netcmp (char *str, void *serv)
{
	char *net = despacify_dup (server_get_network (serv, TRUE));

	if (rfc_casecmp (str, net) == 0)
	{
		free (net);
		return 0;	/* finish & return FALSE from token_foreach() */
	}

	free (net);
	return 1;	/* keep going... */
}

/* monitor this nick on this particular network? */

static gboolean
notify_do_network (struct notify *notify, server *serv)
{
	if (!notify->networks)	/* ALL networks for this nick */
		return TRUE;

	if (token_foreach (notify->networks, ',', notify_netcmp, serv))
		return FALSE;	/* network list doesn't contain this one */

	return TRUE;
}

struct notify_per_server *
notify_find_server_entry (struct notify *notify, struct server *serv)
{
	GSList *list = notify->server_list;
	struct notify_per_server *servnot;

	while (list)
	{
		servnot = (struct notify_per_server *) list->data;
		if (servnot->server == serv)
			return servnot;
		list = list->next;
	}

	/* not found, should we add it, or is this not a network where
      we're monitoring this nick? */
	if (!notify_do_network (notify, serv))
		return NULL;

	servnot = malloc (sizeof (struct notify_per_server));
	if (servnot)
	{
		memset (servnot, 0, sizeof (struct notify_per_server));
		servnot->server = serv;
		servnot->notify = notify;
		notify->server_list = g_slist_prepend (notify->server_list, servnot);
	}
	return servnot;
}

void
notify_save (void)
{
	int fh;
	struct notify *notify;
	GSList *list = notify_list;

	fh = hexchat_open_file ("notify.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
	if (fh != -1)
	{
		while (list)
		{
			notify = (struct notify *) list->data;
			write (fh, notify->name, strlen (notify->name));
			if (notify->networks)
			{
				write (fh, " ", 1);
				write (fh, notify->networks, strlen (notify->networks));
			}
			write (fh, "\n", 1);
			list = list->next;
		}
		close (fh);
	}
}

void
notify_load (void)
{
	int fh;
	char buf[256];
	char *sep;

	fh = hexchat_open_file ("notify.conf", O_RDONLY, 0, 0);
	if (fh != -1)
	{
		while (waitline (fh, buf, sizeof buf, FALSE) != -1)
		{
			if (buf[0] != '#' && buf[0] != 0)
			{
				sep = strchr (buf, ' ');
				if (sep)
				{
					sep[0] = 0;
					notify_adduser (buf, sep + 1);					
				}
				else
					notify_adduser (buf, NULL);
			}
		}
		close (fh);
	}
}

static struct notify_per_server *
notify_find (server *serv, char *nick)
{
	GSList *list = notify_list;
	struct notify_per_server *servnot;
	struct notify *notify;

	while (list)
	{
		notify = (struct notify *) list->data;

		servnot = notify_find_server_entry (notify, serv);
		if (!servnot)
		{
			list = list->next;
			continue;
		}

		if (!serv->p_cmp (notify->name, nick))
			return servnot;

		list = list->next;
	}

	return 0;
}

static void
notify_announce_offline (server * serv, struct notify_per_server *servnot,
								char *nick, int quiet)
{
	session *sess;

	sess = serv->front_session;

	servnot->ison = FALSE;
	servnot->lastoff = time (0);
	if (!quiet)
		EMIT_SIGNAL (XP_TE_NOTIFYOFFLINE, sess, nick, serv->servername,
						 server_get_network (serv, TRUE), NULL, 0);
	fe_notify_update (nick);
	fe_notify_update (0);
}

static void
notify_announce_online (server * serv, struct notify_per_server *servnot,
								char *nick)
{
	session *sess;

	sess = serv->front_session;

	servnot->lastseen = time (0);
	if (servnot->ison)
		return;

	servnot->ison = TRUE;
	servnot->laston = time (0);
	EMIT_SIGNAL (XP_TE_NOTIFYONLINE, sess, nick, serv->servername,
					 server_get_network (serv, TRUE), NULL, 0);
	fe_notify_update (nick);
	fe_notify_update (0);

	if (prefs.hex_notify_whois_online)
	{

	    /* Let's do whois with idle time (like in /quote WHOIS %s %s) */

	    char *wii_str = malloc (strlen (nick) * 2 + 2);
	    sprintf (wii_str, "%s %s", nick, nick);
	    serv->p_whois (serv, wii_str);
	    free (wii_str);
	}
}

/* handles numeric 601 */

void
notify_set_offline (server * serv, char *nick, int quiet)
{
	struct notify_per_server *servnot;

	servnot = notify_find (serv, nick);
	if (!servnot)
		return;

	notify_announce_offline (serv, servnot, nick, quiet);
}

/* handles numeric 604 and 600 */

void
notify_set_online (server * serv, char *nick)
{
	struct notify_per_server *servnot;

	servnot = notify_find (serv, nick);
	if (!servnot)
		return;

	notify_announce_online (serv, servnot, nick);
}

static void
notify_watch (server * serv, char *nick, int add)
{
	char tbuf[256];

	snprintf (tbuf, sizeof (tbuf), "WATCH +%s", nick);
	if (!add)
		tbuf[6] = '-';
	serv->p_raw (serv, tbuf);
}

static void
notify_watch_all (struct notify *notify, int add)
{
	server *serv;
	GSList *list = serv_list;
	while (list)
	{
		serv = list->data;
		if (serv->connected && serv->end_of_motd && serv->supports_watch &&
			 notify_do_network (notify, serv))
			notify_watch (serv, notify->name, add);
		list = list->next;
	}
}

static void
notify_flush_watches (server * serv, GSList *from, GSList *end)
{
	char tbuf[512];
	GSList *list;
	struct notify *notify;

	strcpy (tbuf, "WATCH");

	list = from;
	while (list != end)
	{
		notify = list->data;
		strcat (tbuf, " +");
		strcat (tbuf, notify->name);
		list = list->next;
	}
	serv->p_raw (serv, tbuf);
}

/* called when logging in. e.g. when End of motd. */

void
notify_send_watches (server * serv)
{
	struct notify *notify;
	GSList *list;
	GSList *point;
	int len;

	len = 0;
	point = list = notify_list;
	while (list)
	{
		notify = list->data;

		if (notify_do_network (notify, serv))
		{
			len += strlen (notify->name) + 2 /* + and space */;
			if (len > 500)
			{
				notify_flush_watches (serv, point, list);
				len = strlen (notify->name) + 2;
				point = list;
			}
		}

		list = list->next;
	}

	if (point)
		notify_flush_watches (serv, point, NULL);
}

/* called when receiving a ISON 303 - should this func go? */

void
notify_markonline (server *serv, char *word[])
{
	struct notify *notify;
	struct notify_per_server *servnot;
	GSList *list = notify_list;
	int i, seen;

	while (list)
	{
		notify = (struct notify *) list->data;
		servnot = notify_find_server_entry (notify, serv);
		if (!servnot)
		{
			list = list->next;
			continue;
		}
		i = 4;
		seen = FALSE;
		while (*word[i])
		{
			if (!serv->p_cmp (notify->name, word[i]))
			{
				seen = TRUE;
				notify_announce_online (serv, servnot, notify->name);
				break;
			}
			i++;
			/* FIXME: word[] is only a 32 element array, limits notify list to
			   about 27 people */
			if (i > PDIWORDS - 5)
			{
				/*fprintf (stderr, _("*** HEXCHAT WARNING: notify list too large.\n"));*/
				break;
			}
		}
		if (!seen && servnot->ison)
		{
			notify_announce_offline (serv, servnot, notify->name, FALSE);
		}
		list = list->next;
	}
	fe_notify_update (0);
}

/* yuck! Old routine for ISON notify */

static void
notify_checklist_for_server (server *serv)
{
	char outbuf[512];
	struct notify *notify;
	GSList *list = notify_list;
	int i = 0;

	strcpy (outbuf, "ISON ");
	while (list)
	{
		notify = list->data;
		if (notify_do_network (notify, serv))
		{
			i++;
			strcat (outbuf, notify->name);
			strcat (outbuf, " ");
			if (strlen (outbuf) > 460)
			{
				/* LAME: we can't send more than 512 bytes to the server, but     *
				 * if we split it in two packets, our offline detection wouldn't  *
				 work                                                           */
				/*fprintf (stderr, _("*** HEXCHAT WARNING: notify list too large.\n"));*/
				break;
			}
		}
		list = list->next;
	}

	if (i)
		serv->p_raw (serv, outbuf);
}

int
notify_checklist (void)	/* check ISON list */
{
	struct server *serv;
	GSList *list = serv_list;

	while (list)
	{
		serv = list->data;
		if (serv->connected && serv->end_of_motd && !serv->supports_watch)
		{
			notify_checklist_for_server (serv);
		}
		list = list->next;
	}
	return 1;
}

void
notify_showlist (struct session *sess)
{
	char outbuf[256];
	struct notify *notify;
	GSList *list = notify_list;
	struct notify_per_server *servnot;
	int i = 0;

	EMIT_SIGNAL (XP_TE_NOTIFYHEAD, sess, NULL, NULL, NULL, NULL, 0);
	while (list)
	{
		i++;
		notify = (struct notify *) list->data;
		servnot = notify_find_server_entry (notify, sess->server);
		if (servnot && servnot->ison)
			snprintf (outbuf, sizeof (outbuf), _("  %-20s online\n"), notify->name);
		else
			snprintf (outbuf, sizeof (outbuf), _("  %-20s offline\n"), notify->name);
		PrintText (sess, outbuf);
		list = list->next;
	}
	if (i)
	{
		sprintf (outbuf, "%d", i);
		EMIT_SIGNAL (XP_TE_NOTIFYNUMBER, sess, outbuf, NULL, NULL, NULL, 0);
	} else
		EMIT_SIGNAL (XP_TE_NOTIFYEMPTY, sess, NULL, NULL, NULL, NULL, 0);
}

int
notify_deluser (char *name)
{
	struct notify *notify;
	struct notify_per_server *servnot;
	GSList *list = notify_list;

	while (list)
	{
		notify = (struct notify *) list->data;
		if (!rfc_casecmp (notify->name, name))
		{
			fe_notify_update (notify->name);
			/* Remove the records for each server */
			while (notify->server_list)
			{
				servnot = (struct notify_per_server *) notify->server_list->data;
				notify->server_list =
					g_slist_remove (notify->server_list, servnot);
				free (servnot);
			}
			notify_list = g_slist_remove (notify_list, notify);
			notify_watch_all (notify, FALSE);
			if (notify->networks)
				free (notify->networks);
			free (notify->name);
			free (notify);
			fe_notify_update (0);
			return 1;
		}
		list = list->next;
	}
	return 0;
}

void
notify_adduser (char *name, char *networks)
{
	struct notify *notify = malloc (sizeof (struct notify));
	if (notify)
	{
		memset (notify, 0, sizeof (struct notify));
		if (strlen (name) >= NICKLEN)
		{
			notify->name = malloc (NICKLEN);
			safe_strcpy (notify->name, name, NICKLEN);
		} else
		{
			notify->name = strdup (name);
		}
		if (networks)
			notify->networks = despacify_dup (networks);
		notify->server_list = 0;
		notify_list = g_slist_prepend (notify_list, notify);
		notify_checklist ();
		fe_notify_update (notify->name);
		fe_notify_update (0);
		notify_watch_all (notify, TRUE);
	}
}

gboolean
notify_is_in_list (server *serv, char *name)
{
	struct notify *notify;
	GSList *list = notify_list;

	while (list)
	{
		notify = (struct notify *) list->data;
		if (!serv->p_cmp (notify->name, name))
			return TRUE;
		list = list->next;
	}

	return FALSE;
}

int
notify_isnotify (struct session *sess, char *name)
{
	struct notify *notify;
	struct notify_per_server *servnot;
	GSList *list = notify_list;

	while (list)
	{
		notify = (struct notify *) list->data;
		if (!sess->server->p_cmp (notify->name, name))
		{
			servnot = notify_find_server_entry (notify, sess->server);
			if (servnot && servnot->ison)
				return TRUE;
		}
		list = list->next;
	}

	return FALSE;
}

void
notify_cleanup ()
{
	GSList *list = notify_list;
	GSList *nslist, *srvlist;
	struct notify *notify;
	struct notify_per_server *servnot;
	struct server *serv;
	int valid;

	while (list)
	{
		/* Traverse the list of notify structures */
		notify = (struct notify *) list->data;
		nslist = notify->server_list;
		while (nslist)
		{
			/* Look at each per-server structure */
			servnot = (struct notify_per_server *) nslist->data;

			/* Check the server is valid */
			valid = FALSE;
			srvlist = serv_list;
			while (srvlist)
			{
				serv = (struct server *) srvlist->data;
				if (servnot->server == serv)
				{
					valid = serv->connected;	/* Only valid if server is too */
					break;
				}
				srvlist = srvlist->next;
			}
			if (!valid)
			{
				notify->server_list =
					g_slist_remove (notify->server_list, servnot);
				free (servnot);
				nslist = notify->server_list;
			} else
			{
				nslist = nslist->next;
			}
		}
		list = list->next;
	}
	fe_notify_update (0);
}