/************************************************************************
 *   IRC - Internet Relay Chat, server/s_dcc.c
 *
 *   Copyright (C) 2000-2003 TR-IRCD Development
 *
 *   Copyright (C) 1990 Jarkko Oikarinen and
 *                      University of Oulu, Co Center
 *
 *   See file AUTHORS in IRC package for additional names of
 *   the programmers.
 *
 *   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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
 * $Id: s_dcc.c,v 1.7 2003/08/12 10:22:19 tr-ircd Exp $ 
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "numeric.h"

int add_dccallow(aClient *sptr, aClient *cptr)
{
    dlink_node *ptr;
    int cnt;

    if (!IsPerson(cptr) || !IsPerson(sptr))
	return 0;
    cnt = dlink_list_length(&(sptr->user->dccallow));

    if (dlinkFind(&(sptr->user->dccallow), cptr))
	return 0;
    if (++cnt >= MAXDCCALLOW) {
	send_me_numeric(sptr, ERR_TOOMANYDCC, cptr->name, MAXDCCALLOW);
	return 0;
    }
    ptr = make_dlink_node();
    dlinkAdd(cptr, ptr, &(sptr->user->dccallow));
    ptr = make_dlink_node();
    dlinkAdd(sptr, ptr, &(cptr->user->allowed_by));
    send_me_numeric(sptr, RPL_DCCSTATUS, cptr->name, "added to");
    return 0;
}

int del_dccallow(aClient *sptr, aClient *optr)
{
    dlink_node **inv, *tmp;

    for (inv = &(sptr->user->dccallow.head); (tmp = *inv); inv = &tmp->next) {
	if (tmp->data == optr) {
	    dlinkDeleteNode(tmp, &(sptr->user->dccallow));
	    break;
	}
    }
    for (inv = &(optr->user->allowed_by.head); (tmp = *inv); inv = &tmp->next) {
	if (tmp->data == sptr) {
	    dlinkDeleteNode(tmp, (&(optr->user->allowed_by)));
	    break;
	}
    }
    send_me_numeric(sptr, RPL_DCCSTATUS, optr->name, "removed from");
    return 0;
}

int remove_dcc_references(aClient *sptr)
{
    aClient *acptr;
    dlink_node *lp, *nextlp;
    dlink_node **lpp, *tmp, *next_tmp;
    lp = sptr->user->dccallow.head;
    while (lp) {
	nextlp = lp->next;
	acptr = lp->data;
	for (lpp = &(acptr->user->allowed_by.head); (tmp = *lpp); lpp = &next_tmp) {
	    next_tmp = tmp->next;
	    if (tmp->data == sptr) 
		dlinkDeleteNode(tmp, &(acptr->user->allowed_by));
	}
	dlinkDeleteNode(lp, &(sptr->user->dccallow));
	lp = nextlp;
    }
    lp = sptr->user->allowed_by.head;
    while (lp) {
        nextlp = lp->next;
        acptr = lp->data;
        for (lpp = &(acptr->user->dccallow.head); (tmp = *lpp); lpp = &next_tmp) {
	    next_tmp = tmp->next;
            if (tmp->data == sptr) {
                sendto_one(acptr, ":%C %N %s :%s has been removed from your DCC allow list for signing off",
                           &me, RPL_DCCINFO, acptr->name, sptr->name);
                dlinkDeleteNode(tmp, &(acptr->user->dccallow));
            }
        }
        dlinkDeleteNode(lp, &(sptr->user->allowed_by));
	lp = nextlp;
    }
    return 0;
}

char *exploits_2char[] = {
    "js", "pl", NULL
};
char *exploits_3char[] = {
    "exe", "com", "bat", "dll", "ini", "vbs", "pif", "mrc",
    "scr", "doc", "xls", "lnk", "shs", "htm", NULL
};
char *exploits_4char[] = {
    "html", NULL
};
int check_dccsend(aClient *from, aClient *to, char *msg)
{
    /*
     * we already know that msg will consist of "DCC SEND" so we can skip to the end
     */
    char *filename = msg + 8;
    char *ext;
    char **farray;
    int arraysz;
    int len = 0, extlen = 0, i;
    /*
     * people can send themselves stuff all the like..
     * * opers need to be able to send cleaner files
     * * sanity checks..
     */
    if (from == to || !IsPerson(from) || IsAnOper(from) || !MyClient(to) || IsDccallowAll(to))
	return 0;
    while (*filename == ' ')
	filename++;
    if (!(*filename))
	return 0;
    while (*(filename + len) != ' ') {
	if (!(*(filename + len)))
	    break;
	len++;
    }
    for (ext = filename + len;; ext--) {
	if (ext == filename)
	    return 0;
	if (*ext == '.') {
	    ext++;
	    extlen--;
	    break;
	}
	extlen++;
    }
    switch (extlen) {
	case 2:
	    farray = exploits_2char;
	    arraysz = 2;
	    break;
	case 3:
	    farray = exploits_3char;
	    arraysz = 3;
	    break;
	case 4:
	    farray = exploits_4char;
	    arraysz = 4;
	    break;
	    /*
	     * no executable file here..
	     */
	default:
	    return 0;
    }

    for (i = 0; farray[i]; i++) {
	if (irc_strncmp(farray[i], ext, arraysz) == 0)
	    break;
    }

    if (farray[i] == NULL)
	return 0;
    if (!allow_dcc(to, from)) {
    char tmpext[8];
    char tmpfn[128];
    dlink_node *tlp, *flp;
    aChannel *chptr = NULL;
    aChannel *achptr = NULL;
    aChannel *bchptr = NULL;
	strlcpy_irc(tmpext, ext, extlen);
	tmpext[extlen] = '\0';
	if (len > 127)
	    len = 127;
	strlcpy_irc(tmpfn, filename, len);
	tmpfn[len] = '\0';
	/*
	 * use notices!
	 * *   server notices are hard to script around.
	 * *   server notices are not ignored by clients.
	 */
	send_me_notice(from,
		       ":The user %s is not accepting DCC sends of filetype *.%s from you."
		       " Your file %s was not sent.", to->name, tmpext, tmpfn);
	send_me_notice(to,
		       ":%s (%s@%s) has attempted to send you a file named %s, which was blocked.",
		       from->name, from->user->username, from->user->host, tmpfn);
	if (!SeenDCCNotice(to)) {
	    to->protoflags |= PFLAGS_DCCNOTICE;
	    send_me_notice(to,
			   ":The majority of files sent of this type are malicious virii and trojan horses."
			   " In order to prevent the spread of this problem, we are blocking DCC sends of"
			   " these types of files by default.");
	    send_me_notice(to,
			   ":If you trust %s, and want him/her to send you this file, you may obtain"
			   " more information on using the dccallow system by typing /quote help dccallow",
			   from->name, to->name);
	}
	for (tlp = to->user->channel.head; tlp && !chptr; tlp = tlp->next) {
	    achptr = tlp->data;
	    for (flp = from->user->channel.head; flp && !chptr; flp = flp->next) {
		bchptr = flp->data;
		if (achptr == bchptr)
		    chptr = achptr;
	    }
	}

	sendto_lev(DCCSEND_LEV, "%^C sending forbidden filetyped file %s to %C",
		       from, tmpfn, to);
	return 1;
    }
    return 0;
}

int allow_dcc(aClient *to, aClient *from)
{
    dlink_node *lp;
    aClient *acptr;
    for (lp = to->user->dccallow.head; lp; lp = lp->next) {
	acptr = lp->data;
	if (acptr == from)
	    return 1;
    }
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1