mirror of
https://github.com/EnergyMech/energymech.git
synced 2025-12-29 16:14:43 +00:00
397 lines
8.4 KiB
C
397 lines
8.4 KiB
C
/*
|
|
|
|
EnergyMech, IRC bot software
|
|
Copyright (c) 2001-2005 proton
|
|
|
|
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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
#define BOUNCE_C
|
|
#include "config.h"
|
|
|
|
#ifdef BOUNCE
|
|
#include "defines.h"
|
|
#include "structs.h"
|
|
#include "global.h"
|
|
#include "h.h"
|
|
#include "text.h"
|
|
#include "mcmd.h"
|
|
|
|
#define INTERNAL_NICK "bounce"
|
|
#define INTERNAL_SOURCE ":bounce!bounce@bounce"
|
|
#define TEXT_ASK_HANDLE INTERNAL_SOURCE " PRIVMSG %s :" TEXT_ENTERNICKNAME "\n"
|
|
#define TEXT_ASK_PASSWORD INTERNAL_SOURCE " PRIVMSG %s :" TEXT_ENTERPASSWORD "\n"
|
|
#define TEXT_ASK_SERVER INTERNAL_SOURCE " PRIVMSG %s :Which server would you like to connect to?\n"
|
|
#define TEXT_USING_VHOST INTERNAL_SOURCE " PRIVMSG %s :Using virtual host %s\n"
|
|
#define TEXT_NOW_CONNECTING INTERNAL_SOURCE " PRIVMSG %s :Now connecting to %s:%i ...\n"
|
|
|
|
#define BNC_LOGIN 0
|
|
#define BNC_ASK_HANDLE 1
|
|
#define BNC_ASK_PASSWORD 2
|
|
#define BNC_ASK_SERVER 3
|
|
#define BNC_CONNECTING 4
|
|
#define BNC_ACTIVE 5
|
|
#define BNC_DEAD 6
|
|
|
|
#ifdef IDWRAP
|
|
|
|
#define USE_VHOST 2
|
|
|
|
#else /* not IDWRAP */
|
|
|
|
#define USE_VHOST TRUE
|
|
|
|
#endif /* IDWRAP */
|
|
|
|
void bounce_parse(ircLink *irc, char *message)
|
|
{
|
|
Mech fakebot;
|
|
User *user;
|
|
char *cmd,*server,*aport,*virtual;
|
|
int iport;
|
|
|
|
if (irc->status == BNC_LOGIN)
|
|
{
|
|
cmd = chop(&message);
|
|
if (!stringcasecmp(cmd,"USER"))
|
|
{
|
|
if (irc->userLine)
|
|
return;
|
|
set_mallocdoer(bounce_parse);
|
|
irc->userLine = stringdup(message);
|
|
}
|
|
else
|
|
if (!stringcasecmp(cmd,"NICK"))
|
|
{
|
|
if (irc->nickLine)
|
|
return;
|
|
set_mallocdoer(bounce_parse);
|
|
irc->nickLine = stringdup(message);
|
|
if ((cmd = chop(&message)) == NULL)
|
|
{
|
|
irc->status = BNC_DEAD;
|
|
return;
|
|
}
|
|
set_mallocdoer(bounce_parse);
|
|
irc->nick = stringdup(cmd);
|
|
}
|
|
if (irc->userLine && irc->nickLine)
|
|
{
|
|
to_file(irc->usersock,TEXT_ASK_HANDLE,irc->nick);
|
|
irc->active = now;
|
|
++irc->status;
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* "PRIVMSG bounce :<handle>" */
|
|
/* "PRIVMSG bounce :<password>" */
|
|
/* "PRIVMSG bounce :<server> [port [virtual]]" */
|
|
|
|
server = chop(&message);
|
|
cmd = chop(&message);
|
|
|
|
if (!cmd || stringcasecmp(server,"PRIVMSG") || nickcmp(cmd,INTERNAL_NICK)
|
|
|| (*message != ':'))
|
|
{
|
|
irc->status = BNC_DEAD;
|
|
return;
|
|
}
|
|
|
|
message++;
|
|
|
|
if (irc->status == BNC_ASK_HANDLE)
|
|
{
|
|
for(current=botlist;current;current=current->next)
|
|
{
|
|
if ((user = find_handle(message)))
|
|
{
|
|
set_mallocdoer(bounce_parse);
|
|
irc->handle = stringdup(user->name);
|
|
break;
|
|
}
|
|
}
|
|
to_file(irc->usersock,TEXT_ASK_PASSWORD,irc->nick);
|
|
++irc->status;
|
|
/*
|
|
* dont bomb out even if the username is invalid
|
|
* guessing of valid usernames would be possible otherwise
|
|
*/
|
|
}
|
|
else
|
|
if (irc->status == BNC_ASK_PASSWORD)
|
|
{
|
|
irc->status = BNC_DEAD;
|
|
for(current=botlist;current;current=current->next)
|
|
{
|
|
if (irc->handle && (user = find_handle(irc->handle)))
|
|
{
|
|
if (user->x.x.bounce && user->pass
|
|
&& passmatch(message,user->pass))
|
|
{
|
|
to_file(irc->usersock,TEXT_ASK_SERVER,irc->nick);
|
|
irc->status = BNC_ASK_SERVER;
|
|
irc->active = now;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
if (irc->status == BNC_ASK_SERVER)
|
|
{
|
|
server = chop(&message);
|
|
aport = chop(&message);
|
|
virtual = chop(&message);
|
|
|
|
irc->status = BNC_DEAD;
|
|
|
|
if (!server)
|
|
return;
|
|
|
|
iport = 6667;
|
|
if (aport)
|
|
{
|
|
iport = asc2int(aport);
|
|
if (errno || (iport < 1) || (iport > 65536))
|
|
return;
|
|
}
|
|
|
|
current = &fakebot;
|
|
current->vhost_type = 0;
|
|
current->setting[STR_VIRTUAL].str_var = virtual; /* may be NULL, is OK */
|
|
#ifdef WINGATE
|
|
current->setting[STR_WINGATE].str_var = NULL;
|
|
#endif /* WINGATE */
|
|
#ifdef IDWRAP
|
|
current->identfile = NULL;
|
|
current->setting[STR_IDENT].str_var = irc->handle;
|
|
#endif /* IDWRAP */
|
|
|
|
if (virtual)
|
|
{
|
|
to_file(irc->usersock,TEXT_USING_VHOST,irc->nick,virtual);
|
|
}
|
|
to_file(irc->usersock,TEXT_NOW_CONNECTING,irc->nick,server,iport);
|
|
if ((irc->servsock = SockConnect(server,iport,USE_VHOST)) >= 0)
|
|
{
|
|
irc->status = BNC_CONNECTING;
|
|
irc->active = now + 60; /* 120 second timeout */
|
|
#ifdef IDWRAP
|
|
irc->idfile = current->identfile;
|
|
#endif /* IDWRAP */
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef IDWRAP
|
|
|
|
void bounce_cleanup(void)
|
|
{
|
|
ircLink *irc;
|
|
|
|
for(irc=bnclist;irc;irc=irc->next)
|
|
{
|
|
if (irc->idfile)
|
|
unlink(irc->idfile);
|
|
}
|
|
}
|
|
|
|
#endif /* IDWRAP */
|
|
|
|
void new_port_bounce(const struct Setting *no_op)
|
|
{
|
|
if (bounce_sock != -1)
|
|
close(bounce_sock);
|
|
bounce_sock = -1;
|
|
}
|
|
|
|
void select_bounce(void)
|
|
{
|
|
ircLink *irc;
|
|
|
|
if ((bounce_sock == -1) && (bounce_port > 0))
|
|
{
|
|
bounce_sock = SockListener(bounce_port);
|
|
#ifdef DEBUG
|
|
if (bounce_sock >= 0)
|
|
{
|
|
debug("(select_bounce) {%i} irc proxy socket is active (%i)\n",
|
|
bounce_sock,bounce_port);
|
|
}
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
if (bounce_sock != -1)
|
|
{
|
|
chkhigh(bounce_sock);
|
|
FD_SET(bounce_sock,&read_fds);
|
|
}
|
|
|
|
for(irc=bnclist;irc;irc=irc->next)
|
|
{
|
|
if (irc->servsock != -1)
|
|
{
|
|
chkhigh(irc->servsock);
|
|
if (irc->status == BNC_CONNECTING)
|
|
FD_SET(irc->servsock,&write_fds);
|
|
else
|
|
FD_SET(irc->servsock,&read_fds);
|
|
}
|
|
/*
|
|
* dont read data from client when connecting to server
|
|
*/
|
|
if (irc->status != BNC_CONNECTING)
|
|
{
|
|
chkhigh(irc->usersock);
|
|
FD_SET(irc->usersock,&read_fds);
|
|
}
|
|
}
|
|
}
|
|
|
|
void process_bounce(void)
|
|
{
|
|
char message[MSGLEN];
|
|
ircLink *irc,**pp;
|
|
char *p;
|
|
int s;
|
|
|
|
if ((bounce_sock != -1) && FD_ISSET(bounce_sock,&read_fds))
|
|
{
|
|
if ((s = SockAccept(bounce_sock)) >= 0)
|
|
{
|
|
set_mallocdoer(process_bounce);
|
|
irc = (ircLink*)Calloc(sizeof(ircLink)); /* sets all to zero */
|
|
irc->next = bnclist;
|
|
bnclist = irc;
|
|
irc->active = now;
|
|
irc->usersock = s;
|
|
--irc->servsock; /* == -1 */
|
|
}
|
|
}
|
|
|
|
for(irc=bnclist;irc;irc=irc->next)
|
|
{
|
|
/*
|
|
* client socket has data to read
|
|
*/
|
|
if (FD_ISSET(irc->usersock,&read_fds))
|
|
{
|
|
while((p = sockread(irc->usersock,irc->usermem,message)))
|
|
{
|
|
if (irc->status == BNC_ACTIVE)
|
|
{
|
|
if (to_file(irc->servsock,FMT_PLAINLINE,message) < 0)
|
|
/* fall into switch() with a valid errno */
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
bounce_parse(irc,message);
|
|
}
|
|
}
|
|
switch(errno)
|
|
{
|
|
default:
|
|
irc->status = BNC_DEAD;
|
|
case EAGAIN:
|
|
case EINTR:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (irc->servsock < 0)
|
|
continue;
|
|
|
|
/*
|
|
* server socket just got connected
|
|
*/
|
|
if (FD_ISSET(irc->servsock,&write_fds))
|
|
{
|
|
#ifdef DEBUG
|
|
debug("(process_bounce) {%i} servsock connected\n",irc->servsock);
|
|
#endif /* DEBUG */
|
|
irc->status = BNC_ACTIVE;
|
|
irc->active = now;
|
|
to_file(irc->servsock,"USER %s\n",irc->userLine);
|
|
if (to_file(irc->servsock,"NICK %s\n",irc->nickLine) < 0)
|
|
{
|
|
/*
|
|
* write error of some kind, dump both client and server
|
|
*/
|
|
irc->status = BNC_DEAD;
|
|
}
|
|
Free((char**)&irc->userLine);
|
|
Free((char**)&irc->nickLine);
|
|
}
|
|
/*
|
|
* server socket has data to read
|
|
*/
|
|
if (FD_ISSET(irc->servsock,&read_fds))
|
|
{
|
|
irc->active = now;
|
|
while((p = sockread(irc->servsock,irc->servmem,message)))
|
|
{
|
|
if (to_file(irc->usersock,FMT_PLAINLINE,message) < 0)
|
|
/* fall into switch() with a valid errno */
|
|
break;
|
|
}
|
|
switch(errno)
|
|
{
|
|
default:
|
|
irc->status = BNC_DEAD;
|
|
case EAGAIN:
|
|
case EINTR:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* clean out dead and time outed sockets
|
|
*/
|
|
pp = &bnclist;
|
|
while((irc = *pp))
|
|
{
|
|
if (irc->status == BNC_DEAD || ((irc->status != BNC_ACTIVE) && ((now - irc->active) > 60)))
|
|
{
|
|
#ifdef DEBUG
|
|
debug("(process_bounce) {%i} {%i} BNC_DEAD or timeout, removing...\n",irc->usersock,irc->servsock);
|
|
#endif /* DEBUG */
|
|
*pp = irc->next;
|
|
if (irc->servsock >= 0)
|
|
close(irc->servsock);
|
|
if (irc->usersock >= 0)
|
|
close(irc->usersock);
|
|
Free((char**)&irc->userLine);
|
|
Free((char**)&irc->nickLine);
|
|
Free((char**)&irc->nick);
|
|
Free((char**)&irc->handle);
|
|
#ifdef IDWRAP
|
|
if (irc->idfile)
|
|
{
|
|
unlink(irc->idfile);
|
|
Free((char**)&irc->idfile);
|
|
}
|
|
#endif /* IDWRAP */
|
|
Free((char**)&irc);
|
|
continue;
|
|
}
|
|
pp = &irc->next;
|
|
}
|
|
}
|
|
|
|
#endif /* BOUNCE */
|