home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / games / tinymud2.zip / OLDINTER.C < prev    next >
C/C++ Source or Header  |  1990-09-02  |  25KB  |  1,058 lines

  1. #include "copyright.h"
  2.  
  3. #include <stdio.h>
  4. #include <sys/types.h>
  5. #include <sys/file.h>
  6. #include <sys/time.h>
  7. #include <signal.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/wait.h>
  10. #include <fcntl.h>
  11. #include <sys/errno.h>
  12. #include <ctype.h>
  13. #include <sys/socket.h>
  14. #include <netinet/in.h>
  15. #include <netdb.h>
  16.  
  17. #include "db.h"
  18. #include "interface.h"
  19. #include "config.h"
  20.  
  21. extern int    errno;
  22. int    shutdown_flag = 0;
  23.  
  24. static const char *connect_fail = "Either that player does not exist, or has a different password.\n";
  25. #ifndef REGISTRATION
  26. static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
  27. #endif REGISTRATION
  28. static const char *flushed_message = "<Output Flushed>\n";
  29. static const char *shutdown_message = "Going down - Bye\n";
  30.  
  31. struct text_block {
  32.     int            nchars;
  33.     struct text_block    *nxt;
  34.     char            *start;
  35.     char            *buf;
  36. };
  37.  
  38. struct text_queue {
  39.     struct text_block *head;
  40.     struct text_block **tail;
  41. };
  42.  
  43. struct descriptor_data {
  44.         int descriptor;
  45.     int connected;
  46.     dbref player;
  47.     char *output_prefix;
  48.     char *output_suffix;
  49.     int output_size;
  50.     struct text_queue output;
  51.     struct text_queue input;
  52.     char *raw_input;
  53.     char *raw_input_at;
  54.     long last_time;
  55.     long connected_at;
  56.     int quota;
  57.     struct sockaddr_in address;
  58.     const char *hostname;        /* 5/18/90 - Fuzzy */
  59.     struct descriptor_data *next;
  60.     struct descriptor_data *prev;
  61. } *descriptor_list = 0;
  62.  
  63. static int sock;
  64. static int ndescriptors = 0;
  65.  
  66. void process_commands(void);
  67. void shovechars(int port);
  68. void shutdownsock(struct descriptor_data *d);
  69. struct descriptor_data *initializesock(int s, struct sockaddr_in *a,
  70.                        const char *hostname);
  71. void make_nonblocking(int s);
  72. void freeqs(struct descriptor_data *d);
  73. void welcome_user(struct descriptor_data *d);
  74. void do_motd(dbref);
  75. void check_connect(struct descriptor_data *d, const char *msg);
  76. void close_sockets();
  77. const char *addrout (long);
  78. void dump_users(struct descriptor_data *d, char *user);
  79. void set_signals(void);
  80. struct descriptor_data *new_connection(int sock);
  81. void parse_connect (const char *msg, char *command, char *user, char *pass);
  82. void set_userstring (char **userstring, const char *command);
  83. int do_command (struct descriptor_data *d, char *command);
  84. char *strsave (const char *s);
  85. int make_socket(int);
  86. int queue_string(struct descriptor_data *, const char *);
  87. int queue_write(struct descriptor_data *, const char *, int);
  88. int process_output(struct descriptor_data *d);
  89. int process_input(struct descriptor_data *d);
  90. #ifdef CONNECT_MESSAGES
  91. void announce_connect(dbref);
  92. void announce_disconnect(dbref);
  93. #endif CONNECT_MESSAGES
  94. char *time_format_1(long);
  95. char *time_format_2(long);
  96.  
  97. /* Signal handlers */
  98. int bailout (int, int, struct sigcontext *);
  99. int sigshutdown (int, int, struct sigcontext *);
  100. #ifdef DETACH
  101. int logsynch (int, int, struct sigcontext *);
  102. #endif DETACH
  103.  
  104. char *logfile = LOG_FILE;
  105.  
  106. #define MALLOC(result, type, number) do {            \
  107.     if (!((result) = (type *) malloc ((number) * sizeof (type))))    \
  108.         panic("Out of memory");                \
  109.     } while (0)
  110.  
  111. #define FREE(x) (free((void *) x))
  112.  
  113. #ifndef BOOLEXP_DEBUGGING
  114. void main(int argc, char **argv)
  115. {
  116.     if (argc < 3) {
  117.     fprintf(stderr, "Usage: %s infile dumpfile [port [logfile]]\n", *argv);
  118.     exit (1);
  119.     }
  120.  
  121.     if (argc > 4) logfile = argv[4];
  122.  
  123.     set_signals ();
  124.     if (init_game (argv[1], argv[2]) < 0) {
  125.     writelog("INIT: Couldn't load %s!\n", argv[1]);
  126.     exit (2);
  127.     }
  128.  
  129.     /* go do it */
  130.     shovechars (argc >= 4 ? atoi (argv[3]) : TINYPORT);
  131.     close_sockets ();
  132.     dump_database ();
  133.     exit (0);
  134. }
  135. #endif /*BOOLEXP_DEBUGGING*/
  136.  
  137. void set_signals(void)
  138. {
  139. #ifdef DETACH
  140.     int i;
  141.  
  142.     if (fork() != 0) exit(0);
  143.  
  144.     for (i=getdtablesize(); i >= 0; i--)
  145.     (void) close(i);
  146.  
  147.     i = open("/dev/tty", O_RDWR, 0);
  148.     if (i != -1) {
  149.     ioctl(i, TIOCNOTTY, 0);
  150.     close(i);
  151.     }
  152.  
  153.     freopen(logfile, "a", stderr);
  154.     setbuf(stderr, NULL);
  155. #endif DETACH    
  156.     
  157.     /* we don't care about SIGPIPE, we notice it in select() and write() */
  158.     signal (SIGPIPE, SIG_IGN);
  159.  
  160.     /* standard termination signals */
  161.     signal (SIGINT, (void (*)) sigshutdown);
  162.     signal (SIGTERM, (void (*)) sigshutdown);
  163.  
  164. #ifdef DETACH
  165.     /* SIGUSR2 synchronizes the log file */
  166.     signal (SIGUSR2, (void (*)) logsynch);
  167. #else DETACH    
  168.     signal (SIGUSR2, (void (*)) bailout);
  169. #endif DETACH    
  170.  
  171.     /* catch these because we might as well */
  172.     signal (SIGQUIT, (void (*)) bailout);
  173.     signal (SIGILL, (void (*)) bailout);
  174.     signal (SIGTRAP, (void (*)) bailout);
  175.     signal (SIGIOT, (void (*)) bailout);
  176.     signal (SIGEMT, (void (*)) bailout);
  177.     signal (SIGFPE, (void (*)) bailout);
  178.     signal (SIGBUS, (void (*)) bailout);
  179.     signal (SIGSEGV, (void (*)) bailout);
  180.     signal (SIGSYS, (void (*)) bailout);
  181.     signal (SIGXCPU, (void (*)) bailout);
  182.     signal (SIGXFSZ, (void (*)) bailout);
  183.     signal (SIGVTALRM, (void (*)) bailout);
  184.     signal (SIGUSR1, (void (*)) bailout);
  185. }
  186.  
  187. int notify(dbref player, const char *msg)
  188. {
  189.     struct descriptor_data *d;
  190.     int retval = 0;
  191. #ifdef COMPRESS
  192.     extern const char *uncompress(const char *);
  193.  
  194.     msg = uncompress(msg);
  195. #endif /* COMPRESS */
  196.  
  197.     for(d = descriptor_list; d; d = d->next) {
  198.     if (d->connected && d->player == player) {
  199.         queue_string(d, msg);
  200.         queue_write(d, "\n", 1);
  201.         retval = 1;
  202.     }
  203.     }
  204.     return(retval);
  205. }
  206.  
  207. struct timeval timeval_sub(struct timeval now, struct timeval then)
  208. {
  209.     now.tv_sec -= then.tv_sec;
  210.     now.tv_usec -= then.tv_usec;
  211.     if (now.tv_usec < 0) {
  212.     now.tv_usec += 1000000;
  213.     now.tv_sec--;
  214.     }
  215.     return now;
  216. }
  217.  
  218. int msec_diff(struct timeval now, struct timeval then)
  219. {
  220.     return ((now.tv_sec - then.tv_sec) * 1000
  221.         + (now.tv_usec - then.tv_usec) / 1000);
  222. }
  223.  
  224. struct timeval msec_add(struct timeval t, int x)
  225. {
  226.     t.tv_sec += x / 1000;
  227.     t.tv_usec += (x % 1000) * 1000;
  228.     if (t.tv_usec >= 1000000) {
  229.     t.tv_sec += t.tv_usec / 1000000;
  230.     t.tv_usec = t.tv_usec % 1000000;
  231.     }
  232.     return t;
  233. }
  234.  
  235. struct timeval update_quotas(struct timeval last, struct timeval current)
  236. {
  237.     int nslices;
  238.     struct descriptor_data *d;
  239.  
  240.     nslices = msec_diff (current, last) / COMMAND_TIME_MSEC;
  241.  
  242.     if (nslices > 0) {
  243.     for (d = descriptor_list; d; d = d -> next) {
  244.         d -> quota += COMMANDS_PER_TIME * nslices;
  245.         if (d -> quota > COMMAND_BURST_SIZE)
  246.         d -> quota = COMMAND_BURST_SIZE;
  247.     }
  248.     }
  249.     return msec_add (last, nslices * COMMAND_TIME_MSEC);
  250. }
  251.  
  252. void shovechars(int port)
  253. {
  254.     fd_set input_set, output_set;
  255.     long now;
  256.     struct timeval last_slice, current_time;
  257.     struct timeval next_slice;
  258.     struct timeval timeout, slice_timeout;
  259.     int maxd;
  260.     struct descriptor_data *d, *dnext;
  261.     struct descriptor_data *newd;
  262.     int avail_descriptors;
  263.  
  264.     sock = make_socket (port);
  265.     maxd = sock+1;
  266.     gettimeofday(&last_slice, (struct timezone *) 0);
  267.  
  268.     avail_descriptors = getdtablesize() - 4;
  269.     
  270.     while (shutdown_flag == 0) {
  271.     gettimeofday(¤t_time, (struct timezone *) 0);
  272.     last_slice = update_quotas (last_slice, current_time);
  273.  
  274.     process_commands();
  275.  
  276.     if (shutdown_flag)
  277.         break;
  278.     timeout.tv_sec = 1000;
  279.     timeout.tv_usec = 0;
  280.     next_slice = msec_add (last_slice, COMMAND_TIME_MSEC);
  281.     slice_timeout = timeval_sub (next_slice, current_time);
  282.     
  283.     FD_ZERO (&input_set);
  284.     FD_ZERO (&output_set);
  285.     if (ndescriptors < avail_descriptors)
  286.         FD_SET (sock, &input_set);
  287.     for (d = descriptor_list; d; d=d->next) {
  288.         if (d->input.head)
  289.         timeout = slice_timeout;
  290.         else
  291.         FD_SET (d->descriptor, &input_set);
  292.         if (d->output.head)
  293.         FD_SET (d->descriptor, &output_set);
  294.     }
  295.  
  296.     if (select (maxd, &input_set, &output_set,
  297.             (fd_set *) 0, &timeout) < 0) {
  298.         if (errno != EINTR) {
  299.         perror ("select");
  300.         return;
  301.         }
  302.     } else {
  303.         (void) time (&now);
  304.         if (FD_ISSET (sock, &input_set)) {
  305.         if (!(newd = new_connection (sock))) {
  306.             if (errno
  307.             && errno != EINTR
  308.             && errno != EMFILE
  309.             && errno != ENFILE) {
  310.             perror ("new_connection");
  311.             return;
  312.             }
  313.         } else {
  314.         if (newd->descriptor >= maxd)
  315.             maxd = newd->descriptor + 1;
  316.         }
  317.         }
  318.         for (d = descriptor_list; d; d = dnext) {
  319.         dnext = d->next;
  320.         if (FD_ISSET (d->descriptor, &input_set)) {
  321.             d->last_time = now;
  322.             if (!process_input (d)) {
  323.                 shutdownsock (d);
  324.                 continue;
  325.             }
  326.         }
  327.         if (FD_ISSET (d->descriptor, &output_set)) {
  328.             if (!process_output (d)) {
  329.             shutdownsock (d);
  330.             }
  331.         }
  332.         }
  333.     }
  334.     }
  335. }
  336.  
  337. static char hostname[128];
  338.  
  339. struct descriptor_data *new_connection(int sock)
  340. {
  341.     int newsock;
  342.     struct sockaddr_in addr;
  343.     int addr_len;
  344.  
  345.     addr_len = sizeof (addr);
  346.     newsock = accept (sock, (struct sockaddr *) & addr, &addr_len);
  347.     if (newsock < 0) {
  348.     return 0;
  349. #ifdef LOCKOUT
  350.     } else if(forbidden_site(ntohl(addr.sin_addr.s_addr))) {
  351.     writelog("REFUSED CONNECTION from %s(%d) on descriptor %d\n",
  352.         addrout(addr.sin_addr.s_addr),
  353.         ntohs(addr.sin_port), newsock);
  354.     shutdown(newsock, 2);
  355.     close(newsock);
  356.     errno = 0;
  357.     return 0;
  358. #endif /* LOCKOUT */
  359.     } else {
  360.     strcpy (hostname, addrout (addr.sin_addr.s_addr));
  361. #ifdef NOISY_LOG
  362.     writelog("ACCEPT from %s(%d) on descriptor %d\n",
  363.          hostname,
  364.          ntohs (addr.sin_port), newsock);
  365. #endif NOISY_LOG
  366.     return initializesock (newsock, &addr, hostname);
  367.     }
  368. }
  369.  
  370. const char *addrout(long a)
  371. {
  372.     /* New version: returns host names, not octets.  Uses gethostbyaddr. */
  373.     extern char *inet_ntoa(long);
  374.     
  375. #ifdef HOST_NAME
  376.     struct hostent *he;
  377.  
  378.     he = gethostbyaddr(&a,sizeof(a),AF_INET);
  379.     if (he) return he->h_name;
  380.     else return inet_ntoa(a);
  381. #else
  382.     return inet_ntoa(a);
  383. #endif HOST_NAME
  384. }
  385.  
  386.  
  387. void clearstrings(struct descriptor_data *d)
  388. {
  389.     if (d->output_prefix) {
  390.     FREE(d->output_prefix);
  391.     d->output_prefix = 0;
  392.     }
  393.     if (d->output_suffix) {
  394.     FREE(d->output_suffix);
  395.     d->output_suffix = 0;
  396.     }
  397. }
  398.  
  399. void shutdownsock(struct descriptor_data *d)
  400. {
  401.     if (d->connected) {
  402.     writelog("DISCONNECT player %s(%d) %d %s\n",
  403.         db[d->player].name, d->player, d->descriptor, d->hostname);
  404. #ifdef CONNECT_MESSAGES
  405.     announce_disconnect(d->player);
  406. #endif CONNECT_MESSAGES
  407.     } else {
  408.     writelog("DISCONNECT descriptor %d never connected\n",
  409.         d->descriptor);
  410.     }
  411.     clearstrings (d);
  412.     shutdown (d->descriptor, 2);
  413.     close (d->descriptor);
  414.     freeqs (d);
  415.     if (d->prev) d->prev->next = d->next; else descriptor_list = d->next;
  416.     if (d->next) d->next->prev = d->prev;
  417.     FREE (d);
  418.     ndescriptors--;
  419. }
  420.  
  421. struct descriptor_data *initializesock(int s, struct sockaddr_in *a,
  422.                        const char *hostname)
  423. {
  424.     struct descriptor_data *d;
  425.  
  426.     ndescriptors++;
  427.     MALLOC(d, struct descriptor_data, 1);
  428.     d->descriptor = s;
  429.     d->connected = 0;
  430.     make_nonblocking (s);
  431.     d->output_prefix = 0;
  432.     d->output_suffix = 0;
  433.     d->output_size = 0;
  434.     d->output.head = 0;
  435.     d->output.tail = &d->output.head;
  436.     d->input.head = 0;
  437.     d->input.tail = &d->input.head;
  438.     d->raw_input = 0;
  439.     d->raw_input_at = 0;
  440.     d->quota = COMMAND_BURST_SIZE;
  441.     d->last_time = 0;
  442.     d->address = *a;            /* added 5/3/90 SCG */
  443.     d->hostname = alloc_string(hostname);
  444.     if (descriptor_list)
  445.         descriptor_list->prev = d;
  446.     d->next = descriptor_list;
  447.     d->prev = NULL;
  448.     descriptor_list = d;
  449.     
  450.     welcome_user (d);
  451.     return d;
  452. }
  453.  
  454. int make_socket(int port)
  455. {
  456.     int s;
  457.     struct sockaddr_in server;
  458.     int opt;
  459.  
  460.     s = socket (AF_INET, SOCK_STREAM, 0);
  461.     if (s < 0) {
  462.     perror ("creating stream socket");
  463.     exit (3);
  464.     }
  465.     opt = 1;
  466.     if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
  467.             (char *) &opt, sizeof (opt)) < 0) {
  468.     perror ("setsockopt");
  469.     exit (1);
  470.     }
  471.     server.sin_family = AF_INET;
  472.     server.sin_addr.s_addr = INADDR_ANY;
  473.     server.sin_port = htons (port);
  474.     if (bind (s, (struct sockaddr *) & server, sizeof (server))) {
  475.     perror ("binding stream socket");
  476.     close (s);
  477.     exit (4);
  478.     }
  479.     listen (s, 5);
  480.     return s;
  481. }
  482.  
  483. struct text_block *make_text_block(const char *s, int n)
  484. {
  485.     struct text_block *p;
  486.  
  487.     MALLOC(p, struct text_block, 1);
  488.     MALLOC(p->buf, char, n);
  489.     bcopy (s, p->buf, n);
  490.     p->nchars = n;
  491.     p->start = p->buf;
  492.     p->nxt = 0;
  493.     return p;
  494. }
  495.  
  496. void free_text_block (struct text_block *t)
  497. {
  498.     FREE (t->buf);
  499.     FREE ((char *) t);
  500. }
  501.  
  502. void add_to_queue(struct text_queue *q, const char *b, int n)
  503. {
  504.     struct text_block *p;
  505.  
  506.     if (n == 0) return;
  507.  
  508.     p = make_text_block (b, n);
  509.     p->nxt = 0;
  510.     *q->tail = p;
  511.     q->tail = &p->nxt;
  512. }
  513.  
  514. int flush_queue(struct text_queue *q, int n)
  515. {
  516.         struct text_block *p;
  517.     int really_flushed = 0;
  518.     
  519.     n += strlen(flushed_message);
  520.  
  521.     while (n > 0 && (p = q->head)) {
  522.         n -= p->nchars;
  523.         really_flushed += p->nchars;
  524.         q->head = p->nxt;
  525.         free_text_block (p);
  526.     }
  527.     p = make_text_block(flushed_message, strlen(flushed_message));
  528.     p->nxt = q->head;
  529.     q->head = p;
  530.     if (!p->nxt)
  531.         q->tail = &p->nxt;
  532.     really_flushed -= p->nchars;
  533.     return really_flushed;
  534. }
  535.  
  536. int queue_write(struct descriptor_data *d, const char *b, int n)
  537. {
  538.     int space;
  539.  
  540.     space = MAX_OUTPUT - d->output_size - n;
  541.     if (space < 0)
  542.         d->output_size -= flush_queue(&d->output, -space);
  543.     add_to_queue (&d->output, b, n);
  544.     d->output_size += n;
  545.     return n;
  546. }
  547.  
  548. int queue_string(struct descriptor_data *d, const char *s)
  549. {
  550.     return queue_write (d, s, strlen (s));
  551. }
  552.  
  553. int process_output(struct descriptor_data *d)
  554. {
  555.     struct text_block **qp, *cur;
  556.     int cnt;
  557.  
  558.     for (qp = &d->output.head; cur = *qp;) {
  559.     cnt = write (d->descriptor, cur -> start, cur -> nchars);
  560.     if (cnt < 0) {
  561.         if (errno == EWOULDBLOCK)
  562.         return 1;
  563.         return 0;
  564.     }
  565.     d->output_size -= cnt;
  566.     if (cnt == cur -> nchars) {
  567.         if (!cur -> nxt)
  568.         d->output.tail = qp;
  569.         *qp = cur -> nxt;
  570.         free_text_block (cur);
  571.         continue;        /* do not adv ptr */
  572.     }
  573.     cur -> nchars -= cnt;
  574.     cur -> start += cnt;
  575.     break;
  576.     }
  577.     return 1;
  578. }
  579.  
  580. void make_nonblocking(int s)
  581. {
  582.     if (fcntl (s, F_SETFL, FNDELAY) == -1) {
  583.     perror ("make_nonblocking: fcntl");
  584.     panic ("FNDELAY fcntl failed");
  585.     }
  586. }
  587.  
  588. void freeqs(struct descriptor_data *d)
  589. {
  590.     struct text_block *cur, *next;
  591.  
  592.     cur = d->output.head;
  593.     while (cur) {
  594.     next = cur -> nxt;
  595.     free_text_block (cur);
  596.     cur = next;
  597.     }
  598.     d->output.head = 0;
  599.     d->output.tail = &d->output.head;
  600.  
  601.     cur = d->input.head;
  602.     while (cur) {
  603.     next = cur -> nxt;
  604.     free_text_block (cur);
  605.     cur = next;
  606.     }
  607.     d->input.head = 0;
  608.     d->input.tail = &d->input.head;
  609.  
  610.     if (d->raw_input)
  611.         FREE (d->raw_input);
  612.     d->raw_input = 0;
  613.     d->raw_input_at = 0;
  614. }
  615.  
  616. void welcome_user(struct descriptor_data *d)
  617.     queue_string (d, WELCOME_MESSAGE);
  618. # ifdef CONNECT_FILE
  619.     do_connect_msg(d, CONNECT_FILE);
  620. # endif
  621. }
  622.  
  623. void goodbye_user(struct descriptor_data *d)
  624. {
  625.     write (d->descriptor, LEAVE_MESSAGE, strlen (LEAVE_MESSAGE));
  626. }
  627.  
  628. char *strsave (const char *s)
  629. {
  630.     char *p;
  631.  
  632.     MALLOC (p, char, strlen(s) + 1);
  633.  
  634.     if (p)
  635.     strcpy (p, s);
  636.     return p;
  637. }
  638.  
  639. void save_command (struct descriptor_data *d, const char *command)
  640. {
  641.     add_to_queue (&d->input, command, strlen(command)+1);
  642. }
  643.  
  644. int process_input (struct descriptor_data *d)
  645. {
  646.     char buf[1024];
  647.     int got;
  648.     char *p, *pend, *q, *qend;
  649.  
  650.     got = read (d->descriptor, buf, sizeof buf);
  651.     if (got <= 0)
  652.     return 0;
  653.     if (!d->raw_input) {
  654.     MALLOC(d->raw_input,char,MAX_COMMAND_LEN);
  655.     d->raw_input_at = d->raw_input;
  656.     }
  657.     p = d->raw_input_at;
  658.     pend = d->raw_input + MAX_COMMAND_LEN - 1;
  659.     for (q=buf, qend = buf + got; q < qend; q++) {
  660.     if (*q == '\n') {
  661.         *p = '\0';
  662.         if (p > d->raw_input)
  663.         save_command (d, d->raw_input);
  664.         p = d->raw_input;
  665.     } else if (p < pend && isascii (*q) && isprint (*q)) {
  666.         *p++ = *q;
  667.     }
  668.     }
  669.     if(p > d->raw_input) {
  670.     d->raw_input_at = p;
  671.     } else {
  672.     FREE(d->raw_input);
  673.     d->raw_input = 0;
  674.     d->raw_input_at = 0;
  675.     }
  676.     return 1;
  677. }
  678.  
  679. void set_userstring (char **userstring, const char *command)
  680. {
  681.     if (*userstring) {
  682.     FREE(*userstring);
  683.     *userstring = 0;
  684.     }
  685.     while (*command && isascii (*command) && isspace (*command))
  686.     command++;
  687.     if (*command)
  688.     *userstring = strsave (command);
  689. }
  690.  
  691. void process_commands(void)
  692. {
  693.     int nprocessed;
  694.     struct descriptor_data *d, *dnext;
  695.     struct text_block *t;
  696.  
  697.     do {
  698.     nprocessed = 0;
  699.     for (d = descriptor_list; d; d = dnext) {
  700.         dnext = d->next;
  701.         if (d -> quota > 0 && (t = d -> input.head)) {
  702.         d -> quota--;
  703.         nprocessed++;
  704.         if (!do_command (d, t -> start)) {
  705.             shutdownsock (d);
  706.         } else {
  707.             d -> input.head = t -> nxt;
  708.             if (!d -> input.head)
  709.             d -> input.tail = &d -> input.head;
  710.             free_text_block (t);
  711.         }
  712.         }
  713.     }
  714.     } while (nprocessed > 0);
  715. }
  716.  
  717. int do_command (struct descriptor_data *d, char *command)
  718. {
  719.     if (!strcmp (command, QUIT_COMMAND)) {
  720.     goodbye_user (d);
  721.     return 0;
  722.     } else if (!strncmp (command, WHO_COMMAND, strlen(WHO_COMMAND))) {
  723.     if (d->output_prefix) {
  724.         queue_string (d, d->output_prefix);
  725.         queue_write (d, "\n", 1);
  726.     }
  727.     dump_users (d, command + strlen(WHO_COMMAND));
  728.     if (d->output_suffix) {
  729.         queue_string (d, d->output_suffix);
  730.         queue_write (d, "\n", 1);
  731.     }
  732.     } else if (d->connected &&
  733.            !strncmp (command, PREFIX_COMMAND, strlen (PREFIX_COMMAND))) {
  734. #ifdef ROBOT_MODE
  735.     if (!Robot(d->player)) { 
  736. #ifndef TINKER
  737.         notify(d->player,
  738.            "Only robots can use OUTPUTPREFIX; contact a Wizard.");
  739. #else TINKER
  740.         notify(d->player,
  741.            "Only robots can use OUTPUTPREFIX; contact a Tinker.");
  742. #endif TINKER
  743.         return 1;
  744.     }
  745.     if (!d->connected) return 1;
  746. #endif ROBOT_MODE
  747.     set_userstring (&d->output_prefix, command+strlen(PREFIX_COMMAND));
  748.     } else if (d->connected &&
  749.            !strncmp (command, SUFFIX_COMMAND, strlen (SUFFIX_COMMAND))) {
  750. #ifdef ROBOT_MODE
  751.     if (!Robot(d->player)) { 
  752. #ifndef TINKER
  753.         notify(d->player,
  754.            "Only robots can use OUTPUTSUFFIX; contact a Wizard.");
  755. #else TINKER
  756.         notify(d->player,
  757.            "Only robots can use OUTPUTSUFFIX; contact a Tinker.");
  758. #endif TINKER
  759.         return 1;
  760.     }
  761. #endif ROBOT_MODE
  762.     set_userstring (&d->output_suffix, command+strlen(SUFFIX_COMMAND));
  763.     } else {
  764.     if (d->connected) {
  765.         if (d->output_prefix) {
  766.         queue_string (d, d->output_prefix);
  767.         queue_write (d, "\n", 1);
  768.         }
  769.         process_command (d->player, command);
  770.         if (d->output_suffix) {
  771.         queue_string (d, d->output_suffix);
  772.         queue_write (d, "\n", 1);
  773.         }
  774.     } else {
  775.         check_connect (d, command);
  776.     }
  777.     }
  778.     return 1;
  779. }
  780.  
  781. void check_connect (struct descriptor_data *d, const char *msg)
  782. {
  783.     char command[MAX_COMMAND_LEN];
  784.     char user[MAX_COMMAND_LEN];
  785.     char password[MAX_COMMAND_LEN];
  786.     dbref player;
  787.  
  788.     parse_connect (msg, command, user, password);
  789.  
  790.     if (!strncmp (command, "co", 2)) {
  791.     player = connect_player (user, password);
  792.     if (player == NOTHING) {
  793.         queue_string (d, connect_fail);
  794.         writelog("FAILED CONNECT %s on %d %s\n",
  795.              user, d->descriptor, d->hostname);
  796.     } else {
  797.         writelog("CONNECTED %s(%d) on %d %s\n",
  798.              db[player].name, player, d->descriptor, d->hostname);
  799.         d->connected = 1;
  800.         d->connected_at = time(NULL);
  801.         d->player = player;
  802.  
  803.         do_motd (player);
  804.         do_look_around (player);
  805. #ifdef CONNECT_MESSAGES
  806.         announce_connect(player);
  807. #endif CONNECT_MESSAGES
  808.     }
  809.     } else if (!strncmp (command, "cr", 2)) {
  810. #ifndef REGISTRATION    
  811.     player = create_player (user, password);
  812.     if (player == NOTHING) {
  813.         queue_string (d, create_fail);
  814.         writelog("FAILED CREATE %s on %d %s\n",
  815.              user, d->descriptor, d->hostname);
  816.     } else {
  817.         writelog("CREATED %s(%d) on descriptor %d %s\n",
  818.              db[player].name, player, d->descriptor, d->hostname);
  819.         d->connected = 1;
  820.         d->connected_at = time(NULL);
  821.         d->player = player;
  822.  
  823.         do_motd (player);
  824.         do_look_around (player);
  825. #ifdef CONNECT_MESSAGES
  826.         announce_connect(player);
  827. #endif CONNECT_MESSAGES
  828.     }
  829. #else
  830.     queue_string (d, REGISTER_MESSAGE);
  831. #endif REGISTRATION    
  832.     } else {
  833.     welcome_user (d);
  834.     }
  835. }
  836.  
  837. void parse_connect (const char *msg, char *command, char *user, char *pass)
  838. {
  839.     char *p;
  840.  
  841.     while (*msg && isascii(*msg) && isspace (*msg))
  842.     msg++;
  843.     p = command;
  844.     while (*msg && isascii(*msg) && !isspace (*msg))
  845.     *p++ = *msg++;
  846.     *p = '\0';
  847.     while (*msg && isascii(*msg) && isspace (*msg))
  848.     msg++;
  849.     p = user;
  850.     while (*msg && isascii(*msg) && !isspace (*msg))
  851.     *p++ = *msg++;
  852.     *p = '\0';
  853.     while (*msg && isascii(*msg) && isspace (*msg))
  854.     msg++;
  855.     p = pass;
  856.     while (*msg && isascii(*msg) && !isspace (*msg))
  857.     *p++ = *msg++;
  858.     *p = '\0';
  859. }
  860.  
  861. void close_sockets(void)
  862. {
  863.     struct descriptor_data *d, *dnext;
  864.  
  865.     for (d = descriptor_list; d; d = dnext) {
  866.     dnext = d->next;
  867.     write (d->descriptor, shutdown_message, strlen (shutdown_message));
  868.     if (shutdown (d->descriptor, 2) < 0)
  869.         perror ("shutdown");
  870.     close (d->descriptor);
  871.     }
  872.     close (sock);
  873. }
  874.  
  875. void emergency_shutdown(void)
  876. {
  877.     close_sockets();
  878. }
  879.  
  880. void boot_off(dbref player)
  881. {
  882.     struct descriptor_data *d, *dnext;
  883.     for (d = descriptor_list; d; d = dnext) {
  884.       dnext = d->next;
  885.       if (d->connected && d->player == player) {
  886.           process_output(d);
  887.       shutdownsock(d);
  888.       }
  889.     }
  890. }
  891.  
  892. int bailout (int sig, int code, struct sigcontext *scp)
  893. {
  894.     long *ptr;
  895.     int i;
  896.     
  897.     writelog("BAILOUT: caught signal %d code %d\n", sig, code);
  898.     ptr = (long *) scp;
  899.     for (i=0; i<sizeof(struct sigcontext); i++)
  900.     writelog("  %08lx\n", *ptr);
  901.     panic("PANIC on spurious signal");
  902.     _exit(7);
  903.     return 0;
  904. }
  905.  
  906. int sigshutdown (int sig, int code, struct sigcontext *scp)
  907. {
  908.     writelog("SHUTDOWN: on signal %d code %d\n", sig, code);
  909.     shutdown_flag = 1;
  910.     return 0;
  911. }
  912.  
  913. #ifdef DETACH
  914. int logsynch (int sig, int code, struct sigcontext *scp)
  915. {
  916.     freopen(logfile, "a", stderr);
  917.     setbuf(stderr, NULL);
  918.     writelog("log file reopened\n");
  919.     return 0;
  920. }
  921. #endif DETACH    
  922.  
  923. void dump_users(struct descriptor_data *e, char *user)
  924. {
  925.     struct descriptor_data *d;
  926.     long now;
  927.     char buf[1024];
  928.     int wizard;
  929.     int reversed, tabular;
  930.  
  931.     while (*user && isspace(*user)) user++;
  932.     if (!*user) user = NULL;
  933.  
  934.     reversed = e->connected && Flag(e->player,REVERSED_WHO);
  935.     tabular = e->connected && Flag(e->player,TABULAR_WHO);
  936.  
  937.     (void) time (&now);
  938.     queue_string(e,
  939.          tabular ? "Player Name          On For Idle\n" : "Current Players:\n");
  940. #ifdef GOD_MODE
  941.     wizard = e->connected && God(e->player);
  942. #else GOD_MODE    
  943.     wizard = e->connected && Wizard(e->player);
  944. #endif GOD_MODE
  945.  
  946.     d = descriptor_list;
  947.     
  948.     if (reversed)
  949.     while (d && d->next) d = d->next;
  950.  
  951.     while (d) {
  952.     if (d->connected &&
  953.         (!user || string_prefix(db[d->player].name, user))) {
  954.         if (tabular) {
  955.         sprintf(buf,"%-16s %10s %4s",
  956.             db[d->player].name,
  957.             time_format_1(now - d->connected_at),
  958.             time_format_2(now - d->last_time));
  959.         if (wizard) 
  960.             sprintf(buf+strlen(buf),
  961.                 " %s", d->hostname);
  962.         } else {
  963.         sprintf(buf,
  964.             "%s idle %d seconds",
  965.             db[d->player].name,
  966.             now - d->last_time);
  967.         if (wizard) 
  968.             sprintf(buf+strlen(buf),
  969.                 " from host %s", d->hostname);
  970.         }
  971.         strcat(buf,"\n");
  972.         queue_string (e, buf);
  973.     }
  974.     if (reversed) d = d->prev; else d = d->next;
  975.     }
  976. }
  977.  
  978. char *time_format_1(long dt)
  979. {
  980.     register struct tm *delta;
  981.     static char buf[64];
  982.     
  983.     delta = gmtime(&dt);
  984.     if (delta->tm_yday > 0)
  985.     sprintf(buf, "%dd %02d:%02d",
  986.         delta->tm_yday, delta->tm_hour, delta->tm_min);
  987.     else
  988.     sprintf(buf, "%02d:%02d",
  989.         delta->tm_hour, delta->tm_min);
  990.     return buf;
  991. }
  992.  
  993. char *time_format_2(long dt)
  994. {
  995.     register struct tm *delta;
  996.     static char buf[64];
  997.     
  998.     delta = gmtime(&dt);
  999.     if (delta->tm_yday > 0)
  1000.     sprintf(buf, "%dd", delta->tm_yday);
  1001.     else if (delta->tm_hour > 0)
  1002.     sprintf(buf, "%dh", delta->tm_hour);
  1003.     else if (delta->tm_min > 0)
  1004.     sprintf(buf, "%dm", delta->tm_min);
  1005.     else
  1006.     sprintf(buf, "%ds", delta->tm_sec);
  1007.     return buf;
  1008. }
  1009.  
  1010. #ifdef CONNECT_MESSAGES
  1011. void announce_connect(dbref player)
  1012. {
  1013.     dbref loc;
  1014.     char buf[BUFFER_LEN];
  1015.  
  1016.     if ((loc = getloc(player)) == NOTHING) return;
  1017.     if (Dark(player) || Dark(loc)) return;
  1018.  
  1019.     sprintf(buf, "%s has connected.", db[player].name);
  1020.  
  1021.     notify_except(db[loc].contents, player, buf);
  1022. }
  1023.  
  1024. void announce_disconnect(dbref player)
  1025. {
  1026.     dbref loc;
  1027.     char buf[BUFFER_LEN];
  1028.  
  1029.     if ((loc = getloc(player)) == NOTHING) return;
  1030.     if (Dark(player) || Dark(loc)) return;
  1031.  
  1032.     sprintf(buf, "%s has disconnected.", db[player].name);
  1033.  
  1034.     notify_except(db[loc].contents, player, buf);
  1035. }
  1036. #endif CONNECT_MESSAGES
  1037. int do_connect_msg(struct descriptor_data * d, const char *filename)
  1038. {
  1039.   FILE           *f;
  1040.   char            buf[BUFFER_LEN];
  1041.   char           *p;
  1042.  
  1043.   if ((f = fopen(filename, "r")) == NULL)
  1044.   {
  1045.     return (0);
  1046.   } else
  1047.   {
  1048.     while (fgets(buf, sizeof buf, f))
  1049.     {
  1050.       queue_string(d, (char *)buf);
  1051.  
  1052.     }
  1053.     fclose(f);
  1054.     return (1);
  1055.   }
  1056. }
  1057.