WSCKCOMM.C
上传用户:kesirui
上传日期:2007-01-07
资源大小:263k
文件大小:74k
源码类别:

Internet/网络编程

开发平台:

WINDOWS

  1. /***************************************************************************
  2.  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
  3.  *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
  4.  *                                                                         *
  5.  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
  6.  *  Chastain, Michael Quan, and Mitchell Tse.                              *
  7.  *                                                                         *
  8.  *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
  9.  *  Love, Guilherme 'Willie' Arnold, and Mitchell Tse.                     *
  10.  *                                                                         *
  11.  *  Windows sockets port by Slash.                                         *
  12.  *                                                                         *
  13.  *  In order to use any part of this Envy Diku Mud, you must comply with   *
  14.  *  the original Diku license in 'license.doc', the Merc license in        *
  15.  *  'license.txt', as well as the Envy license in 'license.nvy'.           *
  16.  *  In particular, you may not remove either of these copyright notices.   *
  17.  *                                                                         *
  18.  *  Thanks to abaddon for proof-reading our comm.c and pointing out bugs.  *
  19.  *  Any remaining bugs are, of course, our work, not his.  :)              *
  20.  *                                                                         *
  21.  *  Much time and thought has gone into this software and you are          *
  22.  *  benefitting.  We hope that you share your changes too.  What goes      *
  23.  *  around, comes around.                                                  *
  24.  ***************************************************************************/
  25. #include <time.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. //#include "telnet.h"
  29. #include "merc.h"
  30. #include "merc-win.rh"
  31. #include <windows.h>
  32. // Yes, we want mobprogram support
  33. #define MOBPROGS
  34. // Yes, we want support for Merc 2.2 for Windows additions
  35. #define MERCW32
  36. #define STDERR_FILE "stderr.txt" /* For what Unix writes to standard error */
  37. /*
  38.  * Definitions for the TELNET protocol.
  39.  */
  40. #define IAC 255 /* interpret as command: */
  41. #define WONT 252 /* I won't use option */
  42. #define WILL 251 /* I will use option */
  43. #define GA 249    /* you may reverse the line */
  44. /* telnet options */
  45. #define TELOPT_ECHO 1 /* echo */
  46. struct host_and_name_lookup {
  47.     // These are used by WSAAsyncGetHostByAddr()
  48.     char       hostdata[MAXGETHOSTSTRUCT];
  49.     HANDLE     hRequestHandle;
  50.     struct     in_addr sin_addr;
  51.     // These are used by the identd stuff
  52.     char       username[64];
  53.     SOCKET     sAuth;
  54.     struct sockaddr_in authsock;    // Address of the authentication
  55.     struct sockaddr_in us;          // Address of our socket to this player
  56.     struct sockaddr_in them;        // Address of our socket to this player
  57. };
  58. /* Local #defines for Win32 */
  59. //#define MAKEWORD(a, b)      ((WORD)(((BYTE)(a)) | (((WORD)((BYTE)(b))) << 8)))
  60. #define WM_NET_ACCEPT      (WM_USER+500)
  61. #define WM_NET_READWRITE   (WM_USER+501)
  62. #define WM_NET_GETHOST     (WM_USER+502)
  63. #define WM_NET_AUTHCONNECT (WM_USER+503)
  64. /*
  65.  * Global variables.
  66.  */
  67. DESCRIPTOR_DATA *   descriptor_free; /* Free list for descriptors */
  68. DESCRIPTOR_DATA *   descriptor_list; /* All open descriptors */
  69. DESCRIPTOR_DATA *   d_next; /* Next descriptor in loop */
  70. FILE *     fpReserve; /* Reserved file handle */
  71. bool     god; /* All new chars are gods! */
  72. bool     merc_down; /* Shutdown */
  73. bool     wizlock; /* Game is wizlocked */
  74. int                 numlock = 0;        /* Game is numlocked at <level> (ENVY) */
  75. char     str_boot_time[MAX_INPUT_LENGTH];
  76. time_t     current_time; /* Time of this pulse */
  77. /* Windows version variables */
  78. SOCKET control;
  79. int nPlayers = 0;
  80. int nOldPlayers = 0;
  81. FILE *fpStderr;
  82. BOOL fWantsMessageBox = TRUE; // if TRUE, bring up message box on bugs, else log
  83. /*
  84.  * Other local functions (OS-independent).
  85.  */
  86. bool check_parse_name args( ( char *name ) );
  87. bool check_reconnect args( ( DESCRIPTOR_DATA *d, char *name,
  88.     bool fConn ) );
  89. bool check_playing args( ( DESCRIPTOR_DATA *d, char *name ) );
  90. int main args( ( int argc, char **argv ) );
  91. void nanny args( ( DESCRIPTOR_DATA *d, char *argument ) );
  92. bool process_output args( ( DESCRIPTOR_DATA *d, bool fPrompt ) );
  93. void read_from_buffer args( ( DESCRIPTOR_DATA *d ) );
  94. void stop_idling args( ( CHAR_DATA *ch ) );
  95. //void    bust_a_prompt           args( ( CHAR_DATA *ch ) );
  96. void    bust_a_prompt           args( ( DESCRIPTOR_DATA *d ) );
  97. // @@@ My junk
  98. //char      UserMessage[512];
  99. //BOOL      fUserReady;
  100. const char echo_off_str [] = { IAC, WILL, TELOPT_ECHO, '' };
  101. const char echo_on_str [] = { IAC, WONT, TELOPT_ECHO, '' };
  102. const char  go_ahead_str [] = { IAC, GA, '' };
  103. bool write_to_descriptor args( ( int desc, char *txt, int length ) );
  104. bool BlastedTrumpet(SOCKET sSocket);
  105. LRESULT SocketAccept (WPARAM /*wParam*/, LPARAM lParam);
  106. LRESULT SocketReadWrite (WPARAM wParam, LPARAM lParam);
  107. LRESULT SocketGetHost(WPARAM wParam, LPARAM lParam);
  108. LRESULT SocketAuthConnect(WPARAM wParam, LPARAM lParam);
  109. SOCKET init_socket( int port );
  110. bool read_from_descriptor( DESCRIPTOR_DATA *d );
  111. void send_to_char args( ( const char *txt, CHAR_DATA *ch ) )
  112. {
  113.     if ( txt == NULL || ch->desc == NULL )
  114.         return;
  115.     free_string( ch->desc->showstr_head );
  116. #if 0 // @@@ The next line is from sands, it seems wrong
  117.     ch->desc->showstr_head = str_dup( txt );
  118. #else
  119.     ch->desc->showstr_head = alloc_mem( strlen( txt ) + 1 );
  120.     strcpy( ch->desc->showstr_head, txt );
  121. #endif
  122.     ch->desc->showstr_point = ch->desc->showstr_head;
  123.     show_string( ch->desc, "" );
  124. }
  125. void gettimeofday( struct timeval *tp, void *tzp )
  126. {
  127.     tp->tv_sec  = time( NULL );
  128.     tp->tv_usec = 0;
  129. }
  130. #if 0 // @@@
  131. bool read_from_descriptor( DESCRIPTOR_DATA *d )
  132. {
  133.     int iStart;
  134.     /* Hold horses if pending command already. */
  135.     if ( d->incomm[0] != '' )
  136. return TRUE;
  137.     /* Check for overflow. */
  138.     iStart = strlen(d->inbuf);
  139.     if ( iStart >= sizeof(d->inbuf) - 10 )
  140.     {
  141. sprintf( log_buf, "%s input overflow!", d->host );
  142. log_string( log_buf );
  143. write_to_descriptor( d->descriptor,
  144.     "nr*** PUT A LID ON IT!!! ***nr", 0 );
  145. return FALSE;
  146.     }
  147. #if 0
  148.     /* Snarf input. */
  149.     for ( ; ; )
  150.     {
  151. int c;
  152. c = getc( stdin );
  153. if ( c == '' || c == EOF )
  154.     break;
  155. putc( c, stdout );
  156. if ( c == 'r' )
  157.     putc( 'n', stdout );
  158. d->inbuf[iStart++] = c;
  159. if ( iStart > sizeof(d->inbuf) - 10 )
  160.     break;
  161.     }
  162. #else
  163.     if (fUserReady)
  164.        {
  165.        int nLen = strlen(UserMessage);
  166.        fUserReady = FALSE;
  167.        if (iStart + nLen <= sizeof d->inbuf - 10)
  168.           {
  169.           memcpy(d->inbuf + iStart, UserMessage, nLen);
  170.           iStart += nLen;
  171.           d->inbuf[iStart++] = 'r';
  172.           }
  173.        }
  174. #endif
  175.     d->inbuf[iStart] = '';
  176.     return TRUE;
  177. }
  178. #endif
  179. /*
  180.  * Transfer one line from input buffer to input line.
  181.  */
  182. void read_from_buffer( DESCRIPTOR_DATA *d )
  183. {
  184.     int i, j, k;
  185.     /*
  186.      * Hold horses if pending command already.
  187.      */
  188.     if ( d->incomm[0] != '' )
  189. return;
  190.     /*
  191.      * Look for at least one new line.
  192.      */
  193.     for ( i = 0; d->inbuf[i] != 'n' && d->inbuf[i] != 'r'; i++ )
  194.     {
  195. if ( d->inbuf[i] == '' )
  196.     return;
  197.     }
  198.     /*
  199.      * Canonical input processing.
  200.      */
  201.     for ( i = 0, k = 0; d->inbuf[i] != 'n' && d->inbuf[i] != 'r'; i++ )
  202.     {
  203. if ( k >= MAX_INPUT_LENGTH - 2 )
  204. {
  205.     write_to_descriptor( d->descriptor, "Line too long.nr", 0 );
  206.     /* skip the rest of the line */
  207.     for ( ; d->inbuf[i] != ''; i++ )
  208.     {
  209. if ( d->inbuf[i] == 'n' || d->inbuf[i] == 'r' )
  210.     break;
  211.     }
  212.     d->inbuf[i]   = 'n';
  213.     d->inbuf[i+1] = '';
  214.     break;
  215. }
  216. if ( d->inbuf[i] == 'b' && k > 0 )
  217.     --k;
  218. else if ( isascii(d->inbuf[i]) && isprint(d->inbuf[i]) )
  219.     d->incomm[k++] = d->inbuf[i];
  220.     }
  221.     /*
  222.      * Finish off the line.
  223.      */
  224.     if ( k == 0 )
  225. d->incomm[k++] = ' ';
  226.     d->incomm[k] = '';
  227.     /*
  228.      * Deal with bozos with #repeat 1000 ...
  229.      */
  230.     if ( k > 1 || d->incomm[0] == '!' )
  231.     {
  232.      if ( d->incomm[0] != '!' && strcmp( d->incomm, d->inlast ) )
  233. {
  234.     d->repeat = 0;
  235. }
  236. else
  237. {
  238.     if ( ++d->repeat >= 20 )
  239.     {
  240. sprintf( log_buf, "%s input spamming!", d->host );
  241. log_string( log_buf );
  242. write_to_descriptor( d->descriptor,
  243.     "nr*** PUT A LID ON IT!!! ***nr", 0 );
  244. strcpy( d->incomm, "quit" );
  245.     }
  246. }
  247.     }
  248.     /*
  249.      * Do '!' substitution.
  250.      */
  251.     if ( d->incomm[0] == '!' )
  252. strcpy( d->incomm, d->inlast );
  253.     else
  254. strcpy( d->inlast, d->incomm );
  255.     /*
  256.      * Shift the input buffer.
  257.      */
  258.     while ( d->inbuf[i] == 'n' || d->inbuf[i] == 'r' )
  259. i++;
  260.     for ( j = 0; ( d->inbuf[j] = d->inbuf[i+j] ) != ''; j++ )
  261. ;
  262.     return;
  263. }
  264. void CloseMerc(void)
  265. {
  266. }
  267. HINSTANCE hInst;
  268. HWND      hQryDlgBox;                         // handle of modeless dialog box
  269. HWND      hWndMain;
  270. HWND      hWndOutput;
  271. //char      UserMessage[512];
  272. //bool      fUserReady;
  273. LRESULT CALLBACK _export MercWndProc(HWND hWnd, UINT message,
  274.                              WPARAM wParam, LPARAM lParam)
  275. {
  276.     switch (message)
  277.     {
  278.         case WM_MOVE:
  279.             // Move the dialog box on top of our main window every
  280.             // time the main window moves.
  281.             if (IsWindow(hQryDlgBox))
  282.                 SendMessage(hQryDlgBox, message, wParam, lParam);
  283.             break;
  284.         case WM_SETFOCUS:
  285.             // Always set the input focus to the dialog box.
  286.             if (IsWindow(hQryDlgBox))
  287.                 SendMessage(hQryDlgBox, message, wParam, lParam);
  288.             break;
  289.         case WM_CLOSE:
  290.             // Tell windows to destroy our window.
  291.             DestroyWindow(hWnd);
  292.             break;
  293.         case WM_QUERYENDSESSION:
  294.             // If we return TRUE we are saying it's ok with us to end the
  295. // windows session.
  296.             return((long) TRUE);  // we agree to end session.
  297.         case WM_ENDSESSION:
  298.             // If wParam is not zero, it meany every application said ok
  299.             // to WM_QUERYENDSESSION messages, so we are really ending.
  300.             if (wParam)           // if all apps aggreed to end session.
  301.                 CloseMerc();     // This is the end. We will not get a
  302.                                    // WM_DESTROY message on end session.
  303.             break;
  304.         case WM_DESTROY:
  305.             // This is the end if we were closed by a DestroyWindow call.
  306.             CloseMerc();
  307. PostQuitMessage(0);
  308.             break;
  309.         default:
  310.             return(DefWindowProc(hWnd, message, wParam, lParam));
  311.     }
  312.     return(0L);
  313. }
  314. BOOL CALLBACK _export MercDlgProc(HWND hDlg, UINT message,
  315.                            WPARAM wParam, LPARAM lParam)
  316. {
  317.     static RECT   wrect;
  318.     int           x, y, w, h, i;
  319.     long          rc;
  320. //    char         *cp, *cpd, tmp[30], sdrives[30];
  321. //    HANDLE        hCursor;
  322.     HWND hWndInput;
  323.     switch (message)
  324.     {
  325.         case WM_INITDIALOG:
  326.             // Save the handle of this proc for use by main window proc.
  327.             hQryDlgBox = hDlg;
  328.             // Save the handle to the output window
  329.             hWndOutput = GetDlgItem(hDlg, 102);
  330. //            SendMessage(hWndOutput, WM_SETFONT,
  331. //               (WPARAM) GetStockObject(SYSTEM_FIXED_FONT), 0);
  332.             SetFocus(GetDlgItem(hDlg, 101));
  333.             // Get position of dialog box window.
  334.             GetWindowRect(hDlg, (LPRECT) &wrect);
  335.             w = wrect.right - wrect.left;
  336.             h = wrect.bottom - wrect.top;
  337.             // Move main application window to same position.
  338.             SetWindowPos(hWndMain, hDlg,
  339.                          wrect.left, wrect.top, w, h,
  340.                          0);
  341.             // Tell Winsock we are listening for accepted sockets
  342.             WSAAsyncSelect(control, hDlg, WM_NET_ACCEPT, FD_ACCEPT);
  343.             break;
  344.         case WM_MOVE:
  345.             // Always keep this dialog box on top of main window.
  346.             GetWindowRect(hWndMain, (LPRECT) &wrect);
  347.             x = wrect.left;
  348.             y = wrect.top;
  349.             w = wrect.right - wrect.left;
  350.             h = wrect.bottom - wrect.top;
  351.             MoveWindow(hDlg, x, y, w, h, 1);
  352.             break;
  353.         case WM_SYSCOMMAND:
  354.             // Pass WM_SYSCOMMAND messages on to main window so both
  355.             // main window and dialog box get iconized, minimized etc.
  356.             // in parallel.
  357.             SendMessage(hWndMain, message, wParam, lParam);
  358.             break;
  359.         case WM_COMMAND:
  360.             switch (LOWORD(wParam))
  361.             {
  362. #if 0 // @@@
  363.                 case IDOK:
  364.                     hWndInput = GetDlgItem(hDlg, 101);
  365.                     SendMessage(hWndInput, WM_GETTEXT, sizeof UserMessage, (LPARAM) UserMessage);
  366.                     SendMessage(hWndInput, WM_SETTEXT, 0, (LPARAM) "");
  367.                     SetFocus(hWndInput);
  368.                     fUserReady = TRUE;
  369.                     break;
  370. #endif
  371.                 case IDCANCEL:                  // Cancel button
  372.                     // Tell main application window we want to quit.
  373.                     SendMessage(hWndMain, WM_CLOSE, 0, 0L);
  374.                     break;
  375.                 default:
  376.                     break;
  377.             }
  378.             break;
  379.         case WM_CLOSE:
  380.             // Unlock dialog resource we locked above.
  381.             // Zero handle to this dialog window.
  382.             hQryDlgBox = 0;
  383.             // Tell main window to close.
  384.             PostMessage(hWndMain, WM_CLOSE, 0, 0L);
  385.             // Destroy ourseleves.
  386.             DestroyWindow(hDlg);
  387.             break;
  388.         case WM_NET_ACCEPT:
  389.            SocketAccept(wParam, lParam);
  390.            break;
  391.         case WM_NET_READWRITE:
  392.            SocketReadWrite(wParam, lParam);
  393.            break;
  394.         case WM_NET_GETHOST:
  395.            SocketGetHost(wParam, lParam);
  396.            break;
  397.         case WM_NET_AUTHCONNECT:
  398.            SocketAuthConnect(wParam, lParam);
  399.            break;
  400.         default:
  401.             return FALSE;
  402.     }
  403.     return(TRUE);
  404. }
  405. void InitMerc22(HINSTANCE hInstance, int cmdShow)
  406. {
  407.     WNDCLASS wcMercClass;
  408.     // Define the window class for this application.
  409.     wcMercClass.lpszClassName = "Merc22";
  410.     wcMercClass.hInstance     = hInstance;
  411.     wcMercClass.lpfnWndProc   = MercWndProc;
  412.     wcMercClass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  413. //    wcMercClass.hIcon         = LoadIcon(hInstance, SetUpData.szAppName);
  414.     wcMercClass.hIcon         = 0;
  415.     wcMercClass.lpszMenuName  = (LPSTR) NULL;
  416.     wcMercClass.hbrBackground = GetStockObject(WHITE_BRUSH);
  417.     wcMercClass.style         = CS_HREDRAW | CS_VREDRAW;
  418.     wcMercClass.cbClsExtra    = 0;
  419.     wcMercClass.cbWndExtra    = 0;
  420.     // Register the class
  421.     if (RegisterClass(&wcMercClass) == 0)
  422.        {
  423.        MessageBox(0, "Could not create Window", "@@@", MB_ICONHAND|MB_OK);
  424.        exit(1);
  425.        }
  426.     hInst = hInstance;       // save for use by window procs
  427.     // Create applications main window.
  428.     hWndMain = CreateWindow(
  429.                   "Merc22",
  430.                   "Welcome to Merc22/Win32",
  431.                     WS_BORDER |
  432.                     WS_CAPTION |
  433.                     WS_SYSMENU |
  434.                     WS_MINIMIZEBOX,
  435.                   10,
  436.                   19,
  437.                   256,
  438.                   123,
  439.                   NULL,
  440.                   NULL,
  441.                   hInstance,
  442.                   NULL
  443.                   );
  444.     CreateDialog(hInst, MAKEINTRESOURCE(1), hWndMain, (DLGPROC) MercDlgProc);
  445.     ShowWindow(hWndMain, cmdShow);
  446.     UpdateWindow(hWndMain);
  447. }
  448. /*int SpinTheMessageLoop()
  449. {
  450.    MSG msg;
  451.    if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
  452.       {
  453.       if (msg.message == WM_QUIT)
  454.          return FALSE;
  455.       if (!IsDialogMessage(hQryDlgBox, &msg))
  456.          {
  457.          TranslateMessage(&msg);
  458.          DispatchMessage(&msg);
  459.          }
  460.       }
  461.    return TRUE;
  462. }*/
  463. WPARAM game_loop_win32(HINSTANCE hInstance, HINSTANCE hPrevInstance, int nCmdShow)
  464. {
  465. //    static DESCRIPTOR_DATA dcon;
  466.     DESCRIPTOR_DATA *d;
  467.     MSG   msg;
  468.     DWORD dwTick = 0;
  469.     int   fBackground;
  470. extern char * help_greeting;
  471. //   HDC hDC;
  472.     char szBuffer[128];
  473.    extern int nAllocString;
  474.    extern int sAllocString;
  475.    extern int nAllocPerm;
  476.    extern int sAllocPerm;
  477.    static int nOldNString = -1;
  478.    static int nOldSString = -1;
  479.    static int nOldNPerm = -1;
  480.    static int nOldSPerm = -1;
  481.     /* Main loop */
  482. //    // Go init this application.
  483. //    InitMerc22(hInstance, nCmdShow);
  484.     // Get and dispatch messages for this applicaton.
  485.     fBackground = FALSE;
  486.     for ( ;; )
  487.         {
  488.         // Always give Windows messages priority over Merc execution
  489.         if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE))
  490.             {
  491.             if (msg.message == WM_QUIT)
  492.                break;
  493.             if (!IsDialogMessage(hQryDlgBox, &msg))
  494.                {
  495.                TranslateMessage(&msg);
  496.                DispatchMessage(&msg);
  497.                }
  498.             }
  499.        else if (!fBackground)
  500.           {
  501.           fBackground++;
  502.     time( &current_time );
  503. /*
  504.  * Autonomous game motion.
  505.  * (Synchronize to a clock.
  506.  * Busy wait (blargh).)
  507.  */
  508.     if (GetTickCount() - dwTick >= 1000 / PULSE_PER_SECOND)
  509.        {
  510.        dwTick = GetTickCount();
  511. /*
  512.  * Process input.
  513.  */
  514. for ( d = descriptor_list; d != NULL; d = d_next )
  515.    {
  516.        // Give Windows a change to run other programs
  517. //       if (!SpinTheMessageLoop())
  518. //          goto merc_done;
  519.    d_next = d->next;
  520.    d->fcommand = FALSE;
  521.    if ( d->character != NULL )
  522.         d->character->timer = 0;
  523. #if 0
  524.        // Did the user break connection?
  525.    if ( !read_from_descriptor( d ) )
  526.       {
  527.     if ( d->character != NULL )
  528. save_char_obj( d->character );
  529.     d->outtop = 0;
  530.     close_socket( d );
  531.     continue;
  532.     }
  533. #endif
  534.     if ( d->character != NULL && d->character->wait > 0 )
  535.         {
  536.     --d->character->wait;
  537.     continue;
  538.         }
  539.     read_from_buffer( d );
  540.     if ( d->incomm[0] != '' )
  541.     {
  542. d->fcommand = TRUE;
  543. stop_idling( d->character );
  544. if ( d->connected == CON_PLAYING )
  545.     if ( d->showstr_point )
  546.         show_string( d, d->incomm );
  547.     else
  548.         interpret( d->character, d->incomm );
  549. else
  550.     nanny( d, d->incomm );
  551. d->incomm[0] = '';
  552.     }
  553.    }
  554.        update_handler( );
  555.        // Update the screen
  556.        if (nAllocString != nOldNString || sAllocString != nOldSString)
  557.           {
  558.           nOldNString = nAllocString;
  559.           nOldSString = sAllocString;
  560.           wsprintf( szBuffer, "Strings %5d strings of %7d bytes",
  561.              nAllocString, sAllocString);
  562.           SetDlgItemText(hQryDlgBox, 103, szBuffer);
  563.           }
  564.        if (nAllocPerm != nOldNPerm || sAllocPerm != nOldSPerm)
  565.           {
  566.           wsprintf( szBuffer, "Perms   %5d blocks  of %7d bytes",
  567.             nAllocPerm, sAllocPerm );
  568.           nOldNPerm = nAllocPerm;
  569.           nOldSPerm = sAllocPerm;
  570.           SetDlgItemText(hQryDlgBox, 104, szBuffer);
  571.           }
  572.        if (nPlayers != nOldPlayers)
  573.           {
  574.           wsprintf( szBuffer, "%d", nPlayers);
  575.           nOldPlayers = nPlayers;
  576.           SetDlgItemText(hQryDlgBox, 101, szBuffer);
  577.           }
  578. /*
  579.  * Output.
  580.  */
  581. for ( d = descriptor_list; d != NULL; d = d_next )
  582. {
  583.        // Give Windows a change to run other programs
  584. //       if (!SpinTheMessageLoop())
  585. //          goto merc_done;
  586.     d_next = d->next;
  587.     if ( ( d->fcommand || d->outtop > 0 ) )
  588.     {
  589. if ( !process_output( d, TRUE ) && WSAGetLastError() != WSAEWOULDBLOCK)
  590. {
  591.     if ( d->character != NULL )
  592. save_char_obj( d->character );
  593.     d->outtop = 0;
  594.     close_socket( d );
  595. }
  596.     }
  597. }
  598. #if 0
  599. now_time = last_time;
  600. for ( ; ; )
  601. {
  602.     int delta;
  603.     {
  604. if ( dcon.character != NULL )
  605.     dcon.character->timer = 0;
  606. if ( !read_from_descriptor( &dcon ) )
  607. {
  608.     if ( dcon.character != NULL )
  609. save_char_obj( d->character );
  610.     dcon.outtop = 0;
  611.     close_socket( &dcon );
  612. }
  613. #if defined(MSDOS)
  614. break;
  615. #endif
  616.     }
  617.     gettimeofday( &now_time, NULL );
  618.     delta = ( now_time.tv_sec  - last_time.tv_sec  ) * 1000 * 1000
  619.   + ( now_time.tv_usec - last_time.tv_usec );
  620.     if ( delta >= 1000000 / PULSE_PER_SECOND )
  621. break;
  622. }
  623. last_time    = now_time;
  624. current_time = (time_t) last_time.tv_sec;
  625. #endif
  626.        }
  627.    fBackground--;
  628.           }
  629.        }
  630. merc_done:
  631.     return(msg.wParam);
  632. }
  633. //int main( int argc, char **argv )
  634. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrev, LPSTR lpszCmdLine, int nCmdShow)
  635. {
  636.     extern char * help_greeting;
  637.     struct timeval now_time;
  638.     int port;
  639. //#if defined(unix)
  640. //    int control;
  641. //#endif
  642. #ifdef WIN32
  643.    WORD wVersionRequested = MAKEWORD( 1, 1 );
  644.    WSADATA wsaData;
  645.    int err;
  646. #endif
  647.     /*
  648.      * Memory debugging if needed.
  649.      */
  650. #if defined(MALLOC_DEBUG)
  651.     malloc_debug( 2 );
  652. #endif
  653.     /*
  654.      * Init time.
  655.      */
  656.     gettimeofday( &now_time, NULL );
  657.     current_time = (time_t) now_time.tv_sec;
  658.     strcpy( str_boot_time, ctime( &current_time ) );
  659. #if 0
  660.     /*
  661.      * Reserve one channel for our use.
  662.      */
  663.     if ( ( fpReserve = fopen( NULL_FILE, "r" ) ) == NULL )
  664.     {
  665. perror( NULL_FILE );
  666. return 1;
  667.     }
  668. #endif
  669. #if 0 // @@@
  670.     /*
  671.      * Get the port number.
  672.      */
  673.     port = 1234;
  674.     if ( lpszCmdLine[0] )
  675.     {
  676. if ( !is_number( lpszCmdLine ) )
  677. {
  678. //     fprintf( stderr, "Usage: Merc22sv [port #]n" );
  679.        MessageBox(0, "Usage: Merc22sv [port #]", "Merc22", MB_ICONHAND|MB_OK);
  680.     return 1;
  681. }
  682. #if 0
  683. else if ( ( port = atoi( lpszCmdLine ) ) <= 1024 )
  684. {
  685.     fprintf( stderr, "Port number must be above 1024.n" );
  686.     return 1;
  687. }
  688. #endif
  689.     }
  690. #else
  691.     port = GetProfileInt("MercW32", "PortNum", 23); // %%%
  692. #endif
  693. #ifdef WIN32
  694.    err = WSAStartup( wVersionRequested, &wsaData );
  695.    if ( err != 0 ) {
  696.       MessageBox(0, "No useable WINSOCK.DLL, not loading sockets", "Serv",
  697.          MB_ICONHAND|MB_OK);
  698.       return INVALID_SOCKET;
  699.       }
  700.    /* Confirm that the Windows Sockets DLL supports 1.1.*/
  701.    /* Note that if the DLL supports versions greater    */
  702.    /* than 1.1 in addition to 1.1, it will still return */
  703.    /* 1.1 in wVersion since that is the version we      */
  704.    /* requested.                                        */
  705.    if ( LOBYTE( wsaData.wVersion ) != 1 ||
  706.          HIBYTE( wsaData.wVersion ) != 1 ) {
  707.       /* Tell the user that we couldn't find a useable */
  708.       /* winsock.dll.                                  */
  709.       WSACleanup( );
  710.       MessageBox(0, "Windows sockets version not 1.1, not loading sockets", "Serv",
  711.          MB_ICONHAND|MB_OK);
  712.       return INVALID_SOCKET;
  713.       }
  714.    /* Make sure that the version requested is >= 1.1.   */
  715.    /* The low byte is the major version and the high    */
  716.    /* byte is the minor version.                        */
  717.    if ( LOBYTE( wVersionRequested ) < 1 ||
  718.         ( LOBYTE( wVersionRequested ) == 1 &&
  719.           HIBYTE( wVersionRequested ) < 1 )) {
  720.       MessageBox(0, "Windows sockets version not 1.1, not loading sockets", "Serv",
  721.          MB_ICONHAND|MB_OK);
  722.        return INVALID_SOCKET;
  723.    }
  724.    /* Since we only support 1.1, set both wVersion and  */
  725.    /* wHighVersion to 1.1.                              */
  726. //   wsaData.wVersion = MAKEWORD( 1, 1 );
  727. //   wsaData.wHighVersion = MAKEWORD( 1, 1 );
  728. #endif
  729.     // Go init this application.
  730.     fpStderr = fopen( STDERR_FILE, "a" );
  731.     InitMerc22(hInstance, nCmdShow);
  732.     // Load the areas
  733.     log_string( "Loading areas" );
  734.     UpdateWindow(hWndOutput);
  735.     boot_db( );
  736.     // Validate enough of zones loaded to run Merc
  737.     if (help_greeting == 0)
  738.        log_string( "Error: areas.lst did not include help.are.  Game will crash when players log in" );
  739. #ifdef MERCW32
  740.     if (get_obj_index(OBJ_VNUM_ERROR) == 0)
  741.        {
  742.        log_string( "Error: Object #4 missing (check limbo.are).  MercW32 needs object #4");
  743.        log_string( "  to prevent crashes when players with invalid equipment log in.");
  744.        log_string( "  check LIMBO.ARE");
  745.        }
  746. #endif
  747.     if (get_obj_index(OBJ_VNUM_MONEY_ONE) == 0 || get_obj_index(OBJ_VNUM_MONEY_SOME) == 0)
  748.        log_string( "Error: Money objects #2 #3 did not load.  Check LIMBO.ARE");
  749.     if (get_obj_index(OBJ_VNUM_CORPSE_NPC) == 0 || get_obj_index(OBJ_VNUM_CORPSE_PC) == 0)
  750.        log_string( "Error: Corpse templates did not load.  Check LIMBO.ARE");
  751.     if (get_obj_index(OBJ_VNUM_SEVERED_HEAD) == 0 || get_obj_index(OBJ_VNUM_TORN_HEART) == 0 ||
  752.         get_obj_index(OBJ_VNUM_SLICED_ARM) == 0 || get_obj_index(OBJ_VNUM_SLICED_LEG) == 0 ||
  753.         get_obj_index(OBJ_VNUM_FINAL_TURD) == 0)
  754.        log_string( "Error: Severed body parts did not load.  Check LIMBO.ARE");
  755.     if (get_obj_index(OBJ_VNUM_MUSHROOM) == 0 || get_obj_index(OBJ_VNUM_LIGHT_BALL) == 0 ||
  756.         get_obj_index(OBJ_VNUM_SPRING) == 0)
  757.        log_string( "Error: Spell objects did not load.  Check LIMBO.ARE #20 #21 #22");
  758.     if (get_obj_index(OBJ_VNUM_SCHOOL_MACE) == 0 || get_obj_index(OBJ_VNUM_SCHOOL_DAGGER) == 0 ||
  759.         get_obj_index(OBJ_VNUM_SCHOOL_SWORD) == 0 || get_obj_index(OBJ_VNUM_SCHOOL_VEST) == 0 ||
  760.         get_obj_index(OBJ_VNUM_SCHOOL_SHIELD) == 0 || get_obj_index(OBJ_VNUM_SCHOOL_BANNER) == 0)
  761.        log_string( "Error: New player equipment did not load.  Check SCHOOL.ARE");
  762.     if (get_room_index(ROOM_VNUM_LIMBO) == 0)
  763.        log_string( "Error: The Void did not load.  Check LIMBO.ARE");
  764.     if (get_room_index(ROOM_VNUM_CHAT) == 0)
  765.        log_string( "Error:  Immortal chat-room did not load.  Check HITOWER.ARE");
  766.     if (get_room_index(ROOM_VNUM_TEMPLE) == 0 || get_room_index(ROOM_VNUM_ALTAR) == 0)
  767.        log_string( "Error: Midgaard temple and Alter necessary for game.  Check MIDGAARD.ARE");
  768.     if (get_room_index(ROOM_VNUM_SCHOOL) == 0)
  769.        log_string( "Error: New player initial room did not load.  Check SCHOOL.ARE" );
  770.     // #define MOB_VNUM_CITYGUARD    3060
  771.     // #define MOB_VNUM_VAMPIRE    3404
  772.     // #define MOB_VNUM_WALKING_DEAD 20
  773.     // Initialize sockets
  774.     log_string( "Initializing sockets" );
  775.     UpdateWindow(hWndOutput);
  776.     control = init_socket( port );
  777.     // Tell Winsock we are listening for accepted sockets
  778.     WSAAsyncSelect(control, hQryDlgBox, WM_NET_ACCEPT, FD_ACCEPT);
  779.     sprintf( log_buf, "Merc is ready to rock on port %d.", port );
  780.     log_string( log_buf );
  781.     game_loop_win32(hInstance, hPrev, nCmdShow);
  782.     closesocket( control );
  783.     /*
  784.      * That's all, folks.
  785.      */
  786.     log_string( "Normal termination of game." );
  787.     fclose(fpStderr);
  788. #ifdef WIN32
  789.     WSACleanup( );
  790. #endif
  791.     return 0;
  792. }
  793. // @@@ Orig junk
  794. /*
  795.  * The primary output interface for formatted output.
  796.  */
  797. void act( const char *format, CHAR_DATA *ch, const void *arg1,
  798.  const void *arg2, int type )
  799. {
  800.     static char * const he_she [] = { "it",  "he",  "she" };
  801.     static char * const him_her [] = { "it",  "him", "her" };
  802.     static char * const his_her [] = { "its", "his", "her" };
  803.     char buf[MAX_STRING_LENGTH];
  804.     char fname[MAX_INPUT_LENGTH];
  805.     CHAR_DATA *to;
  806.     CHAR_DATA *vch = (CHAR_DATA *) arg2;
  807.     OBJ_DATA *obj1 = (OBJ_DATA  *) arg1;
  808.     OBJ_DATA *obj2 = (OBJ_DATA  *) arg2;
  809.     const char *str;
  810.     const char *i;
  811.     char *point;
  812.     /*
  813.      * Discard null and zero-length messages.
  814.      */
  815.     if ( format == NULL || format[0] == '' )
  816. return;
  817.     to = ch->in_room->people;
  818.     if ( type == TO_VICT )
  819.     {
  820. if ( vch == NULL )
  821. {
  822.     bug( "Act: null vch with TO_VICT.", 0 );
  823.     return;
  824. }
  825. to = vch->in_room->people;
  826.     }
  827.     
  828.     for ( ; to != NULL; to = to->next_in_room )
  829.     {
  830. if ( ( to->desc == NULL 
  831.     && ( IS_NPC( to ) && !(to->pIndexData->progtypes & ACT_PROG ) ) )
  832.     || !IS_AWAKE(to) )
  833.     continue;
  834. if ( type == TO_CHAR && to != ch )
  835.     continue;
  836. if ( type == TO_VICT && ( to != vch || to == ch ) )
  837.     continue;
  838. if ( type == TO_ROOM && to == ch )
  839.     continue;
  840. if ( type == TO_NOTVICT && (to == ch || to == vch) )
  841.     continue;
  842. point = buf;
  843. str = format;
  844. while ( *str != '' )
  845. {
  846.     if ( *str != '$' )
  847.     {
  848. *point++ = *str++;
  849. continue;
  850.     }
  851.     ++str;
  852.     if ( arg2 == NULL && *str >= 'A' && *str <= 'Z' )
  853.     {
  854. bug( "Act: missing arg2 for code %d.", *str );
  855. i = " <@@@> ";
  856.     }
  857.     else
  858.     {
  859. switch ( *str )
  860. {
  861. default:  bug( "Act: bad code %d.", *str );
  862.   i = " <@@@> "; break;
  863. /* Thx alex for 't' idea */
  864. case 't': i = (char *) arg1; break;
  865. case 'T': i = (char *) arg2;           break;
  866. case 'n': i = PERS( ch,  to  ); break;
  867. case 'N': i = PERS( vch, to  ); break;
  868. case 'e': i = he_she  [URANGE(0, ch  ->sex, 2)]; break;
  869. case 'E': i = he_she  [URANGE(0, vch ->sex, 2)]; break;
  870. case 'm': i = him_her [URANGE(0, ch  ->sex, 2)]; break;
  871. case 'M': i = him_her [URANGE(0, vch ->sex, 2)]; break;
  872. case 's': i = his_her [URANGE(0, ch  ->sex, 2)]; break;
  873. case 'S': i = his_her [URANGE(0, vch ->sex, 2)]; break;
  874. case 'p':
  875.     i = can_see_obj( to, obj1 )
  876.     ? obj1->short_descr
  877.     : "something";
  878.     break;
  879. case 'P':
  880.     i = can_see_obj( to, obj2 )
  881.     ? obj2->short_descr
  882.     : "something";
  883.     break;
  884. case 'd':
  885.     if ( arg2 == NULL || ((char *) arg2)[0] == '' )
  886.     {
  887. i = "door";
  888.     }
  889.     else
  890.     {
  891. one_argument( (char *) arg2, fname );
  892. i = fname;
  893.     }
  894.     break;
  895. }
  896.     }
  897.     ++str;
  898.     while ( ( *point = *i ) != '' )
  899. ++point, ++i;
  900. }
  901. *point++ = 'n';
  902. *point++ = 'r';
  903.    // @@@ Following line added by Slash, to prevent bugs where stuff in the
  904.    // buffers fires mobprogs.  Particularly bad when a player enters the game
  905.    // and gets the greet_prog over and over.
  906.    *point = '';
  907. buf[0]   = UPPER(buf[0]);
  908. if (to->desc)
  909.   write_to_buffer( to->desc, buf, point - buf );
  910. #ifdef MOBPROGS
  911. if (MOBtrigger)
  912.   mprog_act_trigger( buf, to, ch, obj1, vch );
  913.                                             /* Added by Kahn */
  914. #endif
  915.     }
  916. #ifdef MOBPROGS
  917.     MOBtrigger = TRUE;
  918. #endif
  919.     return;
  920. }
  921. /*
  922.  * Append onto an output buffer.
  923.  */
  924. void write_to_buffer( DESCRIPTOR_DATA *d, const char *txt, int length )
  925. {
  926.     /* @@@ ECS */
  927.     if (d == 0)
  928.        return;
  929.        
  930.     /*
  931.      * Find length in case caller didn't.
  932.      */
  933.     if ( length <= 0 )
  934. length = strlen(txt);
  935.    // @@@
  936. //   else if (length < strlen(txt))
  937. //      MessageBox(0, "Length Error", "Merc22Sv", MB_ICONHAND|MB_OK);
  938.     /*
  939.      * Initial nr if needed.
  940.      */
  941.     if ( d->outtop == 0 && !d->fcommand )
  942.     {
  943. d->outbuf[0] = 'n';
  944. d->outbuf[1] = 'r';
  945. d->outtop = 2;
  946.     }
  947.     /*
  948.      * Expand the buffer as needed.
  949.      */
  950.     while ( d->outtop + length >= d->outsize )
  951.     {
  952. char *outbuf;
  953. outbuf      = alloc_mem( 2 * d->outsize );
  954. #if 1 // @@@ Deal with too large a memory increment...
  955.    if (!outbuf)
  956.       {
  957.       length = d->outsize - d->outtop - 1;
  958.       break;
  959.       }
  960. #endif
  961.    strncpy( outbuf, d->outbuf, d->outtop );
  962. free_mem( d->outbuf, d->outsize );
  963. d->outbuf   = outbuf;
  964. d->outsize *= 2;
  965.     }
  966.     /*
  967.      * Copy.
  968.      */
  969. //@@@ Ack!    strcpy( d->outbuf + d->outtop, txt );
  970. #if 1
  971.     if (length > 0)
  972.        {
  973. #endif
  974.     memcpy(d->outbuf + d->outtop, txt, length);
  975.     d->outtop += length;
  976. #if 1
  977.        }
  978. #endif
  979. #ifdef WIN32
  980.     // Tell Winsock to wake us when the socket becomes ready
  981.     if (!BlastedTrumpet(d->descriptor))
  982.        {
  983.  if ( d->character != NULL )
  984.     save_char_obj( d->character );
  985.  d->outtop = 0;
  986.  close_socket( d );
  987.        }
  988. #endif
  989.     return;
  990. }
  991. void close_socket( DESCRIPTOR_DATA *dclose )
  992. {
  993.     CHAR_DATA *ch;
  994.     if ( dclose->outtop > 0 )
  995. process_output( dclose, FALSE );
  996.     if ( dclose->snoop_by != NULL )
  997.     {
  998. write_to_buffer( dclose->snoop_by,
  999.     "Your victim has left the game.nr", 0 );
  1000.     }
  1001.     {
  1002. DESCRIPTOR_DATA *d;
  1003. for ( d = descriptor_list; d != NULL; d = d->next )
  1004. {
  1005.     if ( d->snoop_by == dclose )
  1006. d->snoop_by = NULL;
  1007. }
  1008.     }
  1009.     if ( ( ch = dclose->character ) != NULL )
  1010.     {
  1011. sprintf( log_buf, "Closing link to %s.", ch->name );
  1012. log_string( log_buf );
  1013. if ( dclose->connected == CON_PLAYING )
  1014. {
  1015.     act( "$n has lost $s link.", ch, NULL, NULL, TO_ROOM );
  1016.     ch->desc = NULL;
  1017. }
  1018. else
  1019. {
  1020.     free_char( dclose->character );
  1021. }
  1022.     }
  1023.     if ( d_next == dclose )
  1024. d_next = d_next->next;
  1025.     if ( dclose == descriptor_list )
  1026.     {
  1027. descriptor_list = descriptor_list->next;
  1028.     }
  1029.     else
  1030.     {
  1031. DESCRIPTOR_DATA *d;
  1032. for ( d = descriptor_list; d && d->next != dclose; d = d->next )
  1033.     ;
  1034. if ( d != NULL )
  1035.     d->next = dclose->next;
  1036. else
  1037.     bug( "Close_socket: dclose not found.", 0 );
  1038.     }
  1039.     closesocket( dclose->descriptor );
  1040.     free_string( dclose->host );
  1041.     dclose->next = descriptor_free;
  1042.     descriptor_free = dclose;
  1043.     nPlayers--;
  1044.     
  1045.     return;
  1046. }
  1047. // Write_to_descriptor bypasses the whole buffered output system.  Blech!
  1048. bool write_to_descriptor( int desc, char *txt, int length )
  1049. {
  1050.    int iStart;
  1051.    int nWrite;
  1052.    int nBlock;
  1053.    if ( length <= 0 )
  1054.       length = strlen(txt);
  1055.    for ( iStart = 0; iStart < length; iStart += nWrite )
  1056.       {
  1057.       nBlock = UMIN( length - iStart, 4096 );
  1058.       // @@@ Should check WSAEWOULDBLOCK, and we don't want MessageBox...
  1059.       if ( ( nWrite = send( desc, txt + iStart, nBlock, 0 ) ) == SOCKET_ERROR ||
  1060.          nWrite != nBlock)
  1061.          {
  1062.         log_string( "Write_to_descriptor" );
  1063.          return FALSE;
  1064.          }
  1065.       }
  1066. #ifdef WIN32
  1067.     // Tell Winsock to wake us when the socket becomes ready
  1068.     BlastedTrumpet(desc);
  1069. #endif
  1070.     return TRUE;
  1071. }
  1072. /*
  1073.  * Deal with sockets that haven't logged in yet.
  1074.  */
  1075. void nanny( DESCRIPTOR_DATA *d, char *argument )
  1076. {
  1077.     char buf[MAX_STRING_LENGTH];
  1078.     CHAR_DATA *ch;
  1079.     NOTE_DATA *pnote;
  1080.     char *pwdnew;
  1081.     char *p;
  1082.     int iClass;
  1083.     int iRace;
  1084.     int lines;
  1085.     int notes;
  1086.     bool fOld;
  1087.     while ( isspace(*argument) )
  1088. argument++;
  1089.     ch = d->character;
  1090.     switch ( d->connected )
  1091.     {
  1092.     default:
  1093. bug( "Nanny: bad d->connected %d.", d->connected );
  1094. close_socket( d );
  1095. return;
  1096.     case CON_GET_NAME:
  1097. if ( argument[0] == '' )
  1098. {
  1099.     close_socket( d );
  1100.     return;
  1101. }
  1102. argument[0] = UPPER(argument[0]);
  1103. if ( !check_parse_name( argument ) )
  1104. {
  1105.     write_to_buffer( d, "Illegal name, try another.nrName: ", 0 );
  1106.     return;
  1107. }
  1108. fOld = load_char_obj( d, argument );
  1109. ch   = d->character;
  1110. if ( IS_SET(ch->act, PLR_DENY) )
  1111. {
  1112.     sprintf( log_buf, "Denying access to %s@%s.", argument, d->host );
  1113.     log_string( log_buf );
  1114.     write_to_buffer( d, "You are denied access.nr", 0 );
  1115.     close_socket( d );
  1116.     return;
  1117. }
  1118. if ( check_reconnect( d, argument, FALSE ) )
  1119. {
  1120.     fOld = TRUE;
  1121. }
  1122. else
  1123. {
  1124.     if ( wizlock && !IS_HERO( ch ) && !ch->wizbit )
  1125.     {
  1126. write_to_buffer( d, "The game is wizlocked.nr", 0 );
  1127. close_socket( d );
  1128. return;
  1129.     }
  1130. }
  1131. if ( fOld )
  1132. {
  1133.     /* Old player */
  1134.     write_to_buffer( d, "Password: ", 0 );
  1135.     write_to_buffer( d, echo_off_str, 0 );
  1136.     d->connected = CON_GET_OLD_PASSWORD;
  1137.     return;
  1138. }
  1139. else
  1140. {
  1141.     /* New player */
  1142.     /* New characters with same name fix by Salem's Lot */
  1143.     if ( check_playing( d, ch->name ) )
  1144.         return;
  1145.     sprintf( buf, "Did I get that right, %s (Y/N)? ", argument );
  1146.     write_to_buffer( d, buf, 0 );
  1147.     d->connected = CON_CONFIRM_NEW_NAME;
  1148.     return;
  1149. }
  1150. //@@@ break;
  1151.     case CON_GET_OLD_PASSWORD:
  1152. #if defined(unix)
  1153. write_to_buffer( d, "nr", 2 );
  1154. #endif
  1155. if ( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ) )
  1156. {
  1157.     write_to_buffer( d, "Wrong password.nr", 0 );
  1158.     close_socket( d );
  1159.     return;
  1160. }
  1161. write_to_buffer( d, echo_on_str, 0 );
  1162. if ( check_reconnect( d, ch->name, TRUE ) )
  1163.     return;
  1164. if ( check_playing( d, ch->name ) )
  1165.     return;
  1166.     
  1167. sprintf( log_buf, "%s@%s has connected.", ch->name, d->host );
  1168. log_string( log_buf );
  1169. lines = ch->pcdata->pagelen;
  1170. ch->pcdata->pagelen = 20;
  1171. if ( IS_HERO(ch) )
  1172.     do_help( ch, "imotd" );
  1173. do_help( ch, "motd" );
  1174. ch->pcdata->pagelen = lines;
  1175. d->connected = CON_READ_MOTD;
  1176. break;
  1177.     case CON_CONFIRM_NEW_NAME:
  1178. switch ( *argument )
  1179. {
  1180. case 'y': case 'Y':
  1181.     sprintf( buf, "New character.nrGive me a password for %s: %s",
  1182. ch->name, echo_off_str );
  1183.     write_to_buffer( d, buf, 0 );
  1184.     d->connected = CON_GET_NEW_PASSWORD;
  1185.     break;
  1186. case 'n': case 'N':
  1187.     write_to_buffer( d, "Ok, what IS it, then? ", 0 );
  1188.     free_char( d->character );
  1189.     d->character = NULL;
  1190.     d->connected = CON_GET_NAME;
  1191.     break;
  1192. default:
  1193.     write_to_buffer( d, "Please type Yes or No? ", 0 );
  1194.     break;
  1195. }
  1196. break;
  1197.     case CON_GET_NEW_PASSWORD:
  1198. #if defined(unix)
  1199. write_to_buffer( d, "nr", 2 );
  1200. #endif
  1201. if ( strlen(argument) < 3 )
  1202. {
  1203.     write_to_buffer( d,
  1204. "Password must be at least three characters long.nrPassword: ",
  1205. 0 );
  1206.     return;
  1207. }
  1208. pwdnew = crypt( argument, ch->name );
  1209. for ( p = pwdnew; *p != ''; p++ )
  1210. {
  1211.     if ( *p == '~' )
  1212.     {
  1213. write_to_buffer( d,
  1214.     "New password not acceptable, try again.nrPassword: ",
  1215.     0 );
  1216. return;
  1217.     }
  1218. }
  1219. free_string( ch->pcdata->pwd );
  1220. ch->pcdata->pwd = str_dup( pwdnew );
  1221. write_to_buffer( d, "Please retype password: ", 0 );
  1222. d->connected = CON_CONFIRM_NEW_PASSWORD;
  1223. break;
  1224.     case CON_CONFIRM_NEW_PASSWORD:
  1225. #if defined(unix)
  1226. write_to_buffer( d, "nr", 2 );
  1227. #endif
  1228. if ( strcmp( crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ) )
  1229. {
  1230.     write_to_buffer( d, "Passwords don't match.nrRetype password: ",
  1231. 0 );
  1232.     d->connected = CON_GET_NEW_PASSWORD;
  1233.     return;
  1234. }
  1235. write_to_buffer( d, echo_on_str, 0 );
  1236. write_to_buffer( d, "What is your sex (M/F/N)? ", 0 );
  1237. d->connected = CON_GET_NEW_SEX;
  1238. break;
  1239.     case CON_GET_NEW_SEX:
  1240. switch ( argument[0] )
  1241. {
  1242. case 'm': case 'M': ch->sex = SEX_MALE;    break;
  1243. case 'f': case 'F': ch->sex = SEX_FEMALE;  break;
  1244. case 'n': case 'N': ch->sex = SEX_NEUTRAL; break;
  1245. default:
  1246.     write_to_buffer( d, "That's not a sex.nrWhat IS your sex? ", 0 );
  1247.     return;
  1248. }
  1249. #ifdef RACES
  1250. strcpy( buf, "Select a race [" );
  1251. for ( iRace = 0; iRace < MAX_RACE; iRace++ )
  1252. {
  1253.     if ( iRace > 0 )
  1254. strcat( buf, " " );
  1255.     strcat( buf, race_table[iRace].who_name );
  1256. }
  1257. strcat( buf, "]: " );
  1258. write_to_buffer( d, buf, 0 );
  1259. d->connected = CON_GET_NEW_RACE;
  1260. break;
  1261.     case CON_GET_NEW_RACE:
  1262. for ( iRace = 0; iRace < MAX_RACE; iRace++ )
  1263. {
  1264.     if ( !str_cmp( argument, race_table[iRace].who_name ) )
  1265.     {
  1266. ch->race = iRace;
  1267. break;
  1268.     }
  1269. }
  1270. if ( iRace == MAX_RACE )
  1271. {
  1272.     write_to_buffer( d,
  1273. "That's not a race.nrWhat IS your race? ", 0 );
  1274.     return;
  1275. }
  1276. #endif
  1277. strcpy( buf, "Select a class [" );
  1278. for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
  1279. {
  1280.     if ( iClass > 0 )
  1281. strcat( buf, " " );
  1282.     strcat( buf, class_table[iClass].who_name );
  1283. }
  1284. strcat( buf, "]: " );
  1285. write_to_buffer( d, buf, 0 );
  1286. d->connected = CON_GET_NEW_CLASS;
  1287. break;
  1288.     case CON_GET_NEW_CLASS:
  1289. for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
  1290. {
  1291.     if ( !str_cmp( argument, class_table[iClass].who_name ) )
  1292.     {
  1293. ch->class = iClass;
  1294. break;
  1295.     }
  1296. }
  1297. if ( iClass == MAX_CLASS )
  1298. {
  1299.     write_to_buffer( d,
  1300. "That's not a class.nrWhat IS your class? ", 0 );
  1301.     return;
  1302. }
  1303. sprintf( log_buf, "%s@%s new player.", ch->name, d->host );
  1304. log_string( log_buf );
  1305. write_to_buffer( d, "nr", 2 );
  1306. ch->pcdata->pagelen = 20;
  1307. ch->prompt = "<%hhp %mm %vmv> ";
  1308. do_help( ch, "motd" );
  1309. d->connected = CON_READ_MOTD;
  1310. break;
  1311.     case CON_READ_MOTD:
  1312. ch->next = char_list;
  1313. char_list = ch;
  1314. d->connected = CON_PLAYING;
  1315. send_to_char(
  1316.     "nrWelcome to Merc Diku Mud.  May your visit here be ... Mercenary.nr",
  1317.     ch );
  1318. if ( ch->level == 0 )
  1319. {
  1320.     OBJ_DATA *obj;
  1321.     switch ( class_table[ch->class].attr_prime )
  1322.     {
  1323.     case APPLY_STR: ch->pcdata->perm_str = 16; break;
  1324.     case APPLY_INT: ch->pcdata->perm_int = 16; break;
  1325.     case APPLY_WIS: ch->pcdata->perm_wis = 16; break;
  1326.     case APPLY_DEX: ch->pcdata->perm_dex = 16; break;
  1327.     case APPLY_CON: ch->pcdata->perm_con = 16; break;
  1328.     }
  1329. #ifdef RACES
  1330.        ch->pcdata->perm_str += race_table[ch->race].mod_str;
  1331.        ch->pcdata->perm_int += race_table[ch->race].mod_int;
  1332.        ch->pcdata->perm_wis += race_table[ch->race].mod_wis;
  1333.        ch->pcdata->perm_dex += race_table[ch->race].mod_dex;
  1334.        ch->pcdata->perm_con += race_table[ch->race].mod_con;
  1335. #endif
  1336.     ch->level = 1;
  1337.     ch->exp = 1000;
  1338.     ch->hit = ch->max_hit;
  1339.     ch->mana = ch->max_mana;
  1340.     ch->move = ch->max_move;
  1341. #ifdef RACES
  1342.        ch->affected_by = race_table[ch->race].bitvector;
  1343. #else
  1344.        ch->affected_by = 0;
  1345. #endif
  1346.     sprintf( buf, "the %s",
  1347. title_table [ch->class] [ch->level]
  1348. [ch->sex == SEX_FEMALE ? 1 : 0] );
  1349.     set_title( ch, buf );
  1350.     obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_BANNER), 0 );
  1351.     obj_to_char( obj, ch );
  1352.     equip_char( ch, obj, WEAR_LIGHT );
  1353.     obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_VEST), 0 );
  1354.     obj_to_char( obj, ch );
  1355.     equip_char( ch, obj, WEAR_BODY );
  1356.     obj = create_object( get_obj_index(OBJ_VNUM_SCHOOL_SHIELD), 0 );
  1357.     obj_to_char( obj, ch );
  1358.     equip_char( ch, obj, WEAR_SHIELD );
  1359.     obj = create_object( get_obj_index(class_table[ch->class].weapon),
  1360. 0 );
  1361.     obj_to_char( obj, ch );
  1362.     equip_char( ch, obj, WEAR_WIELD );
  1363.     char_to_room( ch, get_room_index( ROOM_VNUM_SCHOOL ) );
  1364. }
  1365. else if ( ch->in_room != NULL )
  1366. {
  1367.     char_to_room( ch, ch->in_room );
  1368. }
  1369. else if ( IS_IMMORTAL(ch) )
  1370. {
  1371.     char_to_room( ch, get_room_index( ROOM_VNUM_CHAT ) );
  1372. }
  1373. else
  1374. {
  1375. #ifdef RACES
  1376.     char_to_room( ch, get_room_index( race_table[ch->race].city_temple ) );
  1377. #else
  1378.     char_to_room( ch, get_room_index( ROOM_VNUM_TEMPLE ) );
  1379. #endif
  1380. }
  1381. act( "$n has entered the game.", ch, NULL, NULL, TO_ROOM );
  1382. do_look( ch, "auto" );
  1383. /* check for new notes */
  1384. notes = 0;
  1385. for ( pnote = note_list; pnote != NULL; pnote = pnote->next )
  1386.     if ( is_note_to( ch, pnote ) && str_cmp( ch->name, pnote->sender )
  1387. && pnote->date_stamp > ch->last_note )
  1388.         notes++;
  1389. if ( notes == 1 )
  1390.     send_to_char( "nrYou have one new note waiting.nr", ch );
  1391. else
  1392.     if ( notes > 1 )
  1393.     {
  1394. sprintf( buf, "nrYou have %d new notes waiting.nr",
  1395. notes );
  1396. send_to_char( buf, ch );
  1397.     }
  1398. break;
  1399.     }
  1400.     return;
  1401. }
  1402. /*
  1403.  * Parse a name for acceptability.
  1404.  */
  1405. bool check_parse_name( char *name )
  1406. {
  1407.     /*
  1408.      * Reserved words.
  1409.      */
  1410.     if ( is_name( name, "all auto immortal self someone" ) )
  1411. return FALSE;
  1412.     /*
  1413.      * Length restrictions.
  1414.      */
  1415.     if ( strlen(name) <  3 )
  1416. return FALSE;
  1417. #if defined(MSDOS)
  1418.     if ( strlen(name) >  8 )
  1419. return FALSE;
  1420. #endif
  1421. #if defined(macintosh) || defined(unix)
  1422.     if ( strlen(name) > 12 )
  1423. return FALSE;
  1424. #endif
  1425.     /*
  1426.      * Alphanumerics only.
  1427.      * Lock out IllIll twits.
  1428.      */
  1429.     {
  1430. char *pc;
  1431. bool fIll;
  1432. fIll = TRUE;
  1433. for ( pc = name; *pc != ''; pc++ )
  1434. {
  1435.     if ( !isalpha(*pc) )
  1436. return FALSE;
  1437.     if ( LOWER(*pc) != 'i' && LOWER(*pc) != 'l' )
  1438. fIll = FALSE;
  1439. }
  1440. if ( fIll )
  1441.     return FALSE;
  1442.     }
  1443.     /*
  1444.      * Prevent players from naming themselves after mobs.
  1445.      */
  1446.     {
  1447. extern MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH];
  1448. MOB_INDEX_DATA *pMobIndex;
  1449. int iHash;
  1450. for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
  1451. {
  1452.     for ( pMobIndex  = mob_index_hash[iHash];
  1453.   pMobIndex != NULL;
  1454.   pMobIndex  = pMobIndex->next )
  1455.     {
  1456. if ( is_name( name, pMobIndex->player_name ) )
  1457.     return FALSE;
  1458.     }
  1459. }
  1460.     }
  1461.     return TRUE;
  1462. }
  1463. /*
  1464.  * Look for link-dead player to reconnect.
  1465.  */
  1466. bool check_reconnect( DESCRIPTOR_DATA *d, char *name, bool fConn )
  1467. {
  1468.     CHAR_DATA *ch;
  1469.     OBJ_DATA *obj;
  1470.     for ( ch = char_list; ch != NULL; ch = ch->next )
  1471.     {
  1472. if ( !IS_NPC(ch)
  1473. && ( !fConn || ch->desc == NULL )
  1474. &&   !str_cmp( d->character->name, ch->name ) )
  1475. {
  1476.     if ( fConn == FALSE )
  1477.     {
  1478. free_string( d->character->pcdata->pwd );
  1479. d->character->pcdata->pwd = str_dup( ch->pcdata->pwd );
  1480.     }
  1481.     else
  1482.     {
  1483. free_char( d->character );
  1484. d->character = ch;
  1485. ch->desc  = d;
  1486. ch->timer  = 0;
  1487. send_to_char( "Reconnecting.nr", ch );
  1488. act( "$n has reconnected.", ch, NULL, NULL, TO_ROOM );
  1489. sprintf( log_buf, "%s@%s reconnected.", ch->name, d->host );
  1490. log_string( log_buf );
  1491. d->connected = CON_PLAYING;
  1492. /*
  1493.  * Contributed by Gene Choi
  1494.  */
  1495. if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL
  1496.     && obj->item_type == ITEM_LIGHT
  1497.     && obj->value[2] != 0
  1498.     && ch->in_room != NULL )
  1499.     ++ch->in_room->light;
  1500.     }
  1501.     return TRUE;
  1502. }
  1503.     }
  1504.     return FALSE;
  1505. }
  1506. /*
  1507.  * Check if already playing.
  1508.  */
  1509. bool check_playing( DESCRIPTOR_DATA *d, char *name )
  1510. {
  1511.     DESCRIPTOR_DATA *dold;
  1512.     for ( dold = descriptor_list; dold; dold = dold->next )
  1513.     {
  1514. if ( dold != d
  1515. &&   dold->character != NULL
  1516. &&   dold->connected != CON_GET_NAME
  1517. &&   dold->connected != CON_GET_OLD_PASSWORD
  1518. &&   !str_cmp( name, dold->original
  1519.          ? dold->original->name : dold->character->name ) )
  1520. {
  1521.     write_to_buffer( d, "Already playing.nrName: ", 0 );
  1522.     d->connected = CON_GET_NAME;
  1523.     if ( d->character != NULL )
  1524.     {
  1525. free_char( d->character );
  1526. d->character = NULL;
  1527.     }
  1528.     return TRUE;
  1529. }
  1530.     }
  1531.     return FALSE;
  1532. }
  1533. void stop_idling( CHAR_DATA *ch )
  1534. {
  1535.     if ( ch == NULL
  1536.     ||   ch->desc == NULL
  1537.     ||   ch->desc->connected != CON_PLAYING
  1538.     ||   ch->was_in_room == NULL
  1539.     ||   ch->in_room != get_room_index( ROOM_VNUM_LIMBO ) )
  1540. return;
  1541.     ch->timer = 0;
  1542.     char_from_room( ch );
  1543.     char_to_room( ch, ch->was_in_room );
  1544.     ch->was_in_room = NULL;
  1545.     act( "$n has returned from the void.", ch, NULL, NULL, TO_ROOM );
  1546.     return;
  1547. }
  1548. /*
  1549.  * Low level output function.
  1550.  */
  1551. bool process_output( DESCRIPTOR_DATA *d, bool fPrompt )
  1552. {
  1553.     extern bool merc_down;
  1554.     /*
  1555.      * Bust a prompt.
  1556.      */
  1557.     if ( fPrompt && !merc_down && d->connected == CON_PLAYING )
  1558.         if ( d->showstr_point )
  1559.     write_to_buffer( d,
  1560.   "[Please type (c)ontinue, (r)efresh, (b)ack, (h)elp, (q)uit, or RETURN]:  ",
  1561.     0 );
  1562. else
  1563. {
  1564.     CHAR_DATA *ch;
  1565.     ch = d->original ? d->original : d->character;
  1566.     if ( IS_SET(ch->act, PLR_BLANK) )
  1567.         write_to_buffer( d, "nr", 2 );
  1568.     if ( IS_SET(ch->act, PLR_PROMPT) )
  1569. //         bust_a_prompt( ch );
  1570.         bust_a_prompt( d );
  1571.     if ( IS_SET(ch->act, PLR_TELNET_GA) )
  1572.         write_to_buffer( d, go_ahead_str, 0 );
  1573. }
  1574.     /*
  1575.      * Short-circuit if nothing to write.
  1576.      */
  1577.     if ( d->outtop == 0 )
  1578. return TRUE;
  1579.     /*
  1580.      * Snoop-o-rama.
  1581.      */
  1582.     if ( d->snoop_by != NULL )
  1583.     {
  1584. write_to_buffer( d->snoop_by, "% ", 2 );
  1585. write_to_buffer( d->snoop_by, d->outbuf, d->outtop );
  1586.     }
  1587. #if 0
  1588.     /*
  1589.      * OS-dependent output.
  1590.      */
  1591.     if ( !write_to_descriptor( d->descriptor, d->outbuf, d->outtop ) )
  1592.     {
  1593. d->outtop = 0;
  1594. return FALSE;
  1595.     }
  1596.     else
  1597.     {
  1598. d->outtop = 0;
  1599. return TRUE;
  1600.     }
  1601. #endif
  1602.    // Wake up Winsock, if necessary
  1603.     if (!BlastedTrumpet(d->descriptor))
  1604.        {
  1605.  if ( d->character != NULL )
  1606.     save_char_obj( d->character );
  1607.  d->outtop = 0;
  1608.  close_socket( d );
  1609.        return FALSE;
  1610.        }
  1611.    return TRUE;
  1612. }
  1613. /*
  1614.  * Bust a prompt (player settable prompt)
  1615.  * coded by Morgenes for Aldara Mud
  1616.  */
  1617. //void bust_a_prompt( CHAR_DATA *ch )
  1618. void bust_a_prompt( DESCRIPTOR_DATA *d )
  1619. {
  1620.    char buf[MAX_STRING_LENGTH];
  1621.    char buf2[MAX_STRING_LENGTH];
  1622.    const char *str;
  1623.    const char *i;
  1624.    char *point;
  1625.    CHAR_DATA *ch;
  1626.    CHAR_DATA *victim;
  1627.    ch = d->character;
  1628.    if( ch->prompt == NULL || ch->prompt[0] == '' )
  1629.    {
  1630.       send_to_char( "nrnr", ch );
  1631.       return;
  1632.    }
  1633.    point = buf;
  1634.  //  str = ch->prompt;
  1635.    str = d->original != NULL ? d->original->prompt :  /* VERY VERY NEW */
  1636.          d->character->prompt;
  1637.    while( *str != '' )
  1638.    {
  1639.       if( *str != '%' )
  1640.       {
  1641.          *point++ = *str++;
  1642.          continue;
  1643.       }
  1644.       ++str;
  1645.       switch( *str )
  1646.       {
  1647.          default :
  1648.             i = " "; break;
  1649.          case 'h' :
  1650.             sprintf( buf2, "%d", ch->hit );
  1651.             i = buf2; break;
  1652.          case 'H' :
  1653.             sprintf( buf2, "%d", ch->max_hit );
  1654.             i = buf2; break;
  1655.          case 'm' :
  1656.             sprintf( buf2, "%d", ch->mana );
  1657.             i = buf2; break;
  1658.          case 'M' :
  1659.             sprintf( buf2, "%d", ch->max_mana );
  1660.             i = buf2; break;
  1661.          case 'v' :
  1662.             sprintf( buf2, "%d", ch->move );
  1663.             i = buf2; break;
  1664.          case 'V' :
  1665.             sprintf( buf2, "%d", ch->max_move );
  1666.             i = buf2; break;
  1667.          case 'x' :
  1668.             sprintf( buf2, "%d", ch->exp );
  1669.             i = buf2; break;
  1670.          case 'g' :
  1671.             sprintf( buf2, "%d", ch->gold);
  1672.             i = buf2; break;
  1673.          case 'a' :
  1674.             if( ch->level < 5 )
  1675.                sprintf( buf2, "%d", ch->alignment );
  1676.             else
  1677.                sprintf( buf2, "%s", IS_GOOD(ch) ? "good" : IS_EVIL(ch) ?
  1678.                 "evil" : "neutral" );
  1679.             i = buf2; break;
  1680.          case 'r' :
  1681.             if( ch->in_room != NULL )
  1682.                sprintf( buf2, "%s", ch->in_room->name );
  1683.             else
  1684.                sprintf( buf2, " " );
  1685.             i = buf2; break;
  1686.          case 'R' :
  1687.             if( IS_IMMORTAL( ch ) && ch->in_room != NULL )
  1688.                sprintf( buf2, "%d", ch->in_room->vnum );
  1689.             else
  1690.                sprintf( buf2, " " );
  1691.             i = buf2; break;
  1692.          case 'z' :
  1693.             if( IS_IMMORTAL( ch ) && ch->in_room != NULL )
  1694.                sprintf( buf2, "%s", ch->in_room->area->name );
  1695.             else
  1696.                sprintf( buf2, " " );
  1697.             i = buf2; break;
  1698.          case '%' :
  1699.             sprintf( buf2, "%%" );
  1700.             i = buf2; break;
  1701.       }
  1702.       ++str;
  1703.       while( (*point = *i) != '' )
  1704.          ++point, ++i;
  1705.    }
  1706.    
  1707.         /* battle prompt */
  1708.         if ((victim = ch->fighting) != NULL)
  1709.           {
  1710.             int percent;
  1711.             char wound[100];
  1712.             char buf[MAX_STRING_LENGTH];
  1713.  
  1714.             write_to_buffer( d, "nr", 0);
  1715.                 if (victim->max_hit > 0)
  1716.                 percent = victim->hit * 100 / victim->max_hit;
  1717.             else
  1718.                 percent = -1;
  1719.  
  1720.             if (percent >= 100)
  1721.                 sprintf(wound,"is in excellent condition.");
  1722.             else if (percent >= 90)
  1723.                 sprintf(wound,"has a few scratches.");
  1724.             else if (percent >= 75)
  1725.                 sprintf(wound,"has some small wounds and bruises.");
  1726.             else if (percent >= 50)
  1727.                 sprintf(wound,"has quite a few wounds.");
  1728.             else if (percent >= 30)
  1729.                 sprintf(wound,"has some big nasty wounds and scratches.");
  1730.             else if (percent >= 15)
  1731.                 sprintf(wound,"looks pretty hurt.");
  1732.             else if (percent >= 0)
  1733.                 sprintf(wound,"is in awful condition.");
  1734.             else
  1735.                 sprintf(wound,"is bleeding to death.");
  1736.  
  1737.             sprintf(buf,"%s %s nr",
  1738.                     IS_NPC(victim) ? victim->short_descr : victim->name,wound);
  1739.             buf[0] = UPPER(buf[0]);
  1740.             write_to_buffer( d, buf, 0);
  1741.           }
  1742.    write_to_buffer( ch->desc, buf, point - buf );
  1743.    return;
  1744. }
  1745. /* The heart of the pager.  Thanks to N'Atas-Ha, ThePrincedom
  1746.    for porting this SillyMud code for MERC 2.0 and laying down the groundwork.
  1747.    Thanks to Blackstar, hopper.cs.uiowa.edu 4000 for which
  1748.    the improvements to the pager was modeled from.  - Kahn */
  1749. void show_string(struct descriptor_data *d, char *input)
  1750. {
  1751.   char buffer[ MAX_STRING_LENGTH ];
  1752.   char buf[ MAX_INPUT_LENGTH ];
  1753.   register char *scan, *chk;
  1754.   int lines /*= 0*/, toggle=1;
  1755.   one_argument(input, buf);
  1756.   switch( UPPER( buf[0] ) )
  1757.   {
  1758.   case '':
  1759.   case 'C': /* show next page of text */
  1760.     lines = 0;
  1761.     break;
  1762.   case 'R': /* refresh current page of text */
  1763.     lines = - 1 - (d->character->pcdata->pagelen);
  1764.     break;
  1765.   case 'B': /* scroll back a page of text */
  1766.     lines = -(2*d->character->pcdata->pagelen);
  1767.     break;
  1768.   case 'H': /* Show some help */
  1769.     write_to_buffer( d,
  1770.         "C, or Return = continue, R = redraw this page,nr", 0 );
  1771.     write_to_buffer( d,
  1772.         "B = back one page, H = this help, Q or other keys = exit.nrnr",
  1773.     0 );
  1774.     lines = - 1 - (d->character->pcdata->pagelen);
  1775.     break;
  1776.   default: /*otherwise, stop the text viewing */
  1777.     // @@@ Sands had some changes here that lead to double freeing
  1778.     if ( d->showstr_head )
  1779.     {
  1780.       free_string( d->showstr_head );
  1781. //      d->showstr_head = str_dup( "" );
  1782.       d->showstr_head = 0;
  1783.     }
  1784. //    free_string( d->showstr_point );
  1785. //    d->showstr_point = str_dup( "" );
  1786.     d->showstr_point = 0;
  1787.     return;
  1788.   }
  1789.   /* do any backing up necessary */
  1790.   if (lines < 0)
  1791.   {
  1792.     for ( scan = d->showstr_point; scan > d->showstr_head; scan-- )
  1793.          if ( ( *scan == 'n' ) || ( *scan == 'r' ) )
  1794.  {
  1795.      toggle = -toggle;
  1796.      if ( toggle < 0 )
  1797.          if ( !( ++lines ) )
  1798.      break;
  1799.  }
  1800.     d->showstr_point = scan;
  1801.   }
  1802.   /* show a chunk */
  1803.   lines  = 0;
  1804.   toggle = 1;
  1805.   for ( scan = buffer; ; scan++, d->showstr_point++ )
  1806.        if ( ( ( *scan = *d->showstr_point ) == 'n' || *scan == 'r' )
  1807.    && ( toggle = -toggle ) < 0 )
  1808.    lines++;
  1809.        else
  1810.    if ( !*scan || ( d->character && !IS_NPC( d->character )
  1811.   && lines >= d->character->pcdata->pagelen) )
  1812.    {
  1813.        *scan = '';
  1814.        write_to_buffer( d, buffer, strlen( buffer ) );
  1815.      /* See if this is the end (or near the end) of the string */
  1816.        for ( chk = d->showstr_point; isspace( *chk ); chk++ );
  1817.        if ( !*chk )
  1818.        {
  1819.    if ( d->showstr_head )
  1820.    {
  1821.       free_string( d->showstr_head );
  1822.       d->showstr_head  = 0;
  1823.    }
  1824.    d->showstr_point = 0;
  1825.        }
  1826.        return;
  1827.    }
  1828. //@@@  return;
  1829. }
  1830. SOCKET init_socket( int port )
  1831. {
  1832.    // Assume there aren't any sockets
  1833. //@@@   fSockets = FALSE;
  1834.     static struct sockaddr_in sa_zero;
  1835.     struct sockaddr_in sa;
  1836.     SOCKET newsock;
  1837.     int x = 1;
  1838. #if 0
  1839.    WORD wVersionRequested = MAKEWORD( 1, 1 );
  1840.    WSADATA wsaData;
  1841.    int err = WSAStartup( wVersionRequested, &wsaData );
  1842.    if ( err != 0 ) {
  1843.       MessageBox(0, "No useable WINSOCK.DLL, not loading sockets", "Serv",
  1844.          MB_ICONHAND|MB_OK);
  1845.       return INVALID_SOCKET;
  1846.       }
  1847.    /* Confirm that the Windows Sockets DLL supports 1.1.*/
  1848.    /* Note that if the DLL supports versions greater    */
  1849.    /* than 1.1 in addition to 1.1, it will still return */
  1850.    /* 1.1 in wVersion since that is the version we      */
  1851.    /* requested.                                        */
  1852.    if ( LOBYTE( wsaData.wVersion ) != 1 ||
  1853.          HIBYTE( wsaData.wVersion ) != 1 ) {
  1854.       /* Tell the user that we couldn't find a useable */
  1855.       /* winsock.dll.                                  */
  1856.       WSACleanup( );
  1857.       MessageBox(0, "Windows sockets version not 1.1, not loading sockets", "Serv",
  1858.          MB_ICONHAND|MB_OK);
  1859.       return INVALID_SOCKET;
  1860.       }
  1861.    /* Make sure that the version requested is >= 1.1.   */
  1862.    /* The low byte is the major version and the high    */
  1863.    /* byte is the minor version.                        */
  1864.    if ( LOBYTE( wVersionRequested ) < 1 ||
  1865.         ( LOBYTE( wVersionRequested ) == 1 &&
  1866.           HIBYTE( wVersionRequested ) < 1 )) {
  1867.       MessageBox(0, "Windows sockets version not 1.1, not loading sockets", "Serv",
  1868.          MB_ICONHAND|MB_OK);
  1869.        return INVALID_SOCKET;
  1870.    }
  1871.    /* Since we only support 1.1, set both wVersion and  */
  1872.    /* wHighVersion to 1.1.                              */
  1873.    wsaData.wVersion = MAKEWORD( 1, 1 );
  1874.    wsaData.wHighVersion = MAKEWORD( 1, 1 );
  1875. #endif
  1876. //   fSockets = TRUE;
  1877.     if ( ( newsock = socket( PF_INET, SOCK_STREAM, 0 ) ) == INVALID_SOCKET )
  1878.        {
  1879.     MessageBox(0, "Init_socket: socket", __FILE__, MB_OK);
  1880.     return INVALID_SOCKET;
  1881.        }
  1882.     if ( setsockopt( newsock, SOL_SOCKET, SO_REUSEADDR, (char *) &x, sizeof(x) )
  1883.              == SOCKET_ERROR )
  1884.        {
  1885.     MessageBox(0, "Init_socket: SO_REUSEADDR", __FILE__, MB_OK);
  1886.        closesocket(newsock);
  1887.        return INVALID_SOCKET;
  1888.        }
  1889. #if 0
  1890.     {
  1891.    struct linger ld;
  1892. ld.l_onoff  = 1;
  1893. ld.l_linger = 1000;
  1894. if ( setsockopt( fd, SOL_SOCKET, SO_DONTLINGER, (char *) &ld, sizeof(ld) ) < 0 )
  1895. {
  1896.     MessageBox(0, 0, "Init_socket: SO_DONTLINGER", __FILE__, MB_OK );
  1897.     closesocket( fd );
  1898.     return INVALID_SOCKET;
  1899. }
  1900.     }
  1901. #endif
  1902.     sa     = sa_zero;
  1903.     sa.sin_family   = AF_INET;
  1904.     sa.sin_port     = htons( port );
  1905.     if ( bind( newsock, (struct sockaddr *) &sa, sizeof(sa) ) == SOCKET_ERROR )
  1906.     {
  1907. MessageBox(0, "Init_socket: bind", __FILE__, MB_OK );
  1908. closesocket( newsock );
  1909. return INVALID_SOCKET;
  1910.     }
  1911.     if ( listen( newsock, 3 ) == SOCKET_ERROR )
  1912.     {
  1913. MessageBox(0, "Init_socket: listen", __FILE__, MB_OK );
  1914. closesocket( newsock );
  1915. return INVALID_SOCKET;
  1916.     }
  1917.     return newsock;
  1918. }
  1919. LRESULT SocketAccept (WPARAM wParam, LPARAM lParam)
  1920. {
  1921.     static DESCRIPTOR_DATA d_zero;
  1922.       SOCKET sSocket;
  1923.    SOCKADDR_IN saPeer;
  1924.    int iAddrSize;
  1925. //    int iError;
  1926. char     buf[512];
  1927.          DESCRIPTOR_DATA *dnew;
  1928. switch(WSAGETSELECTEVENT(lParam))
  1929. {
  1930.       default:
  1931.          MessageBeep(-1);
  1932.          break;
  1933. case FD_ACCEPT:
  1934.    {
  1935. // LPSOCKADDR_IN lpsaHostAddr;
  1936. //         LPHOSTENT    lpheHostEnt;
  1937. //       struct sockaddr_in isa;
  1938. //       int i = sizeof(isa);
  1939. //        getsockname(s, &isa, &i);
  1940.          struct sockaddr_in sock;
  1941.          int size = sizeof(sock);
  1942. //         MessageBeep(-1);
  1943. /* Get a pending accept */
  1944. iAddrSize = sizeof(SOCKADDR_IN);
  1945. sSocket = accept( control, (LPSOCKADDR) &saPeer, (LPINT) &iAddrSize );
  1946. if ( sSocket == INVALID_SOCKET )
  1947.    {
  1948. //            MessageBox(0, "Couldn't accept() connection.", "Serv",
  1949. //               MB_ICONHAND|MB_OK);
  1950.             log_string("Couldn't accept() connection");
  1951. return FALSE;
  1952.    }
  1953.          // Cons a new descriptor.
  1954.          if ( descriptor_free )
  1955.             {
  1956.             dnew = descriptor_free;
  1957.             descriptor_free = descriptor_free->next;
  1958.             dnew->descriptor = sSocket;
  1959.             }
  1960.          else
  1961.           dnew = alloc_perm( sizeof(*dnew) );
  1962.          *dnew = d_zero;
  1963.          dnew->descriptor = sSocket;
  1964.          dnew->connected = CON_GET_NAME;
  1965.          dnew->showstr_head  = NULL;
  1966.          dnew->showstr_point = NULL;
  1967.          dnew->outsize = 2000;
  1968.          dnew->outbuf = alloc_mem( dnew->outsize );
  1969.          dnew->host_and_name = alloc_mem( sizeof *dnew->host_and_name );
  1970.          strcpy(dnew->host_and_name->username, "<waiting>");
  1971.          if ( getpeername( sSocket, (struct sockaddr *) &sock, &size ) == SOCKET_ERROR )
  1972.             {
  1973. #if 1
  1974.             wsprintf(buf, "new_descriptor(): getpeername() == %d",
  1975.                WSAGetLastError());
  1976.             log_string( buf );
  1977. #else
  1978.             log_string("New_descriptor: getpeername");
  1979. #endif
  1980.           dnew->host = str_dup( "(unknown)" );
  1981.             }
  1982.          else
  1983.             {
  1984.             int ulen = sizeof dnew->host_and_name->us;
  1985.             // Get the caller's machine in quad format
  1986.             u_long addr = ntohl( sock.sin_addr.s_addr );
  1987.             struct hostent *from;
  1988.             wsprintf( buf, "%d.%d.%d.%d",
  1989.                ( addr >> 24 ) & 0xFF, ( addr >> 16 ) & 0xFF,
  1990.                ( addr >>  8 ) & 0xFF, ( addr       ) & 0xFF);
  1991.             wsprintf( log_buf, "Sock.sinaddr:  %s", buf );
  1992.             log_string( log_buf );
  1993.             // Request the name of the caller's machine from DNS
  1994.             dnew->host = str_dup( buf );
  1995.             dnew->host_and_name->sin_addr = sock.sin_addr;
  1996.             dnew->host_and_name->hRequestHandle = WSAAsyncGetHostByAddr( hQryDlgBox,
  1997.                WM_NET_GETHOST, (LPSTR) &dnew->host_and_name->sin_addr, sizeof dnew->host_and_name->sin_addr,
  1998.                PF_INET, dnew->host_and_name->hostdata, sizeof dnew->host_and_name->hostdata);
  1999.             // Look up the local name for this socket
  2000.             if (getsockname(sSocket, (struct sockaddr *)&dnew->host_and_name->us, &ulen) ==
  2001.                                                                  SOCKET_ERROR)
  2002.                {
  2003.                wsprintf(dnew->host_and_name->username, "(getsockname)#%d", WSAGetLastError());
  2004.                goto failure;
  2005.                }
  2006.             // Create a socket to connect to the user's ident port
  2007.             if ((dnew->host_and_name->sAuth = socket(PF_INET, SOCK_STREAM, AF_UNSPEC)) ==
  2008.                                                                INVALID_SOCKET)
  2009.                {
  2010.                wsprintf(dnew->host_and_name->username, "(socket)#%d", WSAGetLastError());
  2011.                goto failure;
  2012.                }
  2013.             // Save the address of their side of the socket
  2014.             dnew->host_and_name->them = sock;
  2015.             // htons convers a u_short from host to network byte order. 113 is
  2016.             //  the auth socket
  2017.             dnew->host_and_name->authsock.sin_port = htons(113);
  2018.             // Use Internet protocol
  2019.             dnew->host_and_name->authsock.sin_family = AF_INET;
  2020.             // Look up the other end of our socket
  2021.             dnew->host_and_name->authsock.sin_addr = sock.sin_addr;
  2022.             WSAAsyncSelect(dnew->host_and_name->sAuth, hQryDlgBox, WM_NET_AUTHCONNECT,
  2023.                FD_CONNECT|FD_READ|FD_WRITE);
  2024.             if (connect(dnew->host_and_name->sAuth, (struct sockaddr *)&dnew->host_and_name->authsock,
  2025.                                        sizeof(dnew->host_and_name->authsock)) == SOCKET_ERROR)
  2026.                {
  2027.                int nError = WSAGetLastError();
  2028.                if (nError != WSAEWOULDBLOCK)
  2029.                   {
  2030.                   wsprintf(dnew->host_and_name->username, "(connect)#%d", nError);
  2031.                   goto failure;
  2032.                   }
  2033.                }
  2034.             }
  2035. failure:
  2036.          // Init descriptor data.
  2037.          dnew->next = descriptor_list;
  2038.          descriptor_list = dnew;
  2039.          nPlayers++;
  2040. // OK now get messages from this socket
  2041.          BlastedTrumpet(sSocket);
  2042.          // Send the greeting.
  2043.          {
  2044.        extern char * help_greeting;
  2045.        if ( help_greeting[0] == '.' )
  2046.           write_to_buffer( dnew, help_greeting+1, 0 );
  2047.        else
  2048.         write_to_buffer( dnew, help_greeting  , 0 );
  2049.          }
  2050.    } // FD_ACCEPT
  2051. }
  2052.    return FALSE;
  2053. }
  2054. LRESULT SocketReadWrite (WPARAM wParam, LPARAM lParam)
  2055. {
  2056. SOCKET sSocket = (SOCKET) wParam;
  2057. // SOCKADDR_IN saPeer;
  2058. // int iAddrSize;
  2059. // int iError;
  2060. //   char     szBuffer[64];
  2061. //   int      len;
  2062. switch(WSAGETSELECTEVENT(lParam))
  2063.      {
  2064.       default:
  2065.          MessageBeep(-1);
  2066.          break;
  2067. case FD_READ: // WinSock has something for us
  2068.    {
  2069.       // Find the descriptor for this FD_READ
  2070.          DESCRIPTOR_DATA *d;
  2071.          for (d = descriptor_list; d; d = d_next )
  2072.             {
  2073.             d_next = d->next;
  2074.             if (d->descriptor == sSocket)
  2075.                {
  2076.                d->fcommand = FALSE;
  2077.                if ( d->character != NULL )
  2078.                   d->character->timer = 0;
  2079.                if ( !read_from_descriptor( d ) )
  2080.              {
  2081. //@@@Dunno what this does?                  FD_CLR( d->descriptor, &out_set );
  2082.                   if ( d->character != NULL )
  2083.              save_char_obj( d->character );
  2084.                   d->outtop = 0;
  2085.                   close_socket( d );
  2086. //@@@                  continue;
  2087.                   }
  2088.                break;
  2089.                }
  2090.             }
  2091.    } // FD_READ
  2092.          break;
  2093. case FD_WRITE: // WinSock ready to send data on this socket
  2094.    {
  2095. #if 0
  2096.          if (!BlastedTrumpet(sSocket))
  2097.             return FALSE;
  2098. #endif
  2099. #if 0
  2100.          send(sSocket, szMessage, strlen(szMessage), 0);
  2101. #else
  2102.          // Output.
  2103.          DESCRIPTOR_DATA *d;
  2104.          for (d = descriptor_list; d != NULL; d = d_next )
  2105.             {
  2106.             d_next = d->next;
  2107.             if (d->descriptor == sSocket)
  2108.                if ( d->fcommand || d->outtop > 0 )
  2109.                   {
  2110. #if 0
  2111.                   if ( !process_output( d, TRUE ) && WSAGetLastError() != WSAEWOULDBLOCK )
  2112.                      {
  2113.                      if ( d->character != NULL )
  2114.                         save_char_obj( d->character );
  2115.                      d->outtop = 0;
  2116.                      close_socket( d );
  2117.                      }
  2118. #endif
  2119.                   int iStart, nWrite;
  2120.                   for ( iStart = 0; iStart < d->outtop; iStart += nWrite )
  2121.                      {
  2122.                      int nBlock = UMIN( d->outtop - iStart, 4096 );
  2123.                      if ( ( nWrite = send( d->descriptor, d->outbuf + iStart, nBlock, 0 ) ) == SOCKET_ERROR)
  2124.                         {
  2125.                         if (WSAGetLastError() != WSAEWOULDBLOCK)
  2126.                            {
  2127.                            log_string( "Write_to_descriptor" );
  2128.                            if ( d->character != NULL )
  2129.                               save_char_obj( d->character );
  2130.                            close_socket( d );
  2131.                            }
  2132.                         break;
  2133.                         }
  2134.                      }
  2135.                   // @@@ It would be better at this point to resend if we got
  2136.                   // EWOULDBLOCK, but we throw all data away...
  2137.                   d->outtop = 0;
  2138.                   }
  2139.             }
  2140. #endif
  2141.          } // FD_WRITE
  2142.          break;
  2143. case FD_CLOSE: // Hey, it closed on us...
  2144. //          MessageBox(0, "Closing", "Serv", MB_ICONINFORMATION|MB_OK);
  2145. //          log_string("Closing");
  2146.           break;
  2147. }
  2148.    return FALSE;
  2149. }
  2150. bool BlastedTrumpet(SOCKET sSocket)
  2151. {
  2152. if ( WSAAsyncSelect( sSocket, hQryDlgBox, WM_NET_READWRITE,
  2153.       FD_READ|FD_WRITE|FD_CLOSE) == SOCKET_ERROR)
  2154.     {
  2155. // MessageBox(0, "Couldn't select() on client socket.", "Serv",
  2156. //         MB_ICONHAND|MB_OK);
  2157. log_string("Couldn't select() on client socket.");
  2158.       return FALSE;
  2159. }
  2160.    return TRUE;
  2161. }
  2162. bool read_from_descriptor( DESCRIPTOR_DATA *d )
  2163. {
  2164.     int iStart;
  2165.     /* Hold horses if pending command already. */
  2166.     if ( d->incomm[0] != '' )
  2167.        {
  2168.        if (!BlastedTrumpet(d->descriptor))
  2169.           {
  2170.      if ( d->character != NULL )
  2171.         save_char_obj( d->character );
  2172.      d->outtop = 0;
  2173.      close_socket( d );
  2174.           }
  2175. //       BlastedTrumpet(d->descriptor);
  2176.        return TRUE;
  2177.        }
  2178.     /* Check for overflow. */
  2179.     iStart = strlen(d->inbuf);
  2180.     if ( iStart >= sizeof(d->inbuf) - 10 )
  2181.     {
  2182. wsprintf( log_buf, "%s input overflow!", d->host );
  2183. log_string( log_buf );
  2184.    BlastedTrumpet(d->descriptor);
  2185. //@@@ MessageBox(0, "input overflow!", "Serv", MB_ICONHAND|MB_OK);
  2186. write_to_descriptor( d->descriptor,
  2187.     "nr*** PUT A LID ON IT!!! ***nr", 0 );
  2188. return FALSE;
  2189.     }
  2190.     /* Snarf input. */
  2191.     for ( ; ; )
  2192.     {
  2193. int nRead;
  2194. nRead = recv( d->descriptor, d->inbuf + iStart,
  2195.     sizeof(d->inbuf) - 10 - iStart, 0 );
  2196. if ( nRead > 0 )
  2197. {
  2198.     iStart += nRead;
  2199.     if ( d->inbuf[iStart-1] == 'n' || d->inbuf[iStart-1] == 'r' )
  2200. break;
  2201. }
  2202. else if ( nRead == 0 )
  2203. {
  2204. //     log_string( "EOF encountered on read." );
  2205.     return FALSE;
  2206. }
  2207. else if ( WSAGetLastError() == WSAEWOULDBLOCK )
  2208.     break;
  2209. else
  2210. {
  2211. //     perror( "Read_from_descriptor" );
  2212. //  MessageBox(0, "Read_from_descriptor", "Serv", MB_ICONHAND|MB_OK);
  2213.        log_string("read_from_descriptor() got error");
  2214.     return FALSE;
  2215. }
  2216.     }
  2217.     d->inbuf[iStart] = '';
  2218.     return TRUE;
  2219. }
  2220. /*
  2221.  * Writes a string to the log.
  2222.  */
  2223. void log_string( const char *str )
  2224. {
  2225.    char *strtime;
  2226.    if (IsWindow(hWndOutput))
  2227.       SendMessage(hWndOutput, LB_ADDSTRING, 0, (LPARAM)(LPCSTR) str);
  2228.    strtime                    = ctime( &current_time );
  2229.    strtime[strlen(strtime)-1] = '';
  2230.    fprintf( fpStderr, "%s :: %sn", strtime, str );
  2231. }
  2232. LRESULT SocketGetHost(WPARAM wParam, LPARAM lParam)
  2233. {
  2234.    DESCRIPTOR_DATA *des = descriptor_list;
  2235.    WORD wError;
  2236. //   MessageBeep(-1);
  2237.    while (des && des->host_and_name->hRequestHandle != (HANDLE) wParam)
  2238.       des = des->next;
  2239.    if (!des)
  2240.       {
  2241.       log_string("Got Host info for unknown descriptor");
  2242.       return FALSE;
  2243.       }
  2244.    wError = WSAGETASYNCERROR(lParam);
  2245.    if (wError)
  2246.       {
  2247.       char szBuf[512];
  2248.       char *p = "(Unknown Error)";
  2249.       if (wError == WSAHOST_NOT_FOUND)
  2250.          p = "(Authoritative Answer:  Host Not Found)";
  2251.       else if (wError == WSATRY_AGAIN)
  2252.          p = "(Host not found, or Server Failure)";
  2253.       else if (wError == WSANO_RECOVERY)
  2254.          p = "(Former, Refused, or Not Implemented)";
  2255.       else if (wError == WSANO_DATA)
  2256.          p = "(Valid name, no data record)";
  2257.       else if (wError == WSANO_DATA)
  2258.          p = "(No Address)";
  2259.       wsprintf(szBuf, "%s %s", des->host, p);
  2260.       free_string( des->host );
  2261.       des->host = str_dup( szBuf );
  2262.       }
  2263.    else
  2264.       {
  2265.       free_string( des->host );
  2266.       des->host = str_dup( ((struct hostent FAR *)(des->host_and_name->hostdata))->h_name );
  2267.       }
  2268.    return TRUE;
  2269. }
  2270. LRESULT SocketAuthConnect(WPARAM wParam, LPARAM lParam)
  2271. {
  2272.    char szIdentRequest[32];
  2273.    char szIdentReply[256];
  2274.    char szUserID[32];
  2275.    u_short port1, port2;
  2276.    char *p;
  2277.    DESCRIPTOR_DATA *des = descriptor_list;
  2278.    while (des && des->host_and_name->sAuth != (SOCKET) wParam)
  2279.       des = des->next;
  2280.    if (!des)
  2281.       {
  2282.       log_string("Ident message info for unknown descriptor");
  2283.       return FALSE;
  2284.       }
  2285. switch(WSAGETSELECTEVENT(lParam))
  2286.       {
  2287.       default:
  2288.          MessageBeep(-1);
  2289.          break;
  2290.       case FD_CONNECT:
  2291. //         log_string("FD_CONNECT to IDENTD port");
  2292. //         break;
  2293. //
  2294. //      case FD_WRITE:
  2295.          // Failure?
  2296.          if (WSAGETSELECTERROR(lParam))
  2297.             {
  2298.             wsprintf(des->host_and_name->username, "(FD_CONNECT)#%d", WSAGetLastError());
  2299.             closesocket((SOCKET) wParam);
  2300.             return FALSE;
  2301.             }
  2302.          // Create a string of the form <port>, <port>rn
  2303.          wsprintf(szIdentRequest, "%u , %urn",
  2304.                ntohs(des->host_and_name->them.sin_port),
  2305.                ntohs(des->host_and_name->us.sin_port));
  2306.          send((SOCKET) wParam, szIdentRequest, strlen(szIdentRequest), 0);
  2307.          // @@@ Should check return value
  2308.          break;
  2309.       case FD_READ:
  2310.          // Read the response from the IDENT port
  2311.          recv((SOCKET) wParam, szIdentReply, sizeof szIdentReply, 0);
  2312.          // @@@ Should check return value
  2313.          // Extract the user name provided by IDENT
  2314.          sscanf(szIdentReply, "%hd , %hd : USERID : %*[^:]: %10s",
  2315.             &port1, &port2, szUserID);
  2316.          log_string(szIdentReply); // @@@
  2317.          // Remove any trailing newline from the user name
  2318.          for (p = szUserID; *p && *p != 'n' && *p != 'r'; p++)
  2319.             ;
  2320.          *p = '';
  2321.          // Save the user name in the descriptor
  2322.          strcpy(des->host_and_name->username, szUserID);
  2323.          // Close this socket
  2324.          closesocket((SOCKET) wParam);
  2325.          break;
  2326.       }
  2327.    return TRUE;
  2328. }
  2329. /*
  2330.  * Write to all characters.
  2331.  */
  2332. void send_to_all_char( const char *text )
  2333. {
  2334.     DESCRIPTOR_DATA *d;
  2335.     if ( !text )
  2336.         return;
  2337.     for ( d = descriptor_list; d; d = d->next )
  2338.         if ( d->connected == CON_PLAYING )
  2339.     send_to_char( text, d->character );
  2340.     return;
  2341. }
  2342. /*
  2343.  * Reports a bug.
  2344.  */
  2345. void bug( const char *str, int param )
  2346. {
  2347.     extern FILE * fpArea;
  2348.     extern char strArea[ MAX_INPUT_LENGTH   ];
  2349.     FILE *fp;
  2350.     char  buf [ MAX_STRING_LENGTH ];
  2351.     char  buf2[ MAX_STRING_LENGTH ];
  2352.     if ( fpArea )
  2353.     {
  2354. int iLine;
  2355. int iChar;
  2356. if ( fpArea == stdin )
  2357. {
  2358.     iLine = 0;
  2359. }
  2360. else
  2361. {
  2362.     iChar = ftell( fpArea );
  2363.     fseek( fpArea, 0, 0 );
  2364.     for ( iLine = 0; ftell( fpArea ) < iChar; iLine++ )
  2365.     {
  2366. while ( getc( fpArea ) != 'n' )
  2367.     ;
  2368.     }
  2369.     fseek( fpArea, iChar, 0 );
  2370. }
  2371. sprintf( buf2, "[*****] FILE: %s LINE: %d", strArea, iLine );
  2372. log_string( buf2 );
  2373. if ( ( fp = fopen( "shutdown.txt", "a" ) ) )
  2374. {
  2375.     fprintf( fp, "[*****] %sn", buf2 );
  2376.     fclose( fp );
  2377. }
  2378.     }
  2379.    else
  2380.       buf2[0] = 0;
  2381.     strcpy( buf, "[*****] BUG: " );
  2382.     sprintf( buf + strlen( buf ), str, param );
  2383.     log_string( buf );
  2384.     fclose( fpReserve );
  2385.     if ( ( fp = fopen( BUG_FILE, "a" ) ) )
  2386.     {
  2387. fprintf( fp, "%sn", buf );
  2388. fclose( fp );
  2389.     }
  2390.     fpReserve = fopen( NULL_FILE, "r" );
  2391.     if (fWantsMessageBox)
  2392.        MessageBox(0, buf, buf2, MB_ICONHAND|MB_OK);
  2393.     return;
  2394. }
  2395. // This was moved out of act_wiz so that I can use the host_and_name member
  2396. void do_users( CHAR_DATA *ch, char *argument )
  2397. {
  2398.     char buf[MAX_STRING_LENGTH];
  2399.     char buf2[MAX_STRING_LENGTH];
  2400.     DESCRIPTOR_DATA *d;
  2401.     int count;
  2402.     count = 0;
  2403.     buf[0] = '';
  2404.     buf2[0]     = '';
  2405.     for ( d = descriptor_list; d != NULL; d = d->next )
  2406.     {
  2407. if ( d->character != NULL && can_see( ch, d->character ) )
  2408. {
  2409.     count++;
  2410.     sprintf( buf + strlen(buf), "[%3d %2d] %s (%s@%s)nr",
  2411. d->descriptor,
  2412. d->connected,
  2413. d->original  ? d->original->name  :
  2414. d->character ? d->character->name : "(none)",
  2415. d->host_and_name->username, d->host
  2416. );
  2417. }
  2418.     }
  2419.     sprintf( buf2, "%d user%snr", count, count == 1 ? "" : "s" );
  2420.     strcat( buf, buf2 );
  2421.     send_to_char( buf, ch );
  2422.     return;
  2423. }