Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
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-
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions