/*
 * notify.c: a few handy routines to notify you when people enter and leave irc 
 *
 * Written By Michael Sandrof
 *
 * Copyright(c) 1990, 1995 Michael Sandroff and others
 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
 *
 * Revamped by lynX - Dec '91
 * Expanded to allow notify on every server by hop, Feb 1996.
 */

#if 0
static	char	rcsid[] = "@(#)$Id: notify.c,v 1.11 1994/07/30 17:31:55 mrg Exp $";
#endif

#include "irc.h"

#include "list.h"
#include "notify.h"
#include "ircaux.h"
#include "whois.h"
#include "hook.h"
#include "server.h"
#include "output.h"
#include "vars.h"

/* NotifyList: the structure for the notify stuff */
typedef	struct	notify_stru
{
	struct	notify_stru	*next;	/* pointer to next notify person */
	char	*nick;			/* nickname of person to notify about */
	int	flag;			/* 1=person on irc, 0=person not on irc */
}	NotifyList;

extern Server *server_list;
extern int number_of_servers;
extern void	ison_notify _((char *, char *));

/* Rewritten, -lynx */
#ifdef __STDC__
void show_notify_list (int all)
#else
void show_notify_list(all)
	int	all;
#endif
{
	NotifyList	*tmp;
	char	*list = (char *) 0;

	malloc_strcpy(&list, empty_string);

	for (tmp = server_list[from_server].notify_list; tmp; tmp = tmp->next)
	{
		if (tmp->flag)
		{
			malloc_strcat(&list, " ");
			malloc_strcat(&list, tmp->nick);
		}
	}

	if (*list)
		say("Currently present:%s", list);

	if (all)
	{
		malloc_strcpy(&list, empty_string);
		for (tmp = server_list[from_server].notify_list; tmp; tmp = tmp->next)
		{
			if (!(tmp->flag))
			{
				malloc_strcat(&list, " ");
				malloc_strcat(&list, tmp->nick);
			}
		}
		if (*list) say("Currently absent:%s", list);
	}
	new_free(&list);
}

/* notify: the NOTIFY command.  Does the whole ball-o-wax */
#ifdef __STDC__
void notify (char *command, char *args, char *subargs)
#else
void notify(command, args, subargs)
	char	*command,
		*args;
	char	*subargs;
#endif
{
	char		*nick,
			*list = (char *) 0,
			*ptr;
	int		no_nicks = 1;
	int		do_ison = 0;
	int		shown = 0;
	NotifyList	*new;
	int		servnum;

	malloc_strcpy(&list, empty_string);
	while ((nick = next_arg(args, &args)) != NULL)
	{
		no_nicks = 0;
		while (nick)
		{
			shown = 0;
			if ((ptr = index(nick, ',')) != NULL)
				*ptr++ = '\0';

			if (*nick == '-')
			{
				nick++;

				if (*nick)
				{
					for (servnum = 0; servnum < number_of_servers; servnum++)
					{
						if ((new = (NotifyList *) remove_from_list((List **)&(server_list[servnum].notify_list), nick)))
						{
							new_free(&(new->nick));
							new_free((char **)&new);
							if (!shown)
							{
								say("%s removed from notification list", nick);
								shown = 1;
							}
						}
						else
						{
							if (!shown)
							{
								say("%s is not on the notification list", nick);
								shown = 1;
							}
						}
					}
				}
				else
				{
					for (servnum = 0; servnum < number_of_servers; servnum++)
					{
						while ((new = server_list[servnum].notify_list))
						{
							server_list[servnum].notify_list = new->next;
							new_free(&new->nick);
							new_free((char **)&new);
						}
					}
					say("Notify list cleared");
				}
			}
			else
			{
				/* compatibility */
				if (*nick == '+')
					nick++;

				if (*nick)
				{
					if (index(nick, '*'))
						say("Wildcards not allowed in NOTIFY nicknames!");
					else
					{
						do_ison = 1;
						for (servnum = 0; servnum < number_of_servers; servnum++)
						{
							if ((new = (NotifyList *) remove_from_list((List **)&server_list[servnum].notify_list, nick)) != NULL)
							{
								new_free(&(new->nick));
								new_free((char **)&new);
							}
							new = (NotifyList *) new_malloc(sizeof(NotifyList));
							new->nick = m_strdup(nick);
							new->flag = 0;
							add_to_list((List **)&server_list[servnum].notify_list, (List *)new);
						}
						malloc_strcat(&list, new->nick);
						malloc_strcat(&list, " ");
						say("%s added to the notification list", nick);
					}
				} 
				else
					show_notify_list(0);
			}
			nick = ptr;
		}
	}

	if (do_ison)
	{
		for (servnum = 0; servnum < number_of_servers; servnum++)
		{
			from_server = servnum;
			add_ison_to_whois(list, ison_notify);
		}
	}

	new_free(&list);

	if (no_nicks)
		show_notify_list(1);
}

/*
 * do_notify:  This goes through the master notify list and collects it
 * into groups of 500 character sets.  Then it sends this out to each 
 * connected server.  It repeats this until the whole list has been parsed.
 */
void do_notify _((void))
{
	int		size;
	char		buf[501];
	NotifyList	*tmp;
	int 		old_from_server = from_server;
	int		servnum;

	if (!number_of_servers)
		return;

	tmp = server_list[0].notify_list;

	while (tmp)
	{
		for (*buf = 0, size = 0; tmp; tmp = tmp->next)
		{
			size += strlen(tmp->nick) + 1;
			if (size < 501)
			{
				strcat(buf, " ");
				strcat(buf, tmp->nick);
			}
			else
				break;
		}

		if (!size)
			continue;

		for (servnum = 0; servnum < number_of_servers; servnum++)
		{
			if (is_server_connected(servnum))
			{
				from_server = servnum;
				add_ison_to_whois(buf, ison_notify);
			}
		}
	}

	from_server = old_from_server;
	return;
}

/*
 * notify_mark: This marks a given person on the notify list as either on irc
 * (if flag is 1), or not on irc (if flag is 0).  If the person's status has
 * changed since the last check, a message is displayed to that effect.  If
 * the person is not on the notify list, this call is ignored 
 * doit if passed as 0 means it comes from a join, or a msg, etc, not from
 * an ison reply.  1 is the other..
 */
#ifdef __STDC__
void notify_mark (char *nick, int flag, int doit)
#else
void notify_mark(nick, flag, doit)
	char	*nick;
	int	flag;
	int	doit;
#endif
{
	NotifyList	*tmp;
	char	*s = get_string_var(NOTIFY_HANDLER_VAR);

	if (!s || (!doit && ('O' == *s)))		/* old notify */
		return;	

	if ('N' == *s)					/* noisy notify */
		doit = 1;

	if ((tmp = (NotifyList *) list_lookup((List **)&(server_list[from_server].notify_list), nick, !USE_WILDCARDS, !REMOVE_FROM_LIST)) != NULL)
	{
		if (flag)
		{
			if (tmp->flag != 1)
			{
				if ((tmp->flag != -1) && do_hook(NOTIFY_SIGNON_LIST, "%s", nick) && doit)
					say("Signon by %s detected", nick);
				/*
				 * copy the correct case of the nick
				 * into our array  ;)
				 */
				malloc_strcpy(&(tmp->nick), nick);
				malloc_strcpy(&last_notify_nick, nick);
				tmp->flag = 1;
			}
		}
		else
		{
			if ((tmp->flag == 1) && do_hook(NOTIFY_SIGNOFF_LIST, "%s", nick) && doit)
				say("Signoff by %s detected", nick);
			tmp->flag = 0;
		}
	}
}

#ifdef __STDC__
void save_notify (FILE *fp)
#else
void save_notify(fp)
	FILE	*fp;
#endif
{
	NotifyList	*tmp;

	if (number_of_servers && server_list[0].notify_list)
	{
		fprintf(fp, "NOTIFY");
		for (tmp = server_list[0].notify_list; tmp; tmp = tmp->next)
			fprintf(fp, " %s", tmp->nick);
		fprintf(fp, "\n");
	}
}

/* I hate broken compilers -mrg */
static	char	*vals[] = { "NOISY", "QUIET", "OLD", (char *) 0 };

#ifdef __STDC__
void set_notify_handler (char *value)
#else
void set_notify_handler(value)
	char	*value;
#endif
{
	int	len;
	int	i;
	char	*s;

	if (!value)
		value = empty_string;
	for (i = 0, len = strlen (value); (s = vals[i]); i++)
		if (0 == my_strnicmp(value, s, len))
			break;
	set_string_var(NOTIFY_HANDLER_VAR, s);
	return;
}

#ifdef __STDC__
void make_notify_list (int servnum)
#else
void make_notify_list (servnum)
	int servnum;
#endif
{
	NotifyList *tmp;
	char *list = NULL;

	server_list[servnum].notify_list = NULL;

	for (tmp = server_list[0].notify_list; tmp; tmp = tmp->next)
	{
		NotifyList *new = (NotifyList *)new_malloc(sizeof(NotifyList));
		new->nick = m_strdup(tmp->nick);
		new->flag = 0;
		add_to_list((List **)&server_list[servnum].notify_list, (List *)new);
		malloc_strcat(&list, new->nick);
		malloc_strcat(&list, " ");

	}

	if (list)
	{
		add_ison_to_whois(list, ison_notify);
		new_free(&list);
	}
}


#ifdef __STDC__
char *get_notify_nicks (int showserver, int showon)
#else
char *get_notify_nicks (showserver, showon)
int showserver, showon;
#endif
{
	NotifyList *tmp;
	char *list = NULL;

	if (showserver >= number_of_servers)
		return m_strdup(empty_string);

	for (tmp = server_list[showserver].notify_list; tmp; tmp = tmp->next)
	{
		if (showon == -1 || showon == tmp->flag)
			m_s3cat(&list, " ", tmp->nick);
	}

	return list ? list : m_strdup(empty_string);
}
