text: //
  // discodlg.cpp: disconnected dialog
  //
  //
  
  #include "stdafx.h"
  
  #define TRC_GROUP TRC_GROUP_UI
  #define TRC_FILE  "disconnecteddlg"
  #include <atrcapi.h>
  
  #include "discodlg.h"
  #include "sh.h"
  
  #include "contwnd.h"
  
  //For error code decoding
  #define DC_DEFINE_GLOBAL_ERROR_STRINGS 1
  #include "tscerrs.h"
  
  //
  // Protocol errors
  //
  #include "rdperr.h"
  
  CDisconnectedDlg::CDisconnectedDlg( HWND hwndOwner, HINSTANCE hInst,
                                      CContainerWnd* pContWnd) :
                                     _pContWnd(pContWnd),
                                     _hInstance(hInst),
                                     _hwndOwner(hwndOwner)
  {
      DC_BEGIN_FN("CDisconnectedDlg");
      TRC_ASSERT(_pContWnd, (TB,_T("_pContWnd not set\n")));
  
      _disconnectReason = 0;
      _extendedDiscReason = exDiscReasonNoInfo;
  
      DC_END_FN();
  }
  
  CDisconnectedDlg::~CDisconnectedDlg()
  {
  }
  
  #define MAX_DISCOMSG_LEN SH_DISCONNECT_RESOURCE_MAX_LENGTH*3
  
  DCINT CDisconnectedDlg::DoModal()
  {
      DCINT retVal = 0;
  
      LPTSTR   szOverallMsgString = NULL;
      INT_PTR  rc = FALSE;
      DCUINT   intRC;
      DC_BEGIN_FN("DoModal");
  
      szOverallMsgString = (LPTSTR) LocalAlloc(LPTR,
                            MAX_DISCOMSG_LEN*sizeof(TCHAR));
      if (!szOverallMsgString)
      {
          return -1;
      }
  
      if (MapErrorToString(_hInstance, _disconnectReason,
                          _extendedDiscReason,
                          szOverallMsgString,
                          MAX_DISCOMSG_LEN))
      {
          TCHAR szDialogCaption[64];
          intRC = LoadString(_hInstance,
                             UI_IDS_DISCONNECTED_CAPTION,
                             szDialogCaption,
                             SIZECHAR(szDialogCaption));
          if(0 == intRC)
          {
              TRC_SYSTEM_ERROR("LoadString");
              TRC_ERR((TB, _T("Failed to load string ID:%u"),
                       UI_IDS_DISCONNECTED_CAPTION));
              szDialogCaption[0] = 0;
          }
  
  
          MessageBox( _hwndOwner,
                      szOverallMsgString,
                      szDialogCaption,
  #ifndef OS_WINCE
                      MB_OK | MB_HELP | MB_ICONSTOP);
  #else
                      MB_OK | MB_ICONSTOP);
  #endif
  
          // Do the cleanup.  This is hackerific but has to happen
          // from here because the disconnect dialog could be initiated
          // in the context of the main dialog via a PostMessage
          // see comment in contwnd.cpp
  
          TRC_ASSERT(_pContWnd, (TB,_T("_pContWnd not set\n")));
          if(_pContWnd)
          {
              _pContWnd->FinishDisconnect();
          }
      }
      
  
      DC_END_FN();
      
      if (szOverallMsgString)
      {
          LocalFree(szOverallMsgString);
      }
      return retVal;
  }
  
  //Returns error string for this message in szErrorMsg
  //szErrorMsg must be large enough to hold error string
  INT
  CDisconnectedDlg::MapErrorToString(
      HINSTANCE hInstance,
      INT disconnectReason,
      ExtendedDisconnectReasonCode extendedDisconnectReason,
      LPTSTR szErrorMsg,
      INT    cchErrorMsgLen
      )
  {
      UINT stringID = 0;
      UINT errorCode;
      int  rc;
      TCHAR szDisconnectedString[SH_DISCONNECT_RESOURCE_MAX_LENGTH];
      LPTSTR pszDebugErrorCodeText = _T("");
  
      DC_BEGIN_FN("MapErrorToString");
  
      TRC_NRM((TB, _T("Main disconnect reason code is:%u"),
               NL_GET_MAIN_REASON_CODE(disconnectReason)));
      TRC_ASSERT(szErrorMsg, (TB, _T("szErrorMsg is null")));
  
      //
      // If extended disconnect reason is set we may
      // just be able to figure out the error right away
      //
      if(extendedDisconnectReason != exDiscReasonNoInfo)
      {
          switch(extendedDisconnectReason)
          {
              case exDiscReasonAPIInitiatedDisconnect:
              {
                  //An RPC call on the server initiated the disconnect
                  //most likely is that it was an admin tool that kicked
                  //off the disconnect
                  stringID = UI_IDS_DISCONNECT_REMOTE_BY_SERVER_TOOL;
              }
              break;
  
              case exDiscReasonAPIInitiatedLogoff:
              {
                  //An RPC call on the server initiated the disconnect
                  //most likely is that it was an admin tool that kicked
                  //off the disconnect
                  stringID = UI_IDS_LOGOFF_REMOTE_BY_SERVER;
              }
              break;
  
              case exDiscReasonServerIdleTimeout:
              {
                  // Idle timeout expired on server
                  stringID = UI_IDS_DISCONNECT_IDLE_TIMEOUT;
              }
              break;
      
              case exDiscReasonServerLogonTimeout:
              {
                  // Total logon timeout expired on server
                  stringID = UI_IDS_DISCONNECT_LOGON_TIMEOUT;
              }
              break;
  
              case exDiscReasonReplacedByOtherConnection:
              {
                  TRC_NRM((TB, _T("Disconnected by other connection")));
                  stringID = UI_IDS_DISCONNECT_BYOTHERCONNECTION;
              }
              break;
      
              case exDiscReasonOutOfMemory:
              {
                  // Server is out of memory
                  stringID = UI_IDS_SERVER_OUT_OF_MEMORY;
              }
              break;
  
              case exDiscReasonServerDeniedConnection:
              {
                  stringID = UI_IDS_SERVER_DENIED_CONNECTION;
              }
              break;
  
              case exDiscReasonServerDeniedConnectionFips:
              {
                  stringID = UI_IDS_SERVER_DENIED_CONNECTION_FIPS;
              }
              break;
  
              case exDiscReasonLicenseInternal:
              {
                  // Internal error in licensing protocol
                  stringID = UI_IDS_LICENSE_INTERNAL;
              }
              break;
  
              case exDiscReasonLicenseNoLicenseServer:
              {
                  // No license server available
                  stringID = UI_IDS_LICENSE_NO_LICENSE_SERVER;
              }
              break;
  
              case exDiscReasonLicenseNoLicense:
              {
                  // No license available for this client
                  stringID = UI_IDS_LICENSE_NO_LICENSE;
              }
              break;
  
              case exDiscReasonLicenseErrClientMsg:
              {
                  // Server got bad message from client
                  stringID = UI_IDS_LICENSE_BAD_CLIENT_MSG;
              }
              break;
  
              case exDiscReasonLicenseHwidDoesntMatchLicense:
              {
                  // HWID in license doesn't match the one sent
                  stringID = UI_IDS_LICENSE_HWID_DOESNT_MATCH_LICENSE;
              }
              break;
  
              case exDiscReasonLicenseErrClientLicense:
              {
                  // Server couldn't decode client license
                  stringID = UI_IDS_LICENSE_BAD_CLIENT_LICENSE;
              }
              break;
  
              case exDiscReasonLicenseCantFinishProtocol:
              {
                  // Server couldn't send final licensing packets
                  stringID = UI_IDS_LICENSE_CANT_FINISH_PROTOCOL;
              }
              break;
  
              case exDiscReasonLicenseClientEndedProtocol:
              {
                  // Client sent licensing error to server
                  stringID = UI_IDS_LICENSE_CLIENT_ENDED_PROTOCOL;
              }
              break;
  
              case exDiscReasonLicenseErrClientEncryption:
              {
                  // Server couldn't decrypt client message
                  stringID = UI_IDS_LICENSE_BAD_CLIENT_ENCRYPTION;
              }
              break;
  
              case exDiscReasonLicenseCantUpgradeLicense:
              {
                  // Client's license couldn't be upgraded
                  stringID = UI_IDS_LICENSE_CANT_UPGRADE_LICENSE;
              }
              break;
  
              case exDiscReasonLicenseNoRemoteConnections:
              {
                  // Server is in null mode - expired or not enough Per-CPU CALs
                  stringID = UI_IDS_LICENSE_NO_REMOTE_CONNECTIONS;
              }
              break;
  
              default:
              {
                  if(extendedDisconnectReason >= exDiscReasonProtocolRangeStart &&
                     extendedDisconnectReason <= exDiscReasonProtocolRangeEnd)
                  {
                      //
                      // It's a protocol error detected (E.g rdpwd broke the link
                      // because it detected an error).
                      //
                      
                      //
                      // For most of these we just return status codes, more common
                      // ones get their own message
                      //
                      if (Log_RDP_ENC_DecryptFailed ==
                          (ULONG)(extendedDisconnectReason -
                                  exDiscReasonProtocolRangeStart))
                      {
                          stringID = UI_IDS_SERVER_DECRYPTION_ERROR;
  
                      }
                      else
                      {
                          stringID = UI_IDS_PROTOCOL_ERROR_WITH_CODE;
                      }
                  }
              }
              break;
          }
      }
  
      //
      // If we still haven't got the string to load then
      // crack the error code to figure out which stringID to load
      //
      if(0 == stringID)
      {
          switch (NL_GET_MAIN_REASON_CODE(disconnectReason))
          {
              case UI_DISCONNECT_ERROR:          // ??08
              {
                  errorCode = NL_GET_ERR_CODE(disconnectReason);
      #ifdef DC_DEBUG
                  //
                  // Extra debugging info for this error
                  //
                  pszDebugErrorCodeText = (PDCTCHAR) uiUIErrorText[errorCode-1];
                  TRC_ALT((TB, _T("UI error occurred - cause:%#x '%s'"),
                           errorCode,
                           pszDebugErrorCodeText));
      #endif /* DC_DEBUG */
      
                  switch (errorCode)
                  {
                      case UI_ERR_DISCONNECT_TIMEOUT:
                      {
                          TRC_NRM((TB, _T("Connection timed out")));
                          stringID = UI_IDS_CONNECTION_TIMEOUT;
                      }
                      break;
      
                      case UI_ERR_GHBNFAILED:
                      case UI_ERR_BADIPADDRESS:
                      case UI_ERR_DNSLOOKUPFAILED:
                      {
                          TRC_NRM((TB, _T("Bad IP address")));
                          stringID = UI_IDS_BAD_SERVER_NAME;
                      }
                      break;
      
                      case UI_ERR_ANSICONVERT:
                      {
                          TRC_NRM((TB, _T("An internal error has occurred.")));
                          stringID = UI_IDS_ILLEGAL_SERVER_NAME;
                      }
                      break;
      
                      case UI_ERR_NOTIMER:
                      {
                          /************************************************/
                          /* Failed to create a timer.                    */
                          /************************************************/
                          TRC_NRM((TB, _T("Failed to create a timer")));
                          stringID = UI_IDS_LOW_MEMORY;
                      }
                      break;
      
                      case UI_ERR_LOOPBACK_CONSOLE_CONNECT:
                      {
                          TRC_NRM((TB, _T("Console loopback connect!!!")));
                          stringID = UI_IDS_CANNOT_LOOPBACK_CONNECT;
                      }
                      break;
      
                      case UI_ERR_LICENSING_TIMEOUT:
                      {
                          TRC_NRM((TB, _T("Licensing timed out")));
                          stringID = UI_IDS_LICENSING_TIMEDOUT;
                      }
                      break;
      
                      case UI_ERR_LICENSING_NEGOTIATION_FAIL:
                      {
                          TRC_NRM((TB, _T("Licensing negotiation failed")));
                          stringID = UI_IDS_LICENSING_NEGOT_FAILED;
                      }
                      break;
  
                      case UI_ERR_DECOMPRESSION_FAILURE:
                      {
                          TRC_NRM((TB,_T("Client decompression failure")));
                          stringID = UI_IDS_CLIENT_DECOMPRESSION_FAILED;
                      }
                      break;
  
                      case UI_ERR_UNEXPECTED_DISCONNECT:
                      {
                          TRC_NRM((TB,_T("Received 'UnexpectedDisconnect' code")));
                          stringID = UI_IDS_INTERNAL_ERROR;
                      }
                      break;
                      
      
                      default:
                      {
                          TRC_ABORT((TB, _T("Unrecognized UI error %#x"),
                                          errorCode));
                          stringID = UI_IDS_INTERNAL_ERROR;
                      }
                      break;
                  }
              }
              break;
      
              case NL_DISCONNECT_REMOTE_BY_SERVER:        // 0003
              {
                  //The server has remotely disconnected us
  
                  TRC_NRM((TB, _T("Remote disconnection by server")));
                  //Unable to get more information
                  stringID = UI_IDS_DISCONNECT_REMOTE_BY_SERVER;
              }
              break;
      
              case SL_DISCONNECT_ERROR:                   // ??06
              {
                  errorCode = NL_GET_ERR_CODE(disconnectReason);
      #ifdef DC_DEBUG
                  /********************************************************/
                  /* Set up the error code text.                          */
                  /********************************************************/
                  pszDebugErrorCodeText = (PDCTCHAR) uiSLErrorText[errorCode-1];
                  TRC_ALT((TB, _T("SL error occurred - cause:%#x '%s'"),
                           errorCode,
                           pszDebugErrorCodeText));
      #endif /* DC_DEBUG */
      
                  /********************************************************/
                  /* An SL error has occurred.  Work out what the actual  */
                  /* code is.                                             */
                  /********************************************************/
                  switch (errorCode)
                  {
                      /****************************************************/
                      /* The following codes all map onto an "out of      */
                      /* memory" string.                                  */
                      /****************************************************/
                      case SL_ERR_NOMEMFORSENDUD:         // 0106
                      case SL_ERR_NOMEMFORRECVUD:         // 0206
                      case SL_ERR_NOMEMFORSECPACKET:      // 0306
                      {
                          TRC_NRM((TB, _T("Out of memory")));
                          stringID = UI_IDS_LOW_MEMORY;
                      }
                      break;
      
                      /****************************************************/
                      /* The following codes all map onto a "security     */
                      /* error" string.                                   */
                      /****************************************************/
                      case SL_ERR_NOSECURITYUSERDATA:     // 0406
                      case SL_ERR_INVALIDENCMETHOD:       // 0506
                      case SL_ERR_INVALIDSRVRAND:         // 0606
                      case SL_ERR_INVALIDSRVCERT:         // 0706
                      case SL_ERR_GENSRVRANDFAILED:       // 0806
                      case SL_ERR_MKSESSKEYFAILED:        // 0906
                      case SL_ERR_ENCCLNTRANDFAILED:      // 0A06 
                      {
                          TRC_NRM((TB, _T("Security error")));
                          stringID = UI_IDS_SECURITY_ERROR;
                      }
                      break;
      
                      case SL_ERR_ENCRYPTFAILED:          // 0B06
                      case SL_ERR_DECRYPTFAILED:          // 0C06
                      {
                          TRC_NRM((TB, _T("Encryption error")));
                          stringID = UI_IDS_ENCRYPTION_ERROR;
                      }
                      break;
  
                      case SL_ERR_INVALIDPACKETFORMAT:    // 0D06
                      {
                          TRC_NRM((TB, _T("Invalid packet format")));
                          stringID = UI_IDS_PROTOCOL_ERROR;
                      }
                      break;
  
                      case SL_ERR_INITFIPSFAILED:
                      {
                          TRC_NRM((TB, _T("Init FIPS encryption failed")));
                          stringID = UI_IDS_FIPS_ERROR;
                      }
                      break;
  
                      default:
                      {
                          /************************************************/
                          /* Whoops - shouldn't get here.  We should be   */
                          /* capable of correctly decoding every error    */
                          /* value.                                       */
                          /************************************************/
                          TRC_ABORT((TB, _T("Unrecognized SL error code:%#x"),
                                     disconnectReason));
                          stringID = UI_IDS_INTERNAL_ERROR;
                      }
                      break;
                  }
              }
              break;
      
              case NL_DISCONNECT_ERROR:                   // ??04
              {
      #ifdef DC_DEBUG
                  DCUINT lowByte;
                  DCUINT highByte;
      #endif /* DC_DEBUG */
      
                  errorCode = NL_GET_ERR_CODE(disconnectReason);
      #ifdef DC_DEBUG
                  /********************************************************/
                  /* Set up the error code text.                          */
                  /********************************************************/
                  highByte = errorCode >> 4;
                  lowByte  = (errorCode & 0xF) - 1;
                  pszDebugErrorCodeText =
                                (PDCTCHAR) uiNLErrorText[highByte][lowByte];
                  TRC_ALT((TB, _T("NL error occurred - cause:%u '%s'"),
                           errorCode,
                           pszDebugErrorCodeText));
      #endif /* DC_DEBUG */
      
                  /********************************************************/
                  /* An NL error has occurred.  Work out what the actual  */
                  /* code is.                                             */
                  /********************************************************/
                  switch (NL_GET_ERR_CODE(disconnectReason))
                  {
                      /****************************************************/
                      /* The following codes all map onto a "bad IP       */
                      /* address" string.                                 */
                      /****************************************************/
                      case NL_ERR_TDDNSLOOKUPFAILED:      // 0104
                      case NL_ERR_TDGHBNFAILED:           // 0604
                      case NL_ERR_TDBADIPADDRESS:         // 0804
                      {
                          TRC_NRM((TB, _T("Bad IP address")));
                          stringID = UI_IDS_BAD_SERVER_NAME;
                      }
                      break;
      
                      /****************************************************/
                      /* The following code maps onto a "connect failed"  */
                      /* string.                                          */
                      /****************************************************/
                      case NL_ERR_TDSKTCONNECTFAILED:     // 0204
                      case NL_ERR_TDTIMEOUT:              // 0704
                      case NL_ERR_NCATTACHUSERFAILED:     // 3604
                      case NL_ERR_NCCHANNELJOINFAILED:    // 3704
                      {
                          TRC_NRM((TB, _T("Failed to establish a connection")));
                          stringID = UI_IDS_NOT_RESPONDING;
                      }
                      break;
      
                      case NL_ERR_MCSNOUSERIDINAUC:       // 2704
                      case NL_ERR_MCSNOCHANNELIDINCJC:    // 2804
                      case NL_ERR_NCBADMCSRESULT:         // 3104
                      case NL_ERR_NCNOUSERDATA:           // 3304
                      case NL_ERR_NCINVALIDH221KEY:       // 3404
                      case NL_ERR_NCNONETDATA:            // 3504
                      case NL_ERR_NCJOINBADCHANNEL:       // 3804
                      case NL_ERR_NCNOCOREDATA:           // 3904
                      {
                          TRC_NRM((TB, _T("Protocol Error")));
                          stringID = UI_IDS_CONNECT_FAILED_PROTOCOL;
                      }
                      break;
      
                      /****************************************************/
                      /* The following codes all map onto a "network      */
                      /* error has occurred" string.                      */
                      /****************************************************/
                      case NL_ERR_TDONCALLTOSEND:         // 0304
                      case NL_ERR_TDONCALLTORECV:         // 0404
                      {
                          TRC_NRM((TB, _T("A network error has occurred")));
                          stringID = UI_IDS_NETWORK_ERROR;
                      }
                      break;
      
                      case NL_ERR_XTBADTPKTVERSION:       // 1104
                      case NL_ERR_XTBADHEADER:            // 1204
                      case NL_ERR_XTUNEXPECTEDDATA:       // 1304
                      case NL_ERR_MCSUNEXPECTEDPDU:       // 2104
                      case NL_ERR_MCSNOTCRPDU:            // 2204
                      case NL_ERR_MCSBADCRLENGTH:         // 2304
                      case NL_ERR_MCSBADCRFIELDS:         // 2404
                      case NL_ERR_MCSINVALIDPACKETFORMAT: // 2904
                      {
                          TRC_NRM((TB, _T("A protocol error has occurred")));
                          stringID = UI_IDS_CLIENTSIDE_PROTOCOL_ERROR;
                      }
                      break;
      
                      /****************************************************/
                      /* This code relates to an incompatible server      */
                      /* version.                                         */
                      /****************************************************/
                      case NL_ERR_MCSBADMCSREASON:        // 2604
                      case NL_ERR_NCVERSIONMISMATCH:      // 3A04
                      {
                          TRC_NRM((TB, _T("Client/Server version mismatch")));
                          stringID = UI_IDS_VERSION_MISMATCH;
                      }
                      break;
      
                      /****************************************************/
                      /* The following codes map onto an "illegal server  */
                      /* name" string.                                    */
                      /****************************************************/
                      case NL_ERR_TDANSICONVERT:          // 0A04
                      {
                          TRC_NRM((TB, _T("Couldn't convert name to ANSI")));
                          stringID = UI_IDS_ILLEGAL_SERVER_NAME;
                      }
                      break;
      
                      case NL_ERR_TDFDCLOSE:              // 0904
                      {
                          TRC_NRM((TB, _T("Socket closed")));
                          stringID = UI_IDS_CONNECTION_BROKEN;
                      }
                      break;
      
                      default:
                      {
                          /************************************************/
                          /* Woops - shouldn't get here.  We should be    */
                          /* capable of correctly decoding every error    */
                          /* value.                                       */
                          /************************************************/
                          TRC_ABORT((TB, _T("Unrecognized NL error code:%#x"),
                                     disconnectReason));
                          stringID = UI_IDS_INTERNAL_ERROR;
                      }
                      break;
                  }
      
              }
              break;
      
              default:
              {
                  /********************************************************/
                  /* Woops - shouldn't get here.  We should be capable    */
                  /* of correctly decoding every disconnection reason     */
                  /* code.                                                */
                  /********************************************************/
                  TRC_ABORT((TB, _T("Unexpected disconnect ID:%#x"),
                             disconnectReason));
                  stringID = UI_IDS_INTERNAL_ERROR;
              }
              break;
          }
      }
  
  
      //
      // First of all get the textual version of the string - we have
      // just worked out which string we need to load.
      //
      rc = LoadString(hInstance,
                      stringID,
                      szDisconnectedString,
                      SIZECHAR(szDisconnectedString));
      if (0 == rc)
      {
           //Oops!  Some problem with the resources.
           TRC_SYSTEM_ERROR("LoadString");
           TRC_ERR((TB, _T("Failed to load string ID:%u"), stringID));
           return FALSE;
      }
      
  
      if(UI_IDS_PROTOCOL_ERROR_WITH_CODE == stringID)
      {
          //
          // Need to add the specific protocol error
          // code to the string
          //
          DC_TSPRINTF(szErrorMsg, szDisconnectedString,
                      extendedDisconnectReason);
      }
      else if (UI_IDS_CLIENTSIDE_PROTOCOL_ERROR == stringID)
      {
          //
          // Client side protocol error, add the appropriate
          // code to the string
          //
          DC_TSPRINTF(szErrorMsg, szDisconnectedString,
                      disconnectReason);
      }
  	else
      {
          //
          // Static error string (doesn't need codes appended)
          //
          _tcscpy(szErrorMsg, szDisconnectedString);
      }
  
  
      #ifdef DC_DEBUG
      
      //
      // In Check builds display the disconnect
      // codes as well as the debug disconnect reason string
      //
  
      TCHAR szDebugDisconnectInfo[128];
  
      // Add the numerical reason code.
  
      _stprintf(szDebugDisconnectInfo,
            _T("DEBUG ONLY: Disconnect code: 0x%x - ") \
            _T("Extended Disconnect code: 0x%x\n"),
            disconnectReason,
            extendedDisconnectReason);
  
      //
      // Add the error code text to the end of the string.
      //
      _tcscat(szErrorMsg, _T("\n\n"));
      _tcscat(szErrorMsg, szDebugDisconnectInfo);
      if (pszDebugErrorCodeText)
      {
          _tcscat(szErrorMsg, pszDebugErrorCodeText);
      }
      #endif
  
      DC_END_FN();
      return TRUE;
  }
  