pkg://Tnos-2.40-src.tar.gz:1189242/convers.c
downloads
/* convers server - based on conversd written by DK5SG
* ported to WNOS by DB3FL - 9109xx/9110xx
* ported to NOS by PE1NMB - 920120
* Mods by PA0GRI
* Cleanup, and additional mods by WG7J
* Major additions, rewrites, enhancements by KO4KS
*/
#include "global.h"
#ifdef CONVERS
#include "commands.h"
#include "ctype.h"
#ifdef UNIX
#include <sys/stat.h>
#endif
#ifdef MSDOS
#include <io.h>
#else
#include <time.h>
#include "session.h"
#endif
#ifdef MAILBOX
#include "mailbox.h"
#endif
#include "files.h"
#ifdef LZW
#include "lzw.h"
#endif
#include "x.h"
#include "domain.h"
#if !defined(_lint)
static char rcsid[] OPTIONAL = "$Id: convers.c,v 1.36 2001/05/06 16:32:55 brian Exp $";
#endif
extern char stars[];
static int conv_rand (void);
/* #pragma option -zEMYFAR */
#define LINK 1
#define space
#if defined(LZW)
void togglelzw (int soc, int mode);
#endif
int32 CT4init = 7200; /* 2 hours default */
static int CChannel = 0; /* default entry to channel 0 */
static int HMaxQ = 6 * 1024L;
static int UMaxQ = 3 * 1024L;
int Sconv = -1;
static int ConvNet0 = 0;
static int ConvHeader = 0;
static int TimeStamp = 0;
extern char shortversion[];
extern char *Months[]; /*lint !e15 * in smtpserv.c */
static int Conv_mutex = TNOS_MUTEX_UNLOCKED;
static int Group_mutex = TNOS_MUTEX_UNLOCKED;
#define PREFIXLEN 10
#define CONVLINELEN 79
static const char *suits[] = { "Hearts", "Clubs", "Diamonds", "Spades" };
static const char *cards[] = { "Ace", "Deuce", "Three", "Four", "Five", "Six",
"Seven", "Eight", "Nine", "Ten", "Jack", "Queen", "King" };
#ifdef STATS_USE
long localConfUsers = 0;
#endif
int Conflogins = 0;
#ifdef space
static char cnumber[] = "*** Channel numbers must be in the range 0..%d.\n";
#else
static char cnumber[] = "* range 0..%d.\n";
#endif
static char trailer[] = "***\n";
static char noinfo[] = "No additional information available";
static char sysinfoheader[] = "%sSystem Information for: %s - email to sysop@%s\n";
static char msgtext[] = "<*%s*>: %s\n";
static char theysigned[] = "%s%s signed o%s at %s.\n";
static char theyswitched[] = "%s%s switched to channel %d at %s.\n";
static char conversd[] = "conversd";
static char fullstr[] = "%s";
static char fullstrcr[] = "%s\n";
static char sosorry[] = "*** Sorry, ";
static char sorry[] = "%s%s Net on %s %d!\n";
static char busystr[] = "%s'%s' is already a %s!\n";
static char logfilestr[] = "%sLogfile is %sed\n";
static char netcontrolstr[] = "Net Control";
static char privatestr[] = "Closed";
static char clearedstr[] = "cleared";
static char passwordstr[] = "Password";
static char nowchannel[] = "%sNow on %s %d (%d user%s).\n";
static char nicknamestr[] = "%s%s%sset to '%s'.\n";
static char channelstr[] = "Channel";
static char systemstr[] = "SYSTEM";
static char unknownstr[] = "*** Unknown ";
static char unkcmdstr[] = "%scommand '/%s'.%s";
static char nouserstr[] = "%suser!\n";
static char gethelpstr[] = " Type /HELP for help.\n";
static char noopenstr[] = "Can't open '%s'\n";
static char activenetstr[] = "%sActive Net '%s'\n";
static char net2str[] = "%sNet %s %s\n";
static char conferencestr[] = "*** TNOS Conference @ ";
static char namecmdstr[] = "%sPlease login with '/n <call>'\n";
static char nonetstr[] = "%sNo Net!\n";
static char recheckstr[] = "*** Recheck";
static char questionstr[] = "*** Question";
static char nicknmstr[] = "Nickname ";
static char tmstr[] = "Time";
static char userstr[] = "User";
static char hoststr[] = "Host";
static char newuserstr[] = "%sNew user '%s' has entered conference area on channel '%d'";
static char urnotstr[] = "%sYou are not %s\n";
static char urassigned[] = "%s'%s' has assigned you as %s on %s %d\n";
static char wrongchannel[] = "%s%s '%s' not on this %s\n";
static char openminutes[] = "%sMinutes starting at %s\n%sNet '%s' - %s is '%s'\n";
static char closeminutes[] = "%sMinutes ending at %s\n";
static char headerstr[] = "User Host Via Channel Time Personal\n";
static char userdata[] = "%-10.10s %-10.10s %-11.11s %6d %s %-31.31s\n";
static char summary[] = "%sTNOS Conference Bridge command summary:\n ";
static char extendedsummary[] = "\n%sExtended Remote Commands:\n ";
static char modeis[] = "Mode is: %s\n";
static char acceptstr[] = "Accept";
static char refuse[] = "Refuse";
static char redun[] = "Conf. redundancy timer (sec)";
static char entrystr[] = "Conf. entry channel";
static char givehead[] = "Display login header on connect";
static char allownets[] = "Allow Nets on Channel 0";
static char timestampstr[] = "Timestamp all user messages";
static char maxwaitstr[] = "Re-link max wait (sec)";
static char hostqueuestr[] = "Max. Host Queue (bytes)";
static char userqueuestr[] = "Max. User Queue (bytes)";
static char motdstr[] = "Conference MOTD: %s\n";
static char sysinfostr[] = "SYStem INFOrmation: %s\n";
static char timestampfmt[] = "<*%s:%s*>:";
static char nontimestampfmt[] = "<*%s*>:";
static char timestampfmt2[] = "<%s:%s>:";
static char nontimestampfmt2[] = "<%s>:";
static char alreadyon[] = "%s%s %s is already on this channel.";
static char exitingstr[] = "Exiting %s%s\n";
static char welcome[] = "%s%s%sNet '%s'";
static char welcome2[] = " - %s is '%s'...";
static char welcome3[] = "\n Welcome, %s!\n";
static char welcomeback[] = "%sWelcome back, %s\n";
static char noinvite[] = "%s%s net, only %s can invite\n";
static char nosuchuser[] = "%sNo such user: %s.\n";
static char online[] = "%sThere are %d users online\n";
static char groupsavail[] = "%sThere %s %d group%s available\n";
static char colorstatus[] = "%sCurrently ANSI Color graphics are O%s\n";
static char personalset[] = "%sPersonal data set to: %s\n";
#ifdef ALLSERV
static char quotebanner[] = "*** Quote of the day:\n";
#endif
static char whobanner[] = "%s %s %s Personal\n";
static char rollstr[] = "%s'%s' has rolled a %d and a %d for a total of %d! %s";
static char cutstr[] = "%s'%s' has cut the deck and selected the %s of %s! %s";
static char gloghdr[] = "*** Current Check-ins\n";
static char glogstr[] = " %s %s In %s\n";
static char grouphdr[] = "%sAvailable Groups:\n Channel Group Name\n ======= ==========\n";
#ifdef space
static char youare[] = "%sYou are %son channel %d.\n";
static char amessage[] = "\n*** Message from ";
static char invitetext[] = "%s%s at %s ...\n%sPlease join conference channel %d.\n";
static char mbinvitetext[] = "%s%s at %s ...\n%sPlease type 'CONF %d' to join conference channel %d.\n";
static char responsetext[] = "%sInvitation sent to %s @ %s";
#else
static char youare[] = "%sOn channel %d.\n";
static char amessage[] = "\n*** Msg frm ";
static char invitetext[] = "%s%s at %s ...\n%sPse join ch. %d.\n";
static char mbinvitetext[] = "%s at %s ...\n%sPse hit 'CONF %d' for conference ch. %d.\n";
static char responsetext[] = "%ssent to %s @ %s";
#endif
static char hinvi[] = "/\377\200INVI %s %s %d %s\n";
static char uaddstr[] = "/\377\200UADD %s %s %s %d %s\n";
static char bumpstr[] = "/\377\200BUMP %s %d\n";
static char ndatstr[] = "/\377\200NDAT %d %d %d %d %d %s|%s|%s|\n";
static char topicstr[] = "/\377\200TOPI %s %s %ld %d %s\n";
static char quesstr[] = "/\377\200QUES %d %c %s %s\n";
static char umsgstr[] = "/\377\200UMSG %s %s %s\n";
static char cmsgstr[] = "/\377\200CMSG %s %d %s\n";
static char hhoststr[] = "/\377\200HOST %s %s %s\n";
static char huserstr[] = "/\377\200USER %s %s %ld %d %d %s\n";
static char loopstr[] = "/\377\200LOOP %s %s %s\n";
static char SYSCOLORS[] = "0C";
static char TEXTCOLORS[] = "09";
static char INFOCOLORS[] = "0B";
#if 0
static char INPUTCOLORS[] = "0F";
#endif
static char ff_str[] = "ff";
static char n_str[] = "n";
static char empty[] = "";
static char myfeatures[] = "dnpu";
#define MAXCHANNEL ((int) 32767)
#ifndef LINELEN
#define LINELEN 256
#endif
#define INBUFLEN 2048
#define MAX_WAITTIME (60*60*3)
#define NAMELEN 16
static long CMaxwait = MAX_WAITTIME;
struct convection {
int type; /* Connection type */
#define CT_UNKNOWN 0
#define CT_USER 1
#define CT_HOST 2
#define CT_CLOSED 3
char name[NAMELEN + 1]; /* Name of user or host */
char host[NAMELEN + 1]; /* Name of host where user is logged on */
char nickname[NAMELEN + 1]; /* Nickname of user */
char password[NAMELEN + 1]; /* Password of user */
struct convection *via; /* Pointer to neighbor host */
char *data; /* room for some personal data */
int channel; /* Channel number */
int net; /* Channel of controlled net */
time_t nettime; /* Time entered channel (used by nets) */
time_t time; /* Connect time */
int maxq; /* Maximum outstanding data before link reset */
int locked; /* Set if mesg already sent */
int fd; /* Socket descriptor */
int flags; /* User flags */
#define CLOSE_SOCK 1
#define USE_SOUND 2
#define CHANGED_INFO 4
#define USE_LZW 8
#define USE_COLOR 16
char colorset[2]; /* current color set */
int features;
#define FEATURE_AWAY 1 /* a - "away feature" */
#define FEATURE_FWD 2 /* d - "destination forwarding" */
#define FEATURE_MODES 4 /* m - "channel modes" */
#define FEATURE_LINK 8 /* p - "ping pong link measurement" */
#define FEATURE_UDAT 16 /* u - "udat command extension and user command understood both" */
#define FEATURE_NICK 32 /* n - "TNOS Nickname extensions" */
/* This buffer is only needed for local users; a lot of space is wasted
* for users from other hosts (256 bytes per user!). Fixed 930728 - WG7J
* char ibuf[INBUFLEN];
*/
char *ibuf; /* Input buffer */
char *ibufpt; /* 2nd buffer pointer, for parsing command line */
int received; /* Number of bytes received */
int xmitted; /* Number of bytes transmitted */
int paged; /* Last channel invited to (paged) */
struct convection *next;/* Linked list pointer */
};
#define CM_UNKNOWN (1 << CT_UNKNOWN)
#define CM_USER (1 << CT_USER)
#define CM_HOST (1 << CT_HOST)
#ifndef _lint
#define CM_CLOSED (1 << CT_CLOSED)
#endif
#define NULLCONNECTION ((struct convection *) 0)
static struct convection *convections;
struct permlink {
char name[NAMELEN + 1]; /* Name of link */
char rev[NAMELEN + 1]; /* revision of software (CT_HOST) */
uint32 addr; /* address to link to */
struct convection *convection; /* Pointer to associated connection */
time_t statetime; /* Time of last (dis)connect */
int tries; /* Number of connect tries */
time_t waittime; /* Time between connect tries */
time_t retrytime; /* Time of next connect try */
time_t testwaittime; /* Time between tries */
time_t testnexttime; /* Time of next test */
time_t rxtime; /* rtt by other side */
time_t txtime; /* rtt found out by me */
unsigned short port; /* port number to connect to */
int fd; /* socket descriptor */
struct permlink *next; /* Linked list pointer */
};
#define NULLPERMLINK ((struct permlink *) 0)
static struct permlink *permlinks;
struct filter_link {
struct filter_link *next;
uint32 addr;
};
#ifndef _lint
#define NULLFL ((struct filter_link *) 0)
#endif
static struct filter_link *Filterlinks;
static int FilterMode;
#ifdef LINK
static struct proc *Linker;
static void connect_permlinks (int a, void *b, void *c);
static void update_permlinks (char *name, struct convection * cp);
#endif
#if 0
#define NR_PERMLINKS 20 /* MUST be changed, later */
#endif
struct destination {
char name[NAMELEN + 1]; /* destination name */
char rev[NAMELEN + 1]; /* revision of software (CT_HOST) */
struct permlink *link; /* link to this destination */
long rtt; /* round trip time to this host */
long last_sent_rtt; /* last donwnstream sent rtt */
#if 0
int downstream[NR_PERMLINKS]; /* all up/downstream times */
#endif
struct destination *next; /* a one dimensional list is ok for now :-) */
};
#define NULLDESTINATION ((struct destination *) 0)
static struct destination *destinations;
extern void statlog (const char *buf);
extern const char *displayMBstatus (int state, int issysop);
#ifndef UNIX
extern int colorchange (register const char *input, register char *last);
#endif
static int ShowConfDest (int s, const char *dest, const char *name);
static void update_destinations (struct permlink * p, char *name, long rtt, const char *rev);
#ifdef ALLSERV
extern char *getquote (void);
#endif
static void conv_randomize (void);
static int conv_random (int num, int base);
static void sysinfo_command (struct convection * cp);
static void h_sysi_command (struct convection * cp);
static void cmdsummary_command (struct convection * cp);
static void personal_command (struct convection * cp);
static void list_command (struct convection * cp);
static void me_command (struct convection * cp);
static void cq_command (struct convection * cp);
static void imsg_command (struct convection * cp);
static void version_command (struct convection * cp);
static void hosts_command (struct convection * cp);
static void nickname_command (struct convection * cp);
static void convcolorchange (struct convection * p, char *str);
static void roll_command (struct convection * cp);
static void cut_command (struct convection * cp);
static void save_personal (struct convection * cp);
static void conv_incom (int s, void *t, void *p);
static void free_connection (register struct convection * cp);
static void free_closed_connections (void);
static struct convection *alloc_connection (int fd);
static void check_buffer_overload (void);
static void clear_locks (void);
static void send_sounds (struct convection * p);
static char *timestring (time_t gmt);
static void send_user_change_msg (char *name, char *host, time_t thetime, int oldchannel, int newchannel, char *pers);
static char *formatline (char *prefix, const char *text);
static void send_msg_to_user (const char *fromname, const char *toname, const char *text);
static void send_msg_to_channel (const char *fromname, int channel, const char *text);
static void send_invite_msg (char *fromname, char *toname, int channel, char *msg);
static void time_command (struct convection * cp);
static int onchannel (int channel);
static void mystatus (struct convection * cp, int old);
static void channel_command (struct convection * cp);
static void uptime_command (struct convection * cp);
static int gatekeeper (struct convection * cp, int channel);
static void accept_command (struct convection * cp);
static void help_command (struct convection * cp);
static void cstat_command (struct convection * cp);
static void news_command (struct convection * cp);
static void invite_command (struct convection * cp);
static void links_command (struct convection * cp);
static void msg_command (struct convection * cp);
static void announce_new_user (struct convection * cp);
static void color_command (struct convection * cp);
static void set_personal (struct convection * cp);
static void name_command (struct convection * cp);
#ifdef LZW
static void compressed_command (struct convection * cp);
#endif
static void sounds_command (struct convection * cp);
static void update_user_data (struct convection * cp, int personal);
static void password_command (struct convection * cp);
static int isrosedigit (char c);
static char *getVia (char *call);
int CountConfUsers (void);
static int CountConfGroups (void);
#ifdef ALLSERV
static void quote_command (struct convection * cp);
#endif
static void who_command (struct convection * cp);
static void whois_command (struct convection * cp);
static void realname_command (struct convection * cp);
static void h_ecmd_command (struct convection * cp);
static void h_cmsg_command (struct convection * cp);
static void h_unknown_command (struct convection * cp);
static void h_dest_command (struct convection * cp);
static void h_topi_command (struct convection * cp);
static void h_rout_command (struct convection * cp);
static void h_ping_command (struct convection * cp);
static void h_pong_command (struct convection * cp);
static void h_link_command (struct convection * cp);
static int Allow_host (int s);
static void h_host_command (struct convection * cp);
static void h_invi_command (struct convection * cp);
static void h_loop_command (struct convection * cp);
static void h_uadd_command (struct convection * cp);
static void initialusers (int channel);
static void h_ndat_command (struct convection * cp);
static void h_ques_command (struct convection * cp);
static void h_umsg_command (struct convection * cp);
static void h_bump_command (struct convection * cp);
static void h_user_command (struct convection * cp);
static void gname_command (struct convection * cp, char *cptr);
static void assignnet_command (struct convection * cp);
static void bumpnet_command (struct convection * cp);
static void process_question (int channel, char type, char *name, const char *cptr);
static void question_command (struct convection * cp, char *cptr);
static void log_command (struct convection * cp, char *cptr);
static void nonet_command (struct convection * cp);
static void gpassword_command (struct convection * cp, char *cptr, int disableit);
static void gprivate_command (struct convection * cp, char *cptr);
static void group_command (struct convection * cp);
static void smiley_command (struct convection * cp);
#ifdef SAMCALLB
static void call_command (struct convection * cp);
#endif
static void glog_command (struct convection * cp);
static void net_command (struct convection * cp);
static void list_groups_command (struct convection * cp);
static void join_command (struct convection * cp);
static void process_commands (struct convection * cp, struct mbx * m);
void conversWriteall (char *str);
void conversWrite (char *str, char *user);
int sockblock (int s, int value);
#if 0
static void conv_usflush (int s);
#endif
static char *ts3 (time_t seconds, char *buffer);
static char *ts4 (time_t seconds);
static int ecmd_exists (char *cmdname);
static void getTXname (struct convection * cp, char *buf);
static int ShowConfLinks2 (int s, char *user, int full);
#undef CNAMELEN
#define CNAMELEN 16
char Chostname[CNAMELEN + 1], CConsole[CNAMELEN + 1];
static char *mysysinfo;
static char *confMOTD = NULLCHAR;
#define TOPICLEN 63
struct group {
int channel; /* channel # for this group info */
char name[TOPICLEN + 1];/* group's name */
char password[NAMELEN + 1]; /* password required to enter group */
char moderator[NAMELEN + 1]; /* real name of current moderator */
FILE *qfile; /* stream of current question file */
short nextq; /* last question number in qfile */
short totalq; /* total questions in qfile */
FILE *logfile; /* stream of current logfile */
char logged; /* status of log file (1=open) */
char private; /* is it private (1 = yes) */
struct group *next; /* next group in queue */
};
#define NULLGROUP ((struct group *) 0)
#define NOCONTROL ((struct group *) -1)
struct extendedcmds {
char *name;
struct extendedcmds *next;
};
#define NULLEXTCMD ((struct extendedcmds *)0)
static struct extendedcmds *ecmds;
static char nonetoverride;
static struct group *groups;
static struct group *find_group (int channel);
static void bye_command (struct convection * cp);
static void update_net_data (struct group * gp);
static struct group *get_group (struct convection * cp);
static struct group *can_gcontrol (struct convection * cp);
static struct group *lookup_group (char *name);
extern char *confMOTD;
extern char Ccall[AXALEN], Calias[AXALEN];
extern time_t StartTime;
static void setparamptr (struct convection *cp, char *str);
static char *getparam (struct convection *cp);
static char *getparamline (struct convection *cp);
static int docfilter (int argc, char *argv[], void *p);
static int doconvconsole (int argc, char *argv[], void *p);
static int dochostname (int argc, char *argv[], void *p);
static int doconvstat (int argc, char *argv[], void *p);
static int doconvcstat (int argc, char *argv[], void *p);
static int dociface (int argc, char *argv[], void *p);
static int doconfcall (int argc, char *argv[], void *p);
static int doconfalias (int argc, char *argv[], void *p);
static int doclink (int argc, char *argv[], void *p);
static int docunlink (int argc, char *argv[], void *p);
static int dodrop (int argc, char *argv[], void *p);
static int doct4 (int argc, char *argv[], void *p);
static int doentrychannel (int argc, char *argv[], void *p);
static int doconfmotd (int argc, char *argv[], void *p);
static int dosysinfo (int argc, char *argv[], void *p);
static int doconvnet0 (int argc, char *argv[], void *p);
static int dotimestamp (int argc, char *argv[], void *p);
static int docmaxwait (int argc, char *argv[], void *p);
static int dohmaxq (int argc, char *argv[], void *p);
static int doumaxq (int argc, char *argv[], void *p);
static int doheader (int argc, char *argv[], void *p);
static struct cmds Ccmds[] =
{
#ifdef AX25
{ "alias", doconfalias, 0, 0, NULLCHAR },
#endif
{ "console", doconvconsole, 0, 0, NULLCHAR },
{ "cstat", doconvcstat, 0, 0, NULLCHAR },
{ "drop", dodrop, 0, 0, NULLCHAR },
{ "entrychannel", doentrychannel, 0, 0, NULLCHAR },
{ "filter", docfilter, 0, 0, NULLCHAR },
{ "hmaxq", dohmaxq, 0, 0, NULLCHAR },
{ "header", doheader, 0, 0, NULLCHAR },
{ "hostname", dochostname, 0, 0, NULLCHAR },
{ "interface", dociface, 0, 0, NULLCHAR },
#ifdef LINK
{ "link", doclink, 0, 0, NULLCHAR },
#endif
{ "maxwait", docmaxwait, 0, 0, NULLCHAR },
#ifdef AX25
{ "motd", doconfmotd, 0, 0, NULLCHAR },
{ "mycall", doconfcall, 0, 0, NULLCHAR },
#endif
{ "net0", doconvnet0, 0, 0, NULLCHAR },
{ "online", doconvstat, 0, 0, NULLCHAR },
{ "sysinfo", dosysinfo, 0, 0, NULLCHAR },
#ifdef AX25
{ "t4", doct4, 0, 0, NULLCHAR },
{ "timestamp", dotimestamp, 0, 0, NULLCHAR },
#endif
{ "umaxq", doumaxq, 0, 0, NULLCHAR },
#ifdef LINK
{ "unlink", docunlink, 0, 0, NULLCHAR },
#endif
{ NULLCHAR, 0, 0, 0, NULLCHAR }
};
/* Multiplexer for top-level convers command */
int
doconvers (int argc, char *argv[], void *p)
{
return subcmd (Ccmds, argc, argv, p);
}
static void setparamptr (struct convection *cp, char *str)
{
cp->ibufpt = str;
}
/*---------------------------------------------------------------------------*/
static char *
getparamline (struct convection *cp)
{
cp->ibufpt = skipwhite (cp->ibufpt);
return cp->ibufpt;
}
/*---------------------------------------------------------------------------*/
static char *getparam (struct convection *cp)
{
char *arg;
cp->ibufpt = skipwhite (cp->ibufpt);
arg = cp->ibufpt;
cp->ibufpt = skipnonwhite (cp->ibufpt);
if (*(cp->ibufpt))
*(cp->ibufpt)++ = '\0';
return arg;
}
#ifdef AX25
/* Display or change our AX.25 conference call */
static int
doconfcall (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (fullstrcr, pax25 (tmp, Ccall));
return 0;
}
if (setcall (Ccall, argv[1]) == -1)
return -1;
return 0;
}
/* Display or change our AX.25 conference alias */
static int
doconfalias (int argc, char *argv[], void *p OPTIONAL)
{
char tmp[AXBUF];
if (argc < 2) {
tprintf (fullstrcr, pax25 (tmp, Calias));
return 0;
}
if (setcall (Calias, argv[1]) == -1)
return -1;
return 0;
}
/* Set link redundancy timer */
static int
doct4 (int argc, char *argv[], void *p OPTIONAL)
{
return setlong (&CT4init, redun, argc, argv);
}
#endif /* AX25 */
/* Set entry channel number */
static int
doentrychannel (int argc, char *argv[], void *p OPTIONAL)
{
return setint (&CChannel, entrystr, argc, argv);
}
/* Allow nets to be held on channel 0 */
static int
doconvnet0 (int argc, char *argv[], void *p OPTIONAL)
{
return setbool (&ConvNet0, allownets, argc, argv);
}
static int
doconvstat (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
if (Current == Command)
Command->flowmode = 0; /* clear 'more' paging on command screen */
(void) ShowConfUsers (Curproc->output, NULLCHAR);
tputs ("\n");
if (Current == Command)
Command->flowmode = 1; /* set 'more' paging on command screen */
return 0;
}
static int
doconvcstat (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
(void) ShowConfLinks (Curproc->output, 1);
tputs ("\n");
(void) ShowConfDest (Curproc->output, "", "");
tputs ("\n");
return 0;
}
/* Give login header */
static int
doheader (int argc, char *argv[], void *p OPTIONAL)
{
return setbool (&ConvHeader, givehead, argc, argv);
}
/* Allow broadcasts to be timestamped */
static int
dotimestamp (int argc, char *argv[], void *p OPTIONAL)
{
return setbool (&TimeStamp, timestampstr, argc, argv);
}
static int
dociface (int argc, char *argv[], void *p)
{
return (dosetflag (argc, argv, p, IS_CONV_IFACE, 1));
}
/* Set maxwait time for timed out links */
static int
docmaxwait (int argc, char *argv[], void *p OPTIONAL)
{
return setlong (&CMaxwait, maxwaitstr, argc, argv);
}
/* Set max qlimit for host links */
static int
dohmaxq (int argc, char *argv[], void *p OPTIONAL)
{
return setint (&HMaxQ, hostqueuestr, argc, argv);
}
/* Set max qlimit for user links */
static int
doumaxq (int argc, char *argv[], void *p OPTIONAL)
{
return setint (&UMaxQ, userqueuestr, argc, argv);
}
static int
dochostname (int argc, char *argv[], void *p OPTIONAL)
{
if (argc == 1)
tprintf (fullstrcr, Chostname);
else {
strncpy (Chostname, argv[1], NAMELEN);
Chostname[NAMELEN] = '\0';
}
return 0;
}
static int
doconvconsole (int argc, char *argv[], void *p OPTIONAL)
{
if (argc == 1)
tprintf (fullstrcr, CConsole);
else {
strncpy (CConsole, argv[1], NAMELEN);
CConsole[NAMELEN] = '\0';
}
return 0;
}
/* View/Change the message we send to new conference connects. */
static int
doconfmotd (int argc, char *argv[], void *p OPTIONAL)
{
if (argc < 2)
tprintf (motdstr, confMOTD);
else {
if (confMOTD != NULL)
free (confMOTD);
confMOTD = strdup (argv[1]);
}
return 0;
}
/* View/Change the message we send in response to sysinfo requests. */
static int
dosysinfo (int argc, char *argv[], void *p OPTIONAL)
{
if (argc < 2)
tprintf (sysinfostr, mysysinfo);
else {
if (mysysinfo != NULL)
free (mysysinfo);
mysysinfo = strdup (argv[1]);
}
return 0;
}
static int
docfilter (int argc, char *argv[], void *p OPTIONAL)
{
uint32 addr;
struct filter_link *fl;
if (argc == 1) {
if (Filterlinks) {
tprintf (modeis, FilterMode ? acceptstr : refuse);
for (fl = Filterlinks; fl; fl = fl->next)
tprintf (fullstrcr, inet_ntoa (fl->addr));
}
return 0;
}
if (!stricmp (argv[1], "mode")) {
if (argc == 2)
tprintf (modeis, FilterMode ? acceptstr : refuse);
else {
if (*argv[2] == 'a' || *argv[2] == 'A')
FilterMode = 1;
else
FilterMode = 0;
}
return 0;
}
if ((addr = resolve (argv[1])) == 0) {
tprintf (Badhost, argv[1]);
return 1;
}
/* check to see if we already have this in the list */
for (fl = Filterlinks; fl; fl = fl->next)
if (fl->addr == addr)
return 0; /* already have this one ! */
/* Seems like a new one */
fl = (struct filter_link *) callocw (1, sizeof (struct filter_link));
fl->addr = addr;
fl->next = Filterlinks;
Filterlinks = fl;
return 0;
}
#ifdef LINK
static int
doclink (int argc, char *argv[], void *p OPTIONAL)
{
uint32 addr;
struct permlink *pl;
if (argc == 1) {
for (pl = permlinks; pl; pl = pl->next)
tprintf (fullstrcr, inet_ntoa (pl->addr));
return 0;
}
if ((addr = resolve (argv[1])) == 0) {
tprintf (Badhost, argv[1]);
return 1;
}
/* check to see if we already have a link to such animal,
* this happens when we stop and restart the server - WG7J
*/
for (pl = permlinks; pl; pl = pl->next)
if (pl->addr == addr)
return 1; /* already have this one ! */
/* Seems like a new link ! Go add it */
pl = (struct permlink *) callocw (1, sizeof (struct permlink));
pl->addr = addr;
pl->next = permlinks;
permlinks = pl;
pl->port = (int16) ((argc > 2) ? atoi (argv[2]) : IPPORT_CONVERS);
if (argc > 3)
strncpy (pl->name, argv[3], NAMELEN);
else
strncpy (pl->name, argv[1], NAMELEN);
update_permlinks (pl->name, NULLCONNECTION);
pl->retrytime -= 55; /* 1st start in 5 seconds */
pl->waittime = 30; /* 2nd after 1 minute */
if (!Linker)
Linker = newproc ("Converse linker", 1024, connect_permlinks, 0, 0, NULL, 0);
return 0;
}
static int
docunlink (int argc, char *argv[], void *p OPTIONAL)
{
uint32 addr;
struct permlink *pl, *pls;
if (argc == 1) {
pl = permlinks;
permlinks = NULLPERMLINK;
while (pl) {
tprintf ("Unlinking %s\n", inet_ntoa (pl->addr));
(void) shutdown (pl->fd, 2);
close_s (pl->fd);
pls = pl->next;
free (pl);
pl = pls;
}
return 0;
}
#if 0
if ((addr = resolve (argv[1])) == 0) {
tprintf (Badhost, argv[1]);
return 1;
}
#else
addr = resolve (argv[1]);
#endif
pls = NULLPERMLINK;
for (pl = permlinks; pl; pls = pl, pl = pl->next)
if ((pl->addr == addr) || !stricmp (pl->name, argv[1])) {
if (pls)
pls->next = pl->next;
else
permlinks = pl->next;
tprintf ("Unlinking %s: %s\n", inet_ntoa (pl->addr), pl->name);
(void) shutdown (pl->fd, 2);
close_s (pl->fd);
free (pl);
return 0;
}
tprintf ("Not linked to %s\n", argv[1]);
return 0;
}
#endif
static int
dodrop (int argc OPTIONAL, char *argv[], void *p OPTIONAL)
{
struct convection *pl, *pls;
pls = NULLCONNECTION;
for (pl = convections; pl; pls = pl, pl = pl->next)
if (!stricmp (pl->name, argv[1])) {
if (pls)
pls->next = pl->next;
else
convections = pl->next;
tprintf ("Droping %s\n", pl->name);
(void) shutdown (pl->fd, 2);
close_s (pl->fd);
free (pl);
return 0;
}
tprintf ("Cannot drop %s: not connected\n", argv[1]);
return 0;
}
/* Stop convers server */
int
conv0 (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
{
#ifdef LINK
if (Linker) {
killproc (Linker);
Linker = 0;
}
#endif
return (deleteserver (&Sconv));
}
/* Start up convers server */
int
conv1 (int argc, char *argv[], void *p OPTIONAL)
{
int port;
Conv_mutex = TNOS_MUTEX_UNLOCKED;
Group_mutex = TNOS_MUTEX_UNLOCKED;
if (!Chostname[0]) {
if (Hostname)
strncpy (Chostname, Hostname, CNAMELEN);
else
strcpy (Chostname, "localhost");
}
port = (argc > 1) ? atoi (argv[1]) : IPPORT_CONVERS;
(void) installserver (argc, argv, &Sconv, "Conference listener", port,
INADDR_ANY, conversd, conv_incom, 1024, NULL);
#ifdef LINK
if (Linker) {
killproc (Linker);
Linker = 0;
}
#endif
return 0;
}
static void
free_connection (register struct convection *cp)
{
register struct permlink *p;
for (p = permlinks; p; p = p->next)
if (p->convection == cp)
p->convection = NULLCONNECTION;
free (cp->ibuf);
if (cp->flags & CLOSE_SOCK)
close_s (cp->fd);
free ((char *) cp);
}
static void
free_closed_connections (void)
{
register struct convection *cp, *p;
time_t currtime;
currtime = time (&currtime);
for (p = NULLCONNECTION, cp = convections; cp;)
if (cp->type == CT_CLOSED || (cp->type == CT_UNKNOWN && cp->time + 300 < currtime)) {
if (p) {
p->next = cp->next;
free_connection (cp);
cp = p->next;
} else {
convections = cp->next;
free_connection (cp);
cp = convections;
}
} else {
p = cp;
cp = cp->next;
}
}
static void
update_permlinks (char *name, struct convection *cp)
{
register struct permlink *p;
time_t currtime;
struct destination *d;
for (p = permlinks; p; p = p->next) {
if (!strcmp (p->name, name)) {
for (d = destinations; d; d = d->next) {
if (d->rtt && (d->link == p))
update_destinations (p, d->name, 0, "");
}
currtime = time (&currtime);
p->convection = cp;
p->statetime = currtime;
p->tries = 0;
p->waittime = 60;
p->rxtime = 0;
p->txtime = 0;
p->testwaittime = currtime;
p->testnexttime = currtime + 60;
p->retrytime = currtime + p->waittime;
}
}
}
static struct convection *
alloc_connection (int fd)
{
register struct convection *cp;
time_t currtime;
currtime = time (NULL);
cp = (struct convection *) callocw (1, sizeof (struct convection));
cp->ibuf = (char *) callocw (1, INBUFLEN + 1);
cp->fd = fd;
cp->maxq = UMaxQ; /* Maximum qlimit for user */
cp->flags = CLOSE_SOCK + USE_SOUND; /* close on exit, by default */
cp->time = currtime;
cp->paged = -1;
cp->net = -1;
cp->features = 0;
kmutex_lock (&Conv_mutex);
cp->next = convections;
convections = cp;
kmutex_unlock (&Conv_mutex);
return cp;
}
#ifdef LINK
/* check the host links for backlogged data.
* If larger then set threshold, kill the link.
* WG7J, 930208
*/
static void
check_buffer_overload (void)
{
struct convection *p;
/* check the size of the outstanding data buffers */
for (p = convections; p; p = p->next)
if ((p->maxq != 0) && (socklen (p->fd, 1) > p->maxq)) {
/* Blow this one out of the water */
(void) shutdown (p->fd, 2);
close_s (p->fd);
}
}
static void
connect_permlinks (int a OPTIONAL, void *b OPTIONAL, void *c OPTIONAL)
{
int s;
register struct permlink *p;
struct sockaddr_in cport;
time_t currtime;
struct destination *d;
char buffer[256];
server_disconnect_io ();
for ( ; ; ) {
kpause (15000L);
currtime = time (&currtime);
for (p = permlinks; p; p = p->next) {
/* Update our existing connections */
if (p->convection) {
if (p->testnexttime < currtime) {
if ((p->testwaittime + 7300) < currtime) {
p->rxtime = 0;
p->txtime = 0;
for (d = destinations; d; d = d->next) {
if (d->link == p)
update_destinations (p, d->name, 0, "");
}
}
p->convection->xmitted += usprintf (p->convection->fd, "/\377\200PING\n");
p->testwaittime = currtime;
p->testnexttime = currtime + 7300;
}
}
}
for (p = permlinks; p; p = p->next) {
if (p->convection || p->retrytime > currtime)
continue;
p->tries++;
p->waittime <<= 1; /*lint !e703 */
if (p->waittime > (time_t) CMaxwait)
p->waittime = (time_t) CMaxwait;
p->retrytime = p->waittime + currtime;
cport.sin_family = AF_INET;
cport.sin_port = p->port;
cport.sin_addr.s_addr = p->addr; /* we've resolved this earlier */
if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1)
continue;
if (connect (s, (char *) &cport, SOCKSIZE) == -1) {
(void) shutdown (s, 2); /* to make sure it doesn't linger around */
close_s (s); /* WG7J - 9207228 */
continue;
}
p->fd = s;
sprintf (buffer, "permlink: %s", inet_ntoa (p->addr));
if (newproc (buffer, 2048, conv_incom, s, 0, NULL, 0) == NULLPROC) {
(void) shutdown (s, 2); /* blow it out of the water :-) */
close_s (s);
}
}
check_buffer_overload ();
}
}
#endif
static int
ecmd_exists (char *cmdname)
{
struct extendedcmds *echk;
echk = ecmds;
while (echk && echk->name) {
if (!stricmp (echk->name, cmdname))
return 1;
echk = echk->next;
}
return 0;
}
static void
clear_locks (void)
{
register struct convection *p;
for (p = convections; p; p = p->next)
p->locked = 0;
}
static void
send_sounds (struct convection *p)
{
if (p->flags & USE_SOUND)
p->xmitted += usputs (p->fd, "");
}
static char *
timestring (time_t gmt)
{
static char buffer[10];
struct tm *tm;
time_t currtime;
currtime = time (&currtime);
tm = localtime (&gmt);
if (gmt + 24 * 60 * 60 > currtime)
sprintf (buffer, " %02d:%02d", tm->tm_hour, tm->tm_min);
else
sprintf (buffer, "%-3.3s %2d", Months[tm->tm_mon], tm->tm_mday);
return buffer;
}
static void
send_user_change_msg (
char *name,
char *host,
time_t mytime,
int oldchannel,
int newchannel,
char *pers
) {
register struct convection *p;
time_t currtime;
register struct group *gold, *gnew;
currtime = time (&currtime);
gold = find_group (oldchannel);
gnew = find_group (newchannel);
if (gold && gold->logfile) {
if (newchannel >= 0)
fprintf (gold->logfile, theyswitched, stars,
name, newchannel, timestring (currtime));
else
fprintf (gold->logfile, theysigned, stars, name, ff_str, timestring (currtime));
}
if (gnew && gnew->logfile)
fprintf (gnew->logfile, theysigned, stars, name, n_str, timestring (currtime));
for (p = convections; p; p = p->next) {
kwait (NULL);
if (p->type == CT_USER && !p->via && !p->locked) {
if ((newchannel == oldchannel) && (newchannel != -1)) {
if (p->channel == newchannel) {
if (pers && (*pers != '\0') && (strcmp (pers, "@")))
p->xmitted += usprintf (p->fd, "*** (%s) %s@%s on channel %d set personal text:\n %s\n", timestring (currtime), name, host, newchannel, pers);
else
p->xmitted += usprintf (p->fd, "*** (%s) %s@%s on channel %d removed personal text.\n", timestring (currtime), name, host, newchannel);
p->locked = 1;
}
} else {
if (p->channel == oldchannel) {
convcolorchange (p, SYSCOLORS);
if (newchannel >= 0)
p->xmitted += usprintf (p->fd, theyswitched, stars,
name, newchannel, timestring (currtime));
else
p->xmitted += usprintf (p->fd,
theysigned, stars, name, ff_str, timestring (currtime));
p->locked = 1;
}
if (p->channel == newchannel) {
convcolorchange (p, SYSCOLORS);
send_sounds (p);
p->xmitted += usprintf (p->fd,
theysigned, stars, name, n_str, timestring (currtime));
p->locked = 1;
}
}
}
if (p->type == CT_HOST && !p->locked) {
p->xmitted += usprintf (p->fd, huserstr, name, host, mytime, oldchannel, newchannel, (pers) ? pers : "");
p->locked = 1;
}
}
#ifdef XSERVER
xnotify (X_CONF);
#endif
}
static char *
formatline (char *prefix, const char *text)
{
register const char *f, *x;
register char *t;
register int l, lw;
static char buf[2 * LINELEN];
for (f = prefix, t = buf; *f; *t++ = *f++)
;
l = (int) (t - buf);
f = text;
*t++ = ' ';
l++;
for ( ; ; ) {
while (isspace (uchar (*f))) {
#ifndef NOSPACES
*t++ = *f;
l++;
#endif
f++;
}
if (!*f) {
*t++ = '\n';
*t = '\0';
return buf;
}
for (x = f; *x && !isspace (uchar (*x)); x++)
;
lw = (int) (x - f);
if (l > PREFIXLEN && l + 1 + lw > CONVLINELEN) {
*t++ = '\n';
l = 0;
}
#ifndef NOSPACES
while (l < PREFIXLEN) {
#else
do {
#endif
*t++ = ' ';
l++;
#ifndef NOSPACES
}
#else
} while (l < PREFIXLEN);
#endif
while (lw--) {
*t++ = *f++;
l++;
}
}
}
static void
send_msg_to_user (const char *fromname, const char *toname, const char *text)
{
register struct convection *p;
char buff2[INBUFLEN];
strncpy (buff2, text, INBUFLEN);
rip (buff2);
for (p = convections; p; p = p->next) {
kwait (NULL);
if (p->type == CT_USER && (!strcmpi (p->name, toname) || !strcmpi (p->nickname, toname))) {
if (p->via) {
if (!p->via->locked) {
p->via->xmitted += usprintf (p->via->fd,
umsgstr, fromname, toname, buff2);
p->via->locked = 1;
}
} else {
if (!p->locked) {
if (strcmp (fromname, conversd)) {
char buffer[8 + (NAMELEN * 2)];
time_t currtime;
currtime = time (&currtime);
convcolorchange (p, INFOCOLORS);
sprintf (buffer, (TimeStamp) ? timestampfmt : nontimestampfmt, fromname, timestring (currtime));
p->xmitted += usprintf (p->fd, fullstr, formatline (buffer, buff2));
} else {
convcolorchange (p, SYSCOLORS);
p->xmitted += usprintf (p->fd, fullstrcr, buff2);
}
p->locked = 1;
}
}
}
}
}
static void
send_msg_to_channel (const char *fromname, int channel, const char *text)
{
char buffer[8 + (NAMELEN * 2)];
register struct convection *p;
register struct group *gp;
time_t currtime;
char buff2[INBUFLEN];
strncpy (buff2, text, INBUFLEN);
rip (buff2);
currtime = time (&currtime);
sprintf (buffer, (TimeStamp) ? timestampfmt2 : nontimestampfmt2, fromname, timestring (currtime));
gp = find_group (channel);
if (gp && gp->logfile) {
if (!strcmp (fromname, conversd))
fprintf (gp->logfile, fullstrcr, buff2);
else
fprintf (gp->logfile, fullstr, formatline (buffer, buff2));
}
for (p = convections; p; p = p->next) {
kwait (NULL);
if (p->type == CT_USER && p->channel == channel) {
if (p->via) {
if (!p->via->locked) {
if ((p->via->features & FEATURE_NICK) || !strchr (fromname, ':'))
p->via->xmitted += usprintf (p->via->fd,
cmsgstr, fromname, channel, buff2);
else {
char *cp2;
char *ctmp = strdup (fromname);
cp2 = strchr (fromname, ':');
if (cp2)
*cp2 = 0;
p->via->xmitted += usprintf (p->via->fd,
cmsgstr, ctmp, channel, buff2);
free (ctmp);
}
p->via->locked = 1;
}
} else {
if (!p->locked) {
convcolorchange (p, TEXTCOLORS);
if (!strcmp (fromname, conversd))
p->xmitted += usprintf (p->fd, fullstrcr, buff2);
else
p->xmitted += usprintf (p->fd, fullstr, formatline (buffer, buff2));
p->locked = 1;
usflush (p->fd);
}
}
}
}
}
static void
send_invite_msg (
char *fromname,
char *toname,
int channel,
char *msg
) {
char buffer[80];
struct convection *p;
time_t currtime;
#ifdef MAILBOX
int i;
struct mbx *m = 0;
#endif
currtime = time (&currtime);
#ifdef MAILBOX
for (i = 0; i < NUMMBX; i++) {
if ((m = Mbox[i]) != NULLMBX) {
if (m->state == MBX_CMD && !stricmp (m->name, toname)) {
usprintf (m->user, mbinvitetext, amessage, fromname, timestring (currtime), stars, channel, channel);
if (msg[0])
usprintf (m->user, msgtext, fromname, msg);
usflush (m->user);
clear_locks ();
sprintf (buffer, responsetext, stars, toname, "BBS@");
strcat (buffer, Hostname);
send_msg_to_user (conversd, fromname, buffer);
return;
}
}
}
#endif
/* check the current convers users */
for (p = convections; p; p = p->next) {
if (p->type == CT_USER && !strcmpi (p->name, toname)) {
if (p->channel == channel) {
clear_locks ();
sprintf (buffer, alreadyon, stars, userstr, toname);
send_msg_to_user (conversd, fromname, buffer);
return;
}
if (!p->via && !p->locked) {
convcolorchange (p, INFOCOLORS);
p->paged = channel;
p->xmitted += usprintf (p->fd, invitetext, amessage, fromname, \
timestring (currtime), stars, channel);
if (msg[0])
p->xmitted += usprintf (p->fd, msgtext, fromname, msg);
clear_locks ();
sprintf (buffer, responsetext, stars, toname, Chostname);
send_msg_to_user (conversd, fromname, buffer);
return;
}
if (p->via && !p->via->locked) {
p->via->xmitted += usprintf (p->via->fd, hinvi, fromname, toname, channel, msg);
return;
}
}
}
/* Nothing found locally, invite user on all links */
for (p = convections; p; p = p->next) {
if (p->type == CT_HOST && !p->locked)
p->xmitted += usprintf (p->fd, hinvi, fromname, toname, channel, msg);
}
}
static void
getTXname (struct convection *cp, char *buf)
{
if (!stricmp (cp->nickname, cp->name))
strcpy (buf, cp->name);
else
sprintf (buf, "%s:%s", cp->name, cp->nickname);
}
static void
cq_command (struct convection *cp)
{
register struct convection *p;
char *s, tmpbuff[2048];
char buf[(NAMELEN * 2) + 2];
s = getparamline (cp);
getTXname (cp, buf);
sprintf (tmpbuff, "*** %s@%s channel %d calling CQ %s", buf, cp->host, cp->channel, s);
for (p = convections; p; p = p->next) {
if (p != cp)
send_msg_to_user ("conversd", p->name, tmpbuff);
}
}
static void
time_command (struct convection *cp)
{
time_t currtime;
char buff[24];
currtime = time (&currtime);
sprintf (buff, "%s%s is %s\n", stars, tmstr, timestring (currtime));
clear_locks ();
send_msg_to_channel (conversd, cp->channel, buff);
}
static void
version_command (struct convection *cp)
{
cp->xmitted += usprintf (cp->fd, "%s%s Conference Bridge\n", stars, Version);
}
static int
onchannel (int channel)
{
int cnt = 0;
struct convection *p;
for (p = convections; p; p = p->next)
if (p->type == CT_USER && channel == p->channel)
cnt++;
return (cnt);
}
static void
bye_command (struct convection *cp)
{
register struct convection *p;
register struct permlink *pp;
if (cp->net != -1) {
int old = cp->channel;
cp->channel = cp->net;
nonet_command (cp);
cp->channel = old;
}
switch (cp->type) {
case CT_UNKNOWN:
cp->type = CT_CLOSED;
break;
case CT_USER:
cp->type = CT_CLOSED;
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, exitingstr, conferencestr, Chostname);
clear_locks ();
send_user_change_msg (cp->name, cp->host, cp->time, cp->channel, -1, cp->data);
save_personal (cp);
break;
case CT_HOST:
cp->type = CT_CLOSED;
for (pp = permlinks; pp; pp = pp->next)
if (pp->convection == cp) {
update_permlinks (pp->name, NULLCONNECTION);
break;
}
for (p = convections; p; p = p->next)
if (p->via == cp) {
p->type = CT_CLOSED;
clear_locks ();
send_user_change_msg (p->name, p->host, p->time, p->channel, -1, p->data);
}
break;
case CT_CLOSED:
default:
break;
}
}
static void
mystatus (struct convection *cp, int old)
{
int now;
struct group *gp;
now = onchannel (cp->channel);
cp->xmitted += usprintf (cp->fd, nowchannel, stars, channelstr, cp->channel, now, (now > 1) ? "s" : empty);
gp = find_group (cp->channel);
if (gp != NULLGROUP) {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, welcome, stars, (gp->private) ? privatestr : empty,
(gp->private) ? " " : empty, gp->name);
if (*gp->moderator)
cp->xmitted += usprintf (cp->fd, welcome2, netcontrolstr, gp->moderator);
cp->xmitted += usprintf (cp->fd, welcome3, cp->nickname);
}
send_user_change_msg (cp->name, cp->host, cp->time, old, cp->channel, cp->data);
}
static void
channel_command (struct convection *cp)
{
char *s;
int newchannel, oldchannel;
s = getparam (cp);
if (*s == '\0') {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, youare, stars, empty, cp->channel);
return;
}
newchannel = atoi (s);
/* if(newchannel < 0 || newchannel > MAXCHANNEL) { */
if (newchannel < 0) {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, cnumber, MAXCHANNEL);
return;
}
if (newchannel == cp->channel) {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, youare, stars, "already ", cp->channel);
return;
}
if (gatekeeper (cp, newchannel))
return;
oldchannel = cp->channel;
cp->channel = newchannel;
cp->nettime = time (&cp->nettime);
cp->locked = 1; /* for bump command */
mystatus (cp, oldchannel);
}
static void
accept_command (struct convection *cp)
{
if (cp->paged == -1) {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, "??? %s\n", channelstr);
} else {
sprintf (cp->ibuf, "/c %d", cp->paged);
setparamptr (cp, &cp->ibuf[3]);
channel_command (cp);
}
}
static void
help_command (struct convection *cp)
{
int k;
char *cptr;
char const *file2open = 0;
(void) sockblock (cp->fd, SOCK_BLOCK);
cptr = getparam (cp);
file2open = (tolower (*cptr) != 'n') ? ConfHlp : (tolower (cptr[2]) == 'w') ? ConfNews : NetControlHlp;
convcolorchange (cp, INFOCOLORS);
k = DisplayFile (file2open, cp->fd);
if (k)
cp->xmitted += k;
else {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, noopenstr, file2open);
}
cp->xmitted += usprintf (cp->fd, trailer);
(void) sockblock (cp->fd, SOCK_NOTXBLOCK);
}
static void
news_command (struct convection *cp)
{
strcpy (cp->ibuf, "h news");
setparamptr (cp, &cp->ibuf[2]);
help_command (cp);
}
static void
invite_command (struct convection *cp)
{
struct group *gp;
char *toname, *chk, *cp2;
toname = getparam (cp);
chk = getparamline (cp);
if (*chk)
chk[51] = 0;
if (*toname) {
if ((cp2 = strchr (toname, '@')) != NULLCHAR)
*cp2 = '\0';
gp = find_group (cp->channel);
if (gp && gp->private && cp->net != cp->channel) {
convcolorchange (cp, SYSCOLORS);
cp->xmitted += usprintf (cp->fd, noinvite, stars, privatestr, netcontrolstr);
} else
send_invite_msg (cp->name, toname, cp->channel, chk);
}
}
static char *
ts4 (time_t seconds)
{
int days, hours, minutes;
static char buffer[50];
char buf[20];
days = (int) (seconds / 86400);
seconds -= days * 86400;
hours = (int) (seconds / 3600);
seconds -= hours * 3600;
minutes = (int) (seconds / 60);
seconds -= minutes * 60;
buffer[0] = '\0';
if (days) {
sprintf (buf, "%d day%s, ", days, (days == 1) ? "" : "s");
strncpy (buffer, buf, 50);
}
if (days + hours) {
sprintf (buf, "%d hour%s, ", hours, (hours == 1) ? "" : "s");
strcat (buffer, buf);
}
if (days + hours + minutes) {
sprintf (buf, "%d minute%s, ", minutes, (minutes == 1) ? "" : "s");
strcat (buffer, buf);
}
sprintf (buf, "%ld second%s.", seconds, (seconds == 1) ? "" : "s");
strcat (buffer, buf);
return buffer;
}
static char *
ts3 (time_t seconds, char *buffer)
{
if (seconds < 100)
sprintf (buffer, "%lds", seconds);
else if (seconds < 6000)
sprintf (buffer, "%ldm", seconds / 60);
else if (seconds < 360000)
sprintf (buffer, "%ldh", seconds / 3600);
else
sprintf (buffer, "%ldd", seconds / 86400);
return buffer;
}
static int
ShowConfLinks2 (int s, char *user, int full)
{
int num = 0;
struct convection *pc;
struct permlink *pp;
char buffer[100], tmp[20], tmp2[64], tmp3[64], tmp4[64];
sprintf (buffer, "Host State Quality Software Since%s",
(full) ? " NextTry Tries Queue RX TX" : "");
if (user) {
clear_locks ();
send_msg_to_user (conversd, user, buffer);
} else
num += usprintf (s, "%s\n", buffer);
for (pc = convections; pc; pc = pc->next) {
kwait (NULL);
strcpy (tmp2, " --- ");
for (pp = permlinks; pp; pp = pp->next) {
if (pp->convection == pc) {
if (pp->txtime || pp->rxtime) {
if (pp->rxtime == (time_t) -1)
sprintf (tmp2, " %3s ", ts3 (pp->txtime, tmp3));
else
sprintf (tmp2, "%3s/%-3s", ts3 (pp->txtime, tmp3), ts3 (pp->rxtime, tmp4));
}
break;
}
}
if (pc->type == CT_HOST) {
sprintf (buffer,
(full) ?
"%-10.10s Connected %7.7s %8.8s %s %5d %4dK %4dK" :
"%-10.10s Connected %7.7s %8.8s %s",
pc->name, tmp2, (pp) ? pp->rev : "",
timestring (pc->time),
socklen (pc->fd, 1),
(pc-