/************************************************************************
 *   IRC - Internet Relay Chat, modules/m_oper.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 softwmare; 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.
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "h.h"
#include "msg.h"
#include "numeric.h"
#include "s_conf.h"
#include "throttle.h"
#include "usermode.h"

static struct Message _msgtab[] = {
    {MSG_OPER, 0, MAXPARA, M_SLOW, 0L,
     m_unregistered, m_oper, m_oper, m_ignore, m_ignore}
};

static int log_oper = -1;

#ifndef STATIC_MODULES

char *_version = "$Revision: 1.3 $";

void _modinit(void)
{
    mod_add_cmd(_msgtab);
    log_oper = logevent_register("oper", LOG_ALWAYS, LOG_LOGFILE, LOG_NOTICE,
                                 "OPER (%s) (%s) by (%s!%s@%s)");
}

void _moddeinit(void)
{
    mod_del_cmd(_msgtab);
    logevent_unregister(log_oper);
}
#else
void m_oper_init(void)
{
    mod_add_cmd(_msgtab);
    log_oper = logevent_register("oper", LOG_ALWAYS, LOG_LOGFILE, LOG_NOTICE,                              
                                 "OPER (%s) (%s) by (%s!%s@%s)");       
}
#endif

static void report_privileges(aClient *cptr)
{
   int l = 0;
   if (OPCanDie(cptr)) {
	send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name, 
			"Allowed to use the /die command");
	l++;
   }
   if (OPCanRestart(cptr)) {
        send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name,          
                        "Allowed to use the /restart command");
        l++;
   }
   if (OPIsAdmin(cptr)) {
        send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name,          
                        "Allowed to use the module interface");
        l++;
   }
   if (OPIsSAdmin(cptr)) {
        send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name,          
                        "Allowed to use the /samode command");
        l++;
   }
   if (OPIsGKLine(cptr)) {
        send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name,          
                        "Allowed to use the /kline, /unkline, /gline, /ungline commands");
        l++;
   }
   if (OPIsOpKill(cptr)) {
        send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name,          
                        "Allowed to use the /kill command");
        l++;
   }
   if (OPIsOperdo(cptr)) {
        send_me_numeric(cptr, RPL_OPERPRIVILEGES, cptr->name,          
                        "Allowed to use the /operdo command");
        l++;
   }
   if (l)
	send_me_numeric(cptr, RPL_ENDOFPRIVLIST);
} 


/*
 * * m_oper * parv[0] = sender prefix *       parv[1] = oper name *
 * parv[2] = oper password
 */
int m_oper(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
    aConfItem *aconf;
    char *name, *password, encr[PASSWDLEN];
    int equal = 0;
    dlink_node *ptr;

    name = parc > 1 ? parv[1] : (char *) NULL;
    password = parc > 2 ? parv[2] : (char *) NULL;

    if (BadPtr(name) || BadPtr(password)) {
	send_me_numeric(sptr, ERR_NEEDMOREPARAMS, MSG_OPER);
	return 0;
    }

    if (IsAnOper(sptr)) {
	send_me_numeric(sptr, RPL_YOUREOPER);
	return 0;
    }

    if (!(sptr->user && sptr->user->real_oper_host)) {
	if (!(aconf = find_conf_exact(name, sptr->username, sptr->sockhost, CONF_OPERATOR))
	    && !(aconf = find_conf_exact(name, sptr->username, cptr->hostip, CONF_OPERATOR))) {
	    send_me_numeric(sptr, ERR_NOOPERHOST);
	    sendto_ops("Failed OPER attempt by %^C using uid [%s] - No matching hostname", sptr, name);
	    return 0;
	}
    } else {
	if (!(aconf =
	      find_conf_exact(name, sptr->username,
			      sptr->user->real_oper_host, CONF_OPERATOR))
	    && !(aconf =
		 find_conf_exact(name, sptr->username,
				 sptr->user->real_oper_ip, CONF_OPERATOR))) {
	    send_me_numeric(sptr, ERR_NOOPERHOST);
	    sendto_ops("Failed OPER attempt by %^C using uid [%s] - No matching hostname", sptr, name);
	    return 0;
	}
    }

    equal = !strcmp(aconf->passwd, calcpass(password, encr));

    if ((aconf->status & CONF_OPERATOR) && equal && !attach_conf(sptr, aconf)) {
    int old = (sptr->umode & SEND_UMODES);

	SetOper(sptr);

	ptr = make_dlink_node();
	dlinkAdd(sptr, ptr, &locoper_list);

	throttle_remove(sptr->hostip);

	sptr->umode |= OPER_UMODES;

	if (IsOperFakehost(sptr))
	    sptr->umode &= ~UMODE_x;

	sptr->oflag = aconf->port;

	if (OPIsSeeHidden(sptr))
	    sptr->umode |= UMODE_H;
	if (OPIsSAdmin(sptr))
	    sptr->umode |= UMODE_a;
	if (OPIsAdmin(sptr))
	    sptr->umode |= UMODE_A;

	Count.oper++;

	sendto_ops
	    ("%^C is now operator (O) using host [%s] with uid [%K]",
	     sptr, aconf->host, aconf);

	sendto_serv_butone(NULL, &me, TOK1_GLOBOPS, 
			   ":%^C is now operator (O) using host [%s] with uid [%K]",
             		   sptr, aconf->host, aconf);

	send_umode_out(cptr, sptr, old);

	send_me_numeric(sptr, RPL_YOUREOPER);

	report_privileges(sptr);

	sptr->pingval = get_client_ping(sptr);

	logevent_call(log_oper, name, encr, parv[0], sptr->user->username, sptr->sockhost);
    } else {
	detach_conf(sptr, aconf);
	send_me_numeric(sptr, ERR_PASSWDMISMATCH);
	sendto_ops("Failed OPER attempt by %^C using uid [%s] - Incorrect password", sptr, name);
    }
    return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1