Esempio n. 1
0
void CManagePasswordPolicies::OnEditPpClick( wxCommandEvent& )
{
  int row = GetSelectedRow();
  if (row < 0)
    return;
  wxString policyname = m_PolicyNames->GetCellValue(row, 0);
  PWPolicy st_pp;

  if (row == 0) { // 1st row is default
    st_pp = m_st_default_pp;
  } else {
    PSWDPolicyMapIter mapIter = m_MapPSWDPLC.find(StringX(policyname.c_str()));
    if (row != 0 && mapIter == m_MapPSWDPLC.end()) {
      ASSERT(0);
      return;
    }
    st_pp = mapIter->second;
  }

  CPasswordPolicy ppdlg(this, m_core, m_MapPSWDPLC);

  ppdlg.SetPolicyData(policyname, st_pp);
  if (ppdlg.ShowModal() == wxID_OK) {
    ppdlg.GetPolicyData(policyname, st_pp);
    ASSERT(!policyname.IsEmpty());
    UpdatePolicy(policyname, st_pp, CPP_MODIFIED);
  }
}
Esempio n. 2
0
void CompareDlg::OnCompare(wxCommandEvent& )
{
  if ( Validate() && TransferDataFromWindow()) {
    if (wxFileName(m_dbPanel->m_filepath).SameAs(towxstring(m_otherCore->GetCurFile())) ||
        ReadCore(*m_otherCore, m_dbPanel->m_filepath, m_dbPanel->m_combination,
                 true, this, true) == PWScore::SUCCESS) {
      m_otherCore->SetCurFile(tostringx(m_dbPanel->m_filepath));
      m_otherCore->SetReadOnly(true);

      // TODO: must copy the selectionCriteria from advanced options pane.  Or else
      // the search would always be conducted on default field criteria
      m_current->data.clear();
      m_comparison->data.clear();
      m_conflicts->data.clear();
      m_identical->data.clear();

      m_conflicts->pane->Collapse();
      m_current->pane->Collapse();
      m_comparison->pane->Collapse();
      m_identical->pane->Collapse();

      wxCommandEvent cmdEvent(EVT_START_COMPARISON, GetId());
      GetEventHandler()->AddPendingEvent(cmdEvent);
    }
  }
  else {
    m_otherCore->SetCurFile(StringX());
  }
}
StringX CYubiMixin::Bin2Hex(const unsigned char *buf, int len)
{
  std::wostringstream os;
  os << std::setw(2);
  os << std::setfill(L'0');
  for (int i = 0; i < len; i++) {
    os << std::hex << std::setw(2) << int(buf[i]);
  }
  return StringX(os.str().c_str());
}
Esempio n. 4
0
void CPasswordPolicyDlg::SetPolicyData(CString &cs_policyname,
                                       PSWDPolicyMap &MapPSWDPLC)
{
  m_MapPSWDPLC = MapPSWDPLC;
  m_policyname = m_oldpolicyname = cs_policyname;

  // Only called for Password Policies
  if (m_uicaller != IDS_PSWDPOLICY)
    return;

  m_iter = m_policyname.IsEmpty() ? m_MapPSWDPLC.end() :
                                    m_MapPSWDPLC.find(StringX((LPCWSTR)m_policyname));

  // Check the find() worked above - if PolicyName not empty, it must be in the map!
  if (!m_policyname.IsEmpty())
    ASSERT(m_iter != m_MapPSWDPLC.end());

  // If New, use default values; otherwise use this policy's values
  PWPolicy xst_pp = m_policyname.IsEmpty() ? m_st_default_pp : m_iter->second;

  m_PWUseLowercase = m_oldPWUseLowercase =
    (xst_pp.flags & PWPolicy::UseLowercase) ==
                       PWPolicy::UseLowercase;
  m_PWUseUppercase = m_oldPWUseUppercase =
    (xst_pp.flags & PWPolicy::UseUppercase) ==
                       PWPolicy::UseUppercase;
  m_PWUseDigits = m_oldPWUseDigits =
    (xst_pp.flags & PWPolicy::UseDigits) ==
                       PWPolicy::UseDigits;
  m_PWUseSymbols = m_oldPWUseSymbols =
    (xst_pp.flags & PWPolicy::UseSymbols) ==
                       PWPolicy::UseSymbols;
  m_PWUseHexdigits = m_oldPWUseHexdigits =
    (xst_pp.flags & PWPolicy::UseHexDigits) ==
                       PWPolicy::UseHexDigits;
  m_PWEasyVision = m_oldPWEasyVision =
    (xst_pp.flags & PWPolicy::UseEasyVision) ==
                       PWPolicy::UseEasyVision;
  m_PWMakePronounceable = m_oldPWMakePronounceable =
    (xst_pp.flags & PWPolicy::MakePronounceable) ==
                       PWPolicy::MakePronounceable;
  m_PWDefaultLength = m_oldPWDefaultLength = xst_pp.length;
  m_PWDigitMinLength = m_oldPWDigitMinLength = xst_pp.digitminlength;
  m_PWLowerMinLength = m_oldPWLowerMinLength = xst_pp.lowerminlength;
  m_PWSymbolMinLength = m_oldPWSymbolMinLength = xst_pp.symbolminlength;
  m_PWUpperMinLength = m_oldPWUpperMinLength = xst_pp.upperminlength;

  CString cs_symbols = xst_pp.symbols.c_str();
  if (m_PWUseSymbols &&!cs_symbols.IsEmpty())
    m_Symbols = m_oldSymbols = cs_symbols;
}
Esempio n. 5
0
void CPasswordPolicyDlg::OnNamesComboChanged()
{
  UpdateData(TRUE);

  int index = m_cbxPolicyNames.GetCurSel();
  m_cbxPolicyNames.GetLBText(index, m_policyname);

  // We need to update the controls' settings based on the selected
  // Named Password Policy or the Database Default Policy

  PWPolicy xst_pp;
  const CString defpol(MAKEINTRESOURCE(IDSC_DEFAULT_POLICY));

  if (m_policyname == defpol || m_policyname.IsEmpty()) {
    // m_policyname shouldn't be empty here, but JIC...
    xst_pp = m_st_default_pp;
  } else { // ! default policy, must be in map
    m_iter = m_MapPSWDPLC.find(StringX((LPCWSTR)m_policyname));
    ASSERT(m_iter != m_MapPSWDPLC.end());
    if (m_iter == m_MapPSWDPLC.end()) // if the impossible happens, at least don't crash
      return;
    xst_pp = m_iter->second;
  }

  // First disable them all
  SetSpecificPolicyControls(FALSE);

  // Now set values
  m_PWUseLowercase = (xst_pp.flags & PWPolicy::UseLowercase) != 0;
  m_PWUseUppercase = (xst_pp.flags & PWPolicy::UseUppercase) != 0;
  m_PWUseDigits = (xst_pp.flags & PWPolicy::UseDigits) != 0;
  m_PWUseSymbols = (xst_pp.flags & PWPolicy::UseSymbols) != 0;
  m_PWUseHexdigits = (xst_pp.flags & PWPolicy::UseHexDigits) != 0;
  m_PWEasyVision = (xst_pp.flags & PWPolicy::UseEasyVision) != 0;
  m_PWMakePronounceable = (xst_pp.flags & PWPolicy::MakePronounceable) != 0;
  
  m_PWDefaultLength = xst_pp.length;
  m_PWDigitMinLength = xst_pp.digitminlength;
  m_PWLowerMinLength = xst_pp.lowerminlength;
  m_PWSymbolMinLength = xst_pp.symbolminlength;
  m_PWUpperMinLength = xst_pp.upperminlength;

  m_Symbols = m_oldSymbols = xst_pp.symbols.c_str();
  m_SymbolsEdit.SetWindowText(m_Symbols);

  UpdateData(FALSE);
}
Esempio n. 6
0
void CManagePasswordPolicies::UpdatePolicy(const wxString &polname, const PWPolicy &pol,
                                           CPP_FLAGS mode)
{
  if (polname == _("Default Policy"))
    m_st_default_pp = pol;
  else
    m_MapPSWDPLC[tostringx(polname)] = pol;
#ifdef NOTYET
    // Save changes for Undo/Redo
    PWPolicyChange st_change;
    st_change.flags = mode;
    st_change.name = policyname;
    st_change.st_pp_save = m_iSelectedItem != 0 ? m_mapIter->second : m_st_default_pp;
    switch (mode) {
    case CPP_ADD:
      break;
    case CPP_MODIFIED:
      break;
    case CPP_DELETE:
      break;
    default:
      ASSERT(0);
    }

    if (m_iSelectedItem != 0) {
      // Changed a named password policy
      PSWDPolicyMapIter iter_new = m_MapPSWDPLC.find(StringX(policyname.c_str()));
      if (iter_new == m_MapPSWDPLC.end())
        ASSERT(0);
      st_change.st_pp_new = iter_new->second;
    } else {
      // Changed the database default policy
      st_change.st_pp_new = m_st_default_pp;
    }
  if (m_iundo_pos != (int)m_vchanges.size() - 1) {
    // We did have changes that could have been redone
    // But not anymore - delete all these to add new change on the end
    m_vchanges.resize(m_iundo_pos + 1);
  }

  // Add new change
  m_vchanges.push_back(st_change);
  // Update pointer to the one that is next to be undone
  m_iundo_pos++;
  // Update buttons appropriately
  FindWindow(wxID_UNDO)->Enable(true);
  FindWindow(wxID_REDO)->Enable(false);
#else
  UNREFERENCED_PARAMETER(mode);
#endif
  // Update lists
  UpdateNames();
  int N = m_PolicyNames->GetNumberRows();
  for (int row = 0; row < N; row++)
    if (m_PolicyNames->GetCellValue(row, 0) == polname) {
      m_PolicyNames->SelectRow(row);
      break;
    }

  UpdateDetails();
}
StringX PWSRun::getruncmd(const StringX &sxFile, bool &bfound) const
{
  // 1. If first parameter is in quotes - assume fully qualified - don't search.
  // 2. If first parameter starts with '%, assume it is going to be replaced by the
  // corresponding environmental variable - no need to search directories.
  // 3. If the first parameter ends in '.xxx', and '.xxx' is in the PATHEXT variable,
  // search for it as-is.  If not, append each of the known extensions to it and then
  // search.
  // 4. If searched and could not find, just issue 'as-is'.

  std::vector<StringX> vpaths;
  std::vector<StringX> vextns;

  StringX full_pgm(sxFile), sx_cwd;
  StringX sx_temp, sx_dirs, sx_extns;

  stringT path, drive, dir, fname, extn;
  stringT s_temp;
  bool bsearch_dirs(true), bsearch_extns(true);

  const StringX::size_type len = full_pgm.length();

  bfound = false;

  if (len == 0)
    return full_pgm;

  // Search order:

  // Current working directory
  s_temp = pws_os::getcwd();
  stringT::size_type Tlen = s_temp.length();
  if (Tlen == 0 || s_temp[Tlen - 1] != _T('\\')) {
    s_temp += _T("\\");
  }
  sx_cwd = StringX(s_temp.c_str());
  vpaths.push_back(sx_cwd);

  // Windows directory
  s_temp = pws_os::getenv("windir", true);
  if (s_temp.length() > 0)
    vpaths.push_back(StringX(s_temp.c_str()));

  // Windows/System32 directory
  if (!s_temp.empty()) {
    s_temp += stringT(_T("System32"));
    vpaths.push_back(StringX(s_temp.c_str()));
  }

  // Directories in PATH
  s_temp = pws_os::getenv("PATH", true);
  sx_temp = s_temp.c_str();
  // tokenize into separate elements using ; as the field separator
  for (StringX::size_type st_startpos = 0;
       st_startpos < sx_temp.size();
       /* st_startpos advanced in body */) {
    StringX::size_type st_next = sx_temp.find(_T(';'), st_startpos);
    if (st_next == StringX::npos)
      st_next = sx_temp.size();
    if (st_next > 0) {
      sx_dirs = sx_temp.substr(st_startpos, st_next - st_startpos);
      vpaths.push_back(sx_dirs);
    }
    st_startpos = st_next + 1; // too complex for for statement
  } // tokenization for loop

  // Apps Paths registry key - see below

  // Get support program extensions
  s_temp = pws_os::getenv("PATHEXT", false);
  sx_temp = s_temp.c_str();
  // tokenize into separate elements using ; as the field separator
  for (StringX::size_type st_startpos = 0;
       st_startpos < sx_temp.size();
       /* st_startpos advanced in body */) {
    StringX::size_type st_next = sx_temp.find(_T(';'), st_startpos);
    if (st_next == StringX::npos)
      st_next = sx_temp.size();
    if (st_next > 0) {
      sx_extns = sx_temp.substr(st_startpos, st_next - st_startpos);
      for(StringX::size_type i = 1; i < sx_extns.size(); i++) {
        sx_extns[i] = _totlower(sx_extns[i]);
      }
      vextns.push_back(sx_extns);
    }
    st_startpos = st_next + 1; // too complex for for statement
  } // tokenization for loop

  // Just need drive, directory and file extension
  path = full_pgm.c_str();
  pws_os::splitpath(path, drive, dir, fname, extn);

  if (!extn.empty()) {
    // ends with '.x-x'
    StringX sx_temp = StringX(extn.c_str());
    for (StringX::size_type i = 1; i < extn.size(); i++) {
      sx_temp[i] = _totlower(sx_temp[i]);
    }
    // Check if a known command extn
    if (std::find(vextns.begin(), vextns.end(), sx_temp) != vextns.end()) {
      bsearch_extns = false;
    }
  }

  if (!drive.empty() || !dir.empty()) {
    // Don't search directories but do search extensions
    bsearch_dirs = false;
    if (drive.empty()) {
      // Drive not specified - so could be relative to current directory
      sx_temp = sx_cwd + full_pgm;
      if (pws_os::FileExists(sx_temp.c_str())) {
        full_pgm = sx_temp;
        bfound = true;
        goto exit;
      }
      // Doesn't exist - add on know program extensions
      for (StringX::size_type ie = 0; ie < vextns.size(); ie++) {
        sx_extns = vextns[ie];
        if (pws_os::FileExists((sx_temp + sx_extns).c_str())) {
          full_pgm = full_pgm + sx_extns;
          bfound = true;
          goto exit;
        }
      }
    } else {
      // Drive specified - so should be full path.
      // Check if file exists as-is
      if (pws_os::FileExists(full_pgm.c_str())) {
        bfound = true;
        goto exit;
      }
      // Doesn't exist - add on know program extensions
      for (StringX::size_type ie = 0; ie < vextns.size(); ie++) {
        sx_extns = vextns[ie];
        if (pws_os::FileExists((full_pgm + sx_extns).c_str())) {
          full_pgm = full_pgm + sx_extns;
          bfound = true;
          goto exit;
        }
      }
    }
  }

  // Now search directories!
  if (bsearch_dirs) {
    // Ensure directory ends in a '/'
    for (StringX::size_type id = 0; id < vpaths.size(); id++) {
      sx_dirs = vpaths[id];
      if (sx_dirs[sx_dirs.length() - 1] != _T('\\'))
        sx_dirs += _T("\\");
      if (bsearch_extns) {
        for (StringX::size_type ie = 0; ie < vextns.size(); ie++) {
          sx_extns = vextns[ie];
          if (pws_os::FileExists((sx_dirs + full_pgm + sx_extns).c_str())) {
            full_pgm = sx_dirs + full_pgm + sx_extns;
            bfound = true;
            goto exit;
          }
        }
      } else {
        if (pws_os::FileExists(stringT((sx_dirs + full_pgm).c_str()))) {
          full_pgm = sx_dirs + full_pgm;
          bfound = true;
          goto exit;
        }
      }
    }
  }

  // If not found directly or within current directory structure, 
  // we so need to search registry.
  // Either: we had to search extensions - 
  //    so full_pgm does not end with known program extn;
  // Or: we didn't have to search -
  //    so full_pgm may end with '.exe' and we must not add
  if (!bfound &&
      (bsearch_extns || (!bsearch_extns && extn == _T(".exe")))) {
    // Check via registry
    if (bsearch_extns)
      full_pgm += _T(".exe");

    // Look for registry key
    bool bexists;
    HKEY hSubkey;
    StringX csSubkey = StringX(_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\")) +
      full_pgm;
    bexists = (::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                              csSubkey.c_str(),
                              0L,
                              KEY_READ,
                              &hSubkey) == ERROR_SUCCESS);
    if (bexists) {
      LONG rv;
      DWORD dwType, dwDataLen(0);
      rv = ::RegQueryValueEx(hSubkey,
                             _T("Path"),
                             NULL,
                             &dwType,
                             NULL,
                             &dwDataLen);
      if (rv == ERROR_SUCCESS && dwType == REG_SZ) {
        dwDataLen++;
        TCHAR *pData = new TCHAR[dwDataLen];
        ::memset(pData, 0, dwDataLen);
        rv = ::RegQueryValueEx(hSubkey,
                               _T("Path"),
                               NULL,
                               &dwType,
                               LPBYTE(pData),
                               &dwDataLen);

        if (rv == ERROR_SUCCESS) {
          sx_temp = pData;
          StringX::size_type len = sx_temp.length();
          if (sx_temp[len - 1] == _T(';'))
            sx_temp = sx_temp.substr(0, len - 1) + _T('\\');
          else
            if (sx_temp[len - 1] != _T('\\') && sx_temp[len - 1] != _T('/'))
              sx_temp = sx_temp + _T('\\');
          full_pgm =  sx_temp + full_pgm;
          bfound = true;
        }

        delete[] pData;
      } // Get the value
      ::RegCloseKey(hSubkey);
    }
  }

 exit:
  return full_pgm;
}
bool PWSRun::runcmd(const StringX &run_command, const bool &bAutotype) const
{
  // Get first parameter either enclosed by quotes or delimited by a space
  StringX full_string(run_command), first_part(_T("")), the_rest(_T(""));
  StringX env_var, sx_temp(_T(""));
  StringX::size_type end_delim;
  bool bfound(true);

  TrimLeft(full_string, _T(" "));
  if (full_string.c_str()[0] == _T('"')) {
    end_delim = full_string.find(_T('"'), 1);
    first_part = full_string.substr(1, end_delim - 1);
    the_rest = full_string.substr(end_delim + 1);
  } else {
    end_delim = full_string.find(_T(' '));
    if (end_delim != StringX::npos) {
      first_part = full_string.substr(0, end_delim);
      the_rest = full_string.substr(end_delim + 1);
    } else
      first_part = full_string;
  }

  // tokenize into separate elements using % as the field separator.
  // If this corresponds to a set envrionmental variable - replace it
  // and rebuild the command
  for (StringX::size_type st_startpos = 0;
       st_startpos < first_part.size();
       /* st_startpos advanced in body */) {
    StringX::size_type st_next = first_part.find(_T('%'), st_startpos);
    if (st_next == StringX::npos) {
      sx_temp += first_part.substr(st_startpos);
      break;
    }
    if (st_next > 0) {
      env_var = first_part.substr(st_startpos, st_next - st_startpos);
      size_t mblen = pws_os::wcstombs(NULL, 0, env_var.c_str(), size_t(-1), false);
      unsigned char * mbtemp = new unsigned char[mblen + 1];
      // Finally get result
      size_t tmplen = pws_os::wcstombs((char *)mbtemp, mblen, env_var.c_str(),
                                       size_t(-1), false);
      if (tmplen != mblen) {
        return false;
      }
      mbtemp[mblen - 1] = '\0';
      StringX envar = (pws_os::getenv((char *)mbtemp, false)).c_str();
      if (!envar.empty()) {
        sx_temp += envar;
      } else {
        sx_temp += StringX(_T("%")) + env_var + StringX(_T("%"));
      }
    }
    st_startpos = st_next + 1; // too complex for for statement
  } // tokenization for loop

  // Replace string by rebuilt string
  first_part = sx_temp;

  first_part = getruncmd(first_part, bfound);

  bool rc;
  if (bfound)
    rc = issuecmd(first_part, the_rest, bAutotype);
  else
    rc = issuecmd(full_string, _T(""), bAutotype);

  return rc;
}
void CCompareResultsDlg::AddCompareEntries(const bool bAddIdentical)
{
  int i, iItem = 0;
  CompareData::iterator cd_iter;

  if (bAddIdentical && m_numIdentical > 0) {
    for (cd_iter = m_Identical.begin(); cd_iter != m_Identical.end(); cd_iter++) {
      st_CompareData &st_data = *cd_iter;

      if (st_data.unknflds0)
        m_LCResults.InsertItem(iItem, L"=*");
      else
        m_LCResults.InsertItem(iItem, L"=");
      if (st_data.unknflds1)
        m_LCResults.SetItemText(iItem, COMPARE, L"=*");
      else
        m_LCResults.SetItemText(iItem, COMPARE, L"=");

      m_LCResults.SetItemText(iItem, GROUP, st_data.group.c_str());
      if (st_data.bIsProtected0)
        m_LCResults.SetItemText(iItem, TITLE, (st_data.title + StringX(L" #")).c_str());
      else
        m_LCResults.SetItemText(iItem, TITLE, st_data.title.c_str());
      m_LCResults.SetItemText(iItem, USER, st_data.user.c_str());
      for (i = USER + 1; i < m_nCols; i++)
        m_LCResults.SetItemText(iItem, i, L"-");

      st_data.listindex = iItem;
      m_LCResults.SetItemData(iItem, MAKELONG(IDENTICAL, st_data.id));
      iItem++;
    }
  }

  if (m_numOnlyInCurrent > 0) {
    for (cd_iter = m_OnlyInCurrent.begin(); cd_iter != m_OnlyInCurrent.end(); cd_iter++) {
      st_CompareData &st_data = *cd_iter;

      if (st_data.unknflds0)
        m_LCResults.InsertItem(iItem, L"Y*");
      else
        m_LCResults.InsertItem(iItem, L"Y");

      m_LCResults.SetItemText(iItem, COMPARE, L"-");
      m_LCResults.SetItemText(iItem, GROUP, st_data.group.c_str());
      if (st_data.bIsProtected0)
        m_LCResults.SetItemText(iItem, TITLE, (st_data.title + StringX(L" #")).c_str());
      else
        m_LCResults.SetItemText(iItem, TITLE, st_data.title.c_str());
      m_LCResults.SetItemText(iItem, USER, st_data.user.c_str());
      for (i = USER + 1; i < m_nCols; i++)
        m_LCResults.SetItemText(iItem, i, L"-");

      st_data.listindex = iItem;
      m_LCResults.SetItemData(iItem, MAKELONG(CURRENT, st_data.id));
      iItem++;
    }
  }

  if (m_numOnlyInComp > 0) {
    for (cd_iter = m_OnlyInComp.begin(); cd_iter != m_OnlyInComp.end(); cd_iter++) {
      st_CompareData &st_data = *cd_iter;

      m_LCResults.InsertItem(iItem, L"-");
      if (st_data.unknflds1)
        m_LCResults.SetItemText(iItem, COMPARE, L"Y*");
      else
        m_LCResults.SetItemText(iItem, COMPARE, L"Y");

      m_LCResults.SetItemText(iItem, GROUP, st_data.group.c_str());
      m_LCResults.SetItemText(iItem, TITLE, st_data.title.c_str());
      m_LCResults.SetItemText(iItem, USER, st_data.user.c_str());
      for (i = USER + 1; i < m_nCols; i++)
        m_LCResults.SetItemText(iItem, i, L"-");

      st_data.listindex = iItem;
      m_LCResults.SetItemData(iItem, MAKELONG(COMPARE, st_data.id));
      iItem++;
    }
  }

  if (m_numConflicts > 0) {
    for (cd_iter = m_Conflicts.begin(); cd_iter != m_Conflicts.end(); cd_iter++) {
      st_CompareData &st_data = *cd_iter;

      if (st_data.unknflds0)
        m_LCResults.InsertItem(iItem, L"Y*");
      else
        m_LCResults.InsertItem(iItem, L"Y");

      if (st_data.unknflds1)
        m_LCResults.SetItemText(iItem, COMPARE, L"Y*");
      else
        m_LCResults.SetItemText(iItem, COMPARE, L"Y");

      m_LCResults.SetItemText(iItem, GROUP, st_data.group.c_str());
      if (st_data.bIsProtected0)
        m_LCResults.SetItemText(iItem, TITLE, (st_data.title + StringX(L" #")).c_str());
      else
        m_LCResults.SetItemText(iItem, TITLE, st_data.title.c_str());
      m_LCResults.SetItemText(iItem, USER, st_data.user.c_str());

      // Start of the 'data' columns (if present)
      int icol = PASSWORD;
      for (i = 0; i < sizeof(OptCols) / sizeof(OptCols[0]); i++) {
        if (m_bsFields.test(OptCols[i].ft)) {
          m_LCResults.SetItemText(iItem, icol++, st_data.bsDiffs.test(OptCols[i].ft) ? L"X" : L"-");
        }
      }

      st_data.listindex = iItem;
      m_LCResults.SetItemData(iItem, MAKELONG(BOTH, st_data.id));
      iItem++;
    }
  }
}