void rfbVeNCryptAuthenticate(rfbClientPtr cl)
{
  struct {
    CARD8 major, minor;
  } serverVersion = { 0, 2 }, clientVersion = { 0, 0 };
  CARD8 reply, count = 0;
  int i, j;
  SecTypeData *s;
  CARD32 subTypes[MAX_VENCRYPT_SUBTYPES], chosenType = 0;
#if USETLS
  rfbSslCtx *ctx;
  int ret;
#endif

  WRITE(&serverVersion.major, 1);
  WRITE(&serverVersion.minor, 1);
  rfbUncorkSock(cl->sock);
  rfbCorkSock(cl->sock);
  READ(&clientVersion, 2);

  if (clientVersion.major == 0 && clientVersion.minor < 2) {
    reply = 0xFF;
    WRITE(&reply, 1);
    rfbCloseClient(cl);
    return;
  } else {
    reply = 0;
    WRITE(&reply, 1);
  }

  memset(subTypes, 0, sizeof(CARD32) * MAX_VENCRYPT_SUBTYPES);
  for (i = 0; i < preferenceLimit; i++) {
    for (s = secTypes; s->name != NULL; s++) {
      if (((s->preference != -1) && (i != s->preference)) || !s->enabled ||
          s->subType == -1)
        continue;

      if (count > MAX_VENCRYPT_SUBTYPES)
        FatalError("rfbVeNCryptAuthenticate: # enabled subtypes > MAX_VENCRYPT_SUBTYPES");

      /* Check whether we have already advertised this subtype */
      for (j = 0; j < count; j++) {
        if (subTypes[j] == s->subType)
          break;
      }
      if (j < count)
        continue;

      subTypes[count++] = s->subType;
    }
  }

  WRITE(&count, 1);
  if (count > 0) {
    for (i = 0; i < count; i++) {
      CARD32 subType = Swap32IfLE(subTypes[i]);
      WRITE(&subType, sizeof(CARD32));
    }
  }

  rfbUncorkSock(cl->sock);
  rfbCorkSock(cl->sock);
  READ(&chosenType, sizeof(CARD32));
  chosenType = Swap32IfLE(chosenType);

  for (i = 0; i < count; i++) {
    if (chosenType == subTypes[i])
      break;
  }
  rfbLog("Client requested VeNCrypt sub-type %d\n", chosenType);
  if (chosenType == 0 || chosenType == rfbSecTypeVeNCrypt || i >= count) {
    rfbLog("Requested VeNCrypt sub-type not supported\n");
    rfbCloseClient(cl);
    return;
  }

  cl->selectedAuthType = chosenType;
  switch (chosenType) {
    case rfbAuthNone:
      rfbClientAuthSucceeded(cl, rfbAuthNone);
      break;
    case rfbAuthVNC:
      rfbVncAuthSendChallenge(cl);
      break;
#ifdef XVNC_AuthPAM
    case rfbVeNCryptPlain:
      AuthPAMUserPwdRspFunc(cl);
      break;
#endif
#if USETLS
    case rfbVeNCryptTLSNone:
      cl->selectedAuthType = rfbAuthNone;
      TLS_INIT(TRUE);
      rfbClientAuthSucceeded(cl, rfbAuthNone);
      break;
    case rfbVeNCryptTLSVnc:
      cl->selectedAuthType = rfbAuthVNC;
      TLS_INIT(TRUE);
      rfbVncAuthSendChallenge(cl);
      break;
#ifdef XVNC_AuthPAM
    case rfbVeNCryptTLSPlain:
      cl->selectedAuthType = rfbAuthUnixLogin;
      TLS_INIT(TRUE);
      AuthPAMUserPwdRspFunc(cl);
      break;
#endif
    case rfbVeNCryptX509None:
      cl->selectedAuthType = rfbAuthNone;
      TLS_INIT(FALSE);
      rfbClientAuthSucceeded(cl, rfbAuthNone);
      break;
    case rfbVeNCryptX509Vnc:
      cl->selectedAuthType = rfbAuthVNC;
      TLS_INIT(FALSE);
      rfbVncAuthSendChallenge(cl);
      break;
#ifdef XVNC_AuthPAM
    case rfbVeNCryptX509Plain:
      cl->selectedAuthType = rfbAuthUnixLogin;
      TLS_INIT(FALSE);
      AuthPAMUserPwdRspFunc(cl);
      break;
#endif
#endif
    default:
      FatalError("rfbVeNCryptAuthenticate: chosen type is invalid (this should never occur)");
  }
}