2011-02-24 04:14:30 +01:00
|
|
|
/* 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 <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
2011-12-11 17:34:02 +01:00
|
|
|
#ifndef WIN32
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2011-02-24 04:14:30 +01:00
|
|
|
#include "xchat.h"
|
|
|
|
#include "ignore.h"
|
|
|
|
#include "cfgfiles.h"
|
|
|
|
#include "fe.h"
|
|
|
|
#include "text.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "xchatc.h"
|
|
|
|
|
|
|
|
|
|
|
|
int ignored_ctcp = 0; /* keep a count of all we ignore */
|
|
|
|
int ignored_priv = 0;
|
|
|
|
int ignored_chan = 0;
|
|
|
|
int ignored_noti = 0;
|
|
|
|
int ignored_invi = 0;
|
|
|
|
static int ignored_total = 0;
|
|
|
|
|
|
|
|
/* ignore_exists ():
|
|
|
|
* returns: struct ig, if this mask is in the ignore list already
|
|
|
|
* NULL, otherwise
|
|
|
|
*/
|
|
|
|
struct ignore *
|
|
|
|
ignore_exists (char *mask)
|
|
|
|
{
|
|
|
|
struct ignore *ig = 0;
|
|
|
|
GSList *list;
|
|
|
|
|
|
|
|
list = ignore_list;
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
ig = (struct ignore *) list->data;
|
|
|
|
if (!rfc_casecmp (ig->mask, mask))
|
|
|
|
return ig;
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ignore_add(...)
|
|
|
|
|
|
|
|
* returns:
|
|
|
|
* 0 fail
|
|
|
|
* 1 success
|
|
|
|
* 2 success (old ignore has been changed)
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
ignore_add (char *mask, int type)
|
|
|
|
{
|
|
|
|
struct ignore *ig = 0;
|
|
|
|
int change_only = FALSE;
|
|
|
|
|
|
|
|
/* first check if it's already ignored */
|
|
|
|
ig = ignore_exists (mask);
|
|
|
|
if (ig)
|
|
|
|
change_only = TRUE;
|
|
|
|
|
|
|
|
if (!change_only)
|
|
|
|
ig = malloc (sizeof (struct ignore));
|
|
|
|
|
|
|
|
if (!ig)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
ig->mask = strdup (mask);
|
|
|
|
ig->type = type;
|
|
|
|
|
|
|
|
if (!change_only)
|
|
|
|
ignore_list = g_slist_prepend (ignore_list, ig);
|
|
|
|
fe_ignore_update (1);
|
|
|
|
|
|
|
|
if (change_only)
|
|
|
|
return 2;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ignore_showlist (session *sess)
|
|
|
|
{
|
|
|
|
struct ignore *ig;
|
|
|
|
GSList *list = ignore_list;
|
|
|
|
char tbuf[256];
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
EMIT_SIGNAL (XP_TE_IGNOREHEADER, sess, 0, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
ig = list->data;
|
|
|
|
i++;
|
|
|
|
|
|
|
|
snprintf (tbuf, sizeof (tbuf), " %-25s ", ig->mask);
|
|
|
|
if (ig->type & IG_PRIV)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
if (ig->type & IG_NOTI)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
if (ig->type & IG_CHAN)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
if (ig->type & IG_CTCP)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
if (ig->type & IG_DCC)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
if (ig->type & IG_INVI)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
if (ig->type & IG_UNIG)
|
|
|
|
strcat (tbuf, _("YES "));
|
|
|
|
else
|
|
|
|
strcat (tbuf, _("NO "));
|
|
|
|
strcat (tbuf, "\n");
|
|
|
|
PrintText (sess, tbuf);
|
|
|
|
/*EMIT_SIGNAL (XP_TE_IGNORELIST, sess, ig->mask, 0, 0, 0, 0); */
|
|
|
|
/* use this later, when TE's support 7 args */
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!i)
|
|
|
|
EMIT_SIGNAL (XP_TE_IGNOREEMPTY, sess, 0, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
EMIT_SIGNAL (XP_TE_IGNOREFOOTER, sess, 0, 0, 0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ignore_del()
|
|
|
|
|
|
|
|
* one of the args must be NULL, use mask OR *ig, not both
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
int
|
|
|
|
ignore_del (char *mask, struct ignore *ig)
|
|
|
|
{
|
|
|
|
if (!ig)
|
|
|
|
{
|
|
|
|
GSList *list = ignore_list;
|
|
|
|
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
ig = (struct ignore *) list->data;
|
|
|
|
if (!rfc_casecmp (ig->mask, mask))
|
|
|
|
break;
|
|
|
|
list = list->next;
|
|
|
|
ig = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ig)
|
|
|
|
{
|
|
|
|
ignore_list = g_slist_remove (ignore_list, ig);
|
|
|
|
free (ig->mask);
|
|
|
|
free (ig);
|
|
|
|
fe_ignore_update (1);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if a msg should be ignored by browsing our ignore list */
|
|
|
|
|
|
|
|
int
|
|
|
|
ignore_check (char *host, int type)
|
|
|
|
{
|
|
|
|
struct ignore *ig;
|
|
|
|
GSList *list = ignore_list;
|
|
|
|
|
|
|
|
/* check if there's an UNIGNORE first, they take precendance. */
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
ig = (struct ignore *) list->data;
|
|
|
|
if (ig->type & IG_UNIG)
|
|
|
|
{
|
|
|
|
if (ig->type & type)
|
|
|
|
{
|
|
|
|
if (match (ig->mask, host))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
list = ignore_list;
|
|
|
|
while (list)
|
|
|
|
{
|
|
|
|
ig = (struct ignore *) list->data;
|
|
|
|
|
|
|
|
if (ig->type & type)
|
|
|
|
{
|
|
|
|
if (match (ig->mask, host))
|
|
|
|
{
|
|
|
|
ignored_total++;
|
|
|
|
if (type & IG_PRIV)
|
|
|
|
ignored_priv++;
|
|
|
|
if (type & IG_NOTI)
|
|
|
|
ignored_noti++;
|
|
|
|
if (type & IG_CHAN)
|
|
|
|
ignored_chan++;
|
|
|
|
if (type & IG_CTCP)
|
|
|
|
ignored_ctcp++;
|
|
|
|
if (type & IG_INVI)
|
|
|
|
ignored_invi++;
|
|
|
|
fe_ignore_update (2);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
list = list->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static char *
|
|
|
|
ignore_read_next_entry (char *my_cfg, struct ignore *ignore)
|
|
|
|
{
|
|
|
|
char tbuf[1024];
|
|
|
|
|
|
|
|
/* Casting to char * done below just to satisfy compiler */
|
|
|
|
|
|
|
|
if (my_cfg)
|
|
|
|
{
|
|
|
|
my_cfg = cfg_get_str (my_cfg, "mask", tbuf, sizeof (tbuf));
|
|
|
|
if (!my_cfg)
|
|
|
|
return NULL;
|
|
|
|
ignore->mask = strdup (tbuf);
|
|
|
|
}
|
|
|
|
if (my_cfg)
|
|
|
|
{
|
|
|
|
my_cfg = cfg_get_str (my_cfg, "type", tbuf, sizeof (tbuf));
|
|
|
|
ignore->type = atoi (tbuf);
|
|
|
|
}
|
|
|
|
return my_cfg;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ignore_load ()
|
|
|
|
{
|
|
|
|
struct ignore *ignore;
|
|
|
|
struct stat st;
|
|
|
|
char *cfg, *my_cfg;
|
|
|
|
int fh, i;
|
|
|
|
|
|
|
|
fh = xchat_open_file ("ignore.conf", O_RDONLY, 0, 0);
|
|
|
|
if (fh != -1)
|
|
|
|
{
|
|
|
|
fstat (fh, &st);
|
|
|
|
if (st.st_size)
|
|
|
|
{
|
|
|
|
cfg = malloc (st.st_size + 1);
|
|
|
|
cfg[0] = '\0';
|
|
|
|
i = read (fh, cfg, st.st_size);
|
|
|
|
if (i >= 0)
|
|
|
|
cfg[i] = '\0';
|
|
|
|
my_cfg = cfg;
|
|
|
|
while (my_cfg)
|
|
|
|
{
|
|
|
|
ignore = malloc (sizeof (struct ignore));
|
|
|
|
memset (ignore, 0, sizeof (struct ignore));
|
|
|
|
if ((my_cfg = ignore_read_next_entry (my_cfg, ignore)))
|
|
|
|
ignore_list = g_slist_prepend (ignore_list, ignore);
|
|
|
|
else
|
|
|
|
free (ignore);
|
|
|
|
}
|
|
|
|
free (cfg);
|
|
|
|
}
|
|
|
|
close (fh);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ignore_save ()
|
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
int fh;
|
|
|
|
GSList *temp = ignore_list;
|
|
|
|
struct ignore *ig;
|
|
|
|
|
|
|
|
fh = xchat_open_file ("ignore.conf", O_TRUNC | O_WRONLY | O_CREAT, 0600, XOF_DOMODE);
|
|
|
|
if (fh != -1)
|
|
|
|
{
|
|
|
|
while (temp)
|
|
|
|
{
|
|
|
|
ig = (struct ignore *) temp->data;
|
|
|
|
if (!(ig->type & IG_NOSAVE))
|
|
|
|
{
|
|
|
|
snprintf (buf, sizeof (buf), "mask = %s\ntype = %d\n\n",
|
|
|
|
ig->mask, ig->type);
|
|
|
|
write (fh, buf, strlen (buf));
|
|
|
|
}
|
|
|
|
temp = temp->next;
|
|
|
|
}
|
|
|
|
close (fh);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
flood_autodialog_timeout (gpointer data)
|
|
|
|
{
|
|
|
|
prefs.autodialog = 1;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
flood_check (char *nick, char *ip, server *serv, session *sess, int what) /*0=ctcp 1=priv */
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
serv
|
|
|
|
int ctcp_counter;
|
|
|
|
time_t ctcp_last_time;
|
|
|
|
prefs
|
|
|
|
unsigned int ctcp_number_limit;
|
|
|
|
unsigned int ctcp_time_limit;
|
|
|
|
*/
|
|
|
|
char buf[512];
|
|
|
|
char real_ip[132];
|
|
|
|
int i;
|
|
|
|
time_t current_time;
|
|
|
|
current_time = time (NULL);
|
|
|
|
|
|
|
|
if (what == 0)
|
|
|
|
{
|
|
|
|
if (serv->ctcp_last_time == 0) /*first ctcp in this server */
|
|
|
|
{
|
|
|
|
serv->ctcp_last_time = time (NULL);
|
|
|
|
serv->ctcp_counter++;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
if (difftime (current_time, serv->ctcp_last_time) < prefs.ctcp_time_limit) /*if we got the ctcp in the seconds limit */
|
|
|
|
{
|
|
|
|
serv->ctcp_counter++;
|
|
|
|
if (serv->ctcp_counter == prefs.ctcp_number_limit) /*if we reached the maximun numbers of ctcp in the seconds limits */
|
|
|
|
{
|
|
|
|
serv->ctcp_last_time = current_time; /*we got the flood, restore all the vars for next one */
|
|
|
|
serv->ctcp_counter = 0;
|
|
|
|
for (i = 0; i < 128; i++)
|
|
|
|
if (ip[i] == '@')
|
|
|
|
break;
|
|
|
|
snprintf (real_ip, sizeof (real_ip), "*!*%s", &ip[i]);
|
|
|
|
/*ignore_add (char *mask, int priv, int noti, int chan,
|
|
|
|
int ctcp, int invi, int unignore, int no_save) */
|
|
|
|
|
|
|
|
snprintf (buf, sizeof (buf),
|
|
|
|
_("You are being CTCP flooded from %s, ignoring %s\n"),
|
|
|
|
nick, real_ip);
|
|
|
|
PrintText (sess, buf);
|
|
|
|
|
|
|
|
/*FIXME: only ignore ctcp or all?, its ignoring ctcps for now */
|
|
|
|
ignore_add (real_ip, IG_CTCP);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
if (serv->msg_last_time == 0)
|
|
|
|
{
|
|
|
|
serv->msg_last_time = time (NULL);
|
|
|
|
serv->ctcp_counter++;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
if (difftime (current_time, serv->msg_last_time) <
|
|
|
|
prefs.msg_time_limit)
|
|
|
|
{
|
|
|
|
serv->msg_counter++;
|
|
|
|
if (serv->msg_counter == prefs.msg_number_limit) /*if we reached the maximun numbers of ctcp in the seconds limits */
|
|
|
|
{
|
|
|
|
snprintf (buf, sizeof (buf),
|
|
|
|
_("You are being MSG flooded from %s, setting gui_auto_open_dialog OFF.\n"),
|
|
|
|
ip);
|
|
|
|
PrintText (sess, buf);
|
|
|
|
serv->msg_last_time = current_time; /*we got the flood, restore all the vars for next one */
|
|
|
|
serv->msg_counter = 0;
|
|
|
|
/*ignore_add (char *mask, int priv, int noti, int chan,
|
|
|
|
int ctcp, int invi, int unignore, int no_save) */
|
|
|
|
|
|
|
|
if (prefs.autodialog)
|
|
|
|
{
|
|
|
|
/*FIXME: only ignore ctcp or all?, its ignoring ctcps for now */
|
|
|
|
prefs.autodialog = 0;
|
|
|
|
/* turn it back on in 30 secs */
|
|
|
|
fe_timeout_add (30000, flood_autodialog_timeout, NULL);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|