This repository has been archived on 2024-04-08. You can view files and clone it, but cannot push or open issues or pull requests.
deb-mbse/mbtask/taskibc.c

443 lines
12 KiB
C
Raw Normal View History

2005-04-15 21:36:44 +00:00
/*****************************************************************************
*
* $Id$
2005-04-16 14:49:58 +00:00
* Purpose ...............: mbtask - Internet BBS Chat (but it looks like...)
2005-04-15 21:36:44 +00:00
*
*****************************************************************************
* Copyright (C) 1997-2005
*
* Michiel Broek FIDO: 2:280/2802
* Beekmansbos 10
* 1971 BV IJmuiden
* the Netherlands
*
* This file is part of MBSE BBS.
*
* This BBS 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.
*
* MBSE BBS 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 MBSE BBS; see the file COPYING. If not, write to the Free
* Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*****************************************************************************/
#include "../config.h"
#include "../lib/mbselib.h"
2005-04-17 10:32:41 +00:00
#include "taskstat.h"
2005-04-16 14:49:58 +00:00
#include "taskibc.h"
2005-04-15 21:36:44 +00:00
#ifdef USE_EXPERIMENT
2005-04-17 10:32:41 +00:00
int ibc_run = FALSE; /* Thread running */
extern int T_Shutdown; /* Program shutdown */
extern int internet; /* Internet status */
time_t scfg_time = (time_t)0; /* Servers config time */
ncs_list *ncsl = NULL; /* Neighbours list */
int ls; /* Listen socket */
struct sockaddr_in myaddr_in; /* Listen socket address */
2005-04-17 11:26:48 +00:00
struct sockaddr_in clientaddr_in; /* Remote socket address */
2005-04-17 14:14:56 +00:00
int changed = FALSE; /* Databases changed */
2005-04-17 11:26:48 +00:00
2005-04-15 21:36:44 +00:00
2005-04-17 14:14:56 +00:00
typedef enum {NCS_INIT, NCS_CALL, NCS_WAITPWD, NCS_CONNECT, NCS_HANGUP, NCS_FAIL, NCS_DEAD} NCSTYPE;
2005-04-17 10:32:41 +00:00
static char *ncsstate[] = {
2005-04-17 14:14:56 +00:00
(char *)"init", (char *)"call", (char *)"waitpwd", (char *)"connect",
(char *)"hangup", (char *)"fail", (char *)"dead"
2005-04-17 10:32:41 +00:00
};
2005-04-15 21:36:44 +00:00
/*
2005-04-17 10:32:41 +00:00
* Add a port to the portlist
2005-04-15 21:36:44 +00:00
*/
2005-04-17 12:08:59 +00:00
void fill_ncslist(ncs_list **, char *, char *, char *);
void fill_ncslist(ncs_list **fdp, char *server, char *myname, char *passwd)
2005-04-15 21:36:44 +00:00
{
2005-04-17 10:32:41 +00:00
ncs_list *tmp, *ta;
2005-04-15 21:36:44 +00:00
2005-04-17 10:32:41 +00:00
tmp = (ncs_list *)malloc(sizeof(ncs_list));
memset(tmp, 0, sizeof(tmp));
tmp->next = NULL;
strncpy(tmp->server, server, 63);
2005-04-17 12:14:31 +00:00
strncpy(tmp->myname, myname, 63);
2005-04-17 10:32:41 +00:00
strncpy(tmp->passwd, passwd, 15);
tmp->state = NCS_INIT;
tmp->action = time(NULL);
tmp->last = (time_t)0;
tmp->version = 0;
tmp->remove = FALSE;
tmp->socket = -1;
tmp->token = 0;
2005-04-17 14:14:56 +00:00
tmp->gotpass = FALSE;
tmp->gotserver = FALSE;
2005-04-15 21:36:44 +00:00
2005-04-17 10:32:41 +00:00
if (*fdp == NULL) {
*fdp = tmp;
} else {
for (ta = *fdp; ta; ta = ta->next)
if (ta->next == NULL) {
ta->next = (ncs_list *)tmp;
break;
}
2005-04-15 21:36:44 +00:00
}
2005-04-17 10:32:41 +00:00
}
2005-04-15 21:36:44 +00:00
2005-04-17 10:32:41 +00:00
void dump_ncslist(void);
void dump_ncslist(void)
{
ncs_list *tmp;
time_t now;
2005-04-15 21:36:44 +00:00
2005-04-17 14:14:56 +00:00
if (!changed)
return;
2005-04-15 21:36:44 +00:00
2005-04-17 14:14:56 +00:00
now = time(NULL);
Syslog('r', "Server State Del Pwd Srv Next action");
Syslog('r', "------------------------------ ------- --- --- --- -----------");
2005-04-17 10:32:41 +00:00
for (tmp = ncsl; tmp; tmp = tmp->next) {
2005-04-17 14:14:56 +00:00
Syslog('r', "%-30s %-7s %s %s %s %d", tmp->server, ncsstate[tmp->state],
tmp->remove ? "yes":"no ", tmp->gotpass ? "yes":"no ",
tmp->gotserver ? "yes":"no ", (int)tmp->action - (int)now);
2005-04-15 21:36:44 +00:00
}
2005-04-17 14:14:56 +00:00
changed = FALSE;
2005-04-15 21:36:44 +00:00
}
/*
* Send a message to all servers
*/
void send_all(char *msg)
{
2005-04-17 10:32:41 +00:00
}
2005-04-17 11:26:48 +00:00
/*
* Send message to a server
*/
int send_msg(int s, struct sockaddr_in servaddr, char *host, char *msg)
{
Syslog('r', "> %s: %s", host, printable(msg, 0));
if (sendto(s, msg, strlen(msg), 0, (struct sockaddr *)&servaddr, sizeof(struct sockaddr_in)) == -1) {
Syslog('r', "$Can't send message");
return -1;
}
return 0;
}
2005-04-17 10:32:41 +00:00
void check_servers(void)
{
char *errmsg, scfgfn[PATH_MAX], buf[512];
FILE *fp;
ncs_list *tnsl;
2005-04-17 14:14:56 +00:00
int inlist;
2005-04-17 10:32:41 +00:00
time_t now;
int a1, a2, a3, a4;
struct servent *se;
struct hostent *he;
sprintf(scfgfn, "%s/etc/ibcsrv.data", getenv("MBSE_ROOT"));
/*
* Check if configuration is changed, if so then apply the changes.
*/
if (file_time(scfgfn) != scfg_time) {
Syslog('r', "%s filetime changed, rereading");
if ((fp = fopen(scfgfn, "r"))) {
fread(&ibcsrvhdr, sizeof(ibcsrvhdr), 1, fp);
while (fread(&ibcsrv, ibcsrvhdr.recsize, 1, fp)) {
Syslog('r', "IBC server \"%s\", Active %s", ibcsrv.server, ibcsrv.Active ?"Yes":"No");
if (ibcsrv.Active) {
inlist = FALSE;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, ibcsrv.server) == 0) {
inlist = TRUE;
}
}
if (!inlist ) {
Syslog('r', " not in neighbour list, add");
2005-04-17 12:08:59 +00:00
fill_ncslist(&ncsl, ibcsrv.server, ibcsrv.myname, ibcsrv.passwd);
2005-04-17 10:32:41 +00:00
changed = TRUE;
Syslog('+', "Added Internet BBS Chatserver %s", ibcsrv.server);
}
}
}
/*
* Now check for neighbours to delete
*/
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
fseek(fp, ibcsrvhdr.hdrsize, SEEK_SET);
inlist = FALSE;
Syslog('r', "IBC server \"%s\"", ibcsrv.server);
while (fread(&ibcsrv, ibcsrvhdr.recsize, 1, fp)) {
if ((strcmp(tnsl->server, ibcsrv.server) == 0) && ibcsrv.Active) {
inlist = TRUE;
}
}
if (!inlist) {
Syslog('r', " not in configuration, remove");
tnsl->remove = TRUE;
tnsl->action = time(NULL);
changed = TRUE;
}
}
fclose(fp);
}
scfg_time = file_time(scfgfn);
}
2005-04-17 14:14:56 +00:00
dump_ncslist();
2005-04-17 10:32:41 +00:00
/*
* Check if we need to make state changes
*/
now = time(NULL);
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (((int)tnsl->action - (int)now) <= 0) {
switch (tnsl->state) {
case NCS_INIT: Syslog('r', "%s init", tnsl->server);
changed = TRUE;
/*
* If Internet is available, setup the connection.
*/
if (internet) {
/*
* Get IP address for the hostname, set default next action
* to 60 seconds.
*/
tnsl->action = now + (time_t)60;
memset(&tnsl->servaddr_in, 0, sizeof(struct sockaddr_in));
se = getservbyname("fido", "udp");
tnsl->servaddr_in.sin_family = AF_INET;
tnsl->servaddr_in.sin_port = se->s_port;
if (sscanf(tnsl->server,"%d.%d.%d.%d",&a1,&a2,&a3,&a4) == 4)
tnsl->servaddr_in.sin_addr.s_addr = inet_addr(tnsl->server);
else if ((he = gethostbyname(tnsl->server)))
memcpy(&tnsl->servaddr_in.sin_addr, he->h_addr, he->h_length);
else {
switch (h_errno) {
case HOST_NOT_FOUND: errmsg = (char *)"Authoritative: Host not found"; break;
case TRY_AGAIN: errmsg = (char *)"Non-Authoritive: Host not found"; break;
case NO_RECOVERY: errmsg = (char *)"Non recoverable errors"; break;
default: errmsg = (char *)"Unknown error"; break;
}
Syslog('+', "No IP address for %s: %s", tnsl->server, errmsg);
tnsl->state = NCS_FAIL;
break;
}
tnsl->socket = socket(AF_INET, SOCK_DGRAM, 0);
if (tnsl->socket == -1) {
Syslog('+', "$Can't create socket for %s", tnsl->server);
tnsl->state = NCS_FAIL;
break;
}
Syslog('r', "socket %d", tnsl->socket);
tnsl->token = gettoken();
tnsl->state = NCS_CALL;
tnsl->action = now + (time_t)1;
} else {
tnsl->action = now + (time_t)10;
}
break;
case NCS_CALL: Syslog('r', "%s call", tnsl->server);
2005-04-17 13:08:04 +00:00
sprintf(buf, "PASS %s 0000 IBC| %s\r\n", tnsl->passwd, tnsl->compress ? "Z":"");
2005-04-17 11:26:48 +00:00
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, buf);
2005-04-17 13:08:04 +00:00
sprintf(buf, "SERVER %s 0 %ld mbsebbs v%s\r\n", tnsl->myname, tnsl->token, VERSION);
2005-04-17 11:26:48 +00:00
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, buf);
2005-04-17 10:32:41 +00:00
tnsl->action = now + (time_t)50;
tnsl->state = NCS_WAITPWD;
changed = TRUE;
break;
case NCS_WAITPWD: /*
* This state can be left by before the timeout is reached
* by a reply from the remote if the connection is accepted.
*/
Syslog('r', "%s waitpwd", tnsl->server);
tnsl->state = NCS_CALL;
break;
}
}
}
2005-04-17 14:14:56 +00:00
dump_ncslist();
}
void command_pass(char *hostname, char *parameters)
{
ncs_list *tnsl;
}
void receiver(struct servent *se)
{
struct pollfd pfd;
struct hostent *hp;
int rc, len, inlist;
socklen_t sl;
ncs_list *tnsl;
char buf[1024], resp[512], *hostname, *prefix, *command, *parameters;
pfd.fd = ls;
pfd.events = POLLIN;
pfd.revents = 0;
if ((rc = poll(&pfd, 1, 1000) < 0)) {
Syslog('r', "$poll/select failed");
return;
}
if (pfd.revents & POLLIN || pfd.revents & POLLERR || pfd.revents & POLLHUP || pfd.revents & POLLNVAL) {
sl = sizeof(myaddr_in);
memset(&clientaddr_in, 0, sizeof(struct sockaddr_in));
memset(&buf, 0, sizeof(buf));
if ((len = recvfrom(ls, &buf, sizeof(buf)-1, 0,(struct sockaddr *)&clientaddr_in, &sl)) != -1) {
hp = gethostbyaddr((char *)&clientaddr_in.sin_addr, sizeof(struct in_addr), clientaddr_in.sin_family);
if (hp == NULL)
hostname = inet_ntoa(clientaddr_in.sin_addr);
else
hostname = hp->h_name;
if ((buf[strlen(buf) -2] != '\r') && (buf[strlen(buf) -1] != '\n')) {
Syslog('r', "Message not terminated with CR-LF, dropped");
return;
}
inlist = FALSE;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
inlist = TRUE;
break;
}
}
if (!inlist) {
Syslog('!', "Message from unknown host (%s), dropped", hostname);
return;
}
buf[strlen(buf) -2] = '\0';
Syslog('r', "< %s: \"%s\"", hostname, printable(buf, 0));
/*
* Parse message
*/
if (buf[0] == ':') {
prefix = strtok(buf, " ");
command = strtok(NULL, " \0");
parameters = strtok(NULL, "\0");
} else {
prefix = NULL;
command = strtok(buf, " \0");
parameters = strtok(NULL, "\0");
}
Syslog('r', "prefix \"%s\"", printable(prefix, 0));
Syslog('r', "command \"%s\"", printable(command, 0));
Syslog('r', "parameters \"%s\"", printable(parameters, 0));
if (! strcmp(command, (char *)"PASS") && parameters) {
command_pass(hostname, parameters);
} else if (tnsl->state == NCS_CONNECT) {
/*
* Only if connected we send a error response
*/
sprintf(resp, "421 %s: Unknown command\r\n", command);
send_msg(tnsl->socket, tnsl->servaddr_in, tnsl->server, resp);
}
} else {
Syslog('r', "recvfrom returned len=%d", len);
}
}
2005-04-15 21:36:44 +00:00
}
/*
2005-04-17 10:32:41 +00:00
* IBC thread
2005-04-15 21:36:44 +00:00
*/
2005-04-16 14:49:58 +00:00
void *ibc_thread(void *dummy)
2005-04-15 21:36:44 +00:00
{
2005-04-16 16:08:32 +00:00
struct servent *se;
2005-04-17 10:32:41 +00:00
Syslog('+', "Starting IBC thread");
2005-04-16 16:08:32 +00:00
if ((se = getservbyname("fido", "udp")) == NULL) {
Syslog('!', "No fido udp entry in /etc/services, cannot start Internet BBS Chat");
goto exit;
}
2005-04-17 10:32:41 +00:00
myaddr_in.sin_family = AF_INET;
myaddr_in.sin_addr.s_addr = INADDR_ANY;
myaddr_in.sin_port = se->s_port;
Syslog('+', "Listen on %s, port %d\n", inet_ntoa(myaddr_in.sin_addr), ntohs(myaddr_in.sin_port));
ls = socket(AF_INET, SOCK_DGRAM, 0);
if (ls == -1) {
Syslog('!', "$Can't create socket");
goto exit;
}
if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) {
Syslog('!', "$Can't bind socket");
goto exit;
}
2005-04-16 14:49:58 +00:00
ibc_run = TRUE;
2005-04-15 21:36:44 +00:00
while (! T_Shutdown) {
2005-04-17 10:32:41 +00:00
/*
* First check Shutdown requested
*/
if (T_Shutdown) {
}
/*
* Check neighbour servers state
*/
check_servers();
/*
* Get any incoming messages
*/
2005-04-17 14:14:56 +00:00
receiver(se);
2005-04-15 21:36:44 +00:00
}
2005-04-16 16:08:32 +00:00
exit:
2005-04-16 14:49:58 +00:00
ibc_run = FALSE;
Syslog('+', "IBC thread stopped");
2005-04-15 21:36:44 +00:00
pthread_exit(NULL);
}
#endif