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

1615 lines
41 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-18 13:37:19 +00:00
#include "taskutil.h"
2005-04-22 21:18:45 +00:00
#include "taskchat.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 */
2005-04-18 15:19:38 +00:00
time_t now; /* Current time */
2005-04-17 10:32:41 +00:00
ncs_list *ncsl = NULL; /* Neighbours list */
2005-04-18 13:21:31 +00:00
srv_list *servers = NULL; /* Active servers */
2005-04-20 16:59:32 +00:00
usr_list *users = NULL; /* Active users */
2005-04-23 14:27:52 +00:00
chn_list *channels = NULL; /* Active channels */
2005-05-01 13:12:41 +00:00
ban_list *banned = NULL; /* Banned users */
nick_list *nicknames = NULL; /* Known nicknames */
2005-04-17 10:32:41 +00:00
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-18 08:54:55 +00:00
char crbuf[512]; /* Chat receive buffer */
2005-05-08 13:17:43 +00:00
int callchg = FALSE; /* Is call state changed */
2005-04-18 20:54:21 +00:00
int srvchg = FALSE; /* Is serverlist changed */
2005-04-20 16:59:32 +00:00
int usrchg = FALSE; /* Is userlist changed */
2005-04-23 14:27:52 +00:00
int chnchg = FALSE; /* Is channellist changed */
2005-05-01 13:12:41 +00:00
int banchg = FALSE; /* Is banned users changed */
int nickchg = FALSE; /* Is nicknames changed */
2005-04-18 08:54:55 +00:00
2005-04-17 11:26:48 +00:00
2005-04-18 20:36:22 +00:00
pthread_mutex_t b_mutex = PTHREAD_MUTEX_INITIALIZER;
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-20 16:59:32 +00:00
2005-04-15 21:36:44 +00:00
/*
2005-04-18 08:54:55 +00:00
* Internal prototypes
2005-04-15 21:36:44 +00:00
*/
2005-04-17 12:08:59 +00:00
void fill_ncslist(ncs_list **, char *, char *, char *);
2005-04-18 08:54:55 +00:00
void dump_ncslist(void);
2005-04-18 14:28:41 +00:00
void tidy_servers(srv_list **);
2005-04-18 18:36:27 +00:00
void add_server(srv_list **, char *, int, char *, char *, char *, char *);
2005-04-18 14:28:41 +00:00
void del_server(srv_list **, char *);
2005-04-18 18:46:08 +00:00
void del_router(srv_list **, char *);
2005-04-21 21:12:50 +00:00
int send_msg(ncs_list *, const char *, ...);
void broadcast(char *, const char *, ...);
2005-04-18 08:54:55 +00:00
void check_servers(void);
2005-04-27 18:02:30 +00:00
int command_pass(char *, char *);
int command_server(char *, char *);
int command_squit(char *, char *);
int command_user(char *, char *);
int command_quit(char *, char *);
2005-04-22 19:40:05 +00:00
int command_nick(char *, char *);
2005-04-27 18:02:30 +00:00
int command_join(char *, char *);
int command_part(char *, char *);
int command_topic(char *, char *);
2005-04-27 19:52:51 +00:00
int command_privmsg(char *, char *);
2005-04-18 08:54:55 +00:00
void receiver(struct servent *);
/*
* Add a server to the serverlist
*/
2005-04-17 12:08:59 +00:00
void fill_ncslist(ncs_list **fdp, char *server, char *myname, char *passwd)
2005-04-15 21:36:44 +00:00
{
2005-04-18 20:36:22 +00:00
ncs_list *tmp, *ta;
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
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;
2005-04-18 15:19:38 +00:00
tmp->action = now;
2005-04-17 10:32:41 +00:00
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 {
2005-04-30 11:31:31 +00:00
for (ta = *fdp; ta; ta = ta->next) {
if (ta->next == NULL) {
ta->next = (ncs_list *)tmp;
break;
}
2005-04-17 10:32:41 +00:00
}
2005-04-15 21:36:44 +00:00
}
2005-04-18 20:36:22 +00:00
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
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)
{
ncs_list *tmp;
2005-04-18 13:21:31 +00:00
srv_list *srv;
2005-04-20 16:59:32 +00:00
usr_list *usrp;
2005-04-23 14:27:52 +00:00
chn_list *chnp;
2005-04-15 21:36:44 +00:00
2005-05-08 13:17:43 +00:00
if (!callchg && !srvchg && !usrchg && !chnchg && !banchg && !nickchg)
2005-04-17 14:14:56 +00:00
return;
2005-04-15 21:36:44 +00:00
2005-05-08 13:17:43 +00:00
if (callchg) {
2005-05-01 13:12:41 +00:00
if (ncsl) {
Syslog('r', "Server State Del Pwd Srv Next action");
Syslog('r', "------------------------------ ------- --- --- --- -----------");
for (tmp = ncsl; tmp; tmp = tmp->next) {
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);
}
} else {
Syslog('r', "No servers configured");
}
2005-05-08 13:17:43 +00:00
}
2005-05-01 13:12:41 +00:00
2005-05-08 13:17:43 +00:00
if (srvchg) {
2005-05-01 13:12:41 +00:00
if (servers) {
Syslog('+', "IBC: Server Router Hops Users Connect time");
Syslog('+', "IBC: ------------------------- ------------------------- ----- ----- --------------------");
for (srv = servers; srv; srv = srv->next) {
Syslog('+', "IBC: %-25s %-25s %5d %5d %s", srv->server, srv->router, srv->hops,
srv->users, rfcdate(srv->connected));
}
} else {
Syslog('+', "IBC: Servers list is empty");
2005-04-18 20:54:21 +00:00
}
2005-04-18 13:21:31 +00:00
}
2005-04-18 20:54:21 +00:00
2005-04-20 16:59:32 +00:00
if (usrchg) {
if (users) {
2005-05-01 13:12:41 +00:00
Syslog('+', "IBC: Server User Name/Nick Channel Sys Connect time");
Syslog('+', "IBC: -------------------- -------------------- --------- ------------- --- --------------------");
for (usrp = users; usrp; usrp = usrp->next) {
Syslog('+', "IBC: %-20s %-20s %-9s %-13s %s %s", usrp->server, usrp->realname, usrp->nick, usrp->channel,
2005-05-01 13:12:41 +00:00
usrp->sysop ? "yes":"no ", rfcdate(usrp->connected));
}
} else {
Syslog('+', "IBC: Users list is empty");
2005-04-20 16:59:32 +00:00
}
}
2005-04-23 14:27:52 +00:00
if (chnchg) {
if (channels) {
Syslog('+', "IBC: Channel Owner Topic Usr Created");
Syslog('+', "IBC: -------------------- --------- ----------------------------------- --- --------------------");
for (chnp = channels; chnp; chnp = chnp->next) {
Syslog('+', "IBC: %-20s %-9s %-35s %3d %s", chnp->name, chnp->owner, chnp->topic,
chnp->users, rfcdate(chnp->created));
}
} else {
Syslog('+', "IBC: Channels list is empty");
}
}
2005-05-08 13:17:43 +00:00
callchg = FALSE;
2005-04-18 20:54:21 +00:00
srvchg = FALSE;
2005-04-20 16:59:32 +00:00
usrchg = FALSE;
2005-04-23 14:27:52 +00:00
chnchg = FALSE;
2005-05-01 13:12:41 +00:00
banchg = FALSE;
nickchg = FALSE;
2005-04-15 21:36:44 +00:00
}
2005-04-18 13:21:31 +00:00
void tidy_servers(srv_list ** fdp)
{
srv_list *tmp, *old;
for (tmp = *fdp; tmp; tmp = old) {
old = tmp->next;
free(tmp);
}
*fdp = NULL;
}
2005-04-20 16:59:32 +00:00
/*
2005-04-21 21:12:50 +00:00
* Add one user to the userlist. Returns:
* 0 = Ok
* 1 = User already registered.
2005-04-20 16:59:32 +00:00
*/
2005-04-22 18:39:48 +00:00
int add_user(usr_list **fap, char *server, char *name, char *realname)
2005-04-20 16:59:32 +00:00
{
usr_list *tmp, *ta;
srv_list *sl;
2005-04-22 18:39:48 +00:00
Syslog('r', "add_user %s %s %s", server, name, realname);
2005-04-20 16:59:32 +00:00
2005-04-20 20:27:32 +00:00
for (ta = *fap; ta; ta = ta->next) {
2005-04-20 16:59:32 +00:00
if ((strcmp(ta->server, server) == 0) && (strcmp(ta->realname, realname) == 0)) {
2005-04-22 18:39:48 +00:00
Syslog('-', "IBC: add_user(%s %s %s), already registered", server, name, realname);
2005-04-21 21:12:50 +00:00
return 1;
2005-04-20 16:59:32 +00:00
}
}
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-20 16:59:32 +00:00
tmp = (usr_list *)malloc(sizeof(usr_list));
2005-04-21 20:07:29 +00:00
memset(tmp, 0, sizeof(usr_list));
2005-04-20 16:59:32 +00:00
tmp->next = NULL;
strncpy(tmp->server, server, 63);
2005-04-22 18:39:48 +00:00
strncpy(tmp->name, name, 9);
2005-04-22 20:01:21 +00:00
strncpy(tmp->nick, name, 9);
2005-04-20 16:59:32 +00:00
strncpy(tmp->realname, realname, 36);
tmp->connected = now;
2005-04-20 20:27:32 +00:00
if (*fap == NULL) {
*fap = tmp;
2005-04-20 16:59:32 +00:00
} else {
2005-04-30 11:31:31 +00:00
for (ta = *fap; ta; ta = ta->next) {
2005-04-20 16:59:32 +00:00
if (ta->next == NULL) {
ta->next = (usr_list *)tmp;
break;
}
2005-04-30 11:31:31 +00:00
}
2005-04-20 16:59:32 +00:00
}
for (sl = servers; sl; sl = sl->next) {
if (strcmp(sl->server, server) == 0) {
2005-04-30 11:31:31 +00:00
sl->users++;
srvchg = TRUE;
2005-04-20 16:59:32 +00:00
}
}
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-20 16:59:32 +00:00
usrchg = TRUE;
2005-04-21 21:12:50 +00:00
return 0;
2005-04-20 16:59:32 +00:00
}
/*
2005-04-23 10:58:43 +00:00
* Delete one user. If name == NULL then delete all users of a server.
2005-04-20 16:59:32 +00:00
*/
2005-04-22 18:39:48 +00:00
void del_user(usr_list **fap, char *server, char *name)
2005-04-20 16:59:32 +00:00
{
2005-04-20 21:27:25 +00:00
usr_list **tmp, *tmpa;
2005-04-20 16:59:32 +00:00
srv_list *sl;
2005-04-23 10:58:43 +00:00
Syslog('r', "deluser %s %s", server, printable(name, 0));
2005-04-20 16:59:32 +00:00
2005-04-20 20:27:32 +00:00
if (*fap == NULL)
2005-04-20 16:59:32 +00:00
return;
2005-04-23 10:58:43 +00:00
if (name)
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-20 16:59:32 +00:00
2005-04-20 21:27:25 +00:00
tmp = fap;
while (*tmp) {
2005-04-23 10:58:43 +00:00
if (name && (strcmp((*tmp)->server, server) == 0) && (strcmp((*tmp)->name, name) == 0)) {
tmpa = *tmp;
*tmp=(*tmp)->next;
free(tmpa);
usrchg = TRUE;
} else if ((name == NULL) && (strcmp((*tmp)->server, server) == 0)) {
2005-04-23 11:25:32 +00:00
Syslog('r', "removed user %s from %s", (*tmp)->name, (*tmp)->server);
2005-04-20 21:27:25 +00:00
tmpa = *tmp;
*tmp=(*tmp)->next;
free(tmpa);
2005-04-20 16:59:32 +00:00
usrchg = TRUE;
2005-04-20 21:27:25 +00:00
} else {
tmp = &((*tmp)->next);
2005-04-20 16:59:32 +00:00
}
}
for (sl = servers; sl; sl = sl->next) {
if ((strcmp(sl->server, server) == 0) && sl->users) {
sl->users--;
srvchg = TRUE;
}
}
2005-04-23 10:58:43 +00:00
if (name)
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-20 16:59:32 +00:00
}
2005-04-23 14:27:52 +00:00
/*
* Add channel with owner.
*/
int add_channel(chn_list **fap, char *name, char *owner, char *server)
{
chn_list *tmp, *ta;
Syslog('r', "add_channel %s %s %s", name, owner, server);
for (ta = *fap; ta; ta = ta->next) {
if ((strcmp(ta->name, name) == 0) && (strcmp(ta->owner, owner) == 0) && (strcmp(ta->server, server) == 0)) {
Syslog('-', "IBC: add_channel(%s %s %s), already registered", name, owner, server);
return 1;
}
}
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-23 14:27:52 +00:00
tmp = (chn_list *)malloc(sizeof(chn_list));
memset(tmp, 0, sizeof(chn_list));
tmp->next = NULL;
strncpy(tmp->name, name, 20);
strncpy(tmp->owner, owner, 9);
strncpy(tmp->server, server, 63);
tmp->users = 1;
tmp->created = now;
if (*fap == NULL) {
*fap = tmp;
} else {
2005-04-30 11:31:31 +00:00
for (ta = *fap; ta; ta = ta->next) {
2005-04-23 14:27:52 +00:00
if (ta->next == NULL) {
ta->next = (chn_list *)tmp;
break;
}
2005-04-30 11:31:31 +00:00
}
2005-04-23 14:27:52 +00:00
}
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-23 14:27:52 +00:00
chnchg = TRUE;
return 0;
}
void del_channel(chn_list **fap, char *name)
{
chn_list **tmp, *tmpa;
Syslog('r', "del_channel %s", name);
if (*fap == NULL)
return;
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-23 14:27:52 +00:00
tmp = fap;
while (*tmp) {
if (strcmp((*tmp)->name, name) == 0) {
tmpa = *tmp;
*tmp=(*tmp)->next;
free(tmpa);
chnchg = TRUE;
} else {
tmp = &((*tmp)->next);
}
}
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-23 14:27:52 +00:00
}
2005-04-18 18:36:27 +00:00
void add_server(srv_list **fdp, char *name, int hops, char *prod, char *vers, char *fullname, char *router)
2005-04-18 13:21:31 +00:00
{
2005-04-18 20:36:22 +00:00
srv_list *tmp, *ta;
2005-04-18 19:13:14 +00:00
2005-04-18 20:36:22 +00:00
Syslog('r', "add_server %s %d %s %s %s", name, hops, prod, vers, fullname);
2005-04-18 19:13:14 +00:00
for (ta = *fdp; ta; ta = ta->next) {
if (strcmp(ta->server, name) == 0) {
Syslog('r', "duplicate, ignore");
return;
}
}
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-18 20:36:22 +00:00
2005-04-18 13:21:31 +00:00
tmp = (srv_list *)malloc(sizeof(srv_list));
memset(tmp, 0, sizeof(tmp));
tmp->next = NULL;
strncpy(tmp->server, name, 63);
2005-04-18 18:36:27 +00:00
strncpy(tmp->router, router, 63);
2005-04-18 15:19:38 +00:00
strncpy(tmp->prod, prod, 20);
strncpy(tmp->vers, vers, 20);
strncpy(tmp->fullname, fullname, 35);
tmp->connected = now;
2005-04-18 13:21:31 +00:00
tmp->users = 0;
2005-04-18 14:28:41 +00:00
tmp->hops = hops;
2005-04-18 13:21:31 +00:00
if (*fdp == NULL) {
*fdp = tmp;
} else {
2005-04-30 11:31:31 +00:00
for (ta = *fdp; ta; ta = ta->next) {
2005-04-18 13:21:31 +00:00
if (ta->next == NULL) {
ta->next = (srv_list *)tmp;
break;
}
2005-04-30 11:31:31 +00:00
}
2005-04-18 13:21:31 +00:00
}
2005-04-18 20:36:22 +00:00
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-18 20:54:21 +00:00
srvchg = TRUE;
2005-04-18 13:21:31 +00:00
}
2005-04-18 18:46:08 +00:00
/*
* Delete server.
*/
2005-04-18 14:49:23 +00:00
void del_server(srv_list **fap, char *name)
2005-04-18 14:28:41 +00:00
{
2005-04-18 20:36:22 +00:00
srv_list *ta, *tan;
2005-04-18 14:28:41 +00:00
Syslog('r', "delserver %s", name);
2005-04-18 14:49:23 +00:00
if (*fap == NULL)
return;
2005-04-18 20:36:22 +00:00
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-18 20:36:22 +00:00
2005-04-18 14:49:23 +00:00
for (ta = *fap; ta; ta = ta->next) {
while ((tan = ta->next) && (strcmp(tan->server, name) == 0)) {
ta->next = tan->next;
free(tan);
2005-04-18 20:54:21 +00:00
srvchg = TRUE;
2005-04-18 14:28:41 +00:00
}
2005-04-18 14:49:23 +00:00
ta->next = tan;
2005-04-18 14:28:41 +00:00
}
2005-04-18 20:36:22 +00:00
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-18 14:28:41 +00:00
}
2005-04-18 18:46:08 +00:00
/*
* Delete router.
*/
void del_router(srv_list **fap, char *name)
{
2005-04-18 20:36:22 +00:00
srv_list *ta, *tan;
2005-04-18 18:46:08 +00:00
Syslog('r', "delrouter %s", name);
if (*fap == NULL)
return;
2005-04-18 20:36:22 +00:00
2005-04-30 11:31:31 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-18 20:36:22 +00:00
2005-04-18 18:46:08 +00:00
for (ta = *fap; ta; ta = ta->next) {
while ((tan = ta->next) && (strcmp(tan->router, name) == 0)) {
2005-04-23 10:58:43 +00:00
del_user(&users, tan->server, NULL);
2005-04-18 18:46:08 +00:00
ta->next = tan->next;
free(tan);
2005-04-18 20:54:21 +00:00
srvchg = TRUE;
2005-04-18 18:46:08 +00:00
}
ta->next = tan;
}
2005-04-18 20:36:22 +00:00
2005-04-30 11:31:31 +00:00
pthread_mutex_unlock(&b_mutex);
2005-04-18 18:46:08 +00:00
}
2005-04-15 21:36:44 +00:00
/*
* Send a message to all servers
*/
2005-04-21 21:12:50 +00:00
void send_all(const char *format, ...)
2005-04-15 21:36:44 +00:00
{
2005-04-18 12:56:28 +00:00
ncs_list *tnsl;
2005-04-21 21:12:50 +00:00
char buf[512];
va_list va_ptr;
2005-04-18 12:56:28 +00:00
2005-04-21 21:12:50 +00:00
va_start(va_ptr, format);
vsprintf(buf, format, va_ptr);
va_end(va_ptr);
2005-04-18 12:56:28 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (tnsl->state == NCS_CONNECT) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, buf);
2005-04-18 12:56:28 +00:00
}
}
2005-04-17 10:32:41 +00:00
}
2005-04-18 16:48:51 +00:00
/*
* Broadcast a message to all servers except the originating server
*/
2005-04-21 21:12:50 +00:00
void broadcast(char *origin, const char *format, ...)
2005-04-18 16:48:51 +00:00
{
ncs_list *tnsl;
2005-04-21 21:12:50 +00:00
va_list va_ptr;
char buf[512];
2005-04-18 16:48:51 +00:00
2005-04-21 21:12:50 +00:00
va_start(va_ptr, format);
vsprintf(buf, format, va_ptr);
va_end(va_ptr);
2005-04-18 16:48:51 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if ((tnsl->state == NCS_CONNECT) && (strcmp(origin, tnsl->server))) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, buf);
2005-04-18 16:48:51 +00:00
}
}
}
2005-04-17 11:26:48 +00:00
/*
* Send message to a server
*/
2005-04-21 21:12:50 +00:00
int send_msg(ncs_list *tnsl, const char *format, ...)
2005-04-17 11:26:48 +00:00
{
2005-04-21 21:12:50 +00:00
char buf[512];
va_list va_ptr;
va_start(va_ptr, format);
vsprintf(buf, format, va_ptr);
va_end(va_ptr);
Syslog('r', "> %s: %s", tnsl->server, printable(buf, 0));
2005-04-17 11:26:48 +00:00
2005-04-21 21:12:50 +00:00
if (sendto(tnsl->socket, buf, strlen(buf), 0, (struct sockaddr *)&tnsl->servaddr_in, sizeof(struct sockaddr_in)) == -1) {
2005-04-30 11:31:31 +00:00
Syslog('!', "$IBC: can't send message");
2005-04-17 11:26:48 +00:00
return -1;
}
return 0;
}
2005-04-17 10:32:41 +00:00
void check_servers(void)
{
2005-04-18 08:54:55 +00:00
char *errmsg, scfgfn[PATH_MAX];
FILE *fp;
2005-05-08 15:50:59 +00:00
ncs_list *tnsl, **tmp;
int j, inlist, Remove;
2005-04-18 08:54:55 +00:00
int a1, a2, a3, a4;
struct servent *se;
struct hostent *he;
2005-04-17 10:32:41 +00:00
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) {
2005-05-08 13:17:43 +00:00
Syslog('r', "%s filetime changed, rereading", scfgfn);
2005-04-17 10:32:41 +00:00
2005-04-20 16:59:32 +00:00
if (servers == NULL) {
/*
* First add this server name to the servers database.
*/
add_server(&servers, CFG.myfqdn, 0, (char *)"mbsebbs", (char *)VERSION, CFG.bbs_name, (char *)"none");
}
2005-04-17 10:32:41 +00:00
if ((fp = fopen(scfgfn, "r"))) {
fread(&ibcsrvhdr, sizeof(ibcsrvhdr), 1, fp);
while (fread(&ibcsrv, ibcsrvhdr.recsize, 1, fp)) {
if (ibcsrv.Active) {
inlist = FALSE;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, ibcsrv.server) == 0) {
inlist = TRUE;
}
}
if (!inlist ) {
2005-04-17 12:08:59 +00:00
fill_ncslist(&ncsl, ibcsrv.server, ibcsrv.myname, ibcsrv.passwd);
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-05-08 15:50:59 +00:00
callchg = TRUE;
2005-04-30 11:31:31 +00:00
Syslog('+', "IBC: new configured Internet BBS Chatserver: %s", ibcsrv.server);
2005-04-17 10:32:41 +00:00
}
}
}
/*
* Now check for neighbours to delete
*/
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
fseek(fp, ibcsrvhdr.hdrsize, SEEK_SET);
inlist = FALSE;
while (fread(&ibcsrv, ibcsrvhdr.recsize, 1, fp)) {
if ((strcmp(tnsl->server, ibcsrv.server) == 0) && ibcsrv.Active) {
inlist = TRUE;
}
}
if (!inlist) {
2005-04-30 11:31:31 +00:00
Syslog('+', "IBC: server %s removed from configuration", tnsl->server);
2005-05-08 17:52:53 +00:00
pthread_mutex_lock(&b_mutex);
2005-04-17 10:32:41 +00:00
tnsl->remove = TRUE;
2005-04-18 15:19:38 +00:00
tnsl->action = now;
2005-05-08 17:52:53 +00:00
pthread_mutex_unlock(&b_mutex);
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-05-08 15:50:59 +00:00
callchg = TRUE;
2005-04-17 10:32:41 +00:00
}
}
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
2005-05-08 15:50:59 +00:00
Remove = FALSE;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (tnsl->remove) {
Remove = TRUE;
Syslog('r', "Remove server %s", tnsl->server);
if (tnsl->state == NCS_CONNECT) {
broadcast(tnsl->server, "SQUIT %s Removed from configuration\r\n", tnsl->server);
send_msg(tnsl, "SQUIT %s Your system is removed from configuration\r\n", tnsl->myname);
del_router(&servers, tnsl->server);
}
if (tnsl->socket != -1) {
Syslog('r', "Closing socket %d", tnsl->socket);
shutdown(tnsl->socket, SHUT_WR);
tnsl->socket = -1;
2005-05-08 17:52:53 +00:00
tnsl->state = NCS_HANGUP;
2005-05-08 15:50:59 +00:00
}
callchg = TRUE;
srvchg = TRUE;
}
}
dump_ncslist();
/*
* If a neighbour is removed by configuration, remove it from the list.
*/
if (Remove) {
Syslog('r', "Starting remove list");
2005-05-08 17:52:53 +00:00
pthread_mutex_lock(&b_mutex);
2005-05-08 15:50:59 +00:00
tmp = &ncsl;
while (*tmp) {
if ((*tmp)->remove) {
Syslog('r', "do %s", (*tmp)->server);
tnsl = *tmp;
*tmp = (*tmp)->next;
free(tnsl);
callchg = TRUE;
} else {
tmp = &((*tmp)->next);
}
}
2005-05-08 17:52:53 +00:00
pthread_mutex_unlock(&b_mutex);
2005-05-08 15:50:59 +00:00
}
dump_ncslist();
2005-04-17 10:32:41 +00:00
/*
* Check if we need to make state changes
*/
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);
/*
* 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;
}
2005-04-18 20:36:22 +00:00
Syslog('!', "IBC: no IP address for %s: %s", tnsl->server, errmsg);
2005-04-18 12:18:41 +00:00
tnsl->action = now + (time_t)120;
2005-04-17 10:32:41 +00:00
tnsl->state = NCS_FAIL;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-04-17 10:32:41 +00:00
break;
}
tnsl->socket = socket(AF_INET, SOCK_DGRAM, 0);
if (tnsl->socket == -1) {
2005-04-18 20:36:22 +00:00
Syslog('!', "$IBC: can't create socket for %s", tnsl->server);
2005-04-17 10:32:41 +00:00
tnsl->state = NCS_FAIL;
2005-04-18 12:18:41 +00:00
tnsl->action = now + (time_t)120;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-04-17 10:32:41 +00:00
break;
}
Syslog('r', "socket %d", tnsl->socket);
tnsl->state = NCS_CALL;
tnsl->action = now + (time_t)1;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-04-17 10:32:41 +00:00
} else {
tnsl->action = now + (time_t)10;
}
break;
2005-04-18 08:54:55 +00:00
case NCS_CALL: /*
* In this state we accept PASS and SERVER commands from
* the remote with the same token as we have sent.
*/
Syslog('r', "%s call", tnsl->server);
tnsl->token = gettoken();
2005-04-21 21:12:50 +00:00
send_msg(tnsl, "PASS %s 0100 %s\r\n", tnsl->passwd, tnsl->compress ? "Z":"");
send_msg(tnsl, "SERVER %s 0 %ld mbsebbs %s %s\r\n", tnsl->myname, tnsl->token,
2005-04-18 15:19:39 +00:00
VERSION, CFG.bbs_name);
2005-04-18 08:54:55 +00:00
tnsl->action = now + (time_t)10;
2005-04-17 10:32:41 +00:00
tnsl->state = NCS_WAITPWD;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-04-17 10:32:41 +00:00
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);
2005-04-18 08:54:55 +00:00
tnsl->token = 0;
2005-04-17 10:32:41 +00:00
tnsl->state = NCS_CALL;
2005-04-18 08:54:55 +00:00
while (TRUE) {
j = 1+(int) (1.0 * CFG.dialdelay * rand() / (RAND_MAX + 1.0));
if ((j > (CFG.dialdelay / 10)) && (j > 9))
break;
}
2005-04-18 10:06:12 +00:00
Syslog('r', "next call in %d %d seconds", CFG.dialdelay, j);
2005-04-18 08:54:55 +00:00
tnsl->action = now + (time_t)j;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-04-17 10:32:41 +00:00
break;
2005-04-18 10:06:12 +00:00
case NCS_CONNECT: /*
* In this state we check if the connection is still alive
*/
2005-05-08 17:52:53 +00:00
j = (int)now - (int)tnsl->last;
2005-04-23 10:58:43 +00:00
if (((int)now - (int)tnsl->last) > 130) {
/*
* Missed 3 PING replies
*/
2005-04-18 11:52:53 +00:00
Syslog('+', "IBC: server %s connection is dead", tnsl->server);
tnsl->state = NCS_DEAD;
tnsl->action = now + (time_t)120; // 2 minutes delay before calling again.
tnsl->gotpass = FALSE;
tnsl->gotserver = FALSE;
tnsl->token = 0;
2005-04-21 21:12:50 +00:00
broadcast(tnsl->server, "SQUIT %s Connection died\r\n", tnsl->server);
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-22 21:18:45 +00:00
system_shout("*** NETWORK SPLIT, lost connection with server %s", tnsl->server);
2005-05-08 15:58:31 +00:00
del_router(&servers, tnsl->server);
2005-04-18 11:52:53 +00:00
break;
2005-04-18 10:06:12 +00:00
}
2005-04-23 10:58:43 +00:00
/*
* Ping at 60, 90 and 120 seconds
*/
if (((int)now - (int)tnsl->last) > 120) {
Syslog('r', "sending 3rd PING at 120 seconds");
send_msg(tnsl, "PING\r\n");
} else if (((int)now - (int)tnsl->last) > 90) {
Syslog('r', "sending 2nd PING at 90 seconds");
send_msg(tnsl, "PING\r\n");
} else if (((int)now - (int)tnsl->last) > 60) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, "PING\r\n");
2005-04-18 10:06:12 +00:00
}
tnsl->action = now + (time_t)10;
break;
2005-04-18 11:38:44 +00:00
2005-04-18 19:07:10 +00:00
case NCS_HANGUP: Syslog('r', "%s hangup => call", tnsl->server);
2005-04-18 11:38:44 +00:00
tnsl->action = now + (time_t)1;
tnsl->state = NCS_CALL;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-18 11:52:53 +00:00
break;
2005-04-18 19:07:10 +00:00
case NCS_DEAD: Syslog('r', "%s dead -> call", tnsl->server);
2005-04-18 11:52:53 +00:00
tnsl->action = now + (time_t)1;
tnsl->state = NCS_CALL;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-18 11:38:44 +00:00
break;
2005-04-18 12:18:41 +00:00
2005-04-18 19:07:10 +00:00
case NCS_FAIL: Syslog('r', "%s fail => init", tnsl->server);
2005-04-18 12:18:41 +00:00
tnsl->action = now + (time_t)1;
tnsl->state = NCS_INIT;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-18 12:18:41 +00:00
break;
2005-04-17 10:32:41 +00:00
}
}
}
2005-04-17 14:14:56 +00:00
dump_ncslist();
}
2005-04-27 18:02:30 +00:00
int command_pass(char *hostname, char *parameters)
2005-04-17 14:14:56 +00:00
{
ncs_list *tnsl;
2005-04-20 18:39:07 +00:00
char *passwd, *version, *lnk;
2005-04-17 14:14:56 +00:00
2005-04-18 08:54:55 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
passwd = strtok(parameters, " \0");
version = strtok(NULL, " \0");
lnk = strtok(NULL, " \0");
if (version == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 PASS: Not enough parameters\r\n");
return 400;
2005-04-18 08:54:55 +00:00
}
if (strcmp(passwd, tnsl->passwd)) {
Syslog('!', "IBC: got bad password %s from %s", passwd, hostname);
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 08:54:55 +00:00
}
2005-05-01 20:46:30 +00:00
if (tnsl->state == NCS_CONNECT) {
send_msg(tnsl, "401: PASS: Already registered\r\n");
return 401;
}
2005-04-18 08:54:55 +00:00
tnsl->gotpass = TRUE;
tnsl->version = atoi(version);
if (lnk && strchr(lnk, 'Z'))
tnsl->compress = TRUE;
2005-04-27 18:02:30 +00:00
return 0;
2005-04-17 14:14:56 +00:00
}
2005-04-18 08:54:55 +00:00
2005-04-27 18:02:30 +00:00
int command_server(char *hostname, char *parameters)
2005-04-18 08:54:55 +00:00
{
ncs_list *tnsl;
2005-04-18 18:22:09 +00:00
srv_list *ta;
usr_list *tmp;
2005-04-27 18:53:30 +00:00
chn_list *tmpc;
2005-04-21 21:12:50 +00:00
char *name, *hops, *id, *prod, *vers, *fullname;
2005-04-18 08:54:55 +00:00
unsigned long token;
2005-04-18 18:08:07 +00:00
int ihops, found = FALSE;
2005-04-18 08:54:55 +00:00
name = strtok(parameters, " \0");
hops = strtok(NULL, " \0");
id = strtok(NULL, " \0");
2005-04-18 15:19:38 +00:00
prod = strtok(NULL, " \0");
2005-04-18 15:26:10 +00:00
vers = strtok(NULL, " \0");
2005-04-18 15:19:38 +00:00
fullname = strtok(NULL, "\0");
ihops = atoi(hops) + 1;
2005-04-18 08:54:55 +00:00
2005-04-18 18:08:07 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, name) == 0) {
found = TRUE;
break;
}
}
2005-04-18 15:19:39 +00:00
if (fullname == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 SERVER: Not enough parameters\r\n");
return 400;
2005-04-18 08:54:55 +00:00
}
token = atoi(id);
2005-04-18 18:08:07 +00:00
if (found && tnsl->token) {
2005-04-18 08:54:55 +00:00
/*
* We are in calling state, so we expect the token from the
* remote is the same as the token we sent.
* In that case, the session is authorized.
*/
if (tnsl->token == token) {
2005-04-21 21:12:50 +00:00
broadcast(tnsl->server, "SERVER %s %d %s %s %s %s\r\n", name, ihops, id, prod, vers, fullname);
2005-04-23 11:25:32 +00:00
system_shout("* New server: %s, %s", name, fullname);
2005-04-18 08:54:55 +00:00
tnsl->gotserver = TRUE;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-18 08:54:55 +00:00
tnsl->state = NCS_CONNECT;
tnsl->action = now + (time_t)10;
2005-04-30 11:41:24 +00:00
Syslog('+', "IBC: connected with neighbour server: %s", tnsl->server);
2005-04-18 18:22:09 +00:00
/*
* Send all already known servers
*/
for (ta = servers; ta; ta = ta->next) {
if (ta->hops) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, "SERVER %s %d 0 %s %s %s\r\n", ta->server, ta->hops, ta->prod, ta->vers, ta->fullname);
2005-04-18 18:22:09 +00:00
}
}
/*
* Send all known users
*/
for (tmp = users; tmp; tmp = tmp->next) {
send_msg(tnsl, "USER %s@%s %s\r\n", tmp->name, tmp->server, tmp->realname);
if (strcmp(tmp->name, tmp->nick))
send_msg(tnsl, "NICK %s %s %s %s\r\n", tmp->nick, tmp->name, tmp->server, tmp->realname);
2005-04-27 18:53:30 +00:00
if (strlen(tmp->channel)) {
for (tmpc = channels; tmpc; tmpc = tmpc->next) {
if (strcasecmp(tmpc->name, tmp->channel) == 0) {
send_msg(tnsl, "JOIN %s@%s %s\r\n", tmpc->owner, tmpc->server, tmpc->name);
if (strlen(tmpc->topic) && (strcmp(tmpc->server, CFG.myfqdn) == 0)) {
send_msg(tnsl, "TOPIC %s %s\r\n", tmpc->name, tmpc->topic);
}
}
}
}
}
2005-04-18 18:36:27 +00:00
add_server(&servers, tnsl->server, ihops, prod, vers, fullname, hostname);
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 08:54:55 +00:00
}
2005-04-30 11:41:24 +00:00
Syslog('r', "IBC: call collision with %s", tnsl->server);
2005-04-22 21:18:45 +00:00
tnsl->state = NCS_WAITPWD; /* Experimental, should fix state when state was connect while it wasn't. */
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 08:54:55 +00:00
}
/*
* We are in waiting state, so we sent our PASS and SERVER
* messages and set the session to connected if we got a
* valid PASS command.
*/
2005-04-18 18:08:07 +00:00
if (found && tnsl->gotpass) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, "PASS %s 0100 %s\r\n", tnsl->passwd, tnsl->compress ? "Z":"");
send_msg(tnsl, "SERVER %s 0 %ld mbsebbs %s %s\r\n", tnsl->myname, token, VERSION, CFG.bbs_name);
broadcast(tnsl->server, "SERVER %s %d %s %s %s %s\r\n", name, ihops, id, prod, vers, fullname);
2005-04-23 11:25:32 +00:00
system_shout("* New server: %s, %s", name, fullname);
2005-04-18 08:54:55 +00:00
tnsl->gotserver = TRUE;
tnsl->state = NCS_CONNECT;
tnsl->action = now + (time_t)10;
2005-04-30 11:41:24 +00:00
Syslog('+', "IBC: connected with neighbour server: %s", tnsl->server);
2005-04-18 18:22:09 +00:00
/*
* Send all already known servers
*/
for (ta = servers; ta; ta = ta->next) {
if (ta->hops) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, "SERVER %s %d 0 %s %s %s\r\n", ta->server, ta->hops, ta->prod, ta->vers, ta->fullname);
2005-04-18 18:22:09 +00:00
}
}
/*
2005-04-27 18:53:30 +00:00
* Send all known users. If a user is in a channel, send a JOIN.
* If the user is one of our own and has set a channel topic, send it.
*/
for (tmp = users; tmp; tmp = tmp->next) {
send_msg(tnsl, "USER %s@%s %s\r\n", tmp->name, tmp->server, tmp->realname);
if (strcmp(tmp->name, tmp->nick))
send_msg(tnsl, "NICK %s %s %s %s\r\n", tmp->nick, tmp->name, tmp->server, tmp->realname);
2005-04-27 18:53:30 +00:00
if (strlen(tmp->channel)) {
for (tmpc = channels; tmpc; tmpc = tmpc->next) {
if (strcasecmp(tmpc->name, tmp->channel) == 0) {
send_msg(tnsl, "JOIN %s@%s %s\r\n", tmpc->owner, tmpc->server, tmpc->name);
if (strlen(tmpc->topic) && (strcmp(tmpc->server, CFG.myfqdn) == 0)) {
send_msg(tnsl, "TOPIC %s %s\r\n", tmpc->name, tmpc->topic);
}
}
}
}
}
2005-04-18 18:36:27 +00:00
add_server(&servers, tnsl->server, ihops, prod, vers, fullname, hostname);
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-05-08 13:17:43 +00:00
callchg = TRUE;
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 08:54:55 +00:00
}
2005-04-18 18:08:07 +00:00
if (! found) {
/*
* Got a message about a server that is not our neighbour.
*/
2005-04-18 18:36:27 +00:00
add_server(&servers, name, ihops, prod, vers, fullname, hostname);
2005-04-21 21:12:50 +00:00
broadcast(hostname, "SERVER %s %d %s %s %s %s\r\n", name, ihops, id, prod, vers, fullname);
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-30 11:41:24 +00:00
Syslog('+', "IBC: new relay server %s: %s", name, fullname);
2005-04-23 11:25:32 +00:00
system_shout("* New server: %s, %s", name, fullname);
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 18:08:07 +00:00
}
Syslog('r', "IBC: got SERVER command without PASS command from %s", hostname);
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 08:54:55 +00:00
}
2005-04-27 18:02:30 +00:00
int command_squit(char *hostname, char *parameters)
2005-04-18 11:38:44 +00:00
{
2005-04-18 15:19:38 +00:00
ncs_list *tnsl;
2005-04-21 21:12:50 +00:00
char *name, *message;
2005-04-18 15:19:38 +00:00
2005-04-18 11:38:44 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
name = strtok(parameters, " \0");
message = strtok(NULL, "\0");
2005-04-18 14:28:41 +00:00
if (strcmp(name, tnsl->server) == 0) {
2005-04-30 11:31:31 +00:00
Syslog('+', "IBC: disconnect neighbour server %s: %s", name, message);
2005-04-18 12:18:41 +00:00
tnsl->state = NCS_HANGUP;
2005-04-18 15:19:38 +00:00
tnsl->action = now + (time_t)120; // 2 minutes delay before calling again.
2005-04-18 12:18:41 +00:00
tnsl->gotpass = FALSE;
tnsl->gotserver = FALSE;
tnsl->token = 0;
2005-04-18 18:46:08 +00:00
del_router(&servers, name);
2005-04-18 12:56:28 +00:00
} else {
2005-04-30 11:31:31 +00:00
Syslog('+', "IBC: disconnect relay server %s: %s", name, message);
2005-04-18 18:46:08 +00:00
del_server(&servers, name);
2005-04-18 11:38:44 +00:00
}
2005-04-18 16:48:51 +00:00
2005-04-23 11:25:32 +00:00
system_shout("* Server %s disconnected: %s", name, message);
2005-04-21 21:12:50 +00:00
broadcast(hostname, "SQUIT %s %s\r\n", name, message);
2005-05-01 13:12:41 +00:00
srvchg = TRUE;
2005-04-27 18:02:30 +00:00
return 0;
2005-04-18 11:38:44 +00:00
}
2005-04-27 18:02:30 +00:00
int command_user(char *hostname, char *parameters)
2005-04-20 21:27:25 +00:00
{
ncs_list *tnsl;
2005-04-22 18:39:48 +00:00
char *name, *server, *realname;
2005-04-20 21:27:25 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
2005-04-22 18:39:48 +00:00
name = strtok(parameters, "@\0");
2005-04-20 21:27:25 +00:00
server = strtok(NULL, " \0");
realname = strtok(NULL, "\0");
if (realname == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 USER: Not enough parameters\r\n");
return 400;
2005-04-20 21:27:25 +00:00
}
2005-04-22 21:18:45 +00:00
if (add_user(&users, server, name, realname) == 0) {
2005-04-22 18:39:48 +00:00
broadcast(hostname, "USER %s@%s %s\r\n", name, server, realname);
2005-04-23 11:25:32 +00:00
system_shout("* New user %s@%s (%s)", name, server, realname);
2005-04-22 21:18:45 +00:00
}
2005-04-27 18:02:30 +00:00
return 0;
2005-04-20 21:27:25 +00:00
}
2005-04-27 18:02:30 +00:00
int command_quit(char *hostname, char *parameters)
2005-04-20 21:27:25 +00:00
{
ncs_list *tnsl;
2005-04-22 18:39:48 +00:00
char *name, *server, *message;
2005-04-20 21:27:25 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
2005-04-22 18:39:48 +00:00
name = strtok(parameters, "@\0");
2005-04-20 21:27:25 +00:00
server = strtok(NULL, " \0");
message = strtok(NULL, "\0");
if (server == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 QUIT: Not enough parameters\r\n");
return 400;
2005-04-20 21:27:25 +00:00
}
2005-04-22 21:18:45 +00:00
if (message) {
2005-04-23 11:25:32 +00:00
system_shout("* User %s is leaving: %s", name, message);
2005-04-22 21:18:45 +00:00
} else {
2005-04-23 11:25:32 +00:00
system_shout("* User %s is leaving", name);
2005-04-22 21:18:45 +00:00
}
2005-04-22 18:39:48 +00:00
del_user(&users, server, name);
broadcast(hostname, "QUIT %s@%s %s\r\n", name, server, parameters);
2005-04-27 18:02:30 +00:00
return 0;
2005-04-20 21:27:25 +00:00
}
2005-04-22 19:40:05 +00:00
int command_nick(char *hostname, char *parameters)
{
ncs_list *tnsl;
usr_list *tmp;
char *nick, *name, *server, *realname;
int found;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
nick = strtok(parameters, " \0");
name = strtok(NULL, " \0");
server = strtok(NULL, " \0");
realname = strtok(NULL, "\0");
if (realname == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 NICK: Not enough parameters\r\n");
2005-04-22 19:40:05 +00:00
return 1;
}
if (strlen(nick) > 9) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "402 %s: Erroneous nickname\r\n", nick);
return 402;
2005-04-22 19:40:05 +00:00
}
// FIXME: check 1st char is alpha, rest alpha/digit
found = FALSE;
for (tmp = users; tmp; tmp = tmp->next) {
2005-04-22 20:01:21 +00:00
if ((strcmp(tmp->name, nick) == 0) || (strcmp(tmp->nick, nick) == 0)) {
2005-04-22 19:40:05 +00:00
found = TRUE;
break;
}
}
if (found) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "403 %s: Nickname is already in use\r\n", nick);
return 403;
2005-04-22 19:40:05 +00:00
}
for (tmp = users; tmp; tmp = tmp->next) {
if ((strcmp(tmp->server, server) == 0) && (strcmp(tmp->realname, realname) == 0) && (strcmp(tmp->name, name) == 0)) {
pthread_mutex_lock(&b_mutex);
2005-04-22 20:01:21 +00:00
strncpy(tmp->nick, nick, 9);
2005-04-22 19:40:05 +00:00
pthread_mutex_unlock(&b_mutex);
found = TRUE;
Syslog('+', "IBC: user %s set nick to %s", name, nick);
usrchg = TRUE;
}
}
if (!found) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "404 %s@%s: Can't change nick\r\n", name, server);
return 404;
2005-04-22 19:40:05 +00:00
}
broadcast(hostname, "NICK %s %s %s %s\r\n", nick, name, server, realname);
return 0;
}
2005-04-27 18:02:30 +00:00
int command_join(char *hostname, char *parameters)
2005-04-23 15:35:39 +00:00
{
ncs_list *tnsl;
chn_list *tmp;
usr_list *tmpu;
2005-04-27 20:54:13 +00:00
char *nick, *server, *channel, msg[81];
2005-04-23 15:35:39 +00:00
int found;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
2005-04-23 15:47:48 +00:00
nick = strtok(parameters, "@\0");
2005-04-23 15:35:39 +00:00
server = strtok(NULL, " \0");
channel = strtok(NULL, "\0");
if (channel == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 JOIN: Not enough parameters\r\n");
return 400;
2005-04-23 15:35:39 +00:00
}
if (strlen(channel) > 20) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "402 %s: Erroneous channelname\r\n", nick);
return 402;
2005-04-23 15:35:39 +00:00
}
if (strcasecmp(channel, "#sysop") == 0) {
Syslog('+', "IBC: ignored JOIN for #sysop channel");
return 0;
}
2005-04-23 15:35:39 +00:00
found = FALSE;
for (tmp = channels; tmp; tmp = tmp->next) {
if (strcmp(tmp->name, channel) == 0) {
found = TRUE;
tmp->users++;
break;
}
}
if (!found) {
Syslog('+', "IBC: create channel %s owned by %s@%s", channel, nick, server);
add_channel(&channels, channel, nick, server);
2005-04-27 20:54:13 +00:00
system_shout("* New channel %s created by %s@%s", channel, nick, server);
2005-04-23 15:35:39 +00:00
}
for (tmpu = users; tmpu; tmpu = tmpu->next) {
2005-04-27 21:26:03 +00:00
if ((strcmp(tmpu->server, server) == 0) && ((strcmp(tmpu->nick, nick) == 0) || (strcmp(tmpu->name, nick) == 0))) {
2005-04-23 15:35:39 +00:00
pthread_mutex_lock(&b_mutex);
strncpy(tmpu->channel, channel, 20);
pthread_mutex_unlock(&b_mutex);
Syslog('+', "IBC: user %s joined channel %s", nick, channel);
usrchg = TRUE;
2005-04-27 20:54:13 +00:00
sprintf(msg, "* %s@%s has joined %s", nick, server, channel);
chat_msg(channel, NULL, msg);
2005-04-23 15:35:39 +00:00
}
}
2005-04-23 15:56:22 +00:00
broadcast(hostname, "JOIN %s@%s %s\r\n", nick, server, channel);
2005-04-23 15:35:39 +00:00
chnchg = TRUE;
2005-04-27 18:02:30 +00:00
return 0;
2005-04-23 15:35:39 +00:00
}
2005-04-27 18:02:30 +00:00
int command_part(char *hostname, char *parameters)
2005-04-23 15:35:39 +00:00
{
ncs_list *tnsl;
chn_list *tmp;
usr_list *tmpu;
2005-04-27 20:54:13 +00:00
char *nick, *server, *channel, *message, msg[81];
2005-04-23 15:35:39 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
2005-04-23 15:47:48 +00:00
nick = strtok(parameters, "@\0");
2005-04-23 15:35:39 +00:00
server = strtok(NULL, " \0");
2005-04-24 12:14:39 +00:00
channel = strtok(NULL, " \0");
message = strtok(NULL, "\0");
2005-04-23 15:35:39 +00:00
if (channel == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 PART: Not enough parameters\r\n");
return 400;
2005-04-23 15:35:39 +00:00
}
if (strcasecmp(channel, "#sysop") == 0) {
Syslog('+', "IBC: ignored PART from #sysop channel");
return 0;
}
2005-04-23 15:35:39 +00:00
for (tmp = channels; tmp; tmp = tmp->next) {
if (strcmp(tmp->name, channel) == 0) {
chnchg = TRUE;
tmp->users--;
if (tmp->users == 0) {
Syslog('+', "IBC: deleted empty channel %s", channel);
del_channel(&channels, channel);
}
break;
}
}
for (tmpu = users; tmpu; tmpu = tmpu->next) {
2005-04-27 21:26:03 +00:00
if ((strcmp(tmpu->server, server) == 0) && ((strcmp(tmpu->nick, nick) == 0) || (strcmp(tmpu->name, nick) == 0))) {
2005-04-23 15:35:39 +00:00
pthread_mutex_lock(&b_mutex);
tmpu->channel[0] = '\0';
pthread_mutex_unlock(&b_mutex);
2005-04-27 20:54:13 +00:00
if (message) {
2005-04-24 12:14:39 +00:00
Syslog('+', "IBC: user %s left channel %s: %s", nick, channel, message);
2005-04-27 20:54:13 +00:00
sprintf(msg, "* %s@%s has left: %s", nick, server, message);
} else {
2005-04-24 12:14:39 +00:00
Syslog('+', "IBC: user %s left channel %s", nick, channel);
2005-04-27 20:54:13 +00:00
sprintf(msg, "* %s@%s has silently left this channel", nick, server);
}
chat_msg(channel, NULL, msg);
2005-04-23 15:35:39 +00:00
usrchg = TRUE;
}
}
2005-04-23 15:56:22 +00:00
2005-04-24 12:14:39 +00:00
if (message)
broadcast(hostname, "PART %s@%s %s %s\r\n", nick, server, channel, message);
else
broadcast(hostname, "PART %s@%s %s\r\n", nick, server, channel);
2005-04-27 18:02:30 +00:00
return 0;
2005-04-23 15:35:39 +00:00
}
2005-04-27 18:02:30 +00:00
int command_topic(char *hostname, char *parameters)
2005-04-23 15:35:39 +00:00
{
ncs_list *tnsl;
chn_list *tmp;
2005-04-27 20:54:13 +00:00
char *channel, *topic, msg[81];
2005-04-23 15:35:39 +00:00
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
channel = strtok(parameters, " \0");
topic = strtok(NULL, "\0");
if (topic == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 TOPIC: Not enough parameters\r\n");
return 400;
2005-04-23 15:35:39 +00:00
}
for (tmp = channels; tmp; tmp = tmp->next) {
if (strcmp(tmp->name, channel) == 0) {
chnchg = TRUE;
strncpy(tmp->topic, topic, 54);
Syslog('+', "IBC: channel %s topic: %s", channel, topic);
2005-04-27 20:54:13 +00:00
sprintf(msg, "* Channel topic is now: %s", tmp->topic);
chat_msg(channel, NULL, msg);
2005-04-27 19:52:51 +00:00
break;
2005-04-23 15:35:39 +00:00
}
}
2005-04-23 15:56:22 +00:00
broadcast(hostname, "TOPIC %s %s\r\n", channel, topic);
2005-04-27 18:02:30 +00:00
return 0;
}
2005-04-27 19:52:51 +00:00
int command_privmsg(char *hostname, char *parameters)
{
ncs_list *tnsl;
chn_list *tmp;
char *channel, *msg;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
channel = strtok(parameters, " \0");
msg = strtok(NULL, "\0");
if (msg == NULL) {
send_msg(tnsl, "412 PRIVMSG: No text to send\r\n");
return 412;
}
if (channel[0] != '#') {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "499 PRIVMSG: Not for a channel\r\n"); // FIXME: also check users
return 499;
2005-04-27 19:52:51 +00:00
}
for (tmp = channels; tmp; tmp = tmp->next) {
if (strcmp(tmp->name, channel) == 0) {
tmp->lastmsg = now;
chat_msg(channel, NULL, msg);
broadcast(hostname, "PRIVMSG %s %s\r\n", channel, msg);
return 0;
}
}
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "409 %s: Cannot sent to channel\r\n", channel);
return 409;
2005-04-27 19:52:51 +00:00
}
2005-04-27 18:02:30 +00:00
int do_command(char *hostname, char *command, char *parameters)
{
ncs_list *tnsl;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
break;
}
}
/*
* First the commands that don't have parameters
*/
if (! strcmp(command, (char *)"PING")) {
send_msg(tnsl, "PONG\r\n");
return 0;
}
if (! strcmp(command, (char *)"PONG")) {
/*
* Just accept
*/
return 0;
}
/*
* Commands with parameters
*/
if (parameters == NULL) {
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "400 %s: Not enough parameters\r\n", command);
return 400;
2005-04-27 18:02:30 +00:00
}
if (! strcmp(command, (char *)"PASS")) {
return command_pass(hostname, parameters);
}
if (! strcmp(command, (char *)"SERVER")) {
return command_server(hostname, parameters);
}
if (! strcmp(command, (char *)"SQUIT")) {
return command_squit(hostname, parameters);
}
if (! strcmp(command, (char *)"USER")) {
return command_user(hostname, parameters);
}
if (! strcmp(command, (char *)"QUIT")) {
return command_quit(hostname, parameters);
}
if (! strcmp(command, (char *)"NICK")) {
return command_nick(hostname, parameters);
2005-04-27 20:26:53 +00:00
}
2005-04-27 20:31:54 +00:00
if (! strcmp(command, (char *)"JOIN")) {
2005-04-27 20:26:53 +00:00
return command_join(hostname, parameters);
}
2005-04-27 18:02:30 +00:00
if (! strcmp(command, (char *)"PART")) {
return command_part(hostname, parameters);
}
if (! strcmp(command, (char *)"TOPIC")) {
return command_topic(hostname, parameters);
}
2005-04-27 19:52:51 +00:00
if (! strcmp(command, (char *)"PRIVMSG")) {
return command_privmsg(hostname, parameters);
}
2005-04-27 18:02:30 +00:00
2005-05-01 20:46:30 +00:00
send_msg(tnsl, "413 %s: Unknown command\r\n", command);
return 413;
2005-04-23 15:35:39 +00:00
}
2005-04-17 14:14:56 +00:00
void receiver(struct servent *se)
{
struct pollfd pfd;
struct hostent *hp;
int rc, len, inlist;
socklen_t sl;
ncs_list *tnsl;
2005-04-24 12:14:39 +00:00
char *hostname, *command, *parameters;
2005-04-17 14:14:56 +00:00
pfd.fd = ls;
pfd.events = POLLIN;
pfd.revents = 0;
if ((rc = poll(&pfd, 1, 1000) < 0)) {
Syslog('r', "$poll/select failed");
return;
2005-05-08 17:52:53 +00:00
}
now = time(NULL);
2005-04-17 14:14:56 +00:00
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));
2005-04-18 08:54:55 +00:00
memset(&crbuf, 0, sizeof(crbuf));
if ((len = recvfrom(ls, &crbuf, sizeof(crbuf)-1, 0,(struct sockaddr *)&clientaddr_in, &sl)) != -1) {
2005-04-17 14:14:56 +00:00
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;
2005-04-18 08:54:55 +00:00
if ((crbuf[strlen(crbuf) -2] != '\r') && (crbuf[strlen(crbuf) -1] != '\n')) {
2005-04-30 11:31:31 +00:00
Syslog('!', "IBC: got message not terminated with CR-LF, dropped");
2005-04-17 14:14:56 +00:00
return;
}
inlist = FALSE;
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (strcmp(tnsl->server, hostname) == 0) {
inlist = TRUE;
break;
}
}
if (!inlist) {
2005-04-18 08:54:55 +00:00
Syslog('!', "IBC: message from unknown host (%s), dropped", hostname);
2005-04-17 14:14:56 +00:00
return;
}
2005-04-18 10:30:35 +00:00
if (tnsl->state == NCS_INIT) {
Syslog('r', "IBC: message received from %s while in init state, dropped", hostname);
return;
}
2005-04-18 15:19:38 +00:00
tnsl->last = now;
2005-04-18 08:54:55 +00:00
crbuf[strlen(crbuf) -2] = '\0';
Syslog('r', "< %s: \"%s\"", hostname, printable(crbuf, 0));
2005-04-17 14:14:56 +00:00
/*
* Parse message
*/
2005-04-24 12:14:39 +00:00
command = strtok(crbuf, " \0");
parameters = strtok(NULL, "\0");
2005-04-18 08:54:55 +00:00
2005-04-27 18:02:30 +00:00
if (atoi(command)) {
2005-04-18 10:37:35 +00:00
Syslog('r', "IBC: Got error %d", atoi(command));
2005-04-27 18:02:30 +00:00
} else {
do_command(hostname, command, parameters);
2005-04-17 14:14:56 +00:00
}
} 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-18 11:38:44 +00:00
ncs_list *tnsl;
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) {
2005-04-18 08:54:55 +00:00
Syslog('!', "IBC: no fido udp entry in /etc/services, cannot start Internet BBS Chat");
2005-04-16 16:08:32 +00:00
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;
2005-04-18 10:37:35 +00:00
Syslog('+', "IBC: listen on %s, port %d", inet_ntoa(myaddr_in.sin_addr), ntohs(myaddr_in.sin_port));
2005-04-17 10:32:41 +00:00
ls = socket(AF_INET, SOCK_DGRAM, 0);
if (ls == -1) {
2005-04-18 08:54:55 +00:00
Syslog('!', "$IBC: can't create listen socket");
2005-04-17 10:32:41 +00:00
goto exit;
}
if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) {
2005-04-18 08:54:55 +00:00
Syslog('!', "$IBC: can't bind listen socket");
2005-04-17 10:32:41 +00:00
goto exit;
}
2005-04-16 14:49:58 +00:00
ibc_run = TRUE;
2005-04-18 20:36:22 +00:00
srand(getpid());
2005-04-15 21:36:44 +00:00
while (! T_Shutdown) {
2005-04-18 15:19:38 +00:00
2005-04-17 10:32:41 +00:00
/*
* Check neighbour servers state
*/
2005-05-08 17:52:53 +00:00
now = time(NULL);
2005-04-17 10:32:41 +00:00
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-18 11:43:16 +00:00
Syslog('r', "IBC: start shutdown connections");
for (tnsl = ncsl; tnsl; tnsl = tnsl->next) {
if (tnsl->state == NCS_CONNECT) {
2005-04-21 21:12:50 +00:00
send_msg(tnsl, "SQUIT %s System shutdown\r\n", tnsl->myname);
2005-04-18 11:43:16 +00:00
}
}
2005-04-18 14:28:41 +00:00
tidy_servers(&servers);
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