EotS/
EotS/area/
EotS/player/
EotS/src/

To: "Tim A. Seever" <tseever@freenet.calgary.ab.ca>

/*************************************************************************
* LodMUD Beta MUD  0.0                                                   *
**************************************************************************

**************************************************************************
* (c) 1993,1994,1995 Erik Jensen, Petter N Hagen, Jan Ove Saevik,        *
* Bjoern Hammer, Edward Kmett, Lars Soepstad, Espen Loevaas, and         *
* Helger Lipmaa.                                                         *
**************************************************************************

**************************************************************************
* land.c (main.c) - main() & communications module (all socket ops. here)*
* Last update: 4 jan 95 - Simkin - added who daemon and authd code       *
*************************************************************************/

/* The headers need to be cleaned up BAD */

#ifdef __sgi__
    #define _BSD_SIGNALS
    #ifdef MIPSEB
        #define _MIPSEB
    #endif
    #include <sys/endian.h>
#endif

#include <sys/types.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#ifdef __sgi__
#include <bstring.h>
#include <sys/socket.h>
#endif

/**** No <unistd.h> or <malloc.h> on the NeXT ****/
/* #if !defined(NeXT) */
    #include <stdarg.h>
    #include <unistd.h>
/*    #include <malloc.h>*/
/*#endif*/
/**************************************************/

#include <memory.h>
#include <errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/file.h>
#include <sys/ioctl.h>
/*#include <netinet/in.h>*/
#include <fcntl.h>
#include <signal.h>
#include <limits.h>
#include "structs.h"

#include "mob.h"
#include "obj.h"
#include "utils.h"
#include "interp.h"
#include "handler.h"
#include "db.h"
#include "matrix.h"

/* All over global */
int MOBtrigger = TRUE;
int pulse = 0;

#if defined(NeXT)
/* System functions */
extern int socket( int domain, int type, int protocol );

extern int setsockopt( int s, int level, int optname, void *optval, int optlen )
;
extern int bind( int s, struct sockaddr *name, int namelen );
extern int select( int width, fd_set *readfds, fd_set *writefds, fd_set *exceptf
ds, struct timeval *timeout );
extern int recv ( int s, char *buf, int len, int flags );
extern int listen( int s, int backlog );


extern int getsockname( int s, struct sockaddr *name, int *namelen );
extern int accept( int s, struct sockaddr *addr, int *addrlen );
extern int getpeername( int s, struct sockaddr *name, int *namelen );
extern int gettimeofday( struct timeval *tp, struct timezone *tzp );
#endif

extern char * inet_ntoa( struct in_addr in );
char * who_list;
int who_flag;

#define DFLT_PORT         5000
#define DFLT_WHO_PORT     5001
#define DFLT_SPLIT_PORT   5002
#define DFLT_EVIL_PORT    5666
#define DFLT_EVIL_SPLIT   5667
#define MAX_NAME_LENGTH     15
#define MAX_HOSTNAME       256
#define OPT_USEC        250000      /* Microseconds per pass    */

extern int errno;

/* externs */


extern char *greetings[2];

extern struct room_data *world;
extern int top_of_world;
extern struct time_info_data time_info;
extern char *help;
extern char *glossary;
extern struct ban_t *ban_list, *ncsa_list;
extern char *vtcolors[];
extern struct obj_index_data *obj_index;

/* local globals */

struct descriptor_data *descriptor_list, *next_to_process;

int god        = 0;  /* all new chars are gods! */
int slow_death = 0;  /* Time of shutdown, active with one of the two below */
int shut_down  = 0;  /* clean shutdown */
int re_boot    = 0;  /* start her up again ? */
int death_msg  = 0;  /* Warning indicator, 100 = shut her down */
char down_by[20];    /* Name of player who scheduled shutdown */
char down_reason[200]; /* Reason given for shutdown */
int spam_o_meter = 0;  

int maxdesc;

void shutdown_request(void);
void wizlogsig(void);
void hupsig(void);

void check_ban(struct descriptor_data *d);
char * get_from_q(struct txt_q *queue);
void game_loop(int control, int who_control, int split_control, int evil_control
 , int evil_split_control);
int init_socket(int port);
int new_connection(int s);
#ifdef NeXT
extern int connect(int s, struct sockaddr *name, int namelen);
#endif

int new_descriptor(int s, int x, int evil); /* socket and display type */
int process_output(struct descriptor_data *t);
int process_input(struct descriptor_data *t, bool newline);

#define FLAG_WRAUTH    1  /* Auth unsent yet, send if able         */
#define FLAG_AUTH      2  /* Authorization in progress             */


void    start_auth(struct descriptor_data *d); /* Open Socket           */
void    send_auth(struct descriptor_data *d);  /* Send to Socket        */
void    read_auth(struct descriptor_data *d);  /* Read Auth Reply       */

void close_socket(struct descriptor_data *d);
void flush_queues(struct descriptor_data *d);
void nonblock(int s);
void parse_name(struct descriptor_data *desc, char *arg);
/* int number_playing(void); */

/* extern functions */
#ifdef EXPLICIT
extern int sendto(int s, const char *msg, int len, int flags,
                  const struct sockaddr *to, int tolen);
extern int recvfrom(int s, char *buf, int len, int flags,
                  struct sockaddr *from, int *fromlen);
#endif
struct char_data *make_char(char *name, struct descriptor_data *desc);
void boot_db( int port );
void zone_update(void);
void bleeding_update(void);
void affect_update( void ); /* In spells.c */
void point_update( int pulse );  /* In limits.c */

void mobile_activity(void);
void move_activity(int);
void string_add(struct descriptor_data *d, char *str);
void editor(struct descriptor_data *d, char *str);
void perform_violence(void);
void show_string(struct descriptor_data *d, char *input, bool first);
void make_prompt( char *buff, struct char_data *ch) ;


int main( int argc, char *argv[] )
{
    int pos;
    int port    = DFLT_PORT;
    int who_port= DFLT_WHO_PORT;
    int split_port = DFLT_SPLIT_PORT;
    int evil_port = DFLT_EVIL_PORT;
    int evil_split_port = DFLT_EVIL_SPLIT;
    char *dir   = DFLT_DIR;
    int control, who_control, split_control, evil_control, evil_split_control;
    char buf[200];

    for ( pos = 1; pos < argc && argv[pos][0] == '-' ; pos++ )
    {


        switch (*(argv[pos] + 1))
        {
        case 'g':
            god = 1;
            wizlog( "God creation mode selected." );
            break;

        case 'd':
            if ( argv[pos][2] != '\0' )
                dir = &argv[pos][2];
            else if (++pos < argc)
                dir = &argv[pos][0];
            else
            {
                fprintf( stderr, "Directory arg expected after -d.\n" );
                exit( 2 );
            }
            break;
        case 'w':
            if ( argv[pos][2] != '\0' )
                who_port=atoi(&argv[pos][2]);
            else if (++pos < argc)
                who_port=atoi(&argv[pos][0]);

            else
            {
                fprintf( stderr, "Port Arg expected after -w.\n" );
                exit( 2 );
            }
            if (who_port<1024)
            {
                fprintf( stderr, "Illegal Port\n");
                exit( 2 );
            }
            break;

        case 's':
            if ( argv[pos][2] != '\0' )
                split_port=atoi(&argv[pos][2]);
            else if (++pos < argc)
                split_port=atoi(&argv[pos][0]);
            else
            {
                fprintf( stderr, "Port Arg expected after -s.\n" );
                exit( 2 );
            }
            if (split_port<1024)


            {
                fprintf( stderr, "Illegal Port\n");
                exit( 2 );
            }
            break;
        case 'e':
            if ( argv[pos][2] != '\0')
                evil_port=atoi(&argv[pos][2]);
            else if (++pos < argc)
                evil_port=atoi(&argv[pos][0]);
            else
            {
                fprintf( stderr, "Port Arg expected after -e.\n" );
                exit( 2 );
            }
            if (evil_port<1024)
            {
                fprintf( stderr, "Illegal Port\n");
                exit( 2 );
            }
            break;
        case 'f':
            if ( argv[pos][2] != '\0')


                evil_split_port=atoi(&argv[pos][2]);
            else if (++pos < argc)
                evil_split_port=atoi(&argv[pos][0]);
            else
            {
                fprintf( stderr, "Port Arg expected after -e.\n" );
                exit( 2 );
            }
            if (evil_split_port<1024)
            {
                fprintf( stderr, "Illegal Port\n");
                exit( 2 );
            }
            break;

        default:
            fprintf( stderr, "Unknown option -%c.\n", argv[pos][1] );
            exit( 2 );
            break;
        }
    }

    if (pos < argc)

    {
        if (!isdigit(argv[pos][0]))
        {
            fprintf( stderr, "Usage: %s [-g][-d pathname][-s split][-w who][-e e
vil][-f evilsplit][port #]\n",
                argv[0] );
            exit( 2 );
        }
        else if ( ( port = atoi(argv[pos]) ) < 1024 )
        {
            printf( "Illegal port #\n" );
            exit( 2 );
        }
    }

    wizlogf("[Who %d] [Split %d] [Port %d] [Dir %s].", who_port, split_port, por
t, dir );

    if ( chdir( dir ) < 0 )
    {
        perror( dir );
        exit( 2 );
    }


    srandom( time(0) );

    /*
     * Optional memory tuning.
     */
#if defined(sun)
    mallopt( M_MXFAST, 96 );
    mallopt( M_NLBLKS, 1024 );
#endif

    signal( SIGPIPE, SIG_IGN );

    who_control = init_socket( who_port );
    split_control = init_socket( split_port );
    control = init_socket( port );
    evil_control = init_socket (evil_port);
    evil_split_control = init_socket (evil_split_port);
    alarm(3*60);       /* If boot's longer that 3 mins, somethings wrong */
    boot_db( port );
    game_loop( control, who_control, split_control, evil_control, evil_split_con
trol );


    sprintf(buf,"%s by %s, Reason: %s\n\n",re_boot ? "Reboot" : "Shutdown",down_
by, down_reason);
    while ( descriptor_list ) {
        if (descriptor_list->character) {
            save_char_obj(descriptor_list->character);
            write_to_q(buf,&descriptor_list->output);
            write_to_q(VT_Normal(descriptor_list->character), &descriptor_list->
output) ;
            write_to_q("\n\n", &descriptor_list->output) ;
        }
        close_socket( descriptor_list );
    }
    wizlog(buf);
    if (re_boot) exit(10) ;
    else exit(0);
    return 0;
}


/* Accept new connects, relay commands, and call 'heartbeat-funcs' */
void game_loop( int control, int who_control, int split_control, int evil_contro
l, int evil_split_control )
{

    fd_set input_set, output_set, exc_set, who_set;
    int nfds;
    struct timeval last_time, now_time, stall_time;
    time_t now;
    static struct timeval null_time = {0, 0};
    struct descriptor_data *point, *next_point;
    char buf[8192], *pcomm, anim[16]="";
    int mask, z;
    bool fStall;
    extern const char *anim_strings[][20];
    extern void do_who(struct char_data *ch, char *argument, int cmd);
    struct char_data who_daemon; /* Pretend the port is a player */
    extern const sbyte anim_point  [][4];
    void mail(struct descriptor_data *d, char *arg);
    extern void return_pets(CHAR_DATA *ch);

    gettimeofday(&last_time, (struct timezone *) 0);

    maxdesc = control;

    mask = sigmask(SIGUSR1) | sigmask(SIGUSR2) | sigmask(SIGINT)  |
           sigmask(SIGPIPE) | sigmask(SIGALRM) | sigmask(SIGTERM) |
           sigmask(SIGURG)  | sigmask(SIGXCPU) | sigmask(SIGHUP)  |

           sigmask(SIGVTALRM);


    who_flag = 0; /* Not using who hack yet */
    GET_LEVEL(&who_daemon)=1; /* All other flags default off 
                                 May one day read a character file, 
                                 But that could cause complications */

#if 0
    mallocmap();
#endif

    /* Main loop */
    while ( (!shut_down && !re_boot) || (slow_death - time(0) >= 0)) 
      {

        /* Check what's happening out there */

        alarm(40);     /* If not back here in 30 sec... down she goes */
                       /* Timeout -> SIGALRM -> Goodbye */

        now = time(NULL);
        FD_ZERO(&who_set);
        FD_ZERO(&input_set);
        FD_ZERO(&output_set);
        FD_ZERO(&exc_set);
        FD_SET(control, &input_set);
        FD_SET(who_control, &input_set);
        FD_SET(split_control, &input_set);
        FD_SET(evil_control, &input_set);
        FD_SET(evil_split_control, &input_set);
        nfds=0;
        for (point = descriptor_list; point; point = point->next) 
          {
            FD_SET(point->descriptor, &input_set);
            FD_SET(point->descriptor, &exc_set);
            FD_SET(point->descriptor, &output_set);
            if (point->auth_fd!=-1) 
              {
               FD_SET(point->auth_fd, &input_set);
               if (IS_SET(point->auth_state,FLAG_WRAUTH)) FD_SET(point->auth_fd,
 &output_set);
              }
          }
        
        sigsetmask(mask);


        if ((select(maxdesc + 1, &input_set, &output_set, &exc_set, &null_time))
 < 0) {
            perror("Select Poll: Main Port");
            exit(2);
        }

        sigsetmask(0);

        /* Respond to whatever might be happening */
        

        /* Who Daemon */

        if (FD_ISSET(who_control, &input_set )){
            who_flag=1; /** Cheesy hard-coded access to the who list */
            do_who(&who_daemon,"",0); /* Load who buffer */ 
            if ((z=new_connection(who_control))>=0) { 
                write_to_descriptor(z,who_list);
                close(z);
            } else wizlog("who connection bombed.");
            wizlog("Who daemon polled.");
            FREE(who_list);

            who_flag=0;
        }

        /* New connection */ 
        if (FD_ISSET(evil_control, &input_set) && new_descriptor(evil_control,0,
1) < 0) perror("Evil Connection");

        if (FD_ISSET(evil_split_control, &input_set) && new_descriptor(evil_spli
t_control,1,1) < 0) perror("Evil Split connection");

        if (FD_ISSET(split_control, &input_set) && new_descriptor(split_control,
1,0) < 0) perror("Split connection");

        if (FD_ISSET(control, &input_set) && new_descriptor(control,0,0) < 0) pe
rror("New connection");

        /* Handle Authorization */
        for (point = descriptor_list; point; point = next_point) 
          {
            next_point = point->next;
            if (FD_ISSET(point->descriptor, &exc_set))
              {
                FD_CLR(point->descriptor, &input_set);
                FD_CLR(point->descriptor, &output_set);
                if ( point->character ) save_char_obj(point->character);
                close_socket(point);
                continue;
              }
             if (point->auth_fd==-1) continue;
             
             if (FD_ISSET(point->auth_fd, &input_set))
                  {
                    read_auth(point);
                    if (!point->auth_state) check_ban(point);
                  }
             else if ((FD_ISSET(point->auth_fd, &output_set))&&
                  IS_SET(point->auth_state,FLAG_WRAUTH))
                  { 
                    send_auth(point);
                    if (!point->auth_state) check_ban(point);
                  }    
          }
                
        /* Read input */
        for (point = descriptor_list; point; point = next_point) 
          {

            next_point = point->next;
            if (FD_ISSET(point->descriptor, &input_set)) 
              {
                if (point->showstr_point ?
                    (process_input(point, FALSE) < 0) :
                    (process_input(point, TRUE) < 0)) 
                  {
                    if ( point->character ) save_char_obj( point->character );
                    close_socket(point);
                    continue;
                  }
                point->newline = FALSE;
              }
            else point->newline = TRUE;

          }

        /* process_commands; */
        for (point = descriptor_list; point; point = next_to_process) 
          {
            next_to_process = point->next;

            if (--(point->wait) <= 0 &&

                (pcomm = get_from_q( &point->input )) != NULL )
              {
                if (point->character &&
                    (point->connected == CON_PLAYING || point->connected == CON_
EDITOR) &&
                    (point->character->specials.was_in_room != NOWHERE)) 
                  {
                    if (point->character->in_room != NOWHERE)
                      char_from_room(point->character);
                    char_to_room(point->character, point->character->specials.wa
s_in_room);
                    point->character->specials.was_in_room = NOWHERE;
                    act("$n has returned.", TRUE, point->character, 0, 0, TO_ROO
M);
                    affect_total(point->character);
                  }

                point->wait = 1;

                if (point->character) point->character->specials.timer = 0;

                if (point->showstr_point) show_string(point, pcomm, FALSE);
                else if (point->connected == CON_EDITOR) editor(point, pcomm);
                else if (point->connected == CON_MAILER) mail(point, pcomm);
                else if (point->connected != CON_PLAYING) nanny(point, pcomm);
                else command_interpreter(point->character, pcomm, 1);
                
                FREE( pcomm );  /*** DUMPER CORE - EJ */

                /* Cheesy way to force prompts */
                write_to_q( "", &point->output );
              } /*
            else if (point->wait > 0 && point->wait_type == ANIM_NOTHING) 
              {
                sprintf(anim, "\r%3d", point->wait) ;
                write_to_descriptor(point->descriptor,anim) ;
              } */
        }

#define anim_type   (point->wait_type)
#define anim_wait   (point->wait-2)
#define anim_num    anim_point[anim_type][0]
#define anim_freeze anim_point[anim_type][1]
#define anim_loop   anim_point[anim_type][2]
#define anim_length anim_point[anim_type][3]


       /* give the people some prompts */

        for (point = descriptor_list; point; point = next_point) 
          {
            next_point = point->next;
            /* autosave ? */
            if (FD_ISSET(point->descriptor, &output_set) && point->character &&
                point->connected == CON_PLAYING && !point->original)
              if ( (time(0) - point->character->player.time.last_save) >= 300 ) 
                {
                  point->character->player.time.last_save = time(0) ;
                  if(!IS_SET(point->character->specials.act,PLR_BUSY))
                    /* STCf("Autosaving %s.\n", point->character, GET_SHORT(poin
t->character)) ; */
                    save_char_obj( point->character ) ;
                    return_pets(point->character);
                }
            if (FD_ISSET(point->descriptor, &output_set) && point->output.head)
              {
                if ( point->wait <= 1 || !anim_freeze ) 
                  {
                    /* editor */
                    if (point->connected == CON_EDITOR) 

                      {
                        if (!point->showstr_point)
                          switch(point->sub_prompt) {
                           case 0 : write_to_q( "==>", &point->output) ;break;
                           case 1 : write_to_q( "Old String: ", &point->output);
 break;
                           case 2 : write_to_q( "New String: ", &point->output);
 break;
                           default: write_to_q( "Bug? ",&point->output); break;
                          }
                      } 
                    else if (point->connected != CON_PLAYING) ;
                    else if (point->showstr_point) ;
                    /* output string */
                    else 
                      {
                        make_prompt(buf, point->character) ;
                        if ((!point->contype)||(point->connected!=CON_PLAYING)) 
{
                                write_to_q(buf, &point->output) ;
                        } else {
                            if (strcasecmp(buf,point->last_prompt)){ /*dif*/
                                write_to_descriptor(point->descriptor,"\033[23;1

H\033[K");
                                write_to_descriptor(point->descriptor,buf);
                                FREE(point->last_prompt);
                                point->last_prompt=str_dup(buf);
                                point->sending=0;
                                sprintf(buf,"\033[24;1H%s",point->buf);
                                write_to_descriptor(point->descriptor,buf);
                            };
                        }
                      }
                    if (process_output(point) < 0) 
                      {
                        if ( point->character )
                          save_char_obj( point->character );
                        close_socket(point) ;
                      }
                  } 
                else if ( anim_length && anim_type >= ANIM_NOTHING && anim_type 
<= ANIM_PRACTICE
                         && (anim_loop || anim_wait < anim_length)) 
                  {
                    sprintf(anim, "\r%s", anim_strings[anim_num][anim_wait % ani
m_length]) ;

                    write_to_descriptor(point->descriptor,anim) ;
                  }
              }
          }

#undef  anim_num*
#undef  anim_freeze
#undef  anim_loop
#undef  anim_length
#undef  anim_type
#undef  anim_wait

        /* See if everyone wants clock FAST. */
        fStall = TRUE;
/*
        for (point = descriptor_list; point; point = next_to_process)
        {
            if ( point->connected != CON_PLAYING ) continue;
            if ( point->tick_wait > 0 ) continue;
            fStall = TRUE;
        }
*/
        /*

mbox (46%)

         * Heartbeat.
         * All autonomous actions (including fighting and healing)
         * are subdivisions of the basic pulse at OPT_USEC interval.
         */
        
        pulse++;

        if ( !(pulse % PULSE_ZONE) ) zone_update();

        if ( !(pulse % PULSE_BLEED) ) bleeding_update();

        if ( !(pulse % PULSE_WEATHER) ) weather_and_time(1);

        if ( !(pulse % PULSE_MOBILE) ) mobile_activity();

        if ( !(pulse % PULSE_VIOLENCE) ) 
        {
            if (re_boot || shut_down) night_watchman();
            perform_violence();
        }

        if ( !(pulse % PULSE_AUTOMOVE) )
            move_activity( (pulse / PULSE_AUTOMOVE) % 3 );

        if ( !(pulse % PULSE_POINTS) )
            point_update( (pulse / PULSE_POINTS) % 10 );

        if ( !(pulse % PULSE_AFFECT) )
            affect_update();

        #define PULSE_DEBUG_MALLOC 60 /* Every 10 sec */
/*      if ( !(pulse % PULSE_DEBUG_MALLOC) ) 
            DebugMalloc();
*/
        /*
         * Synchronize to an OPT_USEC clock.
         * Sleep( last_time + OPT_USEC - now ).
         */

        if ( fStall ) 
          {
            gettimeofday( &now_time, NULL );
            stall_time.tv_usec  = last_time.tv_usec - now_time.tv_usec + OPT_USE
C;
            stall_time.tv_sec   = last_time.tv_sec  - now_time.tv_sec;
            if ( stall_time.tv_usec < 0 ) 

              {
                stall_time.tv_usec += 1000000;
                stall_time.tv_sec--;
              }
            if ( stall_time.tv_usec >= 1000000 ) 
              {
                stall_time.tv_usec -= 1000000;
                stall_time.tv_sec++;
              }

            if ( stall_time.tv_sec > 0 ||
               ( stall_time.tv_sec == 0 && stall_time.tv_usec > 0 ) ) 
              {
                if ( select( 0, NULL, NULL, NULL, &stall_time ) < 0 ) 
                  {
                    perror( "Select stall" );
                    exit( 2 );
                  }
              }
          }
        gettimeofday( &last_time, NULL );
      }
/* } */


}


char * get_from_q(struct txt_q *queue)
{
    struct txt_block *tmp;
    char *dest;

    /* Q empty? */
    if (queue->head==NULL) return NULL;

    tmp         = queue->head;

    dest        = tmp->text;
    queue->head = tmp->next;

    FREE( tmp );
    return dest;
}



void write_to_q(char *txt, struct txt_q *queue)


{
    struct txt_block *new;

    if( !queue || !txt ) return ;

    CREATE(new, struct txt_block, 1);
                                    
    new->text = str_dup(txt);

    /* Q empty? */
    if (!queue->head){
        new->next         = NULL;
        queue->head       = queue->tail = new;
    } else {
        queue->tail->next = new;
        queue->tail       = new;
        new->next         = NULL;
    }
}



/* Empty the queues before closing connection */


void flush_queues(struct descriptor_data *d)
{
    void *tmp = get_from_q( &d->input );
    FREE(tmp);
    tmp = get_from_q( &d->output );
    FREE(tmp);
}



int init_socket(int port)
{
    int s;
    int opt = 1;
    char hostname[MAX_HOSTNAME+1];
    struct sockaddr_in sa;
    struct hostent *hp;

    gethostname(hostname, MAX_HOSTNAME);
    hp = gethostbyname(hostname);
    if (hp == NULL)
    {
        perror("gethostbyname");

        exit(2);
    }

    sa.sin_family      = hp->h_addrtype;
    sa.sin_port        = htons(port);
    sa.sin_addr.s_addr = 0;
    sa.sin_zero[0]     = 0; sa.sin_zero[1]     = 0;
    sa.sin_zero[2]     = 0; sa.sin_zero[3]     = 0;
    sa.sin_zero[4]     = 0; sa.sin_zero[5]     = 0;
    sa.sin_zero[6]     = 0; sa.sin_zero[7]     = 0;

    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0)
    {
        perror("Init-socket");
        exit(2);
    }

    if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
        (char *)&opt, sizeof (opt)) < 0)
    {
        perror ("setsockopt SO_REUSEADDR");
        exit (2);

    }

#if defined(SO_DONTLINGER)

/* Time system will hold socket until it can be reused,
   actually not needed(?) since we have REUSEADDR above, but.. */

    {
        struct linger ld;

        ld.l_onoff  = 1;
        ld.l_linger = 1000;

        if (setsockopt(s, SOL_SOCKET, SO_DONTLINGER, &ld, sizeof(ld)) < 0)
        {
            perror("setsockopt SO_DONTLINGER");
            exit( 2 );
        }
    }
#endif

    if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0)
    {

        perror("bind");
        close(s);
        exit( 1 );
    }
    listen(s, 3);
    return(s);
}


int new_connection(int s)
{
    struct sockaddr_in isa;
    /* struct sockaddr peer; */
    int i;
    int t;

    i = sizeof(isa);
    getsockname(s, (struct sockaddr *) &isa, &i);

    if ((t = accept(s, (struct sockaddr *) &isa, &i)) < 0)
    {
        perror("Accept");
        return(-1);

    }
    nonblock(t);

    return(t);
}


/*
int number_playing(void)
{
    struct descriptor_data *d;

    int i;

    for ( i = 0, d = descriptor_list ; d ; d = d->next )
        i++;

    return(i);
}
*/

int workaround(struct descriptor_data *d)
{

    struct ban_t *tmp;
    char *nicknamehost;
    nicknamehost=str_dupf("%s!%s@%s",d->name,d->user,d->host);
    for ( tmp = ncsa_list; tmp; tmp = tmp->next ) {
        if (!match( tmp->name, nicknamehost ) ) {
            FREE(nicknamehost);
            write_to_descriptor(d->descriptor,"NCSA telnet patch loaded.\n" );
            return 1;
        }
    }
    FREE(nicknamehost);
    return 0;
}

void check_ban(struct descriptor_data *d)
{
    struct ban_t *tmp;
    char *nicknamehost;
    nicknamehost=str_dupf("%s!%s@%s",d->name,d->user,d->host);
    for ( tmp = ban_list; tmp; tmp = tmp->next ) {
        if (!match( tmp->name, nicknamehost ) ) {
            FREE(nicknamehost);
            write_to_descriptor(d->descriptor,"You or your site have been banned

 from LoD.\n" );
            close_socket(d);
            break;
        }
    }
    FREE(nicknamehost);
}
int new_descriptor(int s, int x, int evil)
{
    int desc;
    struct descriptor_data *newd;
    int size;
    struct sockaddr_in sock;
    struct hostent *from;
    int get_country(char *) ;

    if ((desc = new_connection(s)) < 0) return (-1);

    if (desc > maxdesc)
        maxdesc = desc;


    /* find info */

    size = sizeof(sock);
    if (getpeername(desc, (struct sockaddr *) &sock, &size) < 0) {
        perror("getpeername");
        *newd->host = '\0';
    } else {
#if !defined(NeXT)
     /* There sin_addr is u_long s_addr #include <netinet/in.h> */
/*
     if((sock.sin_addr.s_net==199)&&
        (sock.sin_addr.s_host==234)&& 
        (sock.sin_addr.s_lh==141)&& 
        (sock.sin_addr.s_impno==2)) { 
           close(desc);
           spam_o_meter++;
           return -1;
        }
*/

    CREATE(newd, struct descriptor_data, 1);
     wizlogf("Socket Address:  %d.%d.%d.%d",
             (int)*(unsigned char *)&sock.sin_addr.s_addr,             
             (int)*(((unsigned char *)&sock.sin_addr.s_addr)+1),             
             (int)*(((unsigned char *)&sock.sin_addr.s_addr)+2),             
             (int)*(((unsigned char *)&sock.sin_addr.s_addr)+3));
#else             
        wizlogf("Socket Address:  %d.%d.%d.%d",
                sock.sin_addr.s_net,
                sock.sin_addr.s_host,
                sock.sin_addr.s_lh,
                sock.sin_addr.s_impno );
#endif

/**** Had to take away & from sock.sin_addr ****/
        /*bcopy(&sock.sin_addr,&newd->ip,sizeof(struct in_addr));*/
        newd->ip=sock.sin_addr;
        strcpy(newd->host, inet_ntoa(sock.sin_addr));
        
        from = gethostbyaddr( (char *) &sock.sin_addr,
            sizeof(sock.sin_addr), AF_INET );
        if ( from ) {
            strncpy(newd->host, from->h_name, 49);
            *(newd->host + 49) = '\0';
        }
/* localhost.gih.no? Nah... // Helger
        if (!index(newd->host, '.'))
            strcat(newd->host, ".dorm.virginia.edu") ;

*/
        newd->country = get_country(newd->host) ;
    }

    /* init desc data */
    newd->descriptor     = desc;
    newd->last_connected = CON_GET_NAME;
    newd->contype        = x;
    newd->evil           = evil;
    newd->connected      = CON_GET_NAME; 
    if (x) {
       newd->sending=1;
    }
    newd->wait           = 1; 
    *newd->buf           = '\0';
    strcpy(newd->user, "unknown");
    newd->last_prompt    = str_dupf("No Prompt");
    newd->edit_length    = 0; 
    newd->edit_head      = 0; 
    newd->edit_line      = 0;
    newd->edit_head_bu   = 0; 
    newd->edit_line_bu   = 0;
    newd->edit_str       = 0;
    newd->edit_func      = 0;
    newd->edit_param     = 0;
    newd->screen_width   = 80;
    newd->screen_height  = 20;
    newd->showstr_head   = 0;
    newd->showstr_point  = 0;
    newd->showstr_keep   = FALSE;
    newd->newline        = FALSE;
    newd->output.head    = NULL;
    newd->input.head     = NULL;
    newd->next           = descriptor_list;
    newd->character      = 0;
    newd->original       = 0;
    newd->snoop.snooping = 0;
    newd->snoop.snoop_by = 0;
    newd->sx=0;newd->sy=0;
    newd->ox=0;newd->oy=24;

    /* prepend to list */


    newd->next = descriptor_list;
    descriptor_list = newd;

    if (x) write_to_descriptor(desc,"\033[H\033[2JAttempting To Boot Split Scree
n...\n");
    else write_to_q( "\033[H\033[J", &newd->output) ;
    write_to_q( greetings[evil], &newd->output );
    write_to_q( "By what name do you wish to be known? ", &newd->output );
    if (!workaround(newd)) {
        start_auth(newd);
    } else {
        newd->auth_state=0;
        newd->auth_fd=-1;
    }
    
        /* Put in a authorization request ASAP */
    if (!newd->auth_state) check_ban(newd);
    if (!newd) return (-1);
    return(0);
}
char *wrap(struct descriptor_data *t,char *pstr)
{
    register char *i, *j, *ls, *k ;
    register sh_int count, rcount ;
    int ibuf = 0;
    char buf[2*MAX_STRING_LENGTH]="";
    int indent=t->character?IS_SET(GET_PROMPT(t->character),PROMPT_INDENT):0;
/*
    if ( t->newline ) {
        buf[ibuf++] = '\n';
    }
*/
    j=buf+ibuf ;

    /* Cycle thru output queue */

        i=pstr, ls=0, count=0, rcount=0;
        while( *i && (j-buf)<MAX_STRING_LENGTH )
          {

            if ( (*i>=32) && (*i<127) ) {    /* A letter. Add one to count */
                count++      ;               /* Count from last '\n'       */
                rcount++     ;               /* Word length                */
            } else if (*i=='\n' || *i=='\r') { /* Ok. Start count again    */
                count  = 0   ;               /* Reset Count                */
                rcount = 0   ;               /* Reset word length          */
                ls     = 0   ;               /* No 'last-space'            */
                goto CheckLF ;
            } else if ( *i == '\33' ) {      /* Escape sequence. Loop past */
                while( *i && !isalpha(*i) )  /* Copy the [3;2 ...          */
                    *j = *i, i++, j++;       /* Copy...                    */
                *j = *i;                     /* Copy...                    */
                goto CheckLF ;
            } else
                goto CheckLF ;

            if ( *i == ' ' )  {              /* Is it a space ?            */
                ls     = j   ;               /* Yes.. Remember it          */
                rcount = 0   ;               /* Reset word length          */
                goto CheckLF ;
            }
            if ( count > GET_WIDTH(t) ) {   /* To the rescue...           */
                if ( ls ) {                  /* There is a last-space      */
                    count  = rcount;         /* Reset count                */
                    *(ls) = '\n' ;
#if 0
                    if (indent) {
                      ls++;
                      j++;
                      for (k=j;k>ls;k--) *k=*(k-1);
                      *(ls) = 9 ;
                      count=8; /*?*/
                    }
#else
                    if (indent) {
                      j+=4;
                      for (k=j;k>ls+4;k--) *k=*(k-4);
                      *(++ls) = ' ' ;
                      *(++ls) = ' ' ;
                      *(++ls) = ' ' ;
                      *(++ls) = ' ' ;
                      count=4; /*?*/
                    }
#endif
                } else {                     /* There's no ls. PAD!        */
                    count  = 0    ;          /* I will _NOT_ check whether */
                    *(j++) = '-'  ;          /* words are split correctly  */
                    *(j++) = '\n' ;          /* or not! This'll have to do */
                }
                rcount = 0 ;
                ls     = 0 ;                 /* Reset last space           */
                goto CheckLF ;

            }

            CheckLF :                        /* Strip all '\r' and replac  */
         /*   if ( !*i ) break;     */
            *(j++) = *(i++); 
        }

    *j = 0 ;
    return str_dup(buf);
}


int process_output(struct descriptor_data *t)
{
    int j;
    char *pstr, *zstr, buf[MAX_INPUT_LENGTH*10];
    if ((t->last_connected!=t->connected)&&(t->connected==CON_PLAYING)&&
       (t->contype)){
        t->sx=0;t->sy=0;t->ox=strlen(t->buf);t->oy=23;/*actual minus 1*/
        t->last_connected=t->connected;
        t->sending=1;
        write_to_descriptor(t->descriptor,"\033[2J\033[24;1H");
        write_to_descriptor(t->descriptor,t->buf);
        write_to_descriptor(t->descriptor,"\033[23;1H");
        write_to_descriptor(t->descriptor,t->last_prompt);
        write_to_descriptor(t->descriptor,"\033[1;22r");
    } else if ((t->last_connected==CON_PLAYING)&&(t->connected!=CON_PLAYING)&&
        (t->contype)){
        write_to_descriptor(t->descriptor,"\033[1;24r\033[2J");
        t->last_connected=t->connected;
    }
    while ((pstr=get_from_q(&t->output)) )
    {
      if(!(t->contype)||(t->connected!=CON_PLAYING)) { /* Stock Connection */
        if(t->newline) { /* Must send newline before new text */
             write_to_descriptor(t->descriptor,"\n");
             t->newline=0;
        }
        if(t->snoop.snoop_by) { /* Send to snooper */
            write_to_q(VT_ch(t->character, COLOR_SNOOP), &t->snoop.snoop_by->des
c->output);
            write_to_q(pstr, &t->snoop.snoop_by->desc->output);
        }
        zstr = wrap(t,pstr);
      
        j = write_to_descriptor( t->descriptor, zstr ); /* Just dump to desc */

        FREE(zstr);
        FREE( pstr );
      } else { 
        if (!t->sending) { /*not already in above window at right spot */
            sprintf(buf,"\033[%d;%dH",t->sy+1,t->sx+1);
            write_to_descriptor( t->descriptor, buf);
                /* Store Cursor Position, Init Window, go there */
                /* Note eventually shoulder toggle last carriage return */
            t->sending=1;
        }       
        zstr = wrap(t,pstr);
        FREE(pstr);
        pstr=zstr;
        for(;*zstr;zstr++)
            {
                if (*zstr=='\n') { t->sy=MIN(21,t->sy+1);t->sx=0; }
                else if (*zstr=='\r') { t->sx=0; }
                else if (*zstr=='\b') { t->sx=MAX(0,t->sx-1); }
                else if (*zstr==27) {
                        while ((*zstr)&&(!isalpha(*zstr))) zstr++;
                        if (*zstr=='J') { t->sx=0; t->sy=0; }
                }

                else if (*zstr>31) t->sx++;

                if (t->sx==80) {
                        t->sy=MIN(21,t->sy+1);
                        t->sx=0;
                }
            }
        j=write_to_descriptor(t->descriptor,pstr);
      }
      FREE(pstr);
     }
    if ((t->contype)&&(t->connected==CON_PLAYING)){
      sprintf(buf,"\033[24;1H%s",t->buf);
      write_to_descriptor( t->descriptor, buf);
      t->sending=0;
    }
    return j;
}

/* NEW --- not to lose link when buffer overflows... */
int write_to_descriptor(int desc, char *txt)
{
    int sofar, thisround, total, e;


    char ntext[MAX_STRING_LENGTH];
    char *ztxt;

    if (!txt) return 0;
    for (ztxt=ntext;*txt;ztxt++,txt++)
        if (*txt=='\n') {  *ztxt='\r';ztxt++;*ztxt=*txt;} 
        else *ztxt=*txt;
    *ztxt='\0';
             
    total = strlen(ntext);
    sofar = 0;
    do {
        thisround = write(desc, ntext + sofar, total - sofar);
        e = errno;
        if (thisround < 0 && e != EWOULDBLOCK) {
            perror("Write to socket");
            return(-1);
        }
        if (thisround >= 0) sofar += thisround;
    }
    while (sofar < total);
    return(0);
}

/*
int old_write_to_descriptor(int desc, char *txt)
{
    int sofar, thisround, total;

    total = strlen(txt);
    sofar = 0;
    do {
        thisround = write(desc, txt + sofar, total - sofar);
        if (thisround < 0) {
            perror("Write to socket");
            return(-1);
        }
        sofar += thisround;
    }
    while (sofar < total);
    return(0);
}
*/

int process_input(struct descriptor_data *t, bool newline)
{
    int sofar, thisround, begin, squelch, i, k, flag;

    char tmp[MAX_INPUT_LENGTH+2], buffer[MAX_INPUT_LENGTH + 60],
         buf[160];

/* Still in authorization routine, buffer in use, cant take input yet! */

    /* if (t->auth_state) return(0);  ** WRONG **/

    sofar = 0;
    flag = 0;
    begin = strlen(t->buf);

/* Read in some stuff */
    if ((t->connected!=t->last_connected)&&(t->connected==CON_PLAYING)
        &&(t->contype)) { /* set up for split screen */
        t->sx=0;t->sy=0;t->ox=strlen(t->buf)%80;t->oy=23;/*actual minus 1*/
        t->last_connected=t->connected;
        t->sending=0;
        write_to_descriptor(t->descriptor,"\033[2J");
        write_to_descriptor(t->descriptor,"\033[23;1H");
        write_to_descriptor(t->descriptor,t->last_prompt);
        write_to_descriptor(t->descriptor,"\033[1;22r\033[24;1H");
        write_to_descriptor(t->descriptor,t->buf);
    } else if ((t->last_connected==CON_PLAYING)&&(t->connected!=CON_PLAYING)&&

        (t->contype)){ /* Get OUT of split screen *sulk* */
        write_to_descriptor(t->descriptor,"\033[1;24r\033[2J");
        t->last_connected=t->connected;
    }

    do {
        if ((t->contype)&&(t->connected==CON_PLAYING))
          if (t->sending) {
            sprintf(buf,"\033[24;1H%s",t->buf);
            write_to_descriptor(t->descriptor,buf);/*return to cmd line */
            t->sending=0;
          }
/*
        if ((thisround = read(t->descriptor, t->buf + begin + sofar,
           1, MAX_STRING_LENGTH - (begin + sofar) - 1) ) > 0){


*/      if ((thisround = recv(t->descriptor, t->buf + begin + sofar,
           MAX_STRING_LENGTH - (begin + sofar) - 1 , 0)) > 0 ) {
            sofar += thisround;
        } else
            if (thisround < 0)
                if(errno != EWOULDBLOCK) {

                    perror("Read1 - ERROR");
                    return(-1);
                }
                else {
                        t->ox=(strlen(t->buf)%80);
                        break;
                        }
            else {
                wizlog("EOF encountered on socket read.");
                return(-1);
            }
    } while ( !ISNEWL(*(t->buf + begin + sofar - 1)));
    
    *(t->buf + begin + sofar) = 0;

/* if no newline is contained in input, return without proc'ing */
    for (i = begin; !ISNEWL(*(t->buf + i)); i++) if (!*(t->buf + i)) {
                        t->ox=(strlen(t->buf)%80);
                        return(0);
        }

   if ((t->contype) && (t->connected!=CON_EDITOR)) write_to_descriptor(t->descri
ptor,"\033[24;1H\033[K"); /*clear data entry line */


/* input contains 1 or more newlines; process the stuff */
    for (i = 0, k = 0; *(t->buf + i);) {
        if ( !ISNEWL(*(t->buf + i)) && !(flag = (k >= (MAX_INPUT_LENGTH - 2))))
/* backspace */
            if(*(t->buf + i) == '\b') /* Slipped through! */
/* more than one char ? */
                if (k) {
                    if (*(tmp + --k) == '$') k--;
                    i++;
                }
                else
                    i++;  /* no or just one char.. Skip backsp */
            else
                if (isascii(*(t->buf + i)) && isprint(*(t->buf + i))) {
                    *(tmp +k) = *(t->buf + i);
                    k++;
                    i++;
                }
                else
                    i++;
        else {
            *(tmp + k) = 0;


            write_to_q(tmp, &t->input);

            if(t->snoop.snoop_by) {
                    write_to_q(VT_ch(t->character, COLOR_SNOOP), &t->snoop.snoop
_by->desc->output);
                    write_to_q(tmp, &t->snoop.snoop_by->desc->output);
                    write_to_q("\n",&t->snoop.snoop_by->desc->output);
                }

            if ((flag)&&(!t->contype)) {
                sprintf(buffer,"Line too long. Truncated to:\n%s\n", tmp);
                if (write_to_descriptor(t->descriptor, buffer) < 0)
                    return(-1);

/* skip the rest of the line */
                for (; !ISNEWL(*(t->buf + i)); i++);
            }

/* find end of entry */
            for (; ISNEWL(*(t->buf + i)); i++);

/* squelch the entry from the buffer */

           for (squelch = 0;; squelch++)
                if ((*(t->buf + squelch) =
                    *(t->buf + i + squelch)) == '\0')
                    break;
            k = 0;
            i = 0;
        }
    }
    t->ox=(strlen(t->buf)%80);
    return(1);
}

void close_socket(struct descriptor_data *d)
{
    struct descriptor_data *tmp;
    struct char_data *c;
    struct watch_data *w;
    extern struct char_data *character_list;

    if (!d->swap){
       if (d->contype) write_to_descriptor(d->descriptor,"\033[1;24r");
       process_output(d);
       close( d->descriptor );
       if ( d->descriptor == maxdesc ) --maxdesc;
    }

    if (d->last_prompt) FREE(d->last_prompt);

    /* Forget snooping */
    if (d->snoop.snooping) d->snoop.snooping->desc->snoop.snoop_by = 0;
    if (d->snoop.snoop_by) {
        STC("Your victim is no longer among us.\n",d->snoop.snoop_by );
        d->snoop.snoop_by->desc->snoop.snooping = 0;
    }
    /* Purge the watch list too */
    for (c=character_list;c;c=c->next) {
        for (w=c->watching;w;w=w->next) {
            if (w->watcher==d) w->watcher=0; /* fade it out, *shrugs* */
        }
    }

    if (d->character) {
        if ( d->connected == CON_PLAYING || d->connected == CON_EDITOR ) {
            save_char_obj(d->character) ;
            act("$n has lost $s link.", TRUE, d->character, 0, 0, TO_ROOM);
            wizlogf("Closing link to: %s.", GET_NAME(d->character));
            d->character->desc = 0;
        } else {
            wizlogf("Losing player: %s.", GET_NAME(d->character) );
            free_char( d->character );
        }
    } else wizlog( "Losing descriptor without char." );

    if (d->swap) {
        wizlogf( "Unswapping character back to %s.",GET_NAME(d->swap));
        d->character = d->swap;
        d->connected = CON_PLAYING;
        d->swap = 0;
    } else {

    if (next_to_process == d)
        next_to_process = next_to_process->next;

    if ( d == descriptor_list )
        descriptor_list = descriptor_list->next;
    else {
        /* Locate the previous element */

        for (tmp = descriptor_list; (tmp->next != d) && tmp; tmp = tmp->next) ;
        tmp->next = d->next;
    }

    FREE( d->name );
    FREE( d->showstr_head );
    FREE( d->edit_head );
    FREE( d );   /*** DUMPER CORE ***/
    }
}

void nonblock(int s)
{
    if (fcntl(s, F_SETFL, FNDELAY) == -1)
    {
        perror("Noblock");
        exit(2);
    }
}


void send_to_char(char *messg, struct char_data *ch)

{
    if (ch->desc && messg) write_to_q(messg, &ch->desc->output);
    if (!ch->desc&&!IS_NPC(ch)) wizlogf("Null STC %s",messg);
}



/* attempt to authorize user--EXPERIMENTAL 
 * start_auth
 *
 * Flag the client to show that an attempt to contact the ident server on
 * the client's host.  The connect and subsequently the socket are all put
 * into 'non-blocking' mode.  Should the connect or any later phase of the
 * identifing process fail, it is aborted and the user is given a username
 * of "unknown".
 */
void    start_auth(struct descriptor_data *d)
{
        struct  sockaddr_in sock;
        int     err;/* error & result stuffs */
        int     tlen;

        d->auth_fd = socket(AF_INET, SOCK_STREAM, 0);

        err = errno;
        if (d->auth_fd < 0 && err == EAGAIN) 
            wizlog("Can't allocate fd for authorization check");
        nonblock(d->auth_fd);
        /* Clone incoming host address */

        tlen=sizeof(sock);
        getpeername(d->descriptor, (struct sockaddr *)&sock, &tlen);
        /*sock.sin_addr = d->ip;*/
        sock.sin_port = htons(113);
        sock.sin_family = AF_INET;

        if (connect(d->auth_fd, (struct sockaddr *)&sock, sizeof(sock)) == -1 &&
 errno != EINPROGRESS)
            {
                /*
                 * Identd Denied
                 */
                wizlog("Unable to verify userid");
                close(d->auth_fd);
                d->auth_fd = -1;
                d->auth_state = 0; /* Failure */
                return;

            }
        d->auth_state |= (FLAG_WRAUTH|FLAG_AUTH); /* Successful, but not sent */
        if (d->auth_fd > maxdesc) maxdesc = d->auth_fd;
        return;
}

/*
 * send_auth
 *
 * Send the ident server a query giving "theirport , ourport".
 * The write is only attempted *once* so it is deemed to be a fail if the
 * entire write doesn't write all the data given.  This shouldnt be a
 * problem since the socket should have a write buffer far greater than
 * this message to store it in should problems arise. - Simkin
 */

void    send_auth(struct descriptor_data *d)
{
        struct  sockaddr_in     us, them;
        char    authbuf[32];
        int     ulen, tlen, z;

        tlen = ulen = sizeof(us);

        if (getsockname(d->descriptor, (struct sockaddr *)&us, &ulen) ||
            getpeername(d->descriptor, (struct sockaddr *)&them, &tlen))
            {
                wizlog("auth getsockname error");
                goto authsenderr;
            }

        /* compose request */
        sprintf(authbuf, "%u , %u\r\n",
                (unsigned int)ntohs(them.sin_port),
                (unsigned int)ntohs(us.sin_port));

/*      wizlogf("sending [%s] to auth port %s:113",
                authbuf, inet_ntoa(them.sin_addr),d->auth_fd);
*/        
        z = write(d->auth_fd, authbuf, strlen(authbuf));

        if (z != strlen(authbuf))
            {
                wizlogf("auth request, broken pipe [%d/%d]",z,errno);
authsenderr:
                close(d->auth_fd);
                if (d->auth_fd == maxdesc) maxdesc--;
                d->auth_fd = -1;
                d->auth_state &= ~FLAG_AUTH;        /* Failure/Continue */
            }
        d->auth_state&= ~FLAG_WRAUTH ; /* Successfully sent request */
        return;
}

/*
 * read_auth
 *
 * read the reply (if any) from the ident server we connected to.
 * The actual read processijng here is pretty weak - no handling of the reply
 * if it is fragmented by IP.
 */

void    read_auth(struct descriptor_data *d)
{
        char    *s, *t;
        int     len;                 /*length read*/
        char    ruser[20], system[8];/*remote userid*/
        u_short remp = 0, locp = 0;  /*remote port, local port*/
        
        *system = *ruser = '\0';

        /*
         * Nasty.  Cant allow any other reads from client fd while we're
         * waiting on the authfd to return a full valid string.  Use the
         * client's input buffer to buffer the authd reply. May take more
         * than one read.
         */
        if ((len = read(d->auth_fd, d->abuf + d->auth_inc,
                        sizeof(d->abuf) - 1 - d->auth_inc)) >= 0)
            {
                d->auth_inc += len;
                d->abuf[d->auth_inc] = '\0'; /* Null terminate!*/
            }
        
        if ((len > 0) && (d->auth_inc != (sizeof(d->abuf) - 1)) &&
            (sscanf(d->abuf, "%hd , %hd : USERID : %*[^:]: %10s",
                    &remp, &locp, ruser) == 3))
            {
                s = rindex(d->abuf, ':');
                *s++ = '\0';
                for (t = (rindex(d->abuf, ':') + 1); *t; t++)
                        if (!isspace(*t))
                                break;
                strncpy(system, t, sizeof(system));

                for (t = ruser; *s && (t < ruser + sizeof(ruser)); s++)
                        if (!isspace(*s) && *s != ':')
                                *t++ = *s;
                *t = '\0';
                wizlogf("auth reply ok, incoming user: [%s]", ruser);
            }
        else if (len != 0)
            {
                if (!index(d->abuf, '\n') && !index(d->abuf, '\r')) return;
                wizlogf("bad auth reply: %s", d->abuf);
                *ruser = '\0';
            }
        close(d->auth_fd);
        if (d->auth_fd == maxdesc) --maxdesc;
        d->auth_inc = 0;
        *d->abuf='\0';
        d->auth_fd = -1;
        d->auth_state = 0;
        strncpy(d->user, ruser, sizeof(d->user));
        return;
}


void STCf( const char *format, struct char_data *ch, ... )
{
    va_list ap;
    char buf[640] ;

#if !defined(NeXT)
  va_start(ap,ch);
#else
  va_start(ap, format) ;
#endif

    vsprintf(buf, format, ap) ;
    STC(buf, ch);
}

void STRf( const char *format, int room, ... )
{
    va_list ap;
    char buf[640] ;

    va_start(ap, room) ;
    vsprintf(buf, format, ap) ;


    send_to_room(buf, room);
}
void STAf( const char *format, ... )
{
    va_list ap;
    char buf[640] ;

    va_start(ap, format) ;
    vsprintf(buf, format, ap) ;
    send_to_all(buf);
}

void send_to_all(char *messg)
{
    struct descriptor_data *i;

    if (messg)
        for (i = descriptor_list; i; i = i->next)
            if (!i->connected && !IS_SET(i->character->specials.act, PLR_BUSY))
                write_to_q(messg, &i->output);
}

void send_to_all_regardless(char *messg)

{
    struct descriptor_data *i;

    if (messg)
        for (i = descriptor_list; i; i = i->next)
          write_to_q(messg, &i->output);
}

void send_to_outdoor(char *messg)
{
    struct descriptor_data *i;

    if (messg)
        for (i = descriptor_list; i; i = i->next)
            if (!i->connected && !IS_SET(i->character->specials.act, PLR_BUSY))
                if (IS_OUTSIDE(i->character) && i->connected == CON_PLAYING)
                    write_to_q(messg, &i->output);
}

void send_to_room(char *messg, int room)
{

    struct char_data *i;

    if (messg)
        for (i = ROOM_PEOPLE(room); i; i = i->next_in_room)
            if (i->desc && !IS_SET(i->specials.act, PLR_BUSY))
                if (i->desc->connected == CON_PLAYING)
                    write_to_q(messg, &i->desc->output);
}

void actf(char   * str,
         int      hide_invisible,
         struct   char_data *ch,
         struct   obj_data *obj,
         void   * vict_obj,
         int      type,
         ...)
{
    va_list ap;
    char buf[640] ;

    va_start(ap, type) ;
    vsprintf(buf, str, ap) ;
    act(buf,hide_invisible,ch,obj,vict_obj,type);

}


void act(char   * str,
         int      hide_invisible,
         struct   char_data *ch,
         struct   obj_data *obj,
         void   * vict_obj,
         int      type)

{
    void mprog_act_trigger( char *buf, CHAR_DATA *mob, CHAR_DATA *ch,
                       OBJ_DATA *obj, CHAR_DATA *vict, OBJ_DATA *v_obj);

    int x=0;
    struct parasite_data *p;
    int z;
    struct char_data *to;
    char *tstr;
    struct watch_data *w;
    register char *strp, *point, *i = NULL;
/*
    int c=0;

*/
    char buf[MAX_STRING_LENGTH];
    MOBtrigger=TRUE;

    if ( !str || !*str ) return;

    if (type == TO_VICT) to = (struct char_data *) vict_obj;
    else if (type == TO_CHAR) to = ch;
    else if (GET_INROOM(ch)!=NOWHERE) to = ROOM_PEOPLE(GET_INROOM(ch));
    else {
        wizlogf("Action '%s' nowhere.\n",buf);
        return;
    }

    for (; to; to = to->next_in_room) {
        if (IS_SET(to->specials.act, PLR_BUSY))
            continue ;
        if ( (to->desc ? to->desc->connected == CON_PLAYING : 1) &&
           ((to != ch) || (type == TO_CHAR)) &&
           (CAN_SEE(to, ch) || !hide_invisible ||
           (type == TO_VICT)) && AWAKE(to) &&
           !((type == TO_NOTVICT) && (to == (struct char_data *) vict_obj))) {
            for (strp = str, point = buf;;)
                if (*strp == '$') {
                    switch (*(++strp)) {
                        case 'n': i = PERS(ch, to); break;
                        case 'N': i = PERS((struct char_data *) vict_obj, to); b
reak;
                        case 'm': i = HMHR(ch); break;
                        case 'M': i = HMHR((struct char_data *) vict_obj); break
;
                        case 's': i = HSHR(ch); break;
                        case 'S': i = HSHR((struct char_data *) vict_obj); break
;
                        case 'e': i = HSSH(ch); break;
                        case 'E': i = HSSH((struct char_data *) vict_obj); break
;
                        case 'o': i = OBJN(obj, to); break;
                        case 'O': i = OBJN((struct obj_data *) vict_obj, to); br
eak;
                        case 'p': i = OBJS(obj, to); break;
                        case 'P': i = OBJS((struct obj_data *) vict_obj, to); br
eak;
                        case 'a': i = SANA(obj); break;
                        case 'A': i = SANA((struct obj_data *) vict_obj); break;
                        case 'T': i = (char *) vict_obj; break;
                        case 'F': i = fname((char *) vict_obj); break;
                        case '$': i = "$"; break;
                        default : wizlogf("Illegal $-code to act(): %s", str); b
reak;
                    }
                    if (i == NULL) {if (x) FREE(str);return;}
                    while ( ( *point = *(i++) ) != '\0' ) ++point;
                    ++strp;
                }
                else if (!(*(point++) = *(strp++))) break;

            *(--point) = '\n';
            *(++point) = '\0';

            if (to->desc) write_to_q(CAP(buf), &to->desc->output);
            if (MOBtrigger) mprog_act_trigger( buf, to, ch, obj, (struct char_da
ta *)vict_obj, (struct obj_data *) vict_obj );
        }
        if ((type == TO_VICT) || (type == TO_CHAR)) {
            MOBtrigger = TRUE;
            return;
        }
    }

 tstr=str;
#if 0
 str=str_dupf("%s%s",ROOM_PREFIX(GET_INROOM(ch))?ROOM_PREFIX(GET_INROOM(ch)):"",
str);
 for (p=ROOM_PARASITE(GET_INROOM(ch));p;p=p->next) {
    z=real_room(p->room);
    if (z!=NOWHERE)
    for (to=ROOM_PEOPLE(z); to; to = to->next_in_room) {
        if (IS_SET(to->specials.act, PLR_BUSY))
            continue ;
        if ( (to->desc ? to->desc->connected == CON_PLAYING : 1) &&
           ((to != ch) || (type == TO_CHAR)) &&
           (CAN_SEE(to, ch) || !hide_invisible ||
           (type == TO_VICT)) && AWAKE(to) &&
           !((type == TO_NOTVICT) && (to == (struct char_data *) vict_obj))) {
            for (strp = str, point = buf;;)
                if (*strp == '$') {
                    switch (*(++strp)) {
                        case 'n': i = PERS(ch, to); break;
                        case 'N': i = PERS((struct char_data *) vict_obj, to); b
reak;
                        case 'm': i = HMHR(ch); break;
                        case 'M': i = HMHR((struct char_data *) vict_obj); break

;
                        case 's': i = HSHR(ch); break;
                        case 'S': i = HSHR((struct char_data *) vict_obj); break
;
                        case 'e': i = HSSH(ch); break;
                        case 'E': i = HSSH((struct char_data *) vict_obj); break
;
                        case 'o': i = OBJN(obj, to); break;
                        case 'O': i = OBJN((struct obj_data *) vict_obj, to); br
eak;
                        case 'p': i = OBJS(obj, to); break;
                        case 'P': i = OBJS((struct obj_data *) vict_obj, to); br
eak;
                        case 'a': i = SANA(obj); break;
                        case 'A': i = SANA((struct obj_data *) vict_obj); break;
                        case 'T': i = (char *) vict_obj; break;
                        case 'F': i = fname((char *) vict_obj); break;
                        case '$': i = "$"; break;
                        default : wizlogf("Illegal $-code to act(): %s", str); b
reak;
                    }
                    if (i == NULL) {if (x) FREE(str);return;}
                    while ( ( *point = *(i++) ) != '\0' )

                        ++point;
                    ++strp;
                }
                else if (!(*(point++) = *(strp++))) break;

            *(--point) = '\n';
            *(++point) = '\0';

            if (to->desc) write_to_q(CAP(buf), &to->desc->output);
/*          if (MOBtrigger) mprog_act_trigger( buf, to, ch, obj, vict_obj );
*/
         }
        if ((type == TO_VICT) || (type == TO_CHAR)) {
            MOBtrigger = TRUE;
            FREE(str);
            return;
        }
    }
   }
 for (to=ROOM_PEOPLE(GET_INROOM(ch));to;to=to->next) {
    for (w=to->watching; w; w= w->next) {
            for (strp = str, point = buf;;)
                if (*strp == '$') {
                    switch (*(++strp)) {
                        case 'n': i = PERS(ch, to); break;
                        case 'N': i = PERS((struct char_data *) vict_obj, to); b
reak;
                        case 'm': i = HMHR(ch); break;
                        case 'M': i = HMHR((struct char_data *) vict_obj); break
;
                        case 's': i = HSHR(ch); break;
                        case 'S': i = HSHR((struct char_data *) vict_obj); break
;
                        case 'e': i = HSSH(ch); break;
                        case 'E': i = HSSH((struct char_data *) vict_obj); break
;
                        case 'o': i = OBJN(obj, to); break;
                        case 'O': i = OBJN((struct obj_data *) vict_obj, to); br
eak;
                        case 'p': i = OBJS(obj, to); break;
                        case 'P': i = OBJS((struct obj_data *) vict_obj, to); br
eak;
                        case 'a': i = SANA(obj); break;
                        case 'A': i = SANA((struct obj_data *) vict_obj); break;
                        case 'T': i = (char *) vict_obj; break;
                        case 'F': i = fname((char *) vict_obj); break;
                        case '$': i = "$"; break;
                        default : wizlogf("Illegal $-code to act(): %s", str); b
reak;
                    }
                    if (i == NULL) {if (x) FREE(str);return;}
                    while ( ( *point = *(i++) ) != '\0' ) ++point;
                    ++strp;
                }
                else if (!(*(point++) = *(strp++))) break;

            *(--point) = '\n';
            *(++point) = '\0';

            if (to->desc) write_to_q(CAP(buf), &w->watcher->output);
         }
    }
#endif
#if 0
 if (!IS_ONMATRIX(ch)) {
  for (c=0;c<MAX_EXITS;c++) 
   if (EXIT(ch,c)) {
    if ((CAN_GO(ch,c)) && (EXIT(ch,c)->theysee)){
     FREE(str);
     str=str_dupf("%s%s",EXIT(ch,c)->theysee,tstr);
     z=real_room(EXIT(ch,c)->to_room);
     if (z != NOWHERE) 
      for (to=ROOM_PEOPLE(z); to; to = to->next_in_room) {
        if (IS_SET(to->specials.act, PLR_BUSY))
            continue ;
        if ( (to->desc ? to->desc->connected == CON_PLAYING : 1) &&
           ((to != ch) || (type == TO_CHAR)) &&
           (CAN_SEE(to, ch) || !hide_invisible ||
           (type == TO_VICT)) && AWAKE(to) &&
           !((type == TO_NOTVICT) && (to == (struct char_data *) vict_obj))) {
            for (strp = str, point = buf;;)
                if (*strp == '$') {
                    switch (*(++strp)) {
                        case 'n': i = PERS(ch, to); break;
                        case 'N': i = PERS((struct char_data *) vict_obj, to); b
reak;
                        case 'm': i = HMHR(ch); break;
                        case 'M': i = HMHR((struct char_data *) vict_obj); break
;
                        case 's': i = HSHR(ch); break;
                        case 'S': i = HSHR((struct char_data *) vict_obj); break
;

                        case 'e': i = HSSH(ch); break;
                        case 'E': i = HSSH((struct char_data *) vict_obj); break
;
                        case 'o': i = OBJN(obj, to); break;
                        case 'O': i = OBJN((struct obj_data *) vict_obj, to); br
eak;
                        case 'p': i = OBJS(obj, to); break;
                        case 'P': i = OBJS((struct obj_data *) vict_obj, to); br
eak;
                        case 'a': i = SANA(obj); break;
                        case 'A': i = SANA((struct obj_data *) vict_obj); break;
                        case 'T': i = (char *) vict_obj; break;
                        case 'F': i = fname((char *) vict_obj); break;
                        case '$': i = "$"; break;
                        default : wizlogf("Illegal $-code to act(): %s", str); b
reak;
                    }
                    if (i == NULL) {if (x) FREE(str);return;}
                    while ( ( *point = *(i++) ) != '\0' )
                        ++point;
                    ++strp;
                }
                else if (!(*(point++) = *(strp++))) break;

            *(--point) = '\n';
            *(++point) = '\0';

            if (to->desc) write_to_q(CAP(buf), &to->desc->output);
/*
            if (MOBtrigger) mprog_act_trigger( buf, to, ch, obj, vict_obj );
*/
         }
        if ((type == TO_VICT) || (type == TO_CHAR)) {
            MOBtrigger = TRUE;
            FREE(str);
            return;
        }
     }
    }
   }
  }
    FREE(str);
#endif
    MOBtrigger = TRUE;
}

void night_watchman(void)
{

 int secs;
 char buf[200];

 secs = slow_death - time(0);

 if (secs > 600) return;

 if (death_msg < 1 && secs < 600 && secs > 120) {
    sprintf(buf,"Armageddon shouts \"%s is closing the Realm down in less than 1
0 minutes%s.\"\n",
            down_by,re_boot?" for reboot":"");

    send_to_all(buf);
    death_msg = 1;
    return;
 }
 if (death_msg < 2 && secs < 120 && secs > 60) {
    sprintf(buf,"Armageddon shouts \"%s in less than 2 minutes!\"\n", re_boot ? 

"Reboot" : "Shutdown");
    send_to_all_regardless(buf);
    death_msg = 2;
    return;
 }
 if (death_msg < 3 && secs < 60 && secs > 10) {
    sprintf(buf,"Armageddon shouts \"Less than 1 minute to %s!\"\n",
                re_boot ? "Reboot" : "Shutdown");
    send_to_all_regardless(buf);
    death_msg = 3;
    return;
 }
 if (death_msg < 4 && secs < 10 && secs > 5) {
    sprintf(buf,"Armageddon shouts \"Ten seconds to %s!!!\"\n", re_boot ? "Reboo
t" : "Shutdown");
    send_to_all_regardless(buf);
    death_msg = 4;
    return;
 }
 if (death_msg < 5 && secs < 5) {
    sprintf(buf,"Armageddon shouts \"Five seconds to %s!!!\"\n", re_boot ? "Rebo
ot" : "Shutdown");
    send_to_all_regardless(buf);
    death_msg = 5;
    return;
 }
 if (death_msg < 6 && secs < 2) {
    sprintf(buf,"Armageddon shouts \"One second to %s!!!\"\n", re_boot ? "Reboot
" : "Shutdown");
    send_to_all_regardless(buf);
    death_msg = 6;
    return;
 }
/* May one day use this to schedule reboots at given time of day... PNH
    long tc;
    struct tm *t_info;

    extern int shut_down;

    tc = time(0);
    t_info = localtime(&tc);

    if ((t_info->tm_hour == 8) && (t_info->tm_wday > 0) && (t_info->tm_wday < 6)
) {
        if (t_info->tm_min > 50) {
            wizlog("Leaving the scene for the serious folks.");
            send_to_all("Closing down. Thank you for flying the Land.\n");
            shut_down = 1;
        }
        else if (t_info->tm_min > 40)
            send_to_all("ATTENTION: The Land will shut down in 10 minutes.\n");
        else if (t_info->tm_min > 30)
            send_to_all("Warning: The Land will close in 20 minutes.\n");
    }

*/


}