<commit_before>/*=========================================================================

  Program: DICOM for VTK

  Copyright (c) 2012-2014 David Gobbi
  All rights reserved.
  See Copyright.txt or http://dgobbi.github.io/bsd3.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkDICOMDirectory.h"
#include "vtkDICOMMetaData.h"
#include "vtkDICOMItem.h"
#include "vtkDICOMDataElement.h"
#include "vtkDICOMParser.h"
#include "vtkDICOMMetaData.h"

// from dicomcli
#include "readquery.h"

#include <vtkStringArray.h>
#include <vtkSmartPointer.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <iostream>

// print the version
void dicomfind_version(FILE *file, const char *cp)
{
  fprintf(file, "%s %s\n", cp, DICOM_VERSION);
  fprintf(file, "\n"
    "Copyright (c) 2012-2014, David Gobbi.\n\n"
    "This software is distributed under an open-source license.  See the\n"
    "Copyright.txt file that comes with the vtk-dicom source distribution.\n");
}

// print the usage
void dicomfind_usage(FILE *file, const char *cp)
{
  fprintf(file, "usage:\n"
    "  %s -q <query.txt> -o <data.csv> <directory>\n\n", cp);
  fprintf(file, "options:\n"
    "  -q <query.txt>  Provide a file to describe the find query.\n"
    "  -o <data.csv>   Provide a file for the query results.\n"
    "  --help          Print a brief help message.\n"
    "  --version       Print the software version.\n");
}

// print the help
void dicomfind_help(FILE *file, const char *cp)
{
  dicomfind_usage(file, cp);
  fprintf(file, "\n"
    "Dump the metadata from a DICOM series as text.\n");
}

// remove path portion of filename
const char *dicomfind_basename(const char *filename)
{
  const char *cp = filename + strlen(filename);
  while (cp != filename && cp[-1] != '\\' && cp[-1] != '/') { --cp; }
  return cp;
}

typedef vtkDICOMVR VR;

// Write the header
void dicomfind_writeheader(
  const vtkDICOMItem& query, const QueryTagList *ql, std::ostream& os)
{
  // print human-readable names for each tag
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    for (;;)
      {
      vtkDICOMTag tag = tagPath.GetHead();
      vtkDICOMDictEntry e = pitem->FindDictEntry(tag);
      if (e.IsValid())
        {
        os << e.GetName();
        }
      if (!tagPath.HasTail())
        {
        break;
        }
      pitem = pitem->GetAttributeValue(tag).GetSequenceData();
      tagPath = tagPath.GetTail();
      os << "\\";
      }
    }
  os << "\r\n";

  // print the private creator
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    for (;;)
      {
      vtkDICOMTag tag = tagPath.GetHead();
      std::string creator = "DICOM";
      if ((tag.GetGroup() & 0x0001) == 1)
        {
        vtkDICOMTag ctag(tag.GetGroup(), tag.GetElement() >> 8);
        creator = pitem->GetAttributeValue(ctag).AsString();
        }
      os << creator.c_str();
      if (!tagPath.HasTail())
        {
        break;
        }
      pitem = pitem->GetAttributeValue(tag).GetSequenceData();
      tagPath = tagPath.GetTail();
      os << "\\";
      }
    }
  os << "\r\n";

  // print the tag as a hexadecimal number
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    for (;;)
      {
      vtkDICOMTag tag = tagPath.GetHead();
      unsigned short g = tag.GetGroup();
      unsigned short e = tag.GetElement();
      std::string creator;
      if ((tag.GetGroup() & 0x0001) == 1)
        {
        vtkDICOMTag ctag(tag.GetGroup(), tag.GetElement() >> 8);
        creator = pitem->GetAttributeValue(ctag).AsString();
        if (creator.length() > 0)
          {
          // remove the creator portion of the element number
          e &= 0x00FF;
          }
        }
      char tagtext[16];
      sprintf(tagtext, "%04X%04X", g, e);
      os << tagtext;
      if (!tagPath.HasTail())
        {
        break;
        }
      pitem = pitem->GetAttributeValue(tag).GetSequenceData();
      tagPath = tagPath.GetTail();
      os << "\\";
      }
    }
  os << "\r\n";

  // print the VR
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    vtkDICOMValue v = query.GetAttributeValue(tagPath);
    if (v.IsValid())
      {
      os << v.GetVR().GetText();
      }
    else
      {
      for (;;)
        {
        vtkDICOMTag tag = tagPath.GetHead();
        if (!tagPath.HasTail())
          {
          vtkDICOMDictEntry e = pitem->FindDictEntry(tag);
          if (e.IsValid())
            {
            os << e.GetVR().GetText();
            }
          break;
          }
        pitem = pitem->GetAttributeValue(tag).GetSequenceData();
        tagPath = tagPath.GetTail();
        }
      }
    }
  os << "\r\n";
}

// Convert date to format YYYY-MM-DD HH:MM:SS
std::string dicomfind_date(const std::string& dt, vtkDICOMVR vr)
{
  if (vr == VR::TM && dt.length() >= 6)
    {
    return dt.substr(0,2) + ":" + dt.substr(2,2) + ":" + dt.substr(4,2);
    }
  else if (vr == VR::DA && dt.length() >= 8)
    {
    return dt.substr(0,4) + "-" + dt.substr(4,2) + "-" + dt.substr(6,2);
    }
  else if (vr == VR::DT && dt.length() >= 14)
    {
    return dt.substr(0,4) + "-" + dt.substr(4,2) + "-" + dt.substr(6,2) + " " +
           dt.substr(8,2) + ":" + dt.substr(10,2) + ":" + dt.substr(12,2);
    }

  return "";
}

// Quote a string by doubling any double-quotes that are found
// (this follows RFC 4180)
std::string dicomfind_quote(const std::string& s)
{
  size_t i = 0;
  std::string r;

  for (;;)
    {
    size_t j = s.find('\"', i);
    if (j < s.length())
      {
      r += s.substr(i, j-i+1);
      r += "\"";
      i = j+1;
      }
    else
      {
      r += s.substr(i);
      break;
      }
    }

  return r;
}

// Write out the results
void dicomfind_write(vtkDICOMDirectory *finder,
  const vtkDICOMItem& query, const QueryTagList *ql, std::ostream& os)
{
  for (int j = 0; j < finder->GetNumberOfStudies(); j++)
    {
    int k0 = finder->GetFirstSeriesForStudy(j);
    int k1 = finder->GetLastSeriesForStudy(j);
    for (int k = k0; k <= k1; k++)
      {
      vtkStringArray *a = finder->GetFileNamesForSeries(k);

      vtkSmartPointer<vtkDICOMMetaData> meta =
        vtkSmartPointer<vtkDICOMMetaData>::New();
      vtkSmartPointer<vtkDICOMParser> parser =
        vtkSmartPointer<vtkDICOMParser>::New();

      parser->SetFileName(a->GetValue(0));
      parser->SetMetaData(meta);
      parser->SetQueryItem(query);
      parser->Update();

      vtkDICOMDataElementIterator iter;

      // print the value of each tag
      for (size_t i = 0; i < ql->size(); i++)
        {
        if (i != 0)
          {
          os << ",";
          }

        const vtkDICOMItem *qitem = &query;
        const vtkDICOMItem *mitem = 0;
        const vtkDICOMValue *vp = 0;
        vtkDICOMTagPath tagPath = ql->at(i);
        for (;;)
          {
          vtkDICOMTag tag = tagPath.GetHead();
          std::string creator;
          if ((tag.GetGroup() & 0x0001) == 1)
            {
            vtkDICOMTag ctag(tag.GetGroup(), tag.GetElement() >> 8);
            creator = qitem->GetAttributeValue(ctag).AsString();
            if (mitem)
              {
              tag = meta->ResolvePrivateTag(tag, creator);
              }
            else
              {
              tag = mitem->ResolvePrivateTag(tag, creator);
              }
            }
          if (mitem)
            {
            vp = &mitem->GetAttributeValue(tag);
            }
          else
            {
            vp = &meta->GetAttributeValue(tag);
            }
          if (vp && !vp->IsValid())
            {
            vp = 0;
            }
          if (vp == 0 || !tagPath.HasTail())
            {
            break;
            }
          qitem = qitem->GetAttributeValue(
            tagPath.GetHead()).GetSequenceData();
          tagPath = tagPath.GetTail();
          mitem = vp->GetSequenceData();
          if (mitem == 0 || vp->GetNumberOfValues() == 0)
            {
            break;
            }
          }

        if (vp != 0)
          {
          const vtkDICOMValue& v = *vp;
          if (v.GetNumberOfValues() == 1 &&
              (v.GetVR() == VR::SS ||
               v.GetVR() == VR::US ||
               v.GetVR() == VR::SL ||
               v.GetVR() == VR::UL ||
               v.GetVR() == VR::FL ||
               v.GetVR() == VR::FD))
            {
            os << v;
            }
          else if (v.GetVR() == VR::DA ||
                   v.GetVR() == VR::TM ||
                   v.GetVR() == VR::DT)
            {
            os << "\"" << dicomfind_date(v.AsString(), v.GetVR()) << "\"";
            }
          else if (v.GetVR() == VR::SQ)
            {
            // how should a sequence be printed out to the csv file?
            }
          else if (v.GetVL() != 0 && v.GetVL() != 0xFFFFFFFF)
            {
            os << "\"" << dicomfind_quote(v.AsUTF8String()) << "\"";
            }
          }
        else if (tagPath.GetHead() == DC::ReferencedFileID &&
                 !tagPath.HasTail())
          {
          os << "\"" << dicomfind_quote(a->GetValue(0)) << "\"";
          }
        }

      os << "\r\n";
      }
    }
}

// This program will dump all the metadata in the given file
int main(int argc, char *argv[])
{
  int rval = 0;

  vtkSmartPointer<vtkStringArray> a = vtkSmartPointer<vtkStringArray>::New();
  const char *ofile = 0;
  const char *qfile = 0;

  if (argc < 2)
    {
    dicomfind_usage(stdout, dicomfind_basename(argv[0]));
    return rval;
    }
  else if (argc == 2 && strcmp(argv[1], "--help") == 0)
    {
    dicomfind_help(stdout, dicomfind_basename(argv[0]));
    return rval;
    }
  else if (argc == 2 && strcmp(argv[1], "--version") == 0)
    {
    dicomfind_version(stdout, dicomfind_basename(argv[0]));
    return rval;
    }

  for (int argi = 1; argi < argc; argi++)
    {
    const char *arg = argv[argi];
    if (strcmp(arg, "-q") == 0 || strcmp(arg, "-o") == 0)
      {
      if (argi + 1 == argc || argv[argi+1][0] == '-')
        {
        fprintf(stderr, "%s must be followed by a file.\n\n", arg);
        dicomfind_usage(stderr, dicomfind_basename(argv[0]));
        return 1;
        }

      if (arg[1] == 'q')
        {
        qfile = argv[++argi];
        }
      else if (arg[1] == 'o')
        {
        ofile = argv[++argi];
        }
      }
    else if (arg[0] == '-')
      {
      fprintf(stderr, "unrecognized option %s.\n\n", arg);
      dicomfind_usage(stderr, dicomfind_basename(argv[0]));
      return 1;
      }
    else
      {
      a->InsertNextValue(arg);
      }
    }

  if (qfile == 0)
    {
    fprintf(stderr, "No query file.\n\n");
    dicomfind_usage(stderr, dicomfind_basename(argv[0]));
    return 1;
    }

  std::ostream *osp = &std::cout;
  std::ofstream ofs;

  if (ofile)
    {
    ofs.open(ofile,
             std::ofstream::out |
             std::ofstream::binary |
             std::ofstream::trunc);

    if (ofs.bad())
      {
      fprintf(stderr, "Unable to open output file %s.\n", ofile);
      return 1;
      }
    osp = &ofs;
    }

  // read the query file, create a query
  QueryTagList qtlist;
  vtkDICOMItem query = dicomcli_readquery(qfile, &qtlist);

  // Write the header
  dicomfind_writeheader(query, &qtlist, *osp);
  osp->flush();

  // Write data for every input directory
  for (vtkIdType i = 0; i < a->GetNumberOfTuples(); i++)
    {
    vtkSmartPointer<vtkDICOMDirectory> finder =
      vtkSmartPointer<vtkDICOMDirectory>::New();
    finder->SetDirectoryName(a->GetValue(i));
    finder->SetScanDepth(8);
    finder->SetFindQuery(query);
    finder->Update();

    dicomfind_write(finder, query, &qtlist, *osp);
    osp->flush();
    }

  return rval;
}
<commit_msg>Make dicomfind automatically search functional groups.<commit_after>/*=========================================================================

  Program: DICOM for VTK

  Copyright (c) 2012-2014 David Gobbi
  All rights reserved.
  See Copyright.txt or http://dgobbi.github.io/bsd3.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkDICOMDirectory.h"
#include "vtkDICOMMetaData.h"
#include "vtkDICOMItem.h"
#include "vtkDICOMDataElement.h"
#include "vtkDICOMParser.h"
#include "vtkDICOMMetaData.h"
#include "vtkDICOMMetaDataAdapter.h"

// from dicomcli
#include "readquery.h"

#include <vtkStringArray.h>
#include <vtkSmartPointer.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <iostream>

// print the version
void dicomfind_version(FILE *file, const char *cp)
{
  fprintf(file, "%s %s\n", cp, DICOM_VERSION);
  fprintf(file, "\n"
    "Copyright (c) 2012-2014, David Gobbi.\n\n"
    "This software is distributed under an open-source license.  See the\n"
    "Copyright.txt file that comes with the vtk-dicom source distribution.\n");
}

// print the usage
void dicomfind_usage(FILE *file, const char *cp)
{
  fprintf(file, "usage:\n"
    "  %s -q <query.txt> -o <data.csv> <directory>\n\n", cp);
  fprintf(file, "options:\n"
    "  -q <query.txt>  Provide a file to describe the find query.\n"
    "  -o <data.csv>   Provide a file for the query results.\n"
    "  --help          Print a brief help message.\n"
    "  --version       Print the software version.\n");
}

// print the help
void dicomfind_help(FILE *file, const char *cp)
{
  dicomfind_usage(file, cp);
  fprintf(file, "\n"
    "Dump the metadata from a DICOM series as text.\n");
}

// remove path portion of filename
const char *dicomfind_basename(const char *filename)
{
  const char *cp = filename + strlen(filename);
  while (cp != filename && cp[-1] != '\\' && cp[-1] != '/') { --cp; }
  return cp;
}

typedef vtkDICOMVR VR;

// Write the header
void dicomfind_writeheader(
  const vtkDICOMItem& query, const QueryTagList *ql, std::ostream& os)
{
  // print human-readable names for each tag
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    for (;;)
      {
      vtkDICOMTag tag = tagPath.GetHead();
      vtkDICOMDictEntry e = pitem->FindDictEntry(tag);
      if (e.IsValid())
        {
        os << e.GetName();
        }
      if (!tagPath.HasTail())
        {
        break;
        }
      pitem = pitem->GetAttributeValue(tag).GetSequenceData();
      tagPath = tagPath.GetTail();
      os << "\\";
      }
    }
  os << "\r\n";

  // print the private creator
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    for (;;)
      {
      vtkDICOMTag tag = tagPath.GetHead();
      std::string creator = "DICOM";
      if ((tag.GetGroup() & 0x0001) == 1)
        {
        vtkDICOMTag ctag(tag.GetGroup(), tag.GetElement() >> 8);
        creator = pitem->GetAttributeValue(ctag).AsString();
        }
      os << creator.c_str();
      if (!tagPath.HasTail())
        {
        break;
        }
      pitem = pitem->GetAttributeValue(tag).GetSequenceData();
      tagPath = tagPath.GetTail();
      os << "\\";
      }
    }
  os << "\r\n";

  // print the tag as a hexadecimal number
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    for (;;)
      {
      vtkDICOMTag tag = tagPath.GetHead();
      unsigned short g = tag.GetGroup();
      unsigned short e = tag.GetElement();
      std::string creator;
      if ((tag.GetGroup() & 0x0001) == 1)
        {
        vtkDICOMTag ctag(tag.GetGroup(), tag.GetElement() >> 8);
        creator = pitem->GetAttributeValue(ctag).AsString();
        if (creator.length() > 0)
          {
          // remove the creator portion of the element number
          e &= 0x00FF;
          }
        }
      char tagtext[16];
      sprintf(tagtext, "%04X%04X", g, e);
      os << tagtext;
      if (!tagPath.HasTail())
        {
        break;
        }
      pitem = pitem->GetAttributeValue(tag).GetSequenceData();
      tagPath = tagPath.GetTail();
      os << "\\";
      }
    }
  os << "\r\n";

  // print the VR
  for (size_t i = 0; i < ql->size(); i++)
    {
    if (i != 0)
      {
      os << ",";
      }
    const vtkDICOMItem *pitem = &query;
    vtkDICOMTagPath tagPath = ql->at(i);
    vtkDICOMValue v = query.GetAttributeValue(tagPath);
    if (v.IsValid())
      {
      os << v.GetVR().GetText();
      }
    else
      {
      for (;;)
        {
        vtkDICOMTag tag = tagPath.GetHead();
        if (!tagPath.HasTail())
          {
          vtkDICOMDictEntry e = pitem->FindDictEntry(tag);
          if (e.IsValid())
            {
            os << e.GetVR().GetText();
            }
          break;
          }
        pitem = pitem->GetAttributeValue(tag).GetSequenceData();
        tagPath = tagPath.GetTail();
        }
      }
    }
  os << "\r\n";
}

// Convert date to format YYYY-MM-DD HH:MM:SS
std::string dicomfind_date(const std::string& dt, vtkDICOMVR vr)
{
  if (vr == VR::TM && dt.length() >= 6)
    {
    return dt.substr(0,2) + ":" + dt.substr(2,2) + ":" + dt.substr(4,2);
    }
  else if (vr == VR::DA && dt.length() >= 8)
    {
    return dt.substr(0,4) + "-" + dt.substr(4,2) + "-" + dt.substr(6,2);
    }
  else if (vr == VR::DT && dt.length() >= 14)
    {
    return dt.substr(0,4) + "-" + dt.substr(4,2) + "-" + dt.substr(6,2) + " " +
           dt.substr(8,2) + ":" + dt.substr(10,2) + ":" + dt.substr(12,2);
    }

  return "";
}

// Quote a string by doubling any double-quotes that are found
// (this follows RFC 4180)
std::string dicomfind_quote(const std::string& s)
{
  size_t i = 0;
  std::string r;

  for (;;)
    {
    size_t j = s.find('\"', i);
    if (j < s.length())
      {
      r += s.substr(i, j-i+1);
      r += "\"";
      i = j+1;
      }
    else
      {
      r += s.substr(i);
      break;
      }
    }

  return r;
}

// Write out the results
void dicomfind_write(vtkDICOMDirectory *finder,
  const vtkDICOMItem& query, const QueryTagList *ql, std::ostream& os)
{
  for (int j = 0; j < finder->GetNumberOfStudies(); j++)
    {
    int k0 = finder->GetFirstSeriesForStudy(j);
    int k1 = finder->GetLastSeriesForStudy(j);
    for (int k = k0; k <= k1; k++)
      {
      vtkStringArray *a = finder->GetFileNamesForSeries(k);

      vtkSmartPointer<vtkDICOMMetaData> meta =
        vtkSmartPointer<vtkDICOMMetaData>::New();
      vtkSmartPointer<vtkDICOMParser> parser =
        vtkSmartPointer<vtkDICOMParser>::New();

      parser->SetFileName(a->GetValue(0));
      parser->SetMetaData(meta);
      parser->SetQueryItem(query);
      parser->Update();

      // create an adapter, in case of enhanced IOD
      vtkDICOMMetaDataAdapter adapter(meta);

      // print the value of each tag
      for (size_t i = 0; i < ql->size(); i++)
        {
        if (i != 0)
          {
          os << ",";
          }

        const vtkDICOMItem *qitem = &query;
        const vtkDICOMItem *mitem = 0;
        const vtkDICOMValue *vp = 0;
        vtkDICOMTagPath tagPath = ql->at(i);
        for (;;)
          {
          vtkDICOMTag tag = tagPath.GetHead();
          std::string creator;
          if ((tag.GetGroup() & 0x0001) == 1)
            {
            vtkDICOMTag ctag(tag.GetGroup(), tag.GetElement() >> 8);
            creator = qitem->GetAttributeValue(ctag).AsString();
            if (mitem)
              {
              tag = adapter->ResolvePrivateTag(tag, creator);
              }
            else
              {
              tag = mitem->ResolvePrivateTag(tag, creator);
              }
            }
          if (mitem)
            {
            vp = &mitem->GetAttributeValue(tag);
            }
          else
            {
            vp = &adapter->GetAttributeValue(tag);
            }
          if (vp && !vp->IsValid())
            {
            vp = 0;
            }
          if (vp == 0 || !tagPath.HasTail())
            {
            break;
            }
          qitem = qitem->GetAttributeValue(
            tagPath.GetHead()).GetSequenceData();
          tagPath = tagPath.GetTail();
          mitem = vp->GetSequenceData();
          if (mitem == 0 || vp->GetNumberOfValues() == 0)
            {
            break;
            }
          }

        if (vp != 0)
          {
          const vtkDICOMValue& v = *vp;
          if (v.GetNumberOfValues() == 1 &&
              (v.GetVR() == VR::SS ||
               v.GetVR() == VR::US ||
               v.GetVR() == VR::SL ||
               v.GetVR() == VR::UL ||
               v.GetVR() == VR::FL ||
               v.GetVR() == VR::FD))
            {
            os << v;
            }
          else if (v.GetVR() == VR::DA ||
                   v.GetVR() == VR::TM ||
                   v.GetVR() == VR::DT)
            {
            os << "\"" << dicomfind_date(v.AsString(), v.GetVR()) << "\"";
            }
          else if (v.GetVR() == VR::SQ)
            {
            // how should a sequence be printed out to the csv file?
            }
          else if (v.GetVL() != 0 && v.GetVL() != 0xFFFFFFFF)
            {
            os << "\"" << dicomfind_quote(v.AsUTF8String()) << "\"";
            }
          }
        else if (tagPath.GetHead() == DC::ReferencedFileID &&
                 !tagPath.HasTail())
          {
          os << "\"" << dicomfind_quote(a->GetValue(0)) << "\"";
          }
        }

      os << "\r\n";
      }
    }
}

// This program will dump all the metadata in the given file
int main(int argc, char *argv[])
{
  int rval = 0;

  vtkSmartPointer<vtkStringArray> a = vtkSmartPointer<vtkStringArray>::New();
  const char *ofile = 0;
  const char *qfile = 0;

  if (argc < 2)
    {
    dicomfind_usage(stdout, dicomfind_basename(argv[0]));
    return rval;
    }
  else if (argc == 2 && strcmp(argv[1], "--help") == 0)
    {
    dicomfind_help(stdout, dicomfind_basename(argv[0]));
    return rval;
    }
  else if (argc == 2 && strcmp(argv[1], "--version") == 0)
    {
    dicomfind_version(stdout, dicomfind_basename(argv[0]));
    return rval;
    }

  for (int argi = 1; argi < argc; argi++)
    {
    const char *arg = argv[argi];
    if (strcmp(arg, "-q") == 0 || strcmp(arg, "-o") == 0)
      {
      if (argi + 1 == argc || argv[argi+1][0] == '-')
        {
        fprintf(stderr, "%s must be followed by a file.\n\n", arg);
        dicomfind_usage(stderr, dicomfind_basename(argv[0]));
        return 1;
        }

      if (arg[1] == 'q')
        {
        qfile = argv[++argi];
        }
      else if (arg[1] == 'o')
        {
        ofile = argv[++argi];
        }
      }
    else if (arg[0] == '-')
      {
      fprintf(stderr, "unrecognized option %s.\n\n", arg);
      dicomfind_usage(stderr, dicomfind_basename(argv[0]));
      return 1;
      }
    else
      {
      a->InsertNextValue(arg);
      }
    }

  if (qfile == 0)
    {
    fprintf(stderr, "No query file.\n\n");
    dicomfind_usage(stderr, dicomfind_basename(argv[0]));
    return 1;
    }

  std::ostream *osp = &std::cout;
  std::ofstream ofs;

  if (ofile)
    {
    ofs.open(ofile,
             std::ofstream::out |
             std::ofstream::binary |
             std::ofstream::trunc);

    if (ofs.bad())
      {
      fprintf(stderr, "Unable to open output file %s.\n", ofile);
      return 1;
      }
    osp = &ofs;
    }

  // read the query file, create a query
  QueryTagList qtlist;
  vtkDICOMItem query = dicomcli_readquery(qfile, &qtlist);

  // always add the functional sequences for advanced files
  query.SetAttributeValue(
    DC::SharedFunctionalGroupsSequence, vtkDICOMValue(VR::SQ));
  query.SetAttributeValue(
    DC::PerFrameFunctionalGroupsSequence, vtkDICOMValue(VR::SQ));

  // Write the header
  dicomfind_writeheader(query, &qtlist, *osp);
  osp->flush();

  // Write data for every input directory
  for (vtkIdType i = 0; i < a->GetNumberOfTuples(); i++)
    {
    vtkSmartPointer<vtkDICOMDirectory> finder =
      vtkSmartPointer<vtkDICOMDirectory>::New();
    finder->SetDirectoryName(a->GetValue(i));
    finder->SetScanDepth(8);
    finder->SetFindQuery(query);
    finder->Update();

    dicomfind_write(finder, query, &qtlist, *osp);
    osp->flush();
    }

  return rval;
}
<|endoftext|>


<commit_before>#include "inscriptiondialog.h"
#include "ui_inscriptiondialog.h"
#include "burncoinsdialog.h"

// #include "version.h"
#include "init.h" // for pwalletMain
#include "util.h"
#include "guiutil.h"

#include "addresstablemodel.h"
#include "optionsmodel.h"
#include "script.h"
#include "bitcoinunits.h"

#include "sendcoinsdialog.h"
#include "sendcoinsentry.h"
#include "clientmodel.h"
#include "walletmodel.h"

#include <QCloseEvent>
#include <QLabel>
#include <QRegExp>
#include <QTextTable>
#include <QTextCursor>
#include <QVBoxLayout>
#include <QtDebug>

/** class "InscriptionDialog" dialog box */
InscriptionDialog::InscriptionDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::InscriptionDialog),
    walletModel(0),
    clientModel(0)
{
    ui->setupUi(this);
}

void InscriptionDialog::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
    }
}

void InscriptionDialog::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model)
    {
    }
}

InscriptionDialog::~InscriptionDialog()
{
    delete ui;
}

void InscriptionDialog::on_insertButton_clicked()
{
    QString txmsg = ui->lineEditMsg->text();
    // qDebug() << "Text message:" << txmsg << "Other value:" << i;
    qDebug() << "Text message:" << txmsg;

    if ( std::string(txmsg.toStdString().c_str()).length() > 100 )
    {
        QMessageBox::question(this, tr("Message error"),
                              tr("Message length exceeds the limit (100 bytes)!"),
              QMessageBox::Cancel,
              QMessageBox::Cancel);
        return;
    }

    QList<SendCoinsRecipient> recipients;
    SendCoinsRecipient rcpt;
    QString vchDefaultAddr = CBitcoinAddress(pwalletMain->vchDefaultKey.GetID()).ToString().c_str();
    rcpt.address = vchDefaultAddr;
    rcpt.label = "inscription";
    rcpt.amount = 1*CENT;
    recipients.append(rcpt);

    qDebug() << "Recipient created" << vchDefaultAddr << " amount" << 1*CENT;

    // send the transaction
    WalletModel::SendCoinsReturn sendstatus = walletModel->sendCoins(recipients, txmsg, false);

    switch(sendstatus.status)
    {
    case WalletModel::InvalidAddress:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("The recepient address is not valid, please recheck."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::InvalidAmount:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("The amount to pay must be at least one cent (0.01)."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::AmountExceedsBalance:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Amount exceeds your balance"),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::AmountWithFeeExceedsBalance:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Total exceeds your balance when the %1 transaction fee is included").
                             arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::DuplicateAddress:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Duplicate address found, can only send to each address once in one send operation"),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::TransactionCreationFailed:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Error: Transaction creation failed  "),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::TransactionCommitFailed:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::BadBurningCoins:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("You are sending coins to a burn address without using the dedicated \"" BURN_COINS_DIALOG_NAME "\" tab. If you want to burn coins, use the dedicated tab instead of this \"" SEND_COINS_DIALOG_NAME "\" tab. \n\nSending coins aborted."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::Aborted: // User aborted, nothing to do
        break;
    case WalletModel::OK:
        accept();
        QMessageBox::information(NULL, tr("Inscription"), tr("Inscribe on blockchain, Yes"), QMessageBox::Yes , QMessageBox::Yes);
        ui->lineEditMsg->setText("Message inscribed.");
        break;
    }

    /*
    {
        QMessageBox::information(NULL, tr("Failed"), tr("Inscription failed"), QMessageBox::Yes , QMessageBox::Yes);
        ui->lineEditMsg->setText(txmsg);
    }
    */
}

void InscriptionDialog::on_pushButton_clicked()
{
    close();
}

void InscriptionDialog::resetMessage()
{
    ui->lineEditMsg->setText("");
}
<commit_msg>reset to 80 bytes for the interim<commit_after>#include "inscriptiondialog.h"
#include "ui_inscriptiondialog.h"
#include "burncoinsdialog.h"

// #include "version.h"
#include "init.h" // for pwalletMain
#include "util.h"
#include "guiutil.h"

#include "addresstablemodel.h"
#include "optionsmodel.h"
#include "script.h"
#include "bitcoinunits.h"

#include "sendcoinsdialog.h"
#include "sendcoinsentry.h"
#include "clientmodel.h"
#include "walletmodel.h"

#include <QCloseEvent>
#include <QLabel>
#include <QRegExp>
#include <QTextTable>
#include <QTextCursor>
#include <QVBoxLayout>
#include <QtDebug>

/** class "InscriptionDialog" dialog box */
InscriptionDialog::InscriptionDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::InscriptionDialog),
    walletModel(0),
    clientModel(0)
{
    ui->setupUi(this);
}

void InscriptionDialog::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
    }
}

void InscriptionDialog::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model)
    {
    }
}

InscriptionDialog::~InscriptionDialog()
{
    delete ui;
}

void InscriptionDialog::on_insertButton_clicked()
{
    QString txmsg = ui->lineEditMsg->text();
    // qDebug() << "Text message:" << txmsg << "Other value:" << i;
    qDebug() << "Text message:" << txmsg;

    if ( std::string(txmsg.toStdString().c_str()).length() > 100 )
    {
        QMessageBox::question(this, tr("Message error"),
                              tr("Message length exceeds the limit (80 bytes)!"), // MAX_OP_RETURN_RELAY
              QMessageBox::Cancel,
              QMessageBox::Cancel);
        return;
    }

    QList<SendCoinsRecipient> recipients;
    SendCoinsRecipient rcpt;
    QString vchDefaultAddr = CBitcoinAddress(pwalletMain->vchDefaultKey.GetID()).ToString().c_str();
    rcpt.address = vchDefaultAddr;
    rcpt.label = "inscription";
    rcpt.amount = 1*CENT;
    recipients.append(rcpt);

    qDebug() << "Recipient created" << vchDefaultAddr << " amount" << 1*CENT;

    // send the transaction
    WalletModel::SendCoinsReturn sendstatus = walletModel->sendCoins(recipients, txmsg, false);

    switch(sendstatus.status)
    {
    case WalletModel::InvalidAddress:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("The recepient address is not valid, please recheck."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::InvalidAmount:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("The amount to pay must be at least one cent (0.01)."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::AmountExceedsBalance:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Amount exceeds your balance"),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::AmountWithFeeExceedsBalance:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Total exceeds your balance when the %1 transaction fee is included").
                             arg(BitcoinUnits::formatWithUnit(BitcoinUnits::BTC, sendstatus.fee)),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::DuplicateAddress:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Duplicate address found, can only send to each address once in one send operation"),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::TransactionCreationFailed:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Error: Transaction creation failed  "),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::TransactionCommitFailed:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("Error: The transaction was rejected.  This might happen if some of the coins in your wallet were already spent, such as if you used a copy of wallet.dat and coins were spent in the copy but not marked as spent here."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::BadBurningCoins:
        QMessageBox::warning(this, tr("Send Coins"),
                             tr("You are sending coins to a burn address without using the dedicated \"" BURN_COINS_DIALOG_NAME "\" tab. If you want to burn coins, use the dedicated tab instead of this \"" SEND_COINS_DIALOG_NAME "\" tab. \n\nSending coins aborted."),
                             QMessageBox::Ok, QMessageBox::Ok);
        break;
    case WalletModel::Aborted: // User aborted, nothing to do
        break;
    case WalletModel::OK:
        accept();
        QMessageBox::information(NULL, tr("Inscription"), tr("Inscribe on blockchain, Yes"), QMessageBox::Yes , QMessageBox::Yes);
        ui->lineEditMsg->setText("Message inscribed.");
        break;
    }

    /*
    {
        QMessageBox::information(NULL, tr("Failed"), tr("Inscription failed"), QMessageBox::Yes , QMessageBox::Yes);
        ui->lineEditMsg->setText(txmsg);
    }
    */
}

void InscriptionDialog::on_pushButton_clicked()
{
    close();
}

void InscriptionDialog::resetMessage()
{
    ui->lineEditMsg->setText("");
}
<|endoftext|>


<commit_before>#include "masternodemanager.h"
#include "ui_masternodemanager.h"
#include "addeditadrenalinenode.h"
#include "adrenalinenodeconfigdialog.h"

#include "sync.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "activemasternode.h"
#include "masternodeconfig.h"
#include "masternode.h"
#include "walletdb.h"
#include "wallet.h"
#include "init.h"

#include <QAbstractItemDelegate>
#include <QPainter>
#include <QTimer>
#include <QDebug>
#include <QScrollArea>
#include <QScroller>
#include <QDateTime>
#include <QApplication>
#include <QClipboard>
#include <QMessageBox>

MasternodeManager::MasternodeManager(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MasternodeManager),
    clientModel(0),
    walletModel(0)
{
    ui->setupUi(this);

    ui->editButton->setEnabled(false);
    ui->getConfigButton->setEnabled(false);
    ui->startButton->setEnabled(false);
    ui->stopButton->setEnabled(false);
    ui->copyAddressButton->setEnabled(false);

    ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    ui->tableWidget_2->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

    subscribeToCoreSignals();

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList()));
    connect(timer, SIGNAL(timeout()), this, SLOT(updateNodeList()));
    timer->start(30 * 1000); // 30 seconds

    updateMyNodeList();
    updateNodeList();
}

MasternodeManager::~MasternodeManager()
{
    delete ui;
}

static void NotifyAdrenalineNodeUpdated(MasternodeManager *page, CAdrenalineNodeConfig nodeConfig)
{
    // alias, address, privkey, collateral address
    QString alias = QString::fromStdString(nodeConfig.sAlias);
    QString addr = QString::fromStdString(nodeConfig.sAddress);
    QString privkey = QString::fromStdString(nodeConfig.sMasternodePrivKey);
    QString collateral = QString::fromStdString(nodeConfig.sCollateralAddress);

    QMetaObject::invokeMethod(page, "updateAdrenalineNode", Qt::QueuedConnection,
                              Q_ARG(QString, alias),
                              Q_ARG(QString, addr),
                              Q_ARG(QString, privkey),
                              Q_ARG(QString, collateral)
                              );
}

void MasternodeManager::subscribeToCoreSignals()
{
    // Connect signals to core
    uiInterface.NotifyAdrenalineNodeChanged.connect(boost::bind(&NotifyAdrenalineNodeUpdated, this, _1));
}

void MasternodeManager::unsubscribeFromCoreSignals()
{
    // Disconnect signals from core
    uiInterface.NotifyAdrenalineNodeChanged.disconnect(boost::bind(&NotifyAdrenalineNodeUpdated, this, _1));
}

void MasternodeManager::on_tableWidget_2_itemSelectionChanged()
{
    if(ui->tableWidget_2->selectedItems().count() > 0)
    {
        ui->editButton->setEnabled(true);
        ui->getConfigButton->setEnabled(true);
        ui->startButton->setEnabled(true);
        ui->stopButton->setEnabled(true);
    ui->copyAddressButton->setEnabled(true);
    }
}

void MasternodeManager::updateAdrenalineNode(QString alias, QString addr, QString privkey, QString collateral)
{
    LOCK(cs_adrenaline);

    bool bFound = false;
    int nodeRow = 0;
    for(int i=0; i < ui->tableWidget_2->rowCount(); i++)
    {
        if(ui->tableWidget_2->item(i, 0)->text() == alias)
        {
            bFound = true;
            nodeRow = i;
            break;
        }
    }

    ui->tableWidget_2->setSortingEnabled(false);

    if(nodeRow == 0 && !bFound)
        ui->tableWidget_2->insertRow(0);

    QTableWidgetItem *aliasItem = new QTableWidgetItem(alias);
    QTableWidgetItem *addrItem = new QTableWidgetItem(addr);
    QTableWidgetItem *statusItem = new QTableWidgetItem("");
    QTableWidgetItem *collateralItem = new QTableWidgetItem(collateral);

    ui->tableWidget_2->setItem(nodeRow, 0, aliasItem);
    ui->tableWidget_2->setItem(nodeRow, 1, addrItem);
    ui->tableWidget_2->setItem(nodeRow, 2, statusItem);
    ui->tableWidget_2->setItem(nodeRow, 3, collateralItem);

    ui->tableWidget_2->setSortingEnabled(true);
}

static QString seconds_to_DHMS(quint32 duration)
{
  QString res;
  int seconds = (int) (duration % 60);
  duration /= 60;
  int minutes = (int) (duration % 60);
  duration /= 60;
  int hours = (int) (duration % 24);
  int days = (int) (duration / 24);
  if((hours == 0)&&(days == 0))
      return res.sprintf("%02dm:%02ds", minutes, seconds);
  if (days == 0)
      return res.sprintf("%02dh:%02dm:%02ds", hours, minutes, seconds);
  return res.sprintf("%dd %02dh:%02dm:%02ds", days, hours, minutes, seconds);
}

void MasternodeManager::updateMyNodeList()
{
    TRY_LOCK(cs_adrenaline, lockMasternodes);
    if(!lockMasternodes) {
        return;
    }

    if(pwalletMain)
    {
        BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
        {
            updateAdrenalineNode(QString::fromStdString(adrenaline.second.sAlias), QString::fromStdString(adrenaline.second.sAddress), QString::fromStdString(adrenaline.second.sMasternodePrivKey), QString::fromStdString(adrenaline.second.sCollateralAddress));
        }
    }
}

void MasternodeManager::updateNodeList()
{
    TRY_LOCK(cs_masternodes, lockMasternodes);
    if(!lockMasternodes)
        return;

    ui->countLabel->setText("Updating...");
    ui->tableWidget->setSortingEnabled(false);
    ui->tableWidget->clearContents();
    ui->tableWidget->setRowCount(0);

    BOOST_FOREACH(CMasterNode& mn, vecMasternodes)
    {
        // populate list
        // Address, Rank, Active, Active Seconds, Last Seen, Pub Key
        QTableWidgetItem *activeItem = new QTableWidgetItem(QString::number(mn.IsEnabled()));
        QTableWidgetItem *addressItem = new QTableWidgetItem(QString::fromStdString(mn.addr.ToString()));
        QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(mn.protocolVersion));
        QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(seconds_to_DHMS((qint64)(mn.lastTimeSeen - mn.now)));
        QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat(mn.lastTimeSeen)));

        CScript pubkey;
        pubkey =GetScriptForDestination(mn.pubkey.GetID());
        CTxDestination address1;
        ExtractDestination(pubkey, address1);
        CBitcoinAddress address2(address1);
        QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(address2.ToString()));

        ui->tableWidget->insertRow(0);
        ui->tableWidget->setItem(0, 0, addressItem);
        ui->tableWidget->setItem(0, 1, protocolItem);
        ui->tableWidget->setItem(0, 2, activeItem);
        ui->tableWidget->setItem(0, 3, activeSecondsItem);
        ui->tableWidget->setItem(0, 4, lastSeenItem);
        ui->tableWidget->setItem(0, 5, pubkeyItem);
    }

    ui->countLabel->setText(QString::number(ui->tableWidget->rowCount()));
    ui->tableWidget->setSortingEnabled(true);
}

void MasternodeManager::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
    }
}

void MasternodeManager::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model && model->getOptionsModel())
    {
    }

}

void MasternodeManager::on_createButton_clicked()
{
    AddEditAdrenalineNode* aenode = new AddEditAdrenalineNode();
    aenode->exec();
}

void MasternodeManager::on_copyAddressButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sCollateralAddress = ui->tableWidget_2->item(r, 3)->text().toStdString();

    QApplication::clipboard()->setText(QString::fromStdString(sCollateralAddress));
}

void MasternodeManager::on_editButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();

    // get existing config entry

}

void MasternodeManager::on_getConfigButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
    CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
    std::string sPrivKey = c.sMasternodePrivKey;
    AdrenalineNodeConfigDialog* d = new AdrenalineNodeConfigDialog(this, QString::fromStdString(sAddress), QString::fromStdString(sPrivKey));
    d->exec();
}

void MasternodeManager::on_removeButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QMessageBox::StandardButton confirm;
    confirm = QMessageBox::question(this, "Delete Nucleus Node?", "Are you sure you want to delete this nucleus node configuration?", QMessageBox::Yes|QMessageBox::No);

    if(confirm == QMessageBox::Yes)
    {
        QModelIndex index = selected.at(0);
        int r = index.row();
        std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
        CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
        CWalletDB walletdb(pwalletMain->strWalletFile);
        pwalletMain->mapMyAdrenalineNodes.erase(sAddress);
        walletdb.EraseAdrenalineNodeConfig(c.sAddress);
        ui->tableWidget_2->clearContents();
        ui->tableWidget_2->setRowCount(0);
        BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
        {
            updateAdrenalineNode(QString::fromStdString(adrenaline.second.sAlias), QString::fromStdString(adrenaline.second.sAddress), QString::fromStdString(adrenaline.second.sMasternodePrivKey), QString::fromStdString(adrenaline.second.sCollateralAddress));
        }
    }
}

void MasternodeManager::on_startButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    // start the node
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
    CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];

    std::string errorMessage;
    bool result = activeMasternode.RegisterByPubKey(c.sAddress, c.sMasternodePrivKey, c.sCollateralAddress, errorMessage);

    QMessageBox msg;
    if(result)
        msg.setText("Adrenaline Node at " + QString::fromStdString(c.sAddress) + " started.");
    else
        msg.setText("Error: " + QString::fromStdString(errorMessage));

    msg.exec();
}

void MasternodeManager::on_stopButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    // start the node
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
    CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];

    std::string errorMessage;
    bool result = activeMasternode.StopMasterNode(c.sAddress, c.sMasternodePrivKey, errorMessage);
    QMessageBox msg;
    if(result)
    {
        msg.setText("Adrenaline Node at " + QString::fromStdString(c.sAddress) + " stopped.");
    }
    else
    {
        msg.setText("Error: " + QString::fromStdString(errorMessage));
    }
    msg.exec();
}

void MasternodeManager::on_startAllButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    std::string results;
    BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
    {
        CAdrenalineNodeConfig c = adrenaline.second;
    std::string errorMessage;
        bool result = activeMasternode.RegisterByPubKey(c.sAddress, c.sMasternodePrivKey, c.sCollateralAddress, errorMessage);
    if(result)
    {
        results += c.sAddress + ": STARTED\n";
    }
    else
    {
        results += c.sAddress + ": ERROR: " + errorMessage + "\n";
    }
    }

    QMessageBox msg;
    msg.setText(QString::fromStdString(results));
    msg.exec();
}

void MasternodeManager::on_stopAllButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    std::string results;
    BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
    {
        CAdrenalineNodeConfig c = adrenaline.second;
    std::string errorMessage;
        bool result = activeMasternode.StopMasterNode(c.sAddress, c.sMasternodePrivKey, errorMessage);
    if(result)
    {
        results += c.sAddress + ": STOPPED\n";
    }
    else
    {
        results += c.sAddress + ": ERROR: " + errorMessage + "\n";
    }
    }

    QMessageBox msg;
    msg.setText(QString::fromStdString(results));
    msg.exec();
}

void MasternodeManager::on_UpdateButton_clicked()
{
    updateMyNodeList();
    updateNodeList();
}
<commit_msg>Disable masternode edit button that does not work<commit_after>#include "masternodemanager.h"
#include "ui_masternodemanager.h"
#include "addeditadrenalinenode.h"
#include "adrenalinenodeconfigdialog.h"

#include "sync.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "activemasternode.h"
#include "masternodeconfig.h"
#include "masternode.h"
#include "walletdb.h"
#include "wallet.h"
#include "init.h"

#include <QAbstractItemDelegate>
#include <QPainter>
#include <QTimer>
#include <QDebug>
#include <QScrollArea>
#include <QScroller>
#include <QDateTime>
#include <QApplication>
#include <QClipboard>
#include <QMessageBox>

MasternodeManager::MasternodeManager(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MasternodeManager),
    clientModel(0),
    walletModel(0)
{
    ui->setupUi(this);

    ui->editButton->setEnabled(false);
    ui->getConfigButton->setEnabled(false);
    ui->startButton->setEnabled(false);
    ui->stopButton->setEnabled(false);
    ui->copyAddressButton->setEnabled(false);

    ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    ui->tableWidget_2->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

    subscribeToCoreSignals();

    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(updateMyNodeList()));
    connect(timer, SIGNAL(timeout()), this, SLOT(updateNodeList()));
    timer->start(30 * 1000); // 30 seconds

    updateMyNodeList();
    updateNodeList();
}

MasternodeManager::~MasternodeManager()
{
    delete ui;
}

static void NotifyAdrenalineNodeUpdated(MasternodeManager *page, CAdrenalineNodeConfig nodeConfig)
{
    // alias, address, privkey, collateral address
    QString alias = QString::fromStdString(nodeConfig.sAlias);
    QString addr = QString::fromStdString(nodeConfig.sAddress);
    QString privkey = QString::fromStdString(nodeConfig.sMasternodePrivKey);
    QString collateral = QString::fromStdString(nodeConfig.sCollateralAddress);

    QMetaObject::invokeMethod(page, "updateAdrenalineNode", Qt::QueuedConnection,
                              Q_ARG(QString, alias),
                              Q_ARG(QString, addr),
                              Q_ARG(QString, privkey),
                              Q_ARG(QString, collateral)
                              );
}

void MasternodeManager::subscribeToCoreSignals()
{
    // Connect signals to core
    uiInterface.NotifyAdrenalineNodeChanged.connect(boost::bind(&NotifyAdrenalineNodeUpdated, this, _1));
}

void MasternodeManager::unsubscribeFromCoreSignals()
{
    // Disconnect signals from core
    uiInterface.NotifyAdrenalineNodeChanged.disconnect(boost::bind(&NotifyAdrenalineNodeUpdated, this, _1));
}

void MasternodeManager::on_tableWidget_2_itemSelectionChanged()
{
    if(ui->tableWidget_2->selectedItems().count() > 0)
    {
        ui->editButton->setEnabled(false);
        ui->getConfigButton->setEnabled(true);
        ui->startButton->setEnabled(true);
        ui->stopButton->setEnabled(true);
        ui->copyAddressButton->setEnabled(true);
    }
}

void MasternodeManager::updateAdrenalineNode(QString alias, QString addr, QString privkey, QString collateral)
{
    LOCK(cs_adrenaline);

    bool bFound = false;
    int nodeRow = 0;
    for(int i=0; i < ui->tableWidget_2->rowCount(); i++)
    {
        if(ui->tableWidget_2->item(i, 0)->text() == alias)
        {
            bFound = true;
            nodeRow = i;
            break;
        }
    }

    ui->tableWidget_2->setSortingEnabled(false);

    if(nodeRow == 0 && !bFound)
        ui->tableWidget_2->insertRow(0);

    QTableWidgetItem *aliasItem = new QTableWidgetItem(alias);
    QTableWidgetItem *addrItem = new QTableWidgetItem(addr);
    QTableWidgetItem *statusItem = new QTableWidgetItem("");
    QTableWidgetItem *collateralItem = new QTableWidgetItem(collateral);

    ui->tableWidget_2->setItem(nodeRow, 0, aliasItem);
    ui->tableWidget_2->setItem(nodeRow, 1, addrItem);
    ui->tableWidget_2->setItem(nodeRow, 2, statusItem);
    ui->tableWidget_2->setItem(nodeRow, 3, collateralItem);

    ui->tableWidget_2->setSortingEnabled(true);
}

static QString seconds_to_DHMS(quint32 duration)
{
  QString res;
  int seconds = (int) (duration % 60);
  duration /= 60;
  int minutes = (int) (duration % 60);
  duration /= 60;
  int hours = (int) (duration % 24);
  int days = (int) (duration / 24);
  if((hours == 0)&&(days == 0))
      return res.sprintf("%02dm:%02ds", minutes, seconds);
  if (days == 0)
      return res.sprintf("%02dh:%02dm:%02ds", hours, minutes, seconds);
  return res.sprintf("%dd %02dh:%02dm:%02ds", days, hours, minutes, seconds);
}

void MasternodeManager::updateMyNodeList()
{
    TRY_LOCK(cs_adrenaline, lockMasternodes);
    if(!lockMasternodes) {
        return;
    }

    if(pwalletMain)
    {
        BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
        {
            updateAdrenalineNode(QString::fromStdString(adrenaline.second.sAlias), QString::fromStdString(adrenaline.second.sAddress), QString::fromStdString(adrenaline.second.sMasternodePrivKey), QString::fromStdString(adrenaline.second.sCollateralAddress));
        }
    }
}

void MasternodeManager::updateNodeList()
{
    TRY_LOCK(cs_masternodes, lockMasternodes);
    if(!lockMasternodes)
        return;

    ui->countLabel->setText("Updating...");
    ui->tableWidget->setSortingEnabled(false);
    ui->tableWidget->clearContents();
    ui->tableWidget->setRowCount(0);

    BOOST_FOREACH(CMasterNode& mn, vecMasternodes)
    {
        // populate list
        // Address, Rank, Active, Active Seconds, Last Seen, Pub Key
        QTableWidgetItem *activeItem = new QTableWidgetItem(QString::number(mn.IsEnabled()));
        QTableWidgetItem *addressItem = new QTableWidgetItem(QString::fromStdString(mn.addr.ToString()));
        QTableWidgetItem *protocolItem = new QTableWidgetItem(QString::number(mn.protocolVersion));
        QTableWidgetItem *activeSecondsItem = new QTableWidgetItem(seconds_to_DHMS((qint64)(mn.lastTimeSeen - mn.now)));
        QTableWidgetItem *lastSeenItem = new QTableWidgetItem(QString::fromStdString(DateTimeStrFormat(mn.lastTimeSeen)));

        CScript pubkey;
        pubkey =GetScriptForDestination(mn.pubkey.GetID());
        CTxDestination address1;
        ExtractDestination(pubkey, address1);
        CBitcoinAddress address2(address1);
        QTableWidgetItem *pubkeyItem = new QTableWidgetItem(QString::fromStdString(address2.ToString()));

        ui->tableWidget->insertRow(0);
        ui->tableWidget->setItem(0, 0, addressItem);
        ui->tableWidget->setItem(0, 1, protocolItem);
        ui->tableWidget->setItem(0, 2, activeItem);
        ui->tableWidget->setItem(0, 3, activeSecondsItem);
        ui->tableWidget->setItem(0, 4, lastSeenItem);
        ui->tableWidget->setItem(0, 5, pubkeyItem);
    }

    ui->countLabel->setText(QString::number(ui->tableWidget->rowCount()));
    ui->tableWidget->setSortingEnabled(true);
}

void MasternodeManager::setClientModel(ClientModel *model)
{
    this->clientModel = model;
    if(model)
    {
    }
}

void MasternodeManager::setWalletModel(WalletModel *model)
{
    this->walletModel = model;
    if(model && model->getOptionsModel())
    {
    }

}

void MasternodeManager::on_createButton_clicked()
{
    AddEditAdrenalineNode* aenode = new AddEditAdrenalineNode();
    aenode->exec();
}

void MasternodeManager::on_copyAddressButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sCollateralAddress = ui->tableWidget_2->item(r, 3)->text().toStdString();

    QApplication::clipboard()->setText(QString::fromStdString(sCollateralAddress));
}

void MasternodeManager::on_editButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();

    // get existing config entry

}

void MasternodeManager::on_getConfigButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
    CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
    std::string sPrivKey = c.sMasternodePrivKey;
    AdrenalineNodeConfigDialog* d = new AdrenalineNodeConfigDialog(this, QString::fromStdString(sAddress), QString::fromStdString(sPrivKey));
    d->exec();
}

void MasternodeManager::on_removeButton_clicked()
{
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QMessageBox::StandardButton confirm;
    confirm = QMessageBox::question(this, "Delete Nucleus Node?", "Are you sure you want to delete this nucleus node configuration?", QMessageBox::Yes|QMessageBox::No);

    if(confirm == QMessageBox::Yes)
    {
        QModelIndex index = selected.at(0);
        int r = index.row();
        std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
        CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];
        CWalletDB walletdb(pwalletMain->strWalletFile);
        pwalletMain->mapMyAdrenalineNodes.erase(sAddress);
        walletdb.EraseAdrenalineNodeConfig(c.sAddress);
        ui->tableWidget_2->clearContents();
        ui->tableWidget_2->setRowCount(0);
        BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
        {
            updateAdrenalineNode(QString::fromStdString(adrenaline.second.sAlias), QString::fromStdString(adrenaline.second.sAddress), QString::fromStdString(adrenaline.second.sMasternodePrivKey), QString::fromStdString(adrenaline.second.sCollateralAddress));
        }
    }
}

void MasternodeManager::on_startButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    // start the node
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
    CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];

    std::string errorMessage;
    bool result = activeMasternode.RegisterByPubKey(c.sAddress, c.sMasternodePrivKey, c.sCollateralAddress, errorMessage);

    QMessageBox msg;
    if(result)
        msg.setText("Adrenaline Node at " + QString::fromStdString(c.sAddress) + " started.");
    else
        msg.setText("Error: " + QString::fromStdString(errorMessage));

    msg.exec();
}

void MasternodeManager::on_stopButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    // start the node
    QItemSelectionModel* selectionModel = ui->tableWidget_2->selectionModel();
    QModelIndexList selected = selectionModel->selectedRows();
    if(selected.count() == 0)
        return;

    QModelIndex index = selected.at(0);
    int r = index.row();
    std::string sAddress = ui->tableWidget_2->item(r, 1)->text().toStdString();
    CAdrenalineNodeConfig c = pwalletMain->mapMyAdrenalineNodes[sAddress];

    std::string errorMessage;
    bool result = activeMasternode.StopMasterNode(c.sAddress, c.sMasternodePrivKey, errorMessage);
    QMessageBox msg;
    if(result)
    {
        msg.setText("Adrenaline Node at " + QString::fromStdString(c.sAddress) + " stopped.");
    }
    else
    {
        msg.setText("Error: " + QString::fromStdString(errorMessage));
    }
    msg.exec();
}

void MasternodeManager::on_startAllButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    std::string results;
    BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
    {
        CAdrenalineNodeConfig c = adrenaline.second;
    std::string errorMessage;
        bool result = activeMasternode.RegisterByPubKey(c.sAddress, c.sMasternodePrivKey, c.sCollateralAddress, errorMessage);
    if(result)
    {
        results += c.sAddress + ": STARTED\n";
    }
    else
    {
        results += c.sAddress + ": ERROR: " + errorMessage + "\n";
    }
    }

    QMessageBox msg;
    msg.setText(QString::fromStdString(results));
    msg.exec();
}

void MasternodeManager::on_stopAllButton_clicked()
{
    if (ui->tableWidget_2->rowCount() == 0)
        return;
    std::string results;
    BOOST_FOREACH(PAIRTYPE(std::string, CAdrenalineNodeConfig) adrenaline, pwalletMain->mapMyAdrenalineNodes)
    {
        CAdrenalineNodeConfig c = adrenaline.second;
    std::string errorMessage;
        bool result = activeMasternode.StopMasterNode(c.sAddress, c.sMasternodePrivKey, errorMessage);
    if(result)
    {
        results += c.sAddress + ": STOPPED\n";
    }
    else
    {
        results += c.sAddress + ": ERROR: " + errorMessage + "\n";
    }
    }

    QMessageBox msg;
    msg.setText(QString::fromStdString(results));
    msg.exec();
}

void MasternodeManager::on_UpdateButton_clicked()
{
    updateMyNodeList();
    updateNodeList();
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2013, "Kira"
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// This code is HEAVILY based off of the Chromium websocket server source.
// You may view the license for Chromium in 3rdparty/LICENSE.chromium

#include "precompiled_headers.hpp"

#include "websocket.hpp"
#include "sha1.hpp"
#include "base64.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <exception>
#include "startup_config.hpp"
#include "logging.hpp"

#include <map>
#include <vector>

#include <arpa/inet.h>
#include <netinet/in.h>

// NOTE NOTE NOTE NOTE
// These functions have side effects!
// The receive function for these classes DOES modify the input buffer!
// The send function DOES NOT modify the input buffer.
// This is an implementation detail. The input buffering is known to be simple.
// The output buffering is far more complex, involving splitting and other things,
// and thus is beyond the scope of these functions. Input buffering is simple to implement here,
// and saves passing around a size variable to then advance the input buffer only if needed.
// NOTE NOTE NOTE NOTE
namespace Websocket {

    /*
     * Due to some "issues" with the TLS proxy server mangling headers, we
     * have to lowercase headers to normalize the capitalization.
     */
    ProtocolVersion Acceptor::accept(std::string& input, std::string& output,
            std::string& ip) {
        ProtocolVersion ret = PROTOCOL_INCOMPLETE;
        try {
            DLOG(INFO) << "Attempting to parse a websocket header.";
            if (input.find("\r\n\r\n") == std::string::npos)
                return ret;

            std::map<std::string, std::string> headers;
            std::string line;
            std::string remainder = input;
            std::string::size_type end = remainder.find("\r\n");
            while (end != std::string::npos) {
                line = remainder.substr(0, end);
                remainder = remainder.substr(end + 2);

                std::string::size_type pos = line.find(": ");
                if (pos != std::string::npos) {
                    std::string key = line.substr(0, pos);
                    for (size_t i = 0; i < key.length(); ++i) {
                        key[i] = tolower(key[i]);
                    }
                    headers[key] = line.substr(pos + 2);
                }

                end = remainder.find("\r\n");
            }

            std::string outbuffer;

            // Copy the forwarded for ip into our output if it exists.
            // Caller checks for proper remote address before trusting this.
            if (headers.count("x-forwarded-for") != 0) {
                ip = headers["x-forwarded-for"];
            }
            if (headers.count("sec-websocket-version") != 0 && headers.count("sec-websocket-key") != 0) {
                DLOG(INFO) << "Found a Hybi websocket header.";
                if (Hybi::accept(headers["sec-websocket-key"], headers["sec-websocket-origin"], outbuffer) != WS_RESULT_OK) {
                    ret = PROTOCOL_BAD;
                } else {
                    ret = PROTOCOL_HYBI;
                }
            } else {
                ret = PROTOCOL_BAD;
            }
            output = outbuffer;
        } catch (std::exception e) {
            LOG(WARNING) << "Exception occurred in websocket accept. e.what: " << e.what();
            ret = PROTOCOL_BAD;
        } catch (...) {
            LOG(WARNING) << "Unexpected exception occured in websocket accept.";
            ret = PROTOCOL_BAD;
        }
        return ret;
    }

    static const unsigned int wsHeaderSize = 2;
    static const unsigned int wsMaskingKeySize = 4;
    static const unsigned int wsOpcodeMask = 0x0F;
    static const unsigned int wsMaskedMask = 0x80;
    static const unsigned int wsLengthMask = 0x7F;
    static const unsigned int wsSingleByteLength = 125;
    static const unsigned int wsTwoByteLength = 126;
    static const unsigned int wsEightByteLength = 127;
    static const unsigned int wsOpcodeText = 0x01;
    static const unsigned int wsOpcodeClose = 0x08;
    static const unsigned int wsMaximumClientFrameSize = 0x80000; //512kB should be sufficient for any client->server message.
    static const char* const wsMagicalGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    WebSocketResult Hybi::accept(string& key, string& origin, string& output) {
        if (key.empty())
            return WS_RESULT_ERROR;

        //		if(origin.find("f-list.net") == string::npos)
        //		{
        //			return WS_RESULT_ERROR;
        //		}

        char buf[4096];
        bzero(&buf[0], sizeof (buf));
        int len = snprintf(&buf[0], sizeof (buf), "%s%s", key.c_str(), wsMagicalGUID);
        string keystr(&buf[0], len);
        bzero(&buf[0], sizeof (buf));
        string encodedkey;
        string hashkey = thirdparty::SHA1HashString(keystr);
        thirdparty::Base64Encode(hashkey, encodedkey);
        len = snprintf(&buf[0], sizeof (buf),
                "HTTP/1.1 101 Switching Protocols\r\n"
                "Upgrade: websocket\r\n"
                "Connection: Upgrade\r\n"
                "Sec-WebSocket-Accept: %s\r\n\r\n", encodedkey.c_str());
        string tmp(&buf[0], len);
        output.swap(tmp);
        return WS_RESULT_OK;
    }

    WebSocketResult Hybi::receive(std::string& input, std::string& output) {
        unsigned long rlen = input.length();
        if (rlen < wsHeaderSize)
            return WS_RESULT_INCOMPLETE;

        const char* msg = input.c_str();
        unsigned char b1 = *msg++;
        unsigned char b2 = *msg++;

        unsigned int opcode = b1 & wsOpcodeMask;
        bool masked = b2 & wsMaskedMask;
        unsigned int lengthhint = b2 & wsLengthMask;

        // Standard defines that all client to server communication must be masked.
        if (!masked)
            return WS_RESULT_ERROR;

        switch (opcode) {
                // Text
            case wsOpcodeText:
                break;
                // Close
            case wsOpcodeClose:
                return WS_RESULT_CLOSE;
            default:
                return WS_RESULT_ERROR;
        }

        uint64_t payload_length = 0;
        int lengthsize = 0;
        if (lengthhint > wsSingleByteLength) {
            lengthsize = 2;
            if (lengthhint == wsEightByteLength)
                lengthsize = 8;

            if (rlen < wsHeaderSize + lengthsize)
                return WS_RESULT_INCOMPLETE;

            for (int i = 0; i < lengthsize; ++i) {
                payload_length <<= 8;
                payload_length |= static_cast<unsigned char> (*msg++);
            }
        } else {
            payload_length = lengthhint;
        }

        if (payload_length > wsMaximumClientFrameSize)
            return WS_RESULT_ERROR;

        uint64_t totallen = (masked ? wsMaskingKeySize : 0) + payload_length;
        if (rlen < (wsHeaderSize + lengthsize + totallen))
            return WS_RESULT_INCOMPLETE;

        if (masked) {
            output.resize(payload_length);
            const char* mask = msg;
            msg += wsMaskingKeySize;
            for (unsigned int i = 0; i < payload_length; ++i) {
                output[i] = msg[i] ^ mask[i % wsMaskingKeySize];
            }
        } else {
            string tmp(msg, payload_length);
            output.swap(tmp);
        }

        input = input.substr(wsHeaderSize + lengthsize + totallen);

        return WS_RESULT_OK;
    }

    void Hybi::send(string& input, string& output) {
        std::vector<unsigned char> frame;
        unsigned int length = input.length();

        frame.push_back(0x80 | wsOpcodeText);

        if (length <= wsSingleByteLength) {
            frame.push_back(static_cast<unsigned char> (length));
        } else if (length <= 0xFFFF) {
            frame.push_back(wsTwoByteLength);
            frame.push_back((length & 0xFF00) >> 8);
            frame.push_back(length & 0xFF);
        } else {
            uint64_t qlength = length;
            frame.push_back(wsEightByteLength);
            for (size_t i = 0; i < 8; ++i) {
                unsigned char length_piece = (qlength >> 8*(7-i)) & 0xFF;
                frame.push_back(length_piece);
            }
        }
        frame.insert(frame.end(), input.data(), input.data() + length);
        string tmp(frame.begin(), frame.end());
        output.swap(tmp);
    }
}
<commit_msg>Swap from x-forwarded-for to x-real-ip.<commit_after>/*
 * Copyright (c) 2011-2013, "Kira"
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// This code is HEAVILY based off of the Chromium websocket server source.
// You may view the license for Chromium in 3rdparty/LICENSE.chromium

#include "precompiled_headers.hpp"

#include "websocket.hpp"
#include "sha1.hpp"
#include "base64.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <exception>
#include "startup_config.hpp"
#include "logging.hpp"

#include <map>
#include <vector>

#include <arpa/inet.h>
#include <netinet/in.h>

// NOTE NOTE NOTE NOTE
// These functions have side effects!
// The receive function for these classes DOES modify the input buffer!
// The send function DOES NOT modify the input buffer.
// This is an implementation detail. The input buffering is known to be simple.
// The output buffering is far more complex, involving splitting and other things,
// and thus is beyond the scope of these functions. Input buffering is simple to implement here,
// and saves passing around a size variable to then advance the input buffer only if needed.
// NOTE NOTE NOTE NOTE
namespace Websocket {

    /*
     * Due to some "issues" with the TLS proxy server mangling headers, we
     * have to lowercase headers to normalize the capitalization.
     */
    ProtocolVersion Acceptor::accept(std::string& input, std::string& output,
            std::string& ip) {
        ProtocolVersion ret = PROTOCOL_INCOMPLETE;
        try {
            DLOG(INFO) << "Attempting to parse a websocket header.";
            if (input.find("\r\n\r\n") == std::string::npos)
                return ret;

            std::map<std::string, std::string> headers;
            std::string line;
            std::string remainder = input;
            std::string::size_type end = remainder.find("\r\n");
            while (end != std::string::npos) {
                line = remainder.substr(0, end);
                remainder = remainder.substr(end + 2);

                std::string::size_type pos = line.find(": ");
                if (pos != std::string::npos) {
                    std::string key = line.substr(0, pos);
                    for (size_t i = 0; i < key.length(); ++i) {
                        key[i] = tolower(key[i]);
                    }
                    headers[key] = line.substr(pos + 2);
                }

                end = remainder.find("\r\n");
            }

            std::string outbuffer;

            // Copy the forwarded for ip into our output if it exists.
            // Caller checks for proper remote address before trusting this.
            if (headers.count("x-real-ip") != 0) {
                ip = headers["x-real-ip"];
            }
            if (headers.count("sec-websocket-version") != 0 && headers.count("sec-websocket-key") != 0) {
                DLOG(INFO) << "Found a Hybi websocket header.";
                if (Hybi::accept(headers["sec-websocket-key"], headers["sec-websocket-origin"], outbuffer) != WS_RESULT_OK) {
                    ret = PROTOCOL_BAD;
                } else {
                    ret = PROTOCOL_HYBI;
                }
            } else {
                ret = PROTOCOL_BAD;
            }
            output = outbuffer;
        } catch (std::exception e) {
            LOG(WARNING) << "Exception occurred in websocket accept. e.what: " << e.what();
            ret = PROTOCOL_BAD;
        } catch (...) {
            LOG(WARNING) << "Unexpected exception occured in websocket accept.";
            ret = PROTOCOL_BAD;
        }
        return ret;
    }

    static const unsigned int wsHeaderSize = 2;
    static const unsigned int wsMaskingKeySize = 4;
    static const unsigned int wsOpcodeMask = 0x0F;
    static const unsigned int wsMaskedMask = 0x80;
    static const unsigned int wsLengthMask = 0x7F;
    static const unsigned int wsSingleByteLength = 125;
    static const unsigned int wsTwoByteLength = 126;
    static const unsigned int wsEightByteLength = 127;
    static const unsigned int wsOpcodeText = 0x01;
    static const unsigned int wsOpcodeClose = 0x08;
    static const unsigned int wsMaximumClientFrameSize = 0x80000; //512kB should be sufficient for any client->server message.
    static const char* const wsMagicalGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

    WebSocketResult Hybi::accept(string& key, string& origin, string& output) {
        if (key.empty())
            return WS_RESULT_ERROR;

        //		if(origin.find("f-list.net") == string::npos)
        //		{
        //			return WS_RESULT_ERROR;
        //		}

        char buf[4096];
        bzero(&buf[0], sizeof (buf));
        int len = snprintf(&buf[0], sizeof (buf), "%s%s", key.c_str(), wsMagicalGUID);
        string keystr(&buf[0], len);
        bzero(&buf[0], sizeof (buf));
        string encodedkey;
        string hashkey = thirdparty::SHA1HashString(keystr);
        thirdparty::Base64Encode(hashkey, encodedkey);
        len = snprintf(&buf[0], sizeof (buf),
                "HTTP/1.1 101 Switching Protocols\r\n"
                "Upgrade: websocket\r\n"
                "Connection: Upgrade\r\n"
                "Sec-WebSocket-Accept: %s\r\n\r\n", encodedkey.c_str());
        string tmp(&buf[0], len);
        output.swap(tmp);
        return WS_RESULT_OK;
    }

    WebSocketResult Hybi::receive(std::string& input, std::string& output) {
        unsigned long rlen = input.length();
        if (rlen < wsHeaderSize)
            return WS_RESULT_INCOMPLETE;

        const char* msg = input.c_str();
        unsigned char b1 = *msg++;
        unsigned char b2 = *msg++;

        unsigned int opcode = b1 & wsOpcodeMask;
        bool masked = b2 & wsMaskedMask;
        unsigned int lengthhint = b2 & wsLengthMask;

        // Standard defines that all client to server communication must be masked.
        if (!masked)
            return WS_RESULT_ERROR;

        switch (opcode) {
                // Text
            case wsOpcodeText:
                break;
                // Close
            case wsOpcodeClose:
                return WS_RESULT_CLOSE;
            default:
                return WS_RESULT_ERROR;
        }

        uint64_t payload_length = 0;
        int lengthsize = 0;
        if (lengthhint > wsSingleByteLength) {
            lengthsize = 2;
            if (lengthhint == wsEightByteLength)
                lengthsize = 8;

            if (rlen < wsHeaderSize + lengthsize)
                return WS_RESULT_INCOMPLETE;

            for (int i = 0; i < lengthsize; ++i) {
                payload_length <<= 8;
                payload_length |= static_cast<unsigned char> (*msg++);
            }
        } else {
            payload_length = lengthhint;
        }

        if (payload_length > wsMaximumClientFrameSize)
            return WS_RESULT_ERROR;

        uint64_t totallen = (masked ? wsMaskingKeySize : 0) + payload_length;
        if (rlen < (wsHeaderSize + lengthsize + totallen))
            return WS_RESULT_INCOMPLETE;

        if (masked) {
            output.resize(payload_length);
            const char* mask = msg;
            msg += wsMaskingKeySize;
            for (unsigned int i = 0; i < payload_length; ++i) {
                output[i] = msg[i] ^ mask[i % wsMaskingKeySize];
            }
        } else {
            string tmp(msg, payload_length);
            output.swap(tmp);
        }

        input = input.substr(wsHeaderSize + lengthsize + totallen);

        return WS_RESULT_OK;
    }

    void Hybi::send(string& input, string& output) {
        std::vector<unsigned char> frame;
        unsigned int length = input.length();

        frame.push_back(0x80 | wsOpcodeText);

        if (length <= wsSingleByteLength) {
            frame.push_back(static_cast<unsigned char> (length));
        } else if (length <= 0xFFFF) {
            frame.push_back(wsTwoByteLength);
            frame.push_back((length & 0xFF00) >> 8);
            frame.push_back(length & 0xFF);
        } else {
            uint64_t qlength = length;
            frame.push_back(wsEightByteLength);
            for (size_t i = 0; i < 8; ++i) {
                unsigned char length_piece = (qlength >> 8*(7-i)) & 0xFF;
                frame.push_back(length_piece);
            }
        }
        frame.insert(frame.end(), input.data(), input.data() + length);
        string tmp(frame.begin(), frame.end());
        output.swap(tmp);
    }
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2016] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_UTIL_TO_STRING_HPP
#define REALM_UTIL_TO_STRING_HPP

#include <locale>
#include <string>
#include <sstream>

namespace realm {
namespace util {

template<class T> std::string to_string(const T& v)
{
    std::ostringstream out;
    out.imbue(std::locale::classic());
    out.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    out << v; // Throws
    return out.str();
}

} // namespace util
} // namespace realm

#endif // REALM_UTIL_TO_STRING_HPP
<commit_msg>Update template placement<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2016] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_UTIL_TO_STRING_HPP
#define REALM_UTIL_TO_STRING_HPP

#include <locale>
#include <string>
#include <sstream>

namespace realm {
namespace util {

template<class T>
std::string to_string(const T& v)
{
    std::ostringstream out;
    out.imbue(std::locale::classic());
    out.exceptions(std::ios_base::failbit | std::ios_base::badbit);
    out << v; // Throws
    return out.str();
}

} // namespace util
} // namespace realm

#endif // REALM_UTIL_TO_STRING_HPP
<|endoftext|>