Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

comm.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
00003  *  Michael Seifert, Hans Henrik Strfeldt, Tom Madsen, and Katja Nyboe.    *
00004  *                                                                         *
00005  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
00006  *  Chastain, Michael Quan, and Mitchell Tse.                              *
00007  *                                                                         *
00008  *  In order to use any part of this Merc Diku Mud, you must comply with   *
00009  *  both the original Diku license in 'license.doc' as well the Merc       *
00010  *  license in 'license.txt'.  In particular, you may not remove either of *
00011  *  these copyright notices.                                               *
00012  *                                                                         *
00013  *  Thanks to abaddon for proof-reading our comm.c and pointing out bugs.  *
00014  *  Any remaining bugs are, of course, our work, not his.  :)              *
00015  *                                                                         *
00016  *  Much time and thought has gone into this software and you are          *
00017  *  benefitting.  We hope that you share your changes too.  What goes      *
00018  *  around, comes around.                                                  *
00019  ***************************************************************************/
00020 
00021 /***************************************************************************
00022 *    ROM 2.4 is copyright 1993-1998 Russ Taylor                             *
00023 *    ROM has been brought to you by the ROM consortium                      *
00024 *        Russ Taylor (rtaylor@hypercube.org)                                *
00025 *        Gabrielle Taylor (gtaylor@hypercube.org)                           *
00026 *        Brian Moore (zump@rom.org)                                         *
00027 *    By using this code, you have agreed to follow the terms of the         *
00028 *    ROM license, in the file Rom24/doc/rom.license                         *
00029 ****************************************************************************/
00030 
00031 /*
00032  * This file contains all of the OS-dependent stuff:
00033  *   startup, signals, BSD sockets for tcp/ip, i/o, timing.
00034  *
00035  * The data flow for input is:
00036  *    Game_loop ---> Read_from_descriptor ---> Read
00037  *    Game_loop ---> Read_from_buffer
00038  *
00039  * The data flow for output is:
00040  *    Game_loop ---> Process_Output ---> Write_to_descriptor -> Write
00041  *
00042  * The OS-dependent functions are Read_from_descriptor and Write_to_descriptor.
00043  * -- Furey  26 Jan 1993
00044  */
00045 
00046 #if defined(macintosh)
00047 #include <types.h>
00048 #else
00049 #include <sys/types.h>
00050 #include <sys/time.h>
00051 #endif
00052 
00053 #include <ctype.h>
00054 #include <errno.h>
00055 #include <stdio.h>
00056 #include <string.h>
00057 #include <stdlib.h>
00058 #include <time.h>
00059 #include <signal.h>
00060 #include <unistd.h>                /* OLC -- for close read write etc */
00061 #include <stdarg.h>                /* printf_to_char */
00062 
00063 #include "merc.h"
00064 #include "interp.h"
00065 #include "recycle.h"
00066 #include "tables.h"
00067 
00068 /*
00069  * Malloc debugging stuff.
00070  */
00071 #if defined(sun)
00072 #undef MALLOC_DEBUG
00073 #endif
00074 
00075 #if defined(MALLOC_DEBUG)
00076 #include <malloc.h>
00077 extern int malloc_debug args ((int));
00078 extern int malloc_verify args ((void));
00079 #endif
00080 
00081 
00082 
00083 /*
00084  * Signal handling.
00085  * Apollo has a problem with __attribute(atomic) in signal.h,
00086  *   I dance around it.
00087  */
00088 #if defined(apollo)
00089 #define __attribute(x)
00090 #endif
00091 
00092 #if defined(unix)
00093 #include <signal.h>
00094 #endif
00095 
00096 #if defined(apollo)
00097 #undef __attribute
00098 #endif
00099 
00100 
00101 
00102 /*
00103  * Socket and TCP/IP stuff.
00104  */
00105 #if    defined(macintosh) || defined(MSDOS)
00106 const char echo_off_str[] = { '\0' };
00107 const char echo_on_str[] = { '\0' };
00108 const char go_ahead_str[] = { '\0' };
00109 #endif
00110 
00111 #if    defined(unix)
00112 #include <fcntl.h>
00113 #include <netdb.h>
00114 #include <netinet/in.h>
00115 #include <sys/socket.h>
00116 #include <netinet/in.h>
00117 #include <arpa/inet.h>
00118 #include "telnet.h"
00119 const char echo_off_str[] = { IAC, WILL, TELOPT_ECHO, '\0' };
00120 const char echo_on_str[] = { IAC, WONT, TELOPT_ECHO, '\0' };
00121 const char go_ahead_str[] = { IAC, GA, '\0' };
00122 #endif
00123 
00124 
00125 
00126 /*
00127  * OS-dependent declarations.
00128  */
00129 #if    defined(_AIX)
00130 #include <sys/select.h>
00131 int accept args ((int s, struct sockaddr * addr, int *addrlen));
00132 int bind args ((int s, struct sockaddr * name, int namelen));
00133 void bzero args ((char *b, int length));
00134 int getpeername args ((int s, struct sockaddr * name, int *namelen));
00135 int getsockname args ((int s, struct sockaddr * name, int *namelen));
00136 int gettimeofday args ((struct timeval * tp, struct timezone * tzp));
00137 int listen args ((int s, int backlog));
00138 int setsockopt args ((int s, int level, int optname, void *optval,
00139                       int optlen));
00140 int socket args ((int domain, int type, int protocol));
00141 #endif
00142 
00143 #if    defined(apollo)
00144 #include <unistd.h>
00145 void bzero args ((char *b, int length));
00146 #endif
00147 
00148 #if    defined(__hpux)
00149 int accept args ((int s, void *addr, int *addrlen));
00150 int bind args ((int s, const void *addr, int addrlen));
00151 void bzero args ((char *b, int length));
00152 int getpeername args ((int s, void *addr, int *addrlen));
00153 int getsockname args ((int s, void *name, int *addrlen));
00154 int gettimeofday args ((struct timeval * tp, struct timezone * tzp));
00155 int listen args ((int s, int backlog));
00156 int setsockopt args ((int s, int level, int optname,
00157                       const void *optval, int optlen));
00158 int socket args ((int domain, int type, int protocol));
00159 #endif
00160 
00161 #if    defined(interactive)
00162 #include <net/errno.h>
00163 #include <sys/fnctl.h>
00164 #endif
00165 
00166 #if    defined(linux)
00167 /* 
00168     Linux shouldn't need these. If you have a problem compiling, try
00169     uncommenting these functions.
00170 */
00171 /*
00172 int    accept        args( ( int s, struct sockaddr *addr, int *addrlen ) );
00173 int    bind        args( ( int s, struct sockaddr *name, int namelen ) );
00174 int    getpeername    args( ( int s, struct sockaddr *name, int *namelen ) );
00175 int    getsockname    args( ( int s, struct sockaddr *name, int *namelen ) );
00176 int    listen        args( ( int s, int backlog ) );
00177 */
00178 
00179 int close args ((int fd));
00180 int gettimeofday args ((struct timeval * tp, struct timezone * tzp));
00181 /* int    read        args( ( int fd, char *buf, int nbyte ) ); */
00182 int select args ((int width, fd_set * readfds, fd_set * writefds,
00183                   fd_set * exceptfds, struct timeval * timeout));
00184 int socket args ((int domain, int type, int protocol));
00185 /* int    write        args( ( int fd, char *buf, int nbyte ) ); *//* read,write in unistd.h */
00186 #endif
00187 
00188 #if    defined(macintosh)
00189 #include <console.h>
00190 #include <fcntl.h>
00191 #include <unix.h>
00192 struct timeval {
00193     time_t tv_sec;
00194     time_t tv_usec;
00195 };
00196 #if    !defined(isascii)
00197 #define    isascii(c)        ( (c) < 0200 )
00198 #endif
00199 static long theKeys[4];
00200 
00201 int gettimeofday args ((struct timeval * tp, void *tzp));
00202 #endif
00203 
00204 #if    defined(MIPS_OS)
00205 extern int errno;
00206 #endif
00207 
00208 #if    defined(MSDOS)
00209 int gettimeofday args ((struct timeval * tp, void *tzp));
00210 int kbhit args ((void));
00211 #endif
00212 
00213 #if    defined(NeXT)
00214 int close args ((int fd));
00215 int fcntl args ((int fd, int cmd, int arg));
00216 #if    !defined(htons)
00217 u_short htons args ((u_short hostshort));
00218 #endif
00219 #if    !defined(ntohl)
00220 u_long ntohl args ((u_long hostlong));
00221 #endif
00222 int read args ((int fd, char *buf, int nbyte));
00223 int select args ((int width, fd_set * readfds, fd_set * writefds,
00224                   fd_set * exceptfds, struct timeval * timeout));
00225 int write args ((int fd, char *buf, int nbyte));
00226 #endif
00227 
00228 #if    defined(sequent)
00229 int accept args ((int s, struct sockaddr * addr, int *addrlen));
00230 int bind args ((int s, struct sockaddr * name, int namelen));
00231 int close args ((int fd));
00232 int fcntl args ((int fd, int cmd, int arg));
00233 int getpeername args ((int s, struct sockaddr * name, int *namelen));
00234 int getsockname args ((int s, struct sockaddr * name, int *namelen));
00235 int gettimeofday args ((struct timeval * tp, struct timezone * tzp));
00236 #if    !defined(htons)
00237 u_short htons args ((u_short hostshort));
00238 #endif
00239 int listen args ((int s, int backlog));
00240 #if    !defined(ntohl)
00241 u_long ntohl args ((u_long hostlong));
00242 #endif
00243 int read args ((int fd, char *buf, int nbyte));
00244 int select args ((int width, fd_set * readfds, fd_set * writefds,
00245                   fd_set * exceptfds, struct timeval * timeout));
00246 int setsockopt args ((int s, int level, int optname, caddr_t optval,
00247                       int optlen));
00248 int socket args ((int domain, int type, int protocol));
00249 int write args ((int fd, char *buf, int nbyte));
00250 #endif
00251 
00252 /* This includes Solaris Sys V as well */
00253 #if defined(sun)
00254 int accept args ((int s, struct sockaddr * addr, int *addrlen));
00255 int bind args ((int s, struct sockaddr * name, int namelen));
00256 void bzero args ((char *b, int length));
00257 int close args ((int fd));
00258 int getpeername args ((int s, struct sockaddr * name, int *namelen));
00259 int getsockname args ((int s, struct sockaddr * name, int *namelen));
00260 int listen args ((int s, int backlog));
00261 int read args ((int fd, char *buf, int nbyte));
00262 int select args ((int width, fd_set * readfds, fd_set * writefds,
00263                   fd_set * exceptfds, struct timeval * timeout));
00264 
00265 #if !defined(__SVR4)
00266 int gettimeofday args ((struct timeval * tp, struct timezone * tzp));
00267 
00268 #if defined(SYSV)
00269 int setsockopt args ((int s, int level, int optname,
00270                       const char *optval, int optlen));
00271 #else
00272 int setsockopt args ((int s, int level, int optname, void *optval,
00273                       int optlen));
00274 #endif
00275 #endif
00276 int socket args ((int domain, int type, int protocol));
00277 int write args ((int fd, char *buf, int nbyte));
00278 #endif
00279 
00280 #if defined(ultrix)
00281 int accept args ((int s, struct sockaddr * addr, int *addrlen));
00282 int bind args ((int s, struct sockaddr * name, int namelen));
00283 void bzero args ((char *b, int length));
00284 int close args ((int fd));
00285 int getpeername args ((int s, struct sockaddr * name, int *namelen));
00286 int getsockname args ((int s, struct sockaddr * name, int *namelen));
00287 int gettimeofday args ((struct timeval * tp, struct timezone * tzp));
00288 int listen args ((int s, int backlog));
00289 int read args ((int fd, char *buf, int nbyte));
00290 int select args ((int width, fd_set * readfds, fd_set * writefds,
00291                   fd_set * exceptfds, struct timeval * timeout));
00292 int setsockopt args ((int s, int level, int optname, void *optval,
00293                       int optlen));
00294 int socket args ((int domain, int type, int protocol));
00295 int write args ((int fd, char *buf, int nbyte));
00296 #endif
00297 
00298 
00299 
00300 /*
00301  * Global variables.
00302  */
00303 DESCRIPTOR_DATA *descriptor_list;    /* All open descriptors     */
00304 DESCRIPTOR_DATA *d_next;        /* Next descriptor in loop  */
00305 FILE *fpReserve;                /* Reserved file handle     */
00306 bool god;                        /* All new chars are gods!  */
00307 bool merc_down;                    /* Shutdown         */
00308 bool global_peace;      /* Peace to stop all fighting */
00309 bool is_building_area;      /* lock so I wont copyover now while
00310                    people are building. */
00311 bool isAreaPort;
00312 
00313 bool wizlock;                    /* Game is wizlocked        */
00314 bool isCopyover;
00315 int Copyovercount=3;
00316 CHAR_DATA * CopyoverPerson;
00317 char *CopyoverReason;
00318 bool newlock;                    /* Game is newlocked        */
00319 char str_boot_time[MAX_INPUT_LENGTH];
00320 time_t current_time;            /* time of this pulse */
00321 bool MOBtrigger = TRUE;            /* act() switch                 */
00322 bool just_rained;
00323 
00324 /*
00325  * OS-dependent local functions.
00326  */
00327 #if defined(macintosh) || defined(MSDOS)
00328 void game_loop_mac_msdos args ((void));
00329 bool read_from_descriptor args ((DESCRIPTOR_DATA * d));
00330 bool write_to_descriptor args ((int desc, char *txt, int length));
00331 #endif
00332 
00333 #if defined(unix)
00334 void game_loop_unix args ((int control));
00335 int init_socket args ((int port));
00336 void init_descriptor args ((int control));
00337 bool read_from_descriptor args ((DESCRIPTOR_DATA * d));
00338 bool write_to_descriptor args ((int desc, char *txt, int length));
00339 #endif
00340 
00341 
00342 
00343 
00344 /*
00345  * Other local functions (OS-independent).
00346  */
00347 bool check_parse_name args ((char *name));
00348 bool check_reconnect args ((DESCRIPTOR_DATA * d, char *name, bool fConn));
00349 bool check_playing args ((DESCRIPTOR_DATA * d, char *name));
00350 int main args ((int argc, char **argv));
00351 void nanny args ((DESCRIPTOR_DATA * d, char *argument));
00352 bool process_output args ((DESCRIPTOR_DATA * d, bool fPrompt));
00353 void read_from_buffer args ((DESCRIPTOR_DATA * d));
00354 void stop_idling args ((CHAR_DATA * ch));
00355 void bust_a_prompt args ((CHAR_DATA * ch));
00356 
00357 void send_to_all_copyover args ((char *argument));
00358 void send_to_all args ((char *cch, char *argument));
00359 /* Needs to be global because of do_copyover */
00360 int port, control;
00361 
00362 /* Put global mud config values here. Look at qmconfig command for clues.     */
00363 /*   -- JR 09/23/2000                                                         */
00364 /* Set values for all but IP address in ../area/qmconfig.rc file.             */
00365 /*   -- JR 05/10/2001                                                         */
00366 int mud_ansiprompt, mud_ansicolor, mud_telnetga;
00367 
00368 /* Set this to the IP address you want to listen on (127.0.0.1 is good for    */
00369 /* paranoid types who don't want the 'net at large peeking at their MUD)      */
00370 char *mud_ipaddress = "0.0.0.0";
00371 bool fCopyOver = FALSE;
00372 int main (int argc, char **argv)
00373 {
00374     struct timeval now_time;
00375     
00376 
00377     /*
00378      * Memory debugging if needed.
00379      */
00380 #if defined(MALLOC_DEBUG)
00381     malloc_debug (2);
00382 #endif
00383 
00384     /*
00385      * Init time.
00386      */
00387     gettimeofday (&now_time, NULL);
00388     current_time = (time_t) now_time.tv_sec;
00389     strcpy (str_boot_time, ctime (&current_time));
00390 
00391     /*
00392      * Macintosh console initialization.
00393      */
00394 #if defined(macintosh)
00395     console_options.nrows = 31;
00396     cshow (stdout);
00397     csetmode (C_RAW, stdin);
00398     cecho2file ("log file", 1, stderr);
00399 #endif
00400 
00401     /*
00402      * Reserve one channel for our use.
00403      */
00404     if ((fpReserve = fopen (NULL_FILE, "r")) == NULL)
00405     {
00406         perror (NULL_FILE);
00407         exit (1);
00408     }
00409 
00410     /*
00411      * Get the port number.
00412      */
00413     port = 4000;
00414     if (argc > 1)
00415     {
00416         if (!is_number (argv[1]))
00417         {
00418             fprintf (stderr, "Usage: %s [port #]\n", argv[0]);
00419             exit (1);
00420         }
00421         else if ((port = atoi (argv[1])) <= 1024)
00422         {
00423             fprintf (stderr, "Port number must be above 1024.\n");
00424             exit (1);
00425         }
00426 
00427         /* Are we recovering from a copyover? */
00428         if (argv[2] && argv[2][0])
00429         {
00430             logf("We're copyovering?");
00431         fCopyOver = TRUE;
00432             control = atoi (argv[3]);
00433         }
00434         else
00435             fCopyOver = FALSE;
00436 
00437     }
00438     logf("port: %d", port);
00439 
00440     /*
00441      * Run the game.
00442      */
00443 #if defined(macintosh) || defined(MSDOS)
00444     qmconfig_read(); /* Here because it fits, no conflicts with Linux placement -- JR 05/06/01 */
00445     boot_db ();
00446     log_string ("Merc is ready to rock.");
00447     game_loop_mac_msdos ();
00448 #endif
00449 
00450 #if defined(unix)
00451 
00452     qmconfig_read(); /* Here so we can set the IP adress. -- JR 05/06/01 */
00453     if (!fCopyOver)
00454         control = init_socket (port);
00455 
00456     boot_db ();
00457     //send_to_all_copyover("Loading webserver ");
00458     //nit_web(80);
00459     //send_to_all_copyover("Done.(Non-functional)\n\r");
00460     logf ("ROM is ready to rock on port %d (%s).", port, mud_ipaddress);
00461 
00462     if (fCopyOver)
00463         copyover_recover ();
00464 
00465     game_loop_unix (control);
00466     save_kingdom_data();
00467     save_clan_data();
00468     save_game_conf();
00469     save_disabled();
00470     close (control);
00471 #endif
00472 
00473     /*
00474      * That's all, folks.
00475      */
00476     log_string ("Normal termination of game.");
00477     exit (0);
00478     return 0;
00479 }
00480 
00481 
00482 
00483 #if defined(unix)
00484 int init_socket (int port)
00485 {
00486     static struct sockaddr_in sa_zero;
00487     struct sockaddr_in sa;
00488     int x = 1;
00489     int fd;
00490 
00491     if ((fd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
00492     {
00493         perror ("Init_socket: socket");
00494         exit (1);
00495     }
00496 
00497     if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR,
00498                     (char *) &x, sizeof (x)) < 0)
00499     {
00500         perror ("Init_socket: SO_REUSEADDR");
00501         close (fd);
00502         exit (1);
00503     }
00504 
00505 #if defined(SO_DONTLINGER) && !defined(SYSV)
00506     {
00507         struct linger ld;
00508 
00509         ld.l_onoff = 1;
00510         ld.l_linger = 1000;
00511 
00512         if (setsockopt (fd, SOL_SOCKET, SO_DONTLINGER,
00513                         (char *) &ld, sizeof (ld)) < 0)
00514         {
00515             perror ("Init_socket: SO_DONTLINGER");
00516             close (fd);
00517             exit (1);
00518         }
00519     }
00520 #endif
00521 
00522     sa = sa_zero;
00523     sa.sin_family = AF_INET;
00524     sa.sin_port = htons (port);
00525     sa.sin_addr.s_addr = inet_addr( mud_ipaddress );
00526     logf("Set IP address to %s", mud_ipaddress);
00527 
00528     if (bind (fd, (struct sockaddr *) &sa, sizeof (sa)) < 0)
00529     {
00530         perror ("Init socket: bind");
00531         close (fd);
00532         exit (1);
00533     }
00534 
00535 
00536     if (listen (fd, 3) < 0)
00537     {
00538         perror ("Init socket: listen");
00539         close (fd);
00540         exit (1);
00541     }
00542 
00543     return fd;
00544 }
00545 #endif
00546 
00547 
00548 
00549 #if defined(macintosh) || defined(MSDOS)
00550 void game_loop_mac_msdos (void)
00551 {
00552     struct timeval last_time;
00553     struct timeval now_time;
00554     static DESCRIPTOR_DATA dcon;
00555 
00556     gettimeofday (&last_time, NULL);
00557     current_time = (time_t) last_time.tv_sec;
00558 
00559     /*
00560      * New_descriptor analogue.
00561      */
00562     dcon.descriptor = 0;
00563     if (!mud_ansiprompt)
00564     //dcon.connected = CON_GET_NAME;
00565     dcon.connected = CON_SHOW_LOGIN;
00566     else
00567         dcon.connected = CON_ANSI;
00568     dcon.ansi = mud_ansicolor;
00569     dcon.host = str_dup ("localhost");
00570     dcon.outsize = 2000;
00571     dcon.outbuf = alloc_mem (dcon.outsize);
00572     dcon.next = descriptor_list;
00573     dcon.showstr_head = NULL;
00574     dcon.showstr_point = NULL;
00575     dcon.pEdit = NULL;            /* OLC */
00576     dcon.pString = NULL;        /* OLC */
00577     dcon.editor = 0;            /* OLC */
00578     descriptor_list = &dcon;
00579 
00580     /*
00581      * First Contact!
00582      */
00583     if (!mud_ansiprompt)
00584     {
00585         extern char * help_greeting;
00586         if ( help_greeting[0] == '.' )
00587             send_to_desc ( help_greeting+1, &dcon );
00588         else
00589             send_to_desc ( help_greeting  , &dcon );
00590     }
00591 
00592     else
00593         write_to_buffer (&dcon, "Do you want Colour? (Y/n) ", 0);
00594 
00595     /* Main loop */
00596     while (!merc_down)
00597     {
00598         DESCRIPTOR_DATA *d;
00599 
00600         /*
00601          * Process input.
00602          */
00603         for (d = descriptor_list; d != NULL; d = d_next)
00604         {
00605             d_next = d->next;
00606             d->fcommand = FALSE;
00607 
00608 #if defined(MSDOS)
00609             if (kbhit ())
00610 #endif
00611             {
00612                 if (d->character != NULL)
00613                     d->character->timer = 0;
00614                 if (!read_from_descriptor (d))
00615                 {
00616                     if (d->character != NULL && d->connected == CON_PLAYING)
00617                         save_char_obj (d->character);
00618                     d->outtop = 0;
00619                     close_socket (d);
00620                     continue;
00621                 }
00622             }
00623 
00624             if (d->character != NULL && d->character->daze > 0)
00625                 --d->character->daze;
00626 
00627             if (d->character != NULL && d->character->wait > 0)
00628             {
00629                 --d->character->wait;
00630                 continue;
00631             }
00632 
00633             read_from_buffer (d);
00634             if (d->incomm[0] != '\0')
00635             {
00636                 d->fcommand = TRUE;
00637                 stop_idling (d->character);
00638 
00639                 /* OLC */
00640                 if (d->showstr_point)
00641                     show_string (d, d->incomm);
00642                 else if (d->pString)
00643                     string_add (d->character, d->incomm);
00644                 else
00645                     switch (d->connected)
00646                     {
00647                         case CON_PLAYING:
00648                             if (!run_olc_editor (d))
00649                                 substitute_alias (d, d->incomm);
00650                             break;
00651                         default:
00652                             send_to_decriptor("Test.\n\r",d);
00653                 nanny (d, d->incomm);
00654                             break;
00655                     }
00656 
00657                 d->incomm[0] = '\0';
00658             }
00659         }
00660 
00661 
00662 
00663         /*
00664          * Autonomous game motion.
00665          */
00666         update_handler ();
00667 
00668 
00669 
00670         /*
00671          * Output.
00672          */
00673         for (d = descriptor_list; d != NULL; d = d_next)
00674         {
00675             d_next = d->next;
00676 
00677             if ((d->fcommand || d->outtop > 0))
00678             {
00679                 if (!process_output (d, TRUE))
00680                 {
00681                     if (d->character != NULL && d->connected == CON_PLAYING)
00682                         save_char_obj (d->character);
00683                     d->outtop = 0;
00684                     close_socket (d);
00685                 }
00686             }
00687         }
00688 
00689 
00690 
00691         /*
00692          * Synchronize to a clock.
00693          * Busy wait (blargh).
00694          */
00695         now_time = last_time;
00696         for (;;)
00697         {
00698             int delta;
00699 
00700 #if defined(MSDOS)
00701             if (kbhit ())
00702 #endif
00703             {
00704                 if (dcon.character != NULL)
00705                     dcon.character->timer = 0;
00706                 if (!read_from_descriptor (&dcon))
00707                 {
00708                     if (dcon.character != NULL && d->connected == CON_PLAYING)
00709                         save_char_obj (d->character);
00710                     dcon.outtop = 0;
00711                     close_socket (&dcon);
00712                 }
00713 #if defined(MSDOS)
00714                 break;
00715 #endif
00716             }
00717 
00718             gettimeofday (&now_time, NULL);
00719             delta = (now_time.tv_sec - last_time.tv_sec) * 1000 * 1000
00720                 + (now_time.tv_usec - last_time.tv_usec);
00721             if (delta >= 1000000 / PULSE_PER_SECOND)
00722                 break;
00723         }
00724         last_time = now_time;
00725         current_time = (time_t) last_time.tv_sec;
00726     }
00727 
00728     return;
00729 }
00730 #endif
00731 
00732 
00733 
00734 #if defined(unix)
00735 void game_loop_unix (int control)
00736 {
00737     static struct timeval null_time;
00738     struct timeval last_time;
00739 
00740     signal (SIGPIPE, SIG_IGN);
00741     gettimeofday (&last_time, NULL);
00742     current_time = (time_t) last_time.tv_sec;
00743 
00744     /* Main loop */
00745     while (!merc_down)
00746     {
00747         fd_set in_set;
00748         fd_set out_set;
00749         fd_set exc_set;
00750         DESCRIPTOR_DATA *d;
00751         int maxdesc;
00752 
00753 #if defined(MALLOC_DEBUG)
00754         if (malloc_verify () != 1)
00755             abort ();
00756 #endif
00757     if (signal(SIGINT, mud_crashing) == SIG_IGN)
00758         signal(SIGINT, SIG_IGN);
00759     if (signal(SIGHUP, mud_crashing) == SIG_IGN)
00760         signal(SIGHUP, SIG_IGN);
00761     if (signal(SIGSEGV, mud_crashing) == SIG_IGN)
00762         signal(SIGSEGV, mud_crashing);
00763     
00764 
00765         /*
00766          * Poll all active descriptors.
00767          */
00768         FD_ZERO (&in_set);
00769         FD_ZERO (&out_set);
00770         FD_ZERO (&exc_set);
00771         FD_SET (control, &in_set);
00772         maxdesc = control;
00773         for (d = descriptor_list; d; d = d->next)
00774         {
00775             maxdesc = UMAX (maxdesc, d->descriptor);
00776             FD_SET (d->descriptor, &in_set);
00777             FD_SET (d->descriptor, &out_set);
00778             FD_SET (d->descriptor, &exc_set);
00779         }
00780 
00781         if (select (maxdesc + 1, &in_set, &out_set, &exc_set, &null_time) < 0)
00782         {
00783             perror ("Game_loop: select: poll");
00784             exit (1);
00785         }
00786 
00787         /*
00788          * New connection?
00789          */
00790         if (FD_ISSET (control, &in_set))
00791             init_descriptor (control);
00792 
00793         /*
00794          * Kick out the freaky folks.
00795          */
00796         for (d = descriptor_list; d != NULL; d = d_next)
00797         {
00798             d_next = d->next;
00799             if (FD_ISSET (d->descriptor, &exc_set))
00800             {
00801                 FD_CLR (d->descriptor, &in_set);
00802                 FD_CLR (d->descriptor, &out_set);
00803                 if (d->character && d->connected == CON_PLAYING)
00804                     save_char_obj (d->character);
00805                 d->outtop = 0;
00806                 close_socket (d);
00807             }
00808         }
00809 
00810         /*
00811          * Process input.
00812          */
00813         for (d = descriptor_list; d != NULL; d = d_next)
00814         {
00815             d_next = d->next;
00816             d->fcommand = FALSE;
00817 
00818             if (FD_ISSET (d->descriptor, &in_set))
00819             {
00820                 if (d->character != NULL)
00821                     d->character->timer = 0;
00822                 if (!read_from_descriptor (d))
00823                 {
00824                     FD_CLR (d->descriptor, &out_set);
00825                     if (d->character != NULL && d->connected == CON_PLAYING)
00826                         save_char_obj (d->character);
00827                     d->outtop = 0;
00828                     close_socket (d);
00829                     continue;
00830                 }
00831             }
00832 
00833             if (d->character != NULL && d->character->daze > 0)
00834                 --d->character->daze;
00835 
00836             if (d->character != NULL && d->character->wait > 0)
00837             {
00838                 --d->character->wait;
00839                 continue;
00840             }
00841         read_from_buffer(d);
00842         //fead_from_buffer (d);
00843             //send_to_desc(poo,d);
00844 
00845         if (d->incomm[0] != '\0')
00846             {
00847                 d->fcommand = TRUE;
00848                 stop_idling (d->character);
00849 
00850                 /* OLC */
00851                 if (d->showstr_point)
00852                     show_string (d, d->incomm);
00853                 else if (d->pString)
00854                     string_add (d->character, d->incomm);
00855                 else
00856                     switch (d->connected)
00857                     {
00858                         case CON_PLAYING:
00859                             if (!run_olc_editor (d))
00860                                 substitute_alias (d, d->incomm);
00861                             break;
00862                         default:
00863                             nanny (d, d->incomm);
00864                             break;
00865                     }
00866 
00867                 d->incomm[0] = '\0';
00868             }
00869         }
00870 
00871 
00872 
00873         /*
00874          * Autonomous game motion.
00875          */
00876         update_handler ();
00877 
00878 
00879 
00880         /*
00881          * Output.
00882          */
00883         for (d = descriptor_list; d != NULL; d = d_next)
00884         {
00885             d_next = d->next;
00886 
00887             if ((d->fcommand || d->outtop > 0)
00888                 && FD_ISSET (d->descriptor, &out_set))
00889             {
00890                 if (!process_output (d, TRUE))
00891                 {
00892                     if (d->character != NULL && d->connected == CON_PLAYING)
00893                         save_char_obj (d->character);
00894                     d->outtop = 0;
00895                     close_socket (d);
00896                 }
00897             }
00898         }
00899 
00900 
00901 
00902         /*
00903          * Synchronize to a clock.
00904          * Sleep( last_time + 1/PULSE_PER_SECOND - now ).
00905          * Careful here of signed versus unsigned arithmetic.
00906          */
00907         {
00908             struct timeval now_time;
00909             long secDelta;
00910             long usecDelta;
00911 
00912             gettimeofday (&now_time, NULL);
00913             usecDelta = ((int) last_time.tv_usec) - ((int) now_time.tv_usec)
00914                 + 1000000 / PULSE_PER_SECOND;
00915             secDelta = ((int) last_time.tv_sec) - ((int) now_time.tv_sec);
00916             while (usecDelta < 0)
00917             {
00918                 usecDelta += 1000000;
00919                 secDelta -= 1;
00920             }
00921 
00922             while (usecDelta >= 1000000)
00923             {
00924                 usecDelta -= 1000000;
00925                 secDelta += 1;
00926             }
00927 
00928             if (secDelta > 0 || (secDelta == 0 && usecDelta > 0))
00929             {
00930                 struct timeval stall_time;
00931 
00932                 stall_time.tv_usec = usecDelta;
00933                 stall_time.tv_sec = secDelta;
00934                 if (select (0, NULL, NULL, NULL, &stall_time) < 0)
00935                 {
00936                     perror ("Game_loop: select: stall");
00937                     exit (1);
00938                 }
00939             }
00940         }
00941 
00942         gettimeofday (&last_time, NULL);
00943         current_time = (time_t) last_time.tv_sec;
00944     }
00945 
00946     return;
00947 }
00948 #endif
00949 
00950 
00951 
00952 #if defined(unix)
00953 
00954 void init_descriptor (int control)
00955 {
00956     char buf[MAX_STRING_LENGTH];
00957     DESCRIPTOR_DATA *dnew;
00958     struct sockaddr_in sock;
00959     struct hostent *from;
00960     int desc;
00961     int size;
00962 
00963     size = sizeof (sock);
00964     getsockname (control, (struct sockaddr *) &sock, &size);
00965     if ((desc = accept (control, (struct sockaddr *) &sock, &size)) < 0)
00966     {
00967         perror ("New_descriptor: accept");
00968         return;
00969     }
00970 
00971 #if !defined(FNDELAY)
00972 #define FNDELAY O_NDELAY
00973 #endif
00974 
00975     if (fcntl (desc, F_SETFL, FNDELAY) == -1)
00976     {
00977         perror ("New_descriptor: fcntl: FNDELAY");
00978         return;
00979     }
00980 
00981     /*
00982      * Cons a new descriptor.
00983      */
00984     dnew = new_descriptor ();
00985 
00986     dnew->descriptor = desc;
00987     if (!mud_ansiprompt)
00988     //  dnew->connected = CON_GET_NAME;
00989         dnew->connected = CON_SHOW_LOGIN;
00990     else
00991         dnew->connected = CON_ANSI;
00992     dnew->ansi = mud_ansicolor;
00993     dnew->showstr_head = NULL;
00994     dnew->showstr_point = NULL;
00995     dnew->outsize = 2000;
00996     dnew->pEdit = NULL;            /* OLC */
00997     dnew->pString = NULL;        /* OLC */
00998     dnew->editor = 0;            /* OLC */
00999     dnew->outbuf = alloc_mem (dnew->outsize);
01000 
01001     size = sizeof (sock);
01002     if (getpeername (desc, (struct sockaddr *) &sock, &size) < 0)
01003     {
01004         perror ("New_descriptor: getpeername");
01005         dnew->host = str_dup ("(unknown)");
01006     }
01007     else
01008     {
01009         /*
01010          * Would be nice to use inet_ntoa here but it takes a struct arg,
01011          * which ain't very compatible between gcc and system libraries.
01012          */
01013         int addr;
01014 
01015         addr = ntohl (sock.sin_addr.s_addr);
01016         sprintf (buf, "%d.%d.%d.%d",
01017                  (addr >> 24) & 0xFF, (addr >> 16) & 0xFF,
01018                  (addr >> 8) & 0xFF, (addr) & 0xFF);
01019         sprintf (log_buf, "Sock.sinaddr:  %s", buf);
01020         log_string (log_buf);
01021         from = gethostbyaddr ((char *) &sock.sin_addr,
01022                               sizeof (sock.sin_addr), AF_INET);
01023         dnew->host = str_dup (from ? from->h_name : buf);
01024     }
01025 
01026     /*
01027      * Swiftest: I added the following to ban sites.  I don't
01028      * endorse banning of sites, but Copper has few descriptors now
01029      * and some people from certain sites keep abusing access by
01030      * using automated 'autodialers' and leaving connections hanging.
01031      *
01032      * Furey: added suffix check by request of Nickel of HiddenWorlds.
01033      */
01034     if (check_ban (dnew->host, BAN_ALL))
01035     {
01036         write_to_descriptor (desc,
01037                              "Your site has been banned. If you feel this is an error, contact\n\rTribul.\n\r",
01038                              0);
01039         close (desc);
01040         free_descriptor (dnew);
01041         return;
01042     }
01043     /*
01044      * Init descriptor data.
01045      */
01046     dnew->next = descriptor_list;
01047     descriptor_list = dnew;
01048 
01049     /*
01050      * First Contact!
01051      */
01052     if (!mud_ansiprompt)
01053     {
01054         extern char * help_greeting;
01055         if ( help_greeting[0] == '.' )
01056             send_to_desc ( help_greeting+1, dnew );
01057         else
01058             send_to_desc ( help_greeting  , dnew );
01059     }
01060     else
01061             send_to_desc ("Do you want Colour? (Y/n) ", dnew);
01062 
01063     return;
01064 }
01065 #endif
01066 
01067 
01068 
01069 void close_socket (DESCRIPTOR_DATA * dclose)
01070 {
01071     CHAR_DATA *ch;
01072 
01073     if (dclose->outtop > 0)
01074         process_output (dclose, FALSE);
01075 
01076     if (dclose->snoop_by != NULL)
01077     {
01078         write_to_buffer (dclose->snoop_by,
01079                          "Your victim has left the game.\n\r", 0);
01080     }
01081 
01082     {
01083         DESCRIPTOR_DATA *d;
01084 
01085         for (d = descriptor_list; d != NULL; d = d->next)
01086         {
01087             if (d->snoop_by == dclose)
01088                 d->snoop_by = NULL;
01089         }
01090     }
01091 
01092     if ((ch = dclose->character) != NULL)
01093     {
01094         sprintf (log_buf, "Closing link to %s.", ch->name);
01095         log_string (log_buf);
01096         /* cut down on wiznet spam when rebooting */
01097         /* If ch is writing note or playing, just lose link otherwise clear char */
01098         if ((dclose->connected == CON_PLAYING && !merc_down)
01099                 || ((dclose->connected >= CON_NOTE_TO)
01100                         && (dclose->connected <= CON_NOTE_FINISH)))
01101         {
01102             act ("$n has lost $s link.", ch, NULL, NULL, TO_ROOM);
01103            //SET_BIT(ch->comm, WIZ_LD);
01104         wiznet ("Net death has claimed $N.", ch, NULL, WIZ_LINKS, 0, 0);
01105         SET_BIT(ch->link_status, LINK_DEAD);
01106             ch->desc = NULL;
01107         }
01108         else
01109         {
01110             free_char (dclose->original ? dclose->original :
01111                        dclose->character);
01112         }
01113     }
01114 
01115     if (d_next == dclose)
01116         d_next = d_next->next;
01117 
01118     if (dclose == descriptor_list)
01119     {
01120         descriptor_list = descriptor_list->next;
01121     }
01122     else
01123     {
01124         DESCRIPTOR_DATA *d;
01125 
01126         for (d = descriptor_list; d && d->next != dclose; d = d->next);
01127         if (d != NULL)
01128             d->next = dclose->next;
01129         else
01130             bug ("Close_socket: dclose not found.", 0);
01131     }
01132 
01133     close (dclose->descriptor);
01134     free_descriptor (dclose);
01135 #if defined(MSDOS) || defined(macintosh)
01136     exit (1);
01137 #endif
01138     return;
01139 }
01140 
01141 
01142 
01143 bool read_from_descriptor (DESCRIPTOR_DATA * d)
01144 {
01145     int iStart;
01146 
01147     /* Hold horses if pending command already. */
01148     if (d->incomm[0] != '\0')
01149         return TRUE;
01150 
01151     /* Check for overflow. */
01152     iStart = strlen (d->inbuf);
01153     if (iStart >= sizeof (d->inbuf) - 10)
01154     {
01155         sprintf (log_buf, "%s input overflow!", d->host);
01156         log_string (log_buf);
01157         write_to_descriptor (d->descriptor,
01158                              "\n\r*** PUT A LID ON IT!!! ***\n\r", 0);
01159         return FALSE;
01160     }
01161     
01162     /* Snarf input. */
01163 #if defined(macintosh)
01164     for (;;)
01165     {
01166         int c;
01167         c = getc (stdin);
01168         if (c == '\0' || c == EOF)
01169             break;
01170         putc (c, stdout);
01171         if (c == '\r')
01172             putc ('\n', stdout);
01173         d->inbuf[iStart++] = c;
01174         if (iStart > sizeof (d->inbuf) - 10)
01175             break;
01176     }
01177 #endif
01178 
01179 #if defined(MSDOS) || defined(unix)
01180     for (;;)
01181     {
01182         int nRead;
01183 
01184         nRead = read (d->descriptor, d->inbuf + iStart,
01185                       sizeof (d->inbuf) - 10 - iStart);
01186         if (nRead > 0)
01187         {
01188             iStart += nRead;
01189             if (d->inbuf[iStart - 1] == '\n' || d->inbuf[iStart - 1] == '\r' || d->inbuf[iStart -1] == '~')
01190                 break;
01191         }
01192         else if (nRead == 0)
01193         {
01194             log_string ("EOF encountered on read.");
01195             return FALSE;
01196         }
01197         else if (errno == EWOULDBLOCK)
01198             break;
01199         else
01200         {
01201             perror ("Read_from_descriptor");
01202             return FALSE;
01203         }
01204     }
01205 #endif
01206 
01207     d->inbuf[iStart] = '\0';
01208     return TRUE;
01209 }
01210 
01211 
01212 
01213 /*
01214  * Transfer one line from input buffer to input line.
01215  */
01216 void read_from_buffer (DESCRIPTOR_DATA * d)
01217 {
01218     int i, j, k;
01219 
01220     /*
01221      * Hold horses if pending command already.
01222      */
01223     if (d->incomm[0] != '\0')
01224         return;
01225     /*if (d->incomm[0] == '~')
01226      {
01227          d->incomm[0] = '\0';
01228          return;
01229      }
01230 */
01231      
01232     /*
01233      * Look for at least one new line.
01234      */
01235     for (i = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++)
01236     {
01237         if (d->inbuf[i] == '\0')
01238             return;
01239     /*if (d->inbuf[i] == '~')
01240     {
01241          send_to_char("clearing command buffer.\n\r",d->character);
01242          d->inbuf[0] = '\0';
01243          return;
01244     }*/
01245                                                      
01246          
01247     }
01248 
01249     /*
01250      * Canonical input processing.
01251      */
01252     for (i = 0, k = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++)
01253     {
01254         if (k >= MAX_INPUT_LENGTH - 2)
01255         {
01256             write_to_descriptor (d->descriptor, "Line too long.\n\r", 0);
01257 
01258             /* skip the rest of the line */
01259             for (; d->inbuf[i] != '\0'; i++)
01260             {
01261                 if (d->inbuf[i] == '\n' || d->inbuf[i] == '\r')
01262                     break;
01263             }
01264             d->inbuf[i] = '\n';
01265             d->inbuf[i + 1] = '\0';
01266             break;
01267         }
01268       /* if (d->inbuf[i] == '~')
01269     {
01270         send_to_char("clearing command buffer.\n\r",d->character);
01271         d->inbuf[0] = '\0';
01272         return;
01273     }*/
01274         if (d->inbuf[i] == '\b' && k > 0)
01275             --k;
01276         else if (isascii (d->inbuf[i]) && isprint (d->inbuf[i]))
01277             d->incomm[k++] = d->inbuf[i];
01278     }
01279 
01280     /*
01281      * Finish off the line.
01282      */
01283     if (k == 0)
01284         d->incomm[k++] = ' ';
01285     d->incomm[k] = '\0';
01286 
01287     /*
01288      * Deal with bozos with #repeat 1000 ...
01289      */
01290 
01291     if (k > 1 || d->incomm[0] == '!')
01292     {
01293         if (d->incomm[0] != '!' && strcmp (d->incomm, d->inlast))
01294         {
01295             d->repeat = 0;
01296         }
01297         else
01298         {
01299             if (++d->repeat >= 25 && d->character
01300                 && d->connected == CON_PLAYING)
01301             {
01302                 sprintf (log_buf, "%s input spamming!", d->host);
01303                 log_string (log_buf);
01304                 wiznet ("Spam spam spam $N spam spam spam spam spam!",
01305                         d->character, NULL, WIZ_SPAM, 0,
01306                         get_trust (d->character));
01307                 if (d->incomm[0] == '!')
01308                     wiznet (d->inlast, d->character, NULL, WIZ_SPAM, 0,
01309                             get_trust (d->character));
01310                 else
01311                     wiznet (d->incomm, d->character, NULL, WIZ_SPAM, 0,
01312                             get_trust (d->character));
01313 
01314                 d->repeat = 0;
01315 /*
01316         write_to_descriptor( d->descriptor,
01317             "\n\r*** PUT A LID ON IT!!! ***\n\r", 0 );
01318         strcpy( d->incomm, "quit" );
01319 */
01320             }
01321         }
01322     }
01323 
01324 
01325     /*
01326      * Do '!' substitution.
01327      */
01328     if (d->incomm[0] == '!')
01329         strcpy (d->incomm, d->inlast);
01330     else
01331         strcpy (d->inlast, d->incomm);
01332     if (d->incomm[0] == '~')
01333         d->inbuf[0] = '\0';
01334 
01335 
01336     /*
01337      * Shift the input buffer.
01338      */
01339     while (d->inbuf[i] == '\n' || d->inbuf[i] == '\r')
01340         i++;
01341     for (j = 0; (d->inbuf[j] = d->inbuf[i + j]) != '\0'; j++);
01342     return;
01343 }
01344 
01345 
01346 
01347 /*
01348  * Low level output function.
01349  */
01350 bool process_output (DESCRIPTOR_DATA * d, bool fPrompt)
01351 {
01352     extern bool merc_down;
01353     int cnt=1;
01354     static char buf[MAX_STRING_LENGTH * 2];
01355     char tmpb[MAX_STRING_LENGTH];
01356     buf[0] = '\0';
01357 
01358     /*
01359      * Bust a prompt.
01360      */
01361     if (!merc_down)
01362     {
01363         if (d->showstr_point)
01364             send_to_char ("{x{D[{wHit Return to continue{D]{x\n\r", d->character);
01365         else if (fPrompt && d->pString && d->connected == CON_PLAYING)
01366     {
01367         char *string;
01368             string = *d->pString;
01369         while (*string)
01370         {
01371                string = getline (string, tmpb);
01372                cnt++;
01373                //sprintf (buf2, "{W%3d{x. {x%s\n\r", cnt++, tmpb);
01374                //strcat (buf, buf2);
01375                
01376         }
01377         sprintf(buf, "{W%3d{c>{x ", cnt);
01378         
01379            //write_to_buffer (d, /*"{c>{x "*/buf, 2);
01380            send_to_char(buf, d->character);
01381     }
01382     else if (fPrompt && d->connected == CON_PLAYING)
01383         {
01384             CHAR_DATA *ch;
01385             CHAR_DATA *victim;
01386 
01387             ch = d->character;
01388 
01389             /* battle prompt */
01390             
01391         if ((victim = ch->fighting) != NULL && can_see (ch, victim))
01392             {
01393                 int percent;
01394                 char wound[100];
01395                 char *pbuff;
01396                 char buf[MSL];
01397                 char buffer[MSL*2];
01398 
01399                 if (victim->max_hit > 0)
01400                     percent = victim->hit * 100 / victim->max_hit;
01401                 else
01402                     percent = -1;
01403 
01404                 if (percent >= 100)
01405                     sprintf (wound, "is in excellent condition.");
01406                 else if (percent >= 90)
01407                     sprintf (wound, "has a few scratches.");
01408                 else if (percent >= 75)
01409                     sprintf (wound, "has some small wounds and bruises.");
01410                 else if (percent >= 50)
01411                     sprintf (wound, "has quite a few wounds.");
01412                 else if (percent >= 30)
01413                     sprintf (wound,
01414                              "has some big nasty wounds and scratches.");
01415                 else if (percent >= 15)
01416                     sprintf (wound, "looks pretty hurt.");
01417                 else if (percent >= 0)
01418                     sprintf (wound, "is in awful condition.");
01419                 else
01420                     sprintf (wound, "is bleeding to death.");
01421 
01422                 sprintf (buf, "%s %s \n\r",
01423                          IS_NPC (victim) ? victim->short_descr : victim->name,
01424                          wound);
01425                 buf[0] = UPPER (buf[0]);
01426                 pbuff = buffer;
01427                 colourconv (pbuff, buf, CH(d));
01428                 write_to_buffer (d, buffer, 0);
01429             }
01430 
01431 
01432             ch = d->original ? d->original : d->character;
01433             if (!IS_SET (ch->comm, COMM_COMPACT))
01434                 write_to_buffer (d, "\n\r", 2);
01435 
01436 
01437             if (IS_SET (ch->comm, COMM_PROMPT))
01438                 bust_a_prompt (d->character);
01439 
01440             if (IS_SET (ch->comm, COMM_TELNET_GA))
01441                 write_to_buffer (d, go_ahead_str, 0);
01442         }
01443     }
01444 
01445     /*
01446      * Short-circuit if nothing to write.
01447      */
01448     if (d->outtop == 0)
01449         return TRUE;
01450 
01451     /*
01452      * Snoop-o-rama.
01453      */
01454     if (d->snoop_by != NULL)
01455     {
01456         if (d->character != NULL)
01457             write_to_buffer (d->snoop_by, d->character->name, 0);
01458         write_to_buffer (d->snoop_by, "> ", 2);
01459         write_to_buffer (d->snoop_by, d->outbuf, d->outtop);
01460     }
01461 
01462     /*
01463      * OS-dependent output.
01464      */
01465     if (!write_to_descriptor (d->descriptor, d->outbuf, d->outtop))
01466     {
01467         d->outtop = 0;
01468         return FALSE;
01469     }
01470     else
01471     {
01472         d->outtop = 0;
01473         return TRUE;
01474     }
01475 }
01476 
01477 /*
01478  * Bust a prompt (player settable prompt)
01479  * coded by Morgenes for Aldara Mud
01480  */
01481 void bust_a_prompt (CHAR_DATA * ch)
01482 {
01483     char buf[MAX_STRING_LENGTH];
01484     char buf2[MAX_STRING_LENGTH];
01485     const char *str;
01486     const char *i;
01487     char *point;
01488     char *pbuff;
01489     char buffer[MAX_STRING_LENGTH * 2];
01490     char doors[MAX_INPUT_LENGTH];
01491     EXIT_DATA *pexit;
01492     bool found;
01493     const char *dir_name[] = { "N-", "E-", "S-", "W-", "U-", "D-", "Ne-", "Nw-", "Se-", "Sw" };
01494     int door;
01495     extern int port;
01496 
01497     point = buf;
01498     str = ch->prompt;
01499     if (str == NULL || str[0] == '\0')
01500     {
01501         sprintf (buf, "{p<%dhp %dm %dmv>{x %s",
01502                  ch->hit, ch->mana, ch->move, ch->prefix);
01503         send_to_char (buf, ch);
01504         return;
01505     }
01506     if (!IS_NPC(ch) && ch->desc->editor)
01507     {
01508         send_to_char("{R[{WOLC{R]{x ",ch);
01509     }
01510     if (!IS_NPC(ch) && IS_IMMORTAL(ch) && IS_SET(ch->pcdata->immortal, IMMORTAL_PORT))
01511     {
01512         
01513         sprintf(buf, "{r({cPort: {D%d{r){x ",port);
01514         send_to_char(buf,ch);
01515     }
01516         
01517 
01518     
01519     if (IS_SET (ch->comm, COMM_AFK))
01520     {
01521         send_to_char ("{p<AFK>{x ", ch);
01522         return;
01523     }
01524 
01525     while (*str != '\0')
01526     {
01527         if (*str != '%')
01528         {
01529             *point++ = *str++;
01530             continue;
01531         }
01532         ++str;
01533         switch (*str)
01534         {
01535             default:
01536                 i = " ";
01537                 break;
01538             case 'e':
01539                 found = FALSE;
01540                 doors[0] = '\0';
01541                 for (door = 0; door < 10; door++)
01542                 {
01543                     if ((pexit = ch->in_room->exit[door]) != NULL
01544                         && pexit->u1.to_room != NULL
01545                         && (can_see_room (ch, pexit->u1.to_room)
01546                             || (IS_AFFECTED (ch, AFF_INFRARED)
01547                                 && !IS_AFFECTED (ch, AFF_BLIND)))
01548                         && !IS_SET (pexit->exit_info, EX_CLOSED))
01549                     {
01550                         found = TRUE;
01551                         strcat (doors, dir_name[door]);
01552                     }
01553                 }
01554                 if (!found)
01555                     strcat (buf, "none");
01556                 sprintf (buf2, "%s", doors);
01557                 i = buf2;
01558                 break;
01559             case 'c':
01560                 sprintf (buf2, "%s", "\n\r");
01561                 i = buf2;
01562                 break;
01563             case 'h':
01564                 sprintf (buf2, "%d", ch->hit);
01565                 i = buf2;
01566                 break;
01567             case 'H':
01568                 sprintf (buf2, "%d", ch->max_hit);
01569                 i = buf2;
01570                 break;
01571             case 'm':
01572                 sprintf (buf2, "%d", ch->mana);
01573                 i = buf2;
01574                 break;
01575             case 'M':
01576                 sprintf (buf2, "%d", ch->max_mana);
01577                 i = buf2;
01578                 break;
01579             case 'v':
01580                 sprintf (buf2, "%d", ch->move);
01581                 i = buf2;
01582                 break;
01583             case 'V':
01584                 sprintf (buf2, "%d", ch->max_move);
01585                 i = buf2;
01586                 break;
01587             case 'x':
01588                 sprintf (buf2, "%d", ch->exp);
01589                 i = buf2;
01590                 break;
01591             case 'X':
01592                 sprintf (buf2, "%d", IS_NPC (ch) ? 0 :
01593                          (ch->level + 1) * exp_per_level (ch,
01594                                                           ch->pcdata->
01595                                                           points) - ch->exp);
01596                 i = buf2;
01597                 break;
01598             case 'g':
01599                 sprintf (buf2, "%ld", ch->gold);
01600                 i = buf2;
01601                 break;
01602             case 's':
01603                 sprintf (buf2, "%ld", ch->silver);
01604                 i = buf2;
01605                 break;
01606             case 'a':
01607                 if (ch->level > 9)
01608                     sprintf (buf2, "%d", ch->alignment);
01609                 else
01610                     sprintf (buf2, "%s",
01611                              IS_GOOD (ch) ? "good" : IS_EVIL (ch) ? "evil" :
01612                              "neutral");
01613                 i = buf2;
01614                 break;
01615             case 'r':
01616                 if (ch->in_room != NULL)
01617                     sprintf (buf2, "%s",
01618                              ((!IS_NPC
01619                                (ch) && IS_SET (ch->act, PLR_HOLYLIGHT))
01620                               || (!IS_AFFECTED (ch, AFF_BLIND)
01621                                   && !room_is_dark (ch->
01622                                                     in_room))) ? ch->in_room->
01623                              name : "darkness");
01624                 else
01625                     sprintf (buf2, " ");
01626                 i = buf2;
01627                 break;
01628             case 'R':
01629                 if (IS_IMMORTAL (ch) && ch->in_room != NULL)
01630                     sprintf (buf2, "%d", ch->in_room->vnum);
01631                 else
01632                     sprintf (buf2, " ");
01633                 i = buf2;
01634                 break;
01635             case 'z':
01636                 if (IS_IMMORTAL (ch) && ch->in_room != NULL)
01637                     sprintf (buf2, "%s", ch->in_room->area->name);
01638                 else
01639                     sprintf (buf2, " ");
01640                 i = buf2;
01641                 break;
01642             case '%':
01643                 sprintf (buf2, "%%");
01644                 i = buf2;
01645                 break;
01646             case 'o':
01647                 sprintf (buf2, "%s", olc_ed_name (ch));
01648                 i = buf2;
01649                 break;
01650             case 'O':
01651                 sprintf (buf2, "%s", olc_ed_vnum (ch));
01652                 i = buf2;
01653                 break;
01654         }
01655         ++str;
01656         while ((*point = *i) != '\0')
01657             ++point, ++i;
01658     }
01659     *point = '\0';
01660     pbuff = buffer;
01661     colourconv (pbuff, buf, ch);
01662     send_to_char ("{p", ch);
01663     write_to_buffer (ch->desc, buffer, 0);
01664     send_to_char ("{x", ch);
01665 
01666     if (ch->prefix[0] != '\0')
01667         write_to_buffer (ch->desc, ch->prefix, 0);
01668     return;
01669 }
01670 
01671 
01672 
01673 /*
01674  * Append onto an output buffer.
01675  */
01676 void write_to_buffer (DESCRIPTOR_DATA * d, const char *txt, int length)
01677 {
01678     /*
01679      * Find length in case caller didn't.
01680      */
01681     if (length <= 0)
01682         length = strlen (txt);
01683 
01684     /*
01685      * Initial \n\r if needed.
01686      */
01687     if (d->outtop == 0 && !d->fcommand)
01688     {
01689         d->outbuf[0] = '\n';
01690         d->outbuf[1] = '\r';
01691         d->outtop = 2;
01692     }
01693 
01694     /*
01695      * Expand the buffer as needed.
01696      */
01697     while (d->outtop + length >= d->outsize)
01698     {
01699         char *outbuf;
01700 
01701         if (d->outsize >= 32000)
01702         {
01703             bug ("Buffer overflow. Closing.\n\r", 0);
01704             close_socket (d);
01705             return;
01706         }
01707         outbuf = alloc_mem (2 * d->outsize);
01708         strncpy (outbuf, d->outbuf, d->outtop);
01709         free_mem (d->outbuf, d->outsize);
01710         d->outbuf = outbuf;
01711         d->outsize *= 2;
01712     }
01713 
01714     /*
01715      * Copy.
01716      */
01717     strncpy (d->outbuf + d->outtop, txt, length);
01718     d->outtop += length;
01719     return;
01720 }
01721 
01722 
01723 
01724 /*
01725  * Lowest level output function.
01726  * Write a block of text to the file descriptor.
01727  * If this gives errors on very long blocks (like 'ofind all'),
01728  *   try lowering the max block size.
01729  */
01730 bool write_to_descriptor (int desc, char *txt, int length)
01731 {
01732     int iStart;
01733     int nWrite;
01734     int nBlock;
01735 
01736 #if defined(macintosh) || defined(MSDOS)
01737     if (desc == 0)
01738         desc = 1;
01739 #endif
01740 
01741     if (length <= 0)
01742         length = strlen (txt);
01743 
01744     for (iStart = 0; iStart < length; iStart += nWrite)
01745     {
01746         nBlock = UMIN (length - iStart, 4096);
01747             if ((nWrite = write (desc, txt + iStart, nBlock)) < 0)
01748         {
01749             perror ("Write_to_descriptor");
01750             return FALSE;
01751         }
01752     }
01753 
01754     return TRUE;
01755 }
01756 
01757 
01758 
01759 void