<commit_before>// KMail Account
#include <config.h>

#include "kmaccount.h"

#include "accountmanager.h"
using KMail::AccountManager;
#include "kmacctfolder.h"
#include "kmfoldermgr.h"
#include "kmfiltermgr.h"
#include "messagesender.h"
#include "kmmessage.h"
#include "broadcaststatus.h"
using KPIM::BroadcastStatus;
#include "kmfoldercachedimap.h"

#include "progressmanager.h"
using KPIM::ProgressItem;
using KPIM::ProgressManager;

using KMail::FolderJob;

#include <kapplication.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kconfig.h>

#include <qeventloop.h>

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#include <assert.h>

//----------------------
#include "kmaccount.moc"

//-----------------------------------------------------------------------------
KMPrecommand::KMPrecommand(const QString &precommand, QObject *parent)
  : QObject(parent), mPrecommand(precommand)
{
  BroadcastStatus::instance()->setStatusMsg(
      i18n("Executing precommand %1").arg(precommand ));

  mPrecommandProcess.setUseShell(true);
  mPrecommandProcess << precommand;

  connect(&mPrecommandProcess, SIGNAL(processExited(KProcess *)),
          SLOT(precommandExited(KProcess *)));
}

//-----------------------------------------------------------------------------
KMPrecommand::~KMPrecommand()
{
}

//-----------------------------------------------------------------------------
bool KMPrecommand::start()
{
  bool ok = mPrecommandProcess.start( KProcess::NotifyOnExit );
  if (!ok) KMessageBox::error(0, i18n("Could not execute precommand '%1'.")
    .arg(mPrecommand));
  return ok;
}

//-----------------------------------------------------------------------------
void KMPrecommand::precommandExited(KProcess *p)
{
  int exitCode = p->normalExit() ? p->exitStatus() : -1;
  if (exitCode)
    KMessageBox::error(0, i18n("The precommand exited with code %1:\n%2")
      .arg(exitCode).arg(strerror(exitCode)));
  emit finished(!exitCode);
}

//-----------------------------------------------------------------------------
KMAccount::KMAccount(AccountManager* aOwner, const QString& aName, uint id)
  : KAccount( id, aName ),
    mTrash(KMKernel::self()->trashFolder()->idString()),
    mOwner(aOwner),
    mFolder(0),
    mTimer(0),
    mInterval(0),
    mExclude(false),
    mCheckingMail(false),
    mPrecommandSuccess(true),
    mHasInbox(false),
    mMailCheckProgressItem(0)
{
  assert(aOwner != 0);
}

void KMAccount::init() {
  mTrash = kmkernel->trashFolder()->idString();
  mExclude = false;
  mInterval = 0;
  mNewInFolder.clear();
}

//-----------------------------------------------------------------------------
KMAccount::~KMAccount()
{
  if (!kmkernel->shuttingDown() && mFolder) mFolder->removeAccount(this);
  if (mTimer) deinstallTimer();
}

//-----------------------------------------------------------------------------
void KMAccount::setName(const QString& aName)
{
  mName = aName;
}

//-----------------------------------------------------------------------------
void KMAccount::clearPasswd()
{
}

//-----------------------------------------------------------------------------
void KMAccount::setFolder(KMFolder* aFolder, bool addAccount)
{
  if(!aFolder) {
    //kdDebug(5006) << "KMAccount::setFolder() : aFolder == 0" << endl;
    mFolder = 0;
    return;
  }
  mFolder = (KMAcctFolder*)aFolder;
  if (addAccount) mFolder->addAccount(this);
}

//-----------------------------------------------------------------------------
void KMAccount::readConfig(KConfig& config)
{
  QString folderName;
  mFolder = 0;
  folderName = config.readEntry("Folder");
  setCheckInterval(config.readNumEntry("check-interval", 0));
  setTrash(config.readEntry("trash", kmkernel->trashFolder()->idString()));
  setCheckExclude(config.readBoolEntry("check-exclude", false));
  setPrecommand(config.readPathEntry("precommand"));

  if (!folderName.isEmpty())
  {
    setFolder(kmkernel->folderMgr()->findIdString(folderName), true);
  }

  if (mInterval == 0)
    deinstallTimer();
  else
    installTimer();
}

//-----------------------------------------------------------------------------
void KMAccount::writeConfig(KConfig& config)
{
  // ID, Name
  KAccount::writeConfig(config);

  config.writeEntry("Type", type());
  config.writeEntry("Folder", mFolder ? mFolder->idString() : QString::null);
  config.writeEntry("check-interval", mInterval);
  config.writeEntry("check-exclude", mExclude);
  config.writePathEntry("precommand", mPrecommand);
  config.writeEntry("trash", mTrash);
}

//-----------------------------------------------------------------------------
void KMAccount::sendReceipt(KMMessage* aMsg)
{
  KConfig* cfg = KMKernel::config();
  bool sendReceipts;

  KConfigGroupSaver saver(cfg, "General");

  sendReceipts = cfg->readBoolEntry("send-receipts", false);
  if (!sendReceipts) return;

  KMMessage *newMsg = aMsg->createDeliveryReceipt();
  if (newMsg) {
    mReceipts.append(newMsg);
    QTimer::singleShot( 0, this, SLOT( sendReceipts() ) );
  }
}

//-----------------------------------------------------------------------------
bool KMAccount::processNewMsg(KMMessage* aMsg)
{
  int rc, processResult;

  assert(aMsg != 0);

  // Save this one for readding
  KMFolderCachedImap* parent = 0;
  if( type() == "cachedimap" )
    parent = static_cast<KMFolderCachedImap*>( aMsg->storage() );

  // checks whether we should send delivery receipts
  // and sends them.
  sendReceipt(aMsg);

  // Set status of new messages that are marked as old to read, otherwise
  // the user won't see which messages newly arrived.
  // This is only valid for pop accounts and produces wrong stati for imap.
  if ( type() != "cachedimap" && type() != "imap" ) {
    if ( aMsg->isOld() )
      aMsg->setStatus(KMMsgStatusUnread);  // -sanders
    //    aMsg->setStatus(KMMsgStatusRead);
    else
      aMsg->setStatus(KMMsgStatusNew);
  }
/*
QFile fileD0( "testdat_xx-kmaccount-0" );
if( fileD0.open( IO_WriteOnly ) ) {
    QDataStream ds( &fileD0 );
    ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
    fileD0.close();  // If data is 0 we just create a zero length file.
}
*/
  // 0==message moved; 1==processing ok, no move; 2==critical error, abort!

  processResult = kmkernel->filterMgr()->process(aMsg,KMFilterMgr::Inbound,true,id());
  if (processResult == 2) {
    perror("Critical error: Unable to collect mail (out of space?)");
    KMessageBox::information(0,(i18n("Critical error: "
      "Unable to collect mail: ")) + QString::fromLocal8Bit(strerror(errno)));
    return false;
  }
  else if (processResult == 1)
  {
    if( type() == "cachedimap" )
      ; // already done by caller: parent->addMsgInternal( aMsg, false );
    else {
      // TODO: Perhaps it would be best, if this if was handled by a virtual
      // method, so the if( !dimap ) above could die?
      kmkernel->filterMgr()->tempOpenFolder(mFolder);
      rc = mFolder->addMsg(aMsg);
/*
QFile fileD0( "testdat_xx-kmaccount-1" );
if( fileD0.open( IO_WriteOnly ) ) {
    QDataStream ds( &fileD0 );
    ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
    fileD0.close();  // If data is 0 we just create a zero length file.
}
*/
      if (rc) {
        perror("failed to add message");
        KMessageBox::information(0, i18n("Failed to add message:\n") +
                                 QString(strerror(rc)));
        return false;
      }
      int count = mFolder->count();
      // If count == 1, the message is immediately displayed
      if (count != 1) mFolder->unGetMsg(count - 1);
    }
  }

  // Count number of new messages for each folder
  QString folderId;
  if ( processResult == 1 ) {
    folderId = ( type() == "cachedimap" ) ? parent->folder()->idString()
                                          : mFolder->idString();
  }
  else {
    folderId = aMsg->parent()->idString();
  }
  addToNewInFolder( folderId, 1 );

  return true; //Everything's fine - message has been added by filter  }
}

//-----------------------------------------------------------------------------
void KMAccount::setCheckInterval(int aInterval)
{
  if (aInterval <= 0)
    mInterval = 0;
  else
    mInterval = aInterval;
  // Don't call installTimer from here! See #117935.
}

//----------------------------------------------------------------------------
void KMAccount::deleteFolderJobs()
{
  mJobList.setAutoDelete(true);
  mJobList.clear();
  mJobList.setAutoDelete(false);
}

//----------------------------------------------------------------------------
void KMAccount::ignoreJobsForMessage( KMMessage* msg )
{
  //FIXME: remove, make folders handle those
  for( QPtrListIterator<FolderJob> it(mJobList); it.current(); ++it ) {
    if ( it.current()->msgList().first() == msg) {
      FolderJob *job = it.current();
      mJobList.remove( job );
      delete job;
      break;
    }
  }
}

//-----------------------------------------------------------------------------
void KMAccount::setCheckExclude(bool aExclude)
{
  mExclude = aExclude;
}

//-----------------------------------------------------------------------------
void KMAccount::installTimer()
{
  if (mInterval <= 0) return;
  if(!mTimer)
  {
    mTimer = new QTimer();
    connect(mTimer,SIGNAL(timeout()),SLOT(mailCheck()));
  }
  else
  {
    mTimer->stop();
  }
  mTimer->start(mInterval*60000);
}

//-----------------------------------------------------------------------------
void KMAccount::deinstallTimer()
{
  delete mTimer;
  mTimer = 0;
}

//-----------------------------------------------------------------------------
bool KMAccount::runPrecommand(const QString &precommand)
{
  // Run the pre command if there is one
  if ( precommand.isEmpty() )
    return true;

  KMPrecommand precommandProcess(precommand, this);

  BroadcastStatus::instance()->setStatusMsg(
      i18n("Executing precommand %1").arg(precommand ));

  connect(&precommandProcess, SIGNAL(finished(bool)),
          SLOT(precommandExited(bool)));

  kdDebug(5006) << "Running precommand " << precommand << endl;
  if (!precommandProcess.start()) return false;

  kapp->eventLoop()->enterLoop();

  return mPrecommandSuccess;
}

//-----------------------------------------------------------------------------
void KMAccount::precommandExited(bool success)
{
  mPrecommandSuccess = success;
  kapp->eventLoop()->exitLoop();
}

//-----------------------------------------------------------------------------
void KMAccount::mailCheck()
{
  if (mTimer)
    mTimer->stop();

  if ( kmkernel ) {
    AccountManager *acctmgr = kmkernel->acctMgr();
    if ( acctmgr )
      acctmgr->singleCheckMail(this, false);
  }
}

//-----------------------------------------------------------------------------
void KMAccount::sendReceipts()
{
  QValueList<KMMessage*>::Iterator it;
  for(it = mReceipts.begin(); it != mReceipts.end(); ++it)
    kmkernel->msgSender()->send(*it); //might process events
  mReceipts.clear();
}

//-----------------------------------------------------------------------------
QString KMAccount::encryptStr(const QString &aStr)
{
  QString result;
  for (uint i = 0; i < aStr.length(); i++)
    result += (aStr[i].unicode() < 0x20) ? aStr[i] :
      QChar(0x1001F - aStr[i].unicode());
  return result;
}

//-----------------------------------------------------------------------------
QString KMAccount::importPassword(const QString &aStr)
{
  unsigned int i, val;
  unsigned int len = aStr.length();
  QCString result;
  result.resize(len+1);

  for (i=0; i<len; i++)
  {
    val = aStr[i] - ' ';
    val = (255-' ') - val;
    result[i] = (char)(val + ' ');
  }
  result[i] = '\0';

  return encryptStr(result);
}

void KMAccount::invalidateIMAPFolders()
{
  // Default: Don't do anything. The IMAP account will handle it
}

void KMAccount::pseudoAssign( const KMAccount * a ) {
  if ( !a ) return;

  setName( a->name() );
  setId( a->id() );
  setCheckInterval( a->checkInterval() );
  setCheckExclude( a->checkExclude() );
  setFolder( a->folder() );
  setPrecommand( a->precommand() );
  setTrash( a->trash() );
}

//-----------------------------------------------------------------------------
void KMAccount::checkDone( bool newmail, CheckStatus status )
{
    setCheckingMail( false );
  // Reset the timeout for automatic mailchecking. The user might have
  // triggered the check manually.
  if (mTimer)
    mTimer->start(mInterval*60000);
  if ( mMailCheckProgressItem ) {
    // set mMailCheckProgressItem = 0 before calling setComplete() to prevent
    // a race condition
    ProgressItem *savedMailCheckProgressItem = mMailCheckProgressItem;
    mMailCheckProgressItem = 0;
    savedMailCheckProgressItem->setComplete(); // that will delete it
  }

  emit newMailsProcessed( mNewInFolder );
  emit finishedCheck( newmail, status );
  mNewInFolder.clear();
}

//-----------------------------------------------------------------------------
void KMAccount::addToNewInFolder( QString folderId, int num )
{
  if ( mNewInFolder.find( folderId ) == mNewInFolder.end() )
    mNewInFolder[folderId] = num;
  else
    mNewInFolder[folderId] += num;
}
<commit_msg>somehow the fix was forgotten - patch by dirk:    with the recent utf8 decoder fix in Qt (CVE-2007-0242), kmail     fails to restore passwords with '!' correctly from kconfig. <commit_after>// KMail Account
#include <config.h>

#include "kmaccount.h"

#include "accountmanager.h"
using KMail::AccountManager;
#include "kmacctfolder.h"
#include "kmfoldermgr.h"
#include "kmfiltermgr.h"
#include "messagesender.h"
#include "kmmessage.h"
#include "broadcaststatus.h"
using KPIM::BroadcastStatus;
#include "kmfoldercachedimap.h"

#include "progressmanager.h"
using KPIM::ProgressItem;
using KPIM::ProgressManager;

using KMail::FolderJob;

#include <kapplication.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <kconfig.h>

#include <qeventloop.h>

#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

#include <assert.h>

//----------------------
#include "kmaccount.moc"

//-----------------------------------------------------------------------------
KMPrecommand::KMPrecommand(const QString &precommand, QObject *parent)
  : QObject(parent), mPrecommand(precommand)
{
  BroadcastStatus::instance()->setStatusMsg(
      i18n("Executing precommand %1").arg(precommand ));

  mPrecommandProcess.setUseShell(true);
  mPrecommandProcess << precommand;

  connect(&mPrecommandProcess, SIGNAL(processExited(KProcess *)),
          SLOT(precommandExited(KProcess *)));
}

//-----------------------------------------------------------------------------
KMPrecommand::~KMPrecommand()
{
}

//-----------------------------------------------------------------------------
bool KMPrecommand::start()
{
  bool ok = mPrecommandProcess.start( KProcess::NotifyOnExit );
  if (!ok) KMessageBox::error(0, i18n("Could not execute precommand '%1'.")
    .arg(mPrecommand));
  return ok;
}

//-----------------------------------------------------------------------------
void KMPrecommand::precommandExited(KProcess *p)
{
  int exitCode = p->normalExit() ? p->exitStatus() : -1;
  if (exitCode)
    KMessageBox::error(0, i18n("The precommand exited with code %1:\n%2")
      .arg(exitCode).arg(strerror(exitCode)));
  emit finished(!exitCode);
}

//-----------------------------------------------------------------------------
KMAccount::KMAccount(AccountManager* aOwner, const QString& aName, uint id)
  : KAccount( id, aName ),
    mTrash(KMKernel::self()->trashFolder()->idString()),
    mOwner(aOwner),
    mFolder(0),
    mTimer(0),
    mInterval(0),
    mExclude(false),
    mCheckingMail(false),
    mPrecommandSuccess(true),
    mHasInbox(false),
    mMailCheckProgressItem(0)
{
  assert(aOwner != 0);
}

void KMAccount::init() {
  mTrash = kmkernel->trashFolder()->idString();
  mExclude = false;
  mInterval = 0;
  mNewInFolder.clear();
}

//-----------------------------------------------------------------------------
KMAccount::~KMAccount()
{
  if (!kmkernel->shuttingDown() && mFolder) mFolder->removeAccount(this);
  if (mTimer) deinstallTimer();
}

//-----------------------------------------------------------------------------
void KMAccount::setName(const QString& aName)
{
  mName = aName;
}

//-----------------------------------------------------------------------------
void KMAccount::clearPasswd()
{
}

//-----------------------------------------------------------------------------
void KMAccount::setFolder(KMFolder* aFolder, bool addAccount)
{
  if(!aFolder) {
    //kdDebug(5006) << "KMAccount::setFolder() : aFolder == 0" << endl;
    mFolder = 0;
    return;
  }
  mFolder = (KMAcctFolder*)aFolder;
  if (addAccount) mFolder->addAccount(this);
}

//-----------------------------------------------------------------------------
void KMAccount::readConfig(KConfig& config)
{
  QString folderName;
  mFolder = 0;
  folderName = config.readEntry("Folder");
  setCheckInterval(config.readNumEntry("check-interval", 0));
  setTrash(config.readEntry("trash", kmkernel->trashFolder()->idString()));
  setCheckExclude(config.readBoolEntry("check-exclude", false));
  setPrecommand(config.readPathEntry("precommand"));

  if (!folderName.isEmpty())
  {
    setFolder(kmkernel->folderMgr()->findIdString(folderName), true);
  }

  if (mInterval == 0)
    deinstallTimer();
  else
    installTimer();
}

//-----------------------------------------------------------------------------
void KMAccount::writeConfig(KConfig& config)
{
  // ID, Name
  KAccount::writeConfig(config);

  config.writeEntry("Type", type());
  config.writeEntry("Folder", mFolder ? mFolder->idString() : QString::null);
  config.writeEntry("check-interval", mInterval);
  config.writeEntry("check-exclude", mExclude);
  config.writePathEntry("precommand", mPrecommand);
  config.writeEntry("trash", mTrash);
}

//-----------------------------------------------------------------------------
void KMAccount::sendReceipt(KMMessage* aMsg)
{
  KConfig* cfg = KMKernel::config();
  bool sendReceipts;

  KConfigGroupSaver saver(cfg, "General");

  sendReceipts = cfg->readBoolEntry("send-receipts", false);
  if (!sendReceipts) return;

  KMMessage *newMsg = aMsg->createDeliveryReceipt();
  if (newMsg) {
    mReceipts.append(newMsg);
    QTimer::singleShot( 0, this, SLOT( sendReceipts() ) );
  }
}

//-----------------------------------------------------------------------------
bool KMAccount::processNewMsg(KMMessage* aMsg)
{
  int rc, processResult;

  assert(aMsg != 0);

  // Save this one for readding
  KMFolderCachedImap* parent = 0;
  if( type() == "cachedimap" )
    parent = static_cast<KMFolderCachedImap*>( aMsg->storage() );

  // checks whether we should send delivery receipts
  // and sends them.
  sendReceipt(aMsg);

  // Set status of new messages that are marked as old to read, otherwise
  // the user won't see which messages newly arrived.
  // This is only valid for pop accounts and produces wrong stati for imap.
  if ( type() != "cachedimap" && type() != "imap" ) {
    if ( aMsg->isOld() )
      aMsg->setStatus(KMMsgStatusUnread);  // -sanders
    //    aMsg->setStatus(KMMsgStatusRead);
    else
      aMsg->setStatus(KMMsgStatusNew);
  }
/*
QFile fileD0( "testdat_xx-kmaccount-0" );
if( fileD0.open( IO_WriteOnly ) ) {
    QDataStream ds( &fileD0 );
    ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
    fileD0.close();  // If data is 0 we just create a zero length file.
}
*/
  // 0==message moved; 1==processing ok, no move; 2==critical error, abort!

  processResult = kmkernel->filterMgr()->process(aMsg,KMFilterMgr::Inbound,true,id());
  if (processResult == 2) {
    perror("Critical error: Unable to collect mail (out of space?)");
    KMessageBox::information(0,(i18n("Critical error: "
      "Unable to collect mail: ")) + QString::fromLocal8Bit(strerror(errno)));
    return false;
  }
  else if (processResult == 1)
  {
    if( type() == "cachedimap" )
      ; // already done by caller: parent->addMsgInternal( aMsg, false );
    else {
      // TODO: Perhaps it would be best, if this if was handled by a virtual
      // method, so the if( !dimap ) above could die?
      kmkernel->filterMgr()->tempOpenFolder(mFolder);
      rc = mFolder->addMsg(aMsg);
/*
QFile fileD0( "testdat_xx-kmaccount-1" );
if( fileD0.open( IO_WriteOnly ) ) {
    QDataStream ds( &fileD0 );
    ds.writeRawBytes( aMsg->asString(), aMsg->asString().length() );
    fileD0.close();  // If data is 0 we just create a zero length file.
}
*/
      if (rc) {
        perror("failed to add message");
        KMessageBox::information(0, i18n("Failed to add message:\n") +
                                 QString(strerror(rc)));
        return false;
      }
      int count = mFolder->count();
      // If count == 1, the message is immediately displayed
      if (count != 1) mFolder->unGetMsg(count - 1);
    }
  }

  // Count number of new messages for each folder
  QString folderId;
  if ( processResult == 1 ) {
    folderId = ( type() == "cachedimap" ) ? parent->folder()->idString()
                                          : mFolder->idString();
  }
  else {
    folderId = aMsg->parent()->idString();
  }
  addToNewInFolder( folderId, 1 );

  return true; //Everything's fine - message has been added by filter  }
}

//-----------------------------------------------------------------------------
void KMAccount::setCheckInterval(int aInterval)
{
  if (aInterval <= 0)
    mInterval = 0;
  else
    mInterval = aInterval;
  // Don't call installTimer from here! See #117935.
}

//----------------------------------------------------------------------------
void KMAccount::deleteFolderJobs()
{
  mJobList.setAutoDelete(true);
  mJobList.clear();
  mJobList.setAutoDelete(false);
}

//----------------------------------------------------------------------------
void KMAccount::ignoreJobsForMessage( KMMessage* msg )
{
  //FIXME: remove, make folders handle those
  for( QPtrListIterator<FolderJob> it(mJobList); it.current(); ++it ) {
    if ( it.current()->msgList().first() == msg) {
      FolderJob *job = it.current();
      mJobList.remove( job );
      delete job;
      break;
    }
  }
}

//-----------------------------------------------------------------------------
void KMAccount::setCheckExclude(bool aExclude)
{
  mExclude = aExclude;
}

//-----------------------------------------------------------------------------
void KMAccount::installTimer()
{
  if (mInterval <= 0) return;
  if(!mTimer)
  {
    mTimer = new QTimer();
    connect(mTimer,SIGNAL(timeout()),SLOT(mailCheck()));
  }
  else
  {
    mTimer->stop();
  }
  mTimer->start(mInterval*60000);
}

//-----------------------------------------------------------------------------
void KMAccount::deinstallTimer()
{
  delete mTimer;
  mTimer = 0;
}

//-----------------------------------------------------------------------------
bool KMAccount::runPrecommand(const QString &precommand)
{
  // Run the pre command if there is one
  if ( precommand.isEmpty() )
    return true;

  KMPrecommand precommandProcess(precommand, this);

  BroadcastStatus::instance()->setStatusMsg(
      i18n("Executing precommand %1").arg(precommand ));

  connect(&precommandProcess, SIGNAL(finished(bool)),
          SLOT(precommandExited(bool)));

  kdDebug(5006) << "Running precommand " << precommand << endl;
  if (!precommandProcess.start()) return false;

  kapp->eventLoop()->enterLoop();

  return mPrecommandSuccess;
}

//-----------------------------------------------------------------------------
void KMAccount::precommandExited(bool success)
{
  mPrecommandSuccess = success;
  kapp->eventLoop()->exitLoop();
}

//-----------------------------------------------------------------------------
void KMAccount::mailCheck()
{
  if (mTimer)
    mTimer->stop();

  if ( kmkernel ) {
    AccountManager *acctmgr = kmkernel->acctMgr();
    if ( acctmgr )
      acctmgr->singleCheckMail(this, false);
  }
}

//-----------------------------------------------------------------------------
void KMAccount::sendReceipts()
{
  QValueList<KMMessage*>::Iterator it;
  for(it = mReceipts.begin(); it != mReceipts.end(); ++it)
    kmkernel->msgSender()->send(*it); //might process events
  mReceipts.clear();
}

//-----------------------------------------------------------------------------
QString KMAccount::encryptStr(const QString &aStr)
{
  QString result;
  for (uint i = 0; i < aStr.length(); i++)
    /* yes, no typo. can't encode ' ' or '!' because
       they're the unicode BOM. stupid scrambling. stupid. */
    result += (aStr[i].unicode() <= 0x21 ) ? aStr[i] :
      QChar(0x1001F - aStr[i].unicode());
  return result;
}

//-----------------------------------------------------------------------------
QString KMAccount::importPassword(const QString &aStr)
{
  unsigned int i, val;
  unsigned int len = aStr.length();
  QCString result;
  result.resize(len+1);

  for (i=0; i<len; i++)
  {
    val = aStr[i] - ' ';
    val = (255-' ') - val;
    result[i] = (char)(val + ' ');
  }
  result[i] = '\0';

  return encryptStr(result);
}

void KMAccount::invalidateIMAPFolders()
{
  // Default: Don't do anything. The IMAP account will handle it
}

void KMAccount::pseudoAssign( const KMAccount * a ) {
  if ( !a ) return;

  setName( a->name() );
  setId( a->id() );
  setCheckInterval( a->checkInterval() );
  setCheckExclude( a->checkExclude() );
  setFolder( a->folder() );
  setPrecommand( a->precommand() );
  setTrash( a->trash() );
}

//-----------------------------------------------------------------------------
void KMAccount::checkDone( bool newmail, CheckStatus status )
{
    setCheckingMail( false );
  // Reset the timeout for automatic mailchecking. The user might have
  // triggered the check manually.
  if (mTimer)
    mTimer->start(mInterval*60000);
  if ( mMailCheckProgressItem ) {
    // set mMailCheckProgressItem = 0 before calling setComplete() to prevent
    // a race condition
    ProgressItem *savedMailCheckProgressItem = mMailCheckProgressItem;
    mMailCheckProgressItem = 0;
    savedMailCheckProgressItem->setComplete(); // that will delete it
  }

  emit newMailsProcessed( mNewInFolder );
  emit finishedCheck( newmail, status );
  mNewInFolder.clear();
}

//-----------------------------------------------------------------------------
void KMAccount::addToNewInFolder( QString folderId, int num )
{
  if ( mNewInFolder.find( folderId ) == mNewInFolder.end() )
    mNewInFolder[folderId] = num;
  else
    mNewInFolder[folderId] += num;
}
<|endoftext|>


<commit_before>#ifndef KEYTOKEY_HPP
#define KEYTOKEY_HPP

#include "FromEvent.hpp"
#include "RemapFuncBase.hpp"
#include "ToEvent.hpp"
#include "bridge.h"

namespace org_pqrs_Karabiner {
  namespace RemapFunc {
    class KeyToKey : RemapFuncBase {
    public:
      KeyToKey(void) :
        RemapFuncBase(BRIDGE_REMAPTYPE_KEYTOKEY),
        index_(0),
        currentToEvent_(CurrentToEvent::TOKEYS),
        keyboardRepeatID_(-1),
        isRepeatEnabled_(true),
        delayUntilRepeat_(-1),
        keyRepeat_(-1)
      {}

      bool remap(RemapParams& remapParams);

      // ----------------------------------------
      // [0] => fromEvent_
      // [1] => toKeys_[0]
      // [2] => toKeys_[1]
      // [3] => ...
      void add(AddDataType datatype, AddValue newval);

      // ----------------------------------------
      // utility functions
      void add(KeyCode newval) { add(AddDataType(BRIDGE_DATATYPE_KEYCODE), AddValue(newval.get())); }
      void add(Option newval)  { add(AddDataType(BRIDGE_DATATYPE_OPTION),  AddValue(newval.get())); }

      bool call_remap_with_VK_PSEUDO_KEY(EventType eventType);

      size_t toKeysSize(void) const { return toKeys_.size(); }
      void clearToKeys(void);

    private:
      int getDelayUntilRepeat(void);
      int getKeyRepeat(void);

      class CurrentToEvent {
      public:
        enum Value {
          TOKEYS,
          BEFOREKEYS,
          AFTERKEYS,
        };
      };

      Vector_ToEvent& getCurrentToEvent(void) {
        switch (currentToEvent_) {
          case CurrentToEvent::TOKEYS:     return toKeys_;
          case CurrentToEvent::BEFOREKEYS: return beforeKeys_;
          case CurrentToEvent::AFTERKEYS:  return afterKeys_;
        }
      }

      size_t index_;

      FromEvent fromEvent_;
      Vector_ModifierFlag fromModifierFlags_;
      Vector_ModifierFlag pureFromModifierFlags_; // fromModifierFlags_ - fromEvent_.getModifierFlag()

      Vector_ToEvent toKeys_;
      Vector_ToEvent beforeKeys_;
      Vector_ToEvent afterKeys_;
      CurrentToEvent::Value currentToEvent_;

      int keyboardRepeatID_;
      bool isRepeatEnabled_;

      int delayUntilRepeat_;
      int keyRepeat_;
    };
    DECLARE_VECTOR(KeyToKey);
  }
}

#endif
<commit_msg>update #include<commit_after>#ifndef KEYTOKEY_HPP
#define KEYTOKEY_HPP

#include "RemapFuncBase.hpp"

namespace org_pqrs_Karabiner {
  namespace RemapFunc {
    class KeyToKey : RemapFuncBase {
    public:
      KeyToKey(void) :
        RemapFuncBase(BRIDGE_REMAPTYPE_KEYTOKEY),
        index_(0),
        currentToEvent_(CurrentToEvent::TOKEYS),
        keyboardRepeatID_(-1),
        isRepeatEnabled_(true),
        delayUntilRepeat_(-1),
        keyRepeat_(-1)
      {}

      bool remap(RemapParams& remapParams);

      // ----------------------------------------
      // [0] => fromEvent_
      // [1] => toKeys_[0]
      // [2] => toKeys_[1]
      // [3] => ...
      void add(AddDataType datatype, AddValue newval);

      // ----------------------------------------
      // utility functions
      void add(KeyCode newval) { add(AddDataType(BRIDGE_DATATYPE_KEYCODE), AddValue(newval.get())); }
      void add(Option newval)  { add(AddDataType(BRIDGE_DATATYPE_OPTION),  AddValue(newval.get())); }

      bool call_remap_with_VK_PSEUDO_KEY(EventType eventType);

      size_t toKeysSize(void) const { return toKeys_.size(); }
      void clearToKeys(void);

    private:
      int getDelayUntilRepeat(void);
      int getKeyRepeat(void);

      class CurrentToEvent {
      public:
        enum Value {
          TOKEYS,
          BEFOREKEYS,
          AFTERKEYS,
        };
      };

      Vector_ToEvent& getCurrentToEvent(void) {
        switch (currentToEvent_) {
          case CurrentToEvent::TOKEYS:     return toKeys_;
          case CurrentToEvent::BEFOREKEYS: return beforeKeys_;
          case CurrentToEvent::AFTERKEYS:  return afterKeys_;
        }
      }

      size_t index_;

      FromEvent fromEvent_;
      Vector_ModifierFlag fromModifierFlags_;
      Vector_ModifierFlag pureFromModifierFlags_; // fromModifierFlags_ - fromEvent_.getModifierFlag()

      Vector_ToEvent toKeys_;
      Vector_ToEvent beforeKeys_;
      Vector_ToEvent afterKeys_;
      CurrentToEvent::Value currentToEvent_;

      int keyboardRepeatID_;
      bool isRepeatEnabled_;

      int delayUntilRepeat_;
      int keyRepeat_;
    };
    DECLARE_VECTOR(KeyToKey);
  }
}

#endif
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * Description:
 *     helper functions in replica object
 *
 * Revision history:
 *     Mar., 2015, @imzhenyu (Zhenyu Guo), first version
 *     xxxx-xx-xx, author, fix bug about xxx
 */

#include "replica.h"
#include "mutation.h"
#include "mutation_log.h"
#include "replica_stub.h"
#include <dsn/cpp/json_helper.h>

# ifdef __TITLE__
# undef __TITLE__
# endif
# define __TITLE__ "replica"

namespace dsn { namespace replication {

replica::replica(replica_stub* stub, global_partition_id gpid, const char* app_type, const char* dir)
    : serverlet<replica>("replica"),
    _primary_states(gpid, stub->options().staleness_for_commit, stub->options().batch_write_disabled)
{
    dassert(stub != nullptr, "");
    _stub = stub;
    _app_type = app_type;
    _dir = dir;
    sprintf(_name, "%u.%u@%s", gpid.app_id, gpid.pidx, stub->_primary_address.to_string());
    _options = &stub->options();
    init_state();
    _config.gpid = gpid;

    std::stringstream ss;
    ss << _name << ".2pc.latency(ns)";
    _counter_commit_latency.init("eon.replication", ss.str().c_str(), COUNTER_TYPE_NUMBER_PERCENTILES, "commit latency (from mutation create to commit)");
}

void replica::json_state(std::stringstream& out) const
{
    JSON_DICT_ENTRIES(out, *this, name(), _config, _app->last_committed_decree(), _app->last_durable_decree());
}

void replica::update_commit_statistics(int count)
{
    _stub->_counter_replicas_total_commit_throught.add((uint64_t)count);
}

void replica::init_state()
{
    _inactive_is_transient = false;
    _prepare_list = new prepare_list(
        0,
        _options->max_mutation_count_in_prepare_list,
        std::bind(
            &replica::execute_mutation,
            this,
            std::placeholders::_1
            )
    );

    _config.ballot = 0;
    _config.gpid.pidx = 0;
    _config.gpid.app_id = 0;
    _config.status = PS_INACTIVE;
    _primary_states.membership.ballot = 0;
    _last_config_change_time_ms = now_ms();
    _private_log = nullptr;
}

replica::~replica(void)
{
    close();

    if (nullptr != _prepare_list)
    {
        delete _prepare_list;
        _prepare_list = nullptr;
    }

    dinfo("%s: replica destroyed", name());
}

void replica::on_client_read(const read_request_header& meta, dsn_message_t request)
{
    if (status() == PS_INACTIVE || status() == PS_POTENTIAL_SECONDARY)
    {
        derror("%s: invalid status: read_semantic=%s, partition_status=%s",
               name(), enum_to_string(meta.semantic), enum_to_string(status()));
        response_client_message(request, ERR_INVALID_STATE);
        return;
    }

    if (meta.semantic == read_semantic::ReadLastUpdate)
    {
        if (status() != PS_PRIMARY)
        {
            derror("%s: invalid status: read_semantic=%s, partition_status=%s",
                   name(), enum_to_string(meta.semantic), enum_to_string(status()));
            response_client_message(request, ERR_INVALID_STATE);
            return;
        }

        if (last_committed_decree() < _primary_states.last_prepare_decree_on_new_primary)
        {
            derror("%s: last_committed_decree(%" PRId64 ") < last_prepare_decree_on_new_primary(" PRId64 ")",
                   name(), last_committed_decree(), _primary_states.last_prepare_decree_on_new_primary);
            response_client_message(request, ERR_INVALID_STATE);
            return;
        }
    }

    dassert (_app != nullptr, "");

    rpc_read_stream reader(request);
    _app->dispatch_rpc_call(meta.code, reader, dsn_msg_create_response(request));
}

void replica::response_client_message(dsn_message_t request, error_code error, decree d/* = invalid_decree*/)
{
    if (nullptr == request)
    {
        error.end_tracking();
        return;
    }

    if (error == ERR_OK)
    {
        ddebug("%s: reply client read/write, err = %s", name(), error.to_string());
    }
    else
    {
        derror("%s: reply client read/write, err = %s", name(), error.to_string());
    }

    // well, replication layer error is 1
    // application layer result is 2
    reply_field(request, error, 1);
}

//error_code replica::check_and_fix_private_log_completeness()
//{
//    error_code err = ERR_OK;
//
//    auto mind = _private_log->max_gced_decree(get_gpid());
//    if (_prepare_list->max_decree())
//
//    if (!(mind <= last_durable_decree()))
//    {
//        err = ERR_INCOMPLETE_DATA;
//        derror("%s: private log is incomplete (gced/durable): %" PRId64 " vs %" PRId64,
//            name(),
//            mind,
//            last_durable_decree()
//            );
//    }
//    else
//    {
//        mind = _private_log->max_decree(get_gpid());
//        if (!(mind >= _app->last_committed_decree()))
//        {
//            err = ERR_INCOMPLETE_DATA;
//            derror("%s: private log is incomplete (max/commit): %" PRId64 " vs %" PRId64,
//                name(),
//                mind,
//                _app->last_committed_decree()
//                );
//        }
//    }
//
//    if (ERR_INCOMPLETE_DATA == err)
//    {
//        _private_log->close(true);
//        _private_log->open(nullptr);
//        _private_log->set_private(get_gpid(), _app->last_durable_decree());
//    }
//
//    return err;
//}

void replica::check_state_completeness()
{
    /* prepare commit durable */
    dassert(max_prepared_decree() >= last_committed_decree(), "");
    dassert(last_committed_decree() >= last_durable_decree(), "");

    auto mind = _stub->_log->max_gced_decree(get_gpid(), _app->init_info().init_offset_in_shared_log);
    dassert(mind <= last_durable_decree(), "");
    _stub->_log->check_valid_start_offset(get_gpid(), _app->init_info().init_offset_in_shared_log);

    if (_private_log != nullptr)
    {
        auto mind = _private_log->max_gced_decree(get_gpid(), _app->init_info().init_offset_in_private_log);
        dassert(mind <= last_durable_decree(), "");
        _private_log->check_valid_start_offset(get_gpid(), _app->init_info().init_offset_in_private_log);
    }
}

void replica::execute_mutation(mutation_ptr& mu)
{
    dinfo("%s: execute mutation %s: request_count = %u",
        name(),
        mu->name(),
        static_cast<int>(mu->client_requests.size())
        );

    error_code err = ERR_OK;
    decree d = mu->data.header.decree;

    switch (status())
    {
    case PS_INACTIVE:
        if (_app->last_committed_decree() + 1 == d)
        {
            err = _app->write_internal(mu);
        }
        else
        {
            ddebug(
                "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64,
                name(), mu->name(),
                enum_to_string(status()),
                _app->last_committed_decree()
                );
        }
        break;
    case PS_PRIMARY:
        {
            check_state_completeness();
            dassert(_app->last_committed_decree() + 1 == d, "");
            err = _app->write_internal(mu);
        }
        break;

    case PS_SECONDARY:
        if (!_secondary_states.checkpoint_is_running)
        {
            check_state_completeness();
            dassert (_app->last_committed_decree() + 1 == d, "");
            err = _app->write_internal(mu);
        }
        else
        {
            ddebug(
                "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64,
                name(), mu->name(),
                enum_to_string(status()),
                _app->last_committed_decree()
                );

            // make sure private log saves the state
            // catch-up will be done later after checkpoint task is fininished
            dassert(_private_log != nullptr, "");
        }
        break;
    case PS_POTENTIAL_SECONDARY:
        if (_potential_secondary_states.learning_status == LearningSucceeded ||
            _potential_secondary_states.learning_status == LearningWithPrepareTransient)
        {
            dassert(_app->last_committed_decree() + 1 == d, "");
            err = _app->write_internal(mu);
        }
        else
        {
            // prepare also happens with LearningWithPrepare, in this case
            // make sure private log saves the state,
            // catch-up will be done later after the checkpoint task is finished

            ddebug(
                "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64,
                name(), mu->name(),
                enum_to_string(status()),
                _app->last_committed_decree()
                );
        }
        break;
    case PS_ERROR:
        break;
    }

    ddebug("TwoPhaseCommit, %s: mutation %s committed, err = %s", name(), mu->name(), err.to_string());

    _counter_commit_latency.set(dsn_now_ns() - mu->create_ts_ns());

    if (err != ERR_OK)
    {
        handle_local_failure(err);
    }

    if (status() == PS_PRIMARY)
    {
        mutation_ptr next = _primary_states.write_queue.check_possible_work(
            static_cast<int>(_prepare_list->max_decree() - d)
            );

        if (next)
        {
            init_prepare(next);
        }
    }
}

mutation_ptr replica::new_mutation(decree decree)
{
    mutation_ptr mu(new mutation());
    mu->data.header.gpid = get_gpid();
    mu->data.header.ballot = get_ballot();
    mu->data.header.decree = decree;
    mu->data.header.log_offset = invalid_offset;
    return mu;
}

bool replica::group_configuration(/*out*/ partition_configuration& config) const
{
    if (PS_PRIMARY != status())
        return false;

    config = _primary_states.membership;
    return true;
}

decree replica::last_durable_decree() const { return _app->last_durable_decree(); }

decree replica::last_prepared_decree() const
{
    ballot lastBallot = 0;
    decree start = last_committed_decree();
    while (true)
    {
        auto mu = _prepare_list->get_mutation_by_decree(start + 1);
        if (mu == nullptr
            || mu->data.header.ballot < lastBallot
            || !mu->is_logged()
            )
            break;

        start++;
        lastBallot = mu->data.header.ballot;
    }
    return start;
}

void replica::close()
{
    dassert(
        status() == PS_ERROR || status() == PS_INACTIVE,
        "%s: invalid state %s when calling replica::close",
        name(),
        enum_to_string(status())
        );

    if (nullptr != _checkpoint_timer)
    {
        _checkpoint_timer->cancel(true);
        _checkpoint_timer = nullptr;
    }

    cleanup_preparing_mutations(true);
    dassert(_primary_states.is_cleaned(), "primary context is not cleared");

    if (PS_INACTIVE == status())
    {
        dassert(_secondary_states.is_cleaned(), "secondary context is not cleared");
        dassert(_potential_secondary_states.is_cleaned(), "potential secondary context is not cleared");
    }

    // for PS_ERROR, context cleanup is done here as they may block
    else
    {
        bool r = _secondary_states.cleanup(true);
        dassert(r, "secondary context is not cleared");

        r = _potential_secondary_states.cleanup(true);
        dassert(r, "potential secondary context is not cleared");
    }

    if (_private_log != nullptr)
    {
        _private_log->close();
        _private_log = nullptr;
    }

    if (_app != nullptr)
    {
        _app->close(false);
    }
}

}} // namespace
<commit_msg>smallfix<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

/*
 * Description:
 *     helper functions in replica object
 *
 * Revision history:
 *     Mar., 2015, @imzhenyu (Zhenyu Guo), first version
 *     xxxx-xx-xx, author, fix bug about xxx
 */

#include "replica.h"
#include "mutation.h"
#include "mutation_log.h"
#include "replica_stub.h"
#include <dsn/cpp/json_helper.h>

# ifdef __TITLE__
# undef __TITLE__
# endif
# define __TITLE__ "replica"

namespace dsn { namespace replication {

replica::replica(replica_stub* stub, global_partition_id gpid, const char* app_type, const char* dir)
    : serverlet<replica>("replica"),
    _primary_states(gpid, stub->options().staleness_for_commit, stub->options().batch_write_disabled)
{
    dassert(stub != nullptr, "");
    _stub = stub;
    _app_type = app_type;
    _dir = dir;
    sprintf(_name, "%u.%u@%s", gpid.app_id, gpid.pidx, stub->_primary_address.to_string());
    _options = &stub->options();
    init_state();
    _config.gpid = gpid;

    std::stringstream ss;
    ss << _name << ".2pc.latency(ns)";
    _counter_commit_latency.init("eon.replication", ss.str().c_str(), COUNTER_TYPE_NUMBER_PERCENTILES, "commit latency (from mutation create to commit)");
}

void replica::json_state(std::stringstream& out) const
{
    JSON_DICT_ENTRIES(out, *this, name(), _config, _app->last_committed_decree(), _app->last_durable_decree());
}

void replica::update_commit_statistics(int count)
{
    _stub->_counter_replicas_total_commit_throught.add((uint64_t)count);
}

void replica::init_state()
{
    _inactive_is_transient = false;
    _prepare_list = new prepare_list(
        0,
        _options->max_mutation_count_in_prepare_list,
        std::bind(
            &replica::execute_mutation,
            this,
            std::placeholders::_1
            )
    );

    _config.ballot = 0;
    _config.gpid.pidx = 0;
    _config.gpid.app_id = 0;
    _config.status = PS_INACTIVE;
    _primary_states.membership.ballot = 0;
    _last_config_change_time_ms = now_ms();
    _private_log = nullptr;
}

replica::~replica(void)
{
    close();

    if (nullptr != _prepare_list)
    {
        delete _prepare_list;
        _prepare_list = nullptr;
    }

    dinfo("%s: replica destroyed", name());
}

void replica::on_client_read(const read_request_header& meta, dsn_message_t request)
{
    if (status() == PS_INACTIVE || status() == PS_POTENTIAL_SECONDARY)
    {
        derror("%s: invalid status: read_semantic=%s, partition_status=%s",
               name(), enum_to_string(meta.semantic), enum_to_string(status()));
        response_client_message(request, ERR_INVALID_STATE);
        return;
    }

    if (meta.semantic == read_semantic::ReadLastUpdate)
    {
        if (status() != PS_PRIMARY)
        {
            derror("%s: invalid status: read_semantic=%s, partition_status=%s",
                   name(), enum_to_string(meta.semantic), enum_to_string(status()));
            response_client_message(request, ERR_INVALID_STATE);
            return;
        }

        if (last_committed_decree() < _primary_states.last_prepare_decree_on_new_primary)
        {
            derror("%s: last_committed_decree(%" PRId64 ") < last_prepare_decree_on_new_primary(%" PRId64 ")",
                   name(), last_committed_decree(), _primary_states.last_prepare_decree_on_new_primary);
            response_client_message(request, ERR_INVALID_STATE);
            return;
        }
    }

    dassert (_app != nullptr, "");

    rpc_read_stream reader(request);
    _app->dispatch_rpc_call(meta.code, reader, dsn_msg_create_response(request));
}

void replica::response_client_message(dsn_message_t request, error_code error, decree d/* = invalid_decree*/)
{
    if (nullptr == request)
    {
        error.end_tracking();
        return;
    }

    if (error == ERR_OK)
    {
        ddebug("%s: reply client read/write, err = %s", name(), error.to_string());
    }
    else
    {
        derror("%s: reply client read/write, err = %s", name(), error.to_string());
    }

    // well, replication layer error is 1
    // application layer result is 2
    reply_field(request, error, 1);
}

//error_code replica::check_and_fix_private_log_completeness()
//{
//    error_code err = ERR_OK;
//
//    auto mind = _private_log->max_gced_decree(get_gpid());
//    if (_prepare_list->max_decree())
//
//    if (!(mind <= last_durable_decree()))
//    {
//        err = ERR_INCOMPLETE_DATA;
//        derror("%s: private log is incomplete (gced/durable): %" PRId64 " vs %" PRId64,
//            name(),
//            mind,
//            last_durable_decree()
//            );
//    }
//    else
//    {
//        mind = _private_log->max_decree(get_gpid());
//        if (!(mind >= _app->last_committed_decree()))
//        {
//            err = ERR_INCOMPLETE_DATA;
//            derror("%s: private log is incomplete (max/commit): %" PRId64 " vs %" PRId64,
//                name(),
//                mind,
//                _app->last_committed_decree()
//                );
//        }
//    }
//
//    if (ERR_INCOMPLETE_DATA == err)
//    {
//        _private_log->close(true);
//        _private_log->open(nullptr);
//        _private_log->set_private(get_gpid(), _app->last_durable_decree());
//    }
//
//    return err;
//}

void replica::check_state_completeness()
{
    /* prepare commit durable */
    dassert(max_prepared_decree() >= last_committed_decree(), "");
    dassert(last_committed_decree() >= last_durable_decree(), "");

    auto mind = _stub->_log->max_gced_decree(get_gpid(), _app->init_info().init_offset_in_shared_log);
    dassert(mind <= last_durable_decree(), "");
    _stub->_log->check_valid_start_offset(get_gpid(), _app->init_info().init_offset_in_shared_log);

    if (_private_log != nullptr)
    {
        auto mind = _private_log->max_gced_decree(get_gpid(), _app->init_info().init_offset_in_private_log);
        dassert(mind <= last_durable_decree(), "");
        _private_log->check_valid_start_offset(get_gpid(), _app->init_info().init_offset_in_private_log);
    }
}

void replica::execute_mutation(mutation_ptr& mu)
{
    dinfo("%s: execute mutation %s: request_count = %u",
        name(),
        mu->name(),
        static_cast<int>(mu->client_requests.size())
        );

    error_code err = ERR_OK;
    decree d = mu->data.header.decree;

    switch (status())
    {
    case PS_INACTIVE:
        if (_app->last_committed_decree() + 1 == d)
        {
            err = _app->write_internal(mu);
        }
        else
        {
            ddebug(
                "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64,
                name(), mu->name(),
                enum_to_string(status()),
                _app->last_committed_decree()
                );
        }
        break;
    case PS_PRIMARY:
        {
            check_state_completeness();
            dassert(_app->last_committed_decree() + 1 == d, "");
            err = _app->write_internal(mu);
        }
        break;

    case PS_SECONDARY:
        if (!_secondary_states.checkpoint_is_running)
        {
            check_state_completeness();
            dassert (_app->last_committed_decree() + 1 == d, "");
            err = _app->write_internal(mu);
        }
        else
        {
            ddebug(
                "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64,
                name(), mu->name(),
                enum_to_string(status()),
                _app->last_committed_decree()
                );

            // make sure private log saves the state
            // catch-up will be done later after checkpoint task is fininished
            dassert(_private_log != nullptr, "");
        }
        break;
    case PS_POTENTIAL_SECONDARY:
        if (_potential_secondary_states.learning_status == LearningSucceeded ||
            _potential_secondary_states.learning_status == LearningWithPrepareTransient)
        {
            dassert(_app->last_committed_decree() + 1 == d, "");
            err = _app->write_internal(mu);
        }
        else
        {
            // prepare also happens with LearningWithPrepare, in this case
            // make sure private log saves the state,
            // catch-up will be done later after the checkpoint task is finished

            ddebug(
                "%s: mutation %s commit to %s skipped, app.last_committed_decree = %" PRId64,
                name(), mu->name(),
                enum_to_string(status()),
                _app->last_committed_decree()
                );
        }
        break;
    case PS_ERROR:
        break;
    }

    ddebug("TwoPhaseCommit, %s: mutation %s committed, err = %s", name(), mu->name(), err.to_string());

    _counter_commit_latency.set(dsn_now_ns() - mu->create_ts_ns());

    if (err != ERR_OK)
    {
        handle_local_failure(err);
    }

    if (status() == PS_PRIMARY)
    {
        mutation_ptr next = _primary_states.write_queue.check_possible_work(
            static_cast<int>(_prepare_list->max_decree() - d)
            );

        if (next)
        {
            init_prepare(next);
        }
    }
}

mutation_ptr replica::new_mutation(decree decree)
{
    mutation_ptr mu(new mutation());
    mu->data.header.gpid = get_gpid();
    mu->data.header.ballot = get_ballot();
    mu->data.header.decree = decree;
    mu->data.header.log_offset = invalid_offset;
    return mu;
}

bool replica::group_configuration(/*out*/ partition_configuration& config) const
{
    if (PS_PRIMARY != status())
        return false;

    config = _primary_states.membership;
    return true;
}

decree replica::last_durable_decree() const { return _app->last_durable_decree(); }

decree replica::last_prepared_decree() const
{
    ballot lastBallot = 0;
    decree start = last_committed_decree();
    while (true)
    {
        auto mu = _prepare_list->get_mutation_by_decree(start + 1);
        if (mu == nullptr
            || mu->data.header.ballot < lastBallot
            || !mu->is_logged()
            )
            break;

        start++;
        lastBallot = mu->data.header.ballot;
    }
    return start;
}

void replica::close()
{
    dassert(
        status() == PS_ERROR || status() == PS_INACTIVE,
        "%s: invalid state %s when calling replica::close",
        name(),
        enum_to_string(status())
        );

    if (nullptr != _checkpoint_timer)
    {
        _checkpoint_timer->cancel(true);
        _checkpoint_timer = nullptr;
    }

    cleanup_preparing_mutations(true);
    dassert(_primary_states.is_cleaned(), "primary context is not cleared");

    if (PS_INACTIVE == status())
    {
        dassert(_secondary_states.is_cleaned(), "secondary context is not cleared");
        dassert(_potential_secondary_states.is_cleaned(), "potential secondary context is not cleared");
    }

    // for PS_ERROR, context cleanup is done here as they may block
    else
    {
        bool r = _secondary_states.cleanup(true);
        dassert(r, "secondary context is not cleared");

        r = _potential_secondary_states.cleanup(true);
        dassert(r, "potential secondary context is not cleared");
    }

    if (_private_log != nullptr)
    {
        _private_log->close();
        _private_log = nullptr;
    }

    if (_app != nullptr)
    {
        _app->close(false);
    }
}

}} // namespace
<|endoftext|>


<commit_before>#include "sniffer.h"

#include "util.h"
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <pcap.h>
#include <map>

using namespace std;

static pcap_t *handle = NULL;
static int datalink;
char * interface;

const int num_channels = 12;
int current_channel = 0;

void set_monitor_mode(char * iface) {
  interface = iface;
  char * const argv[] = {(char*)("iwconfig"),iface,(char*)("mode"),(char*)("monitor"),0};
  run_command(argv);
}

const float max_time = 10;
const float round_time = 1;

float channel_prob[num_channels+1];
float channel_time[num_channels+1];
int channel_packets[num_channels+1];

void initialize(char * interface) {
  if ( handle ) {
    error("Trying to reinitialize using interface %s",interface);
    abort();
  }

  char errbuf[BUFSIZ];

  set_monitor_mode(interface);

  handle = pcap_open_live(interface, BUFSIZ, 1, 1000, errbuf);
  if (handle == NULL) {
    error("Couldn't open interface %s. Error: %s",interface,errbuf);
    abort();
  }

  datalink = pcap_datalink(handle);

  verbose("Opened interface %s.",interface);
  debug("Datalink is %d.", datalink);

  for ( int i = 1 ; i <= num_channels ; i++ ) {
    channel_prob[i] = 1.0/num_channels;
    channel_time[i] = 0;
    channel_packets[i] = 0;
  }
}

struct ieee80211_radiotap_header {
        u_int8_t        it_version;     /* set to 0 */
        u_int8_t        it_pad;
        u_int16_t       it_len;         /* entire length */
        u_int32_t       it_present;     /* fields present */
} __attribute__((__packed__));

struct prism_value{
  u_int32_t did;
  u_int16_t status;
  u_int16_t len;
  u_int32_t data;
};

struct prism_header{
  u_int32_t msgcode;
  u_int32_t msglen;
  prism_value hosttime;
  prism_value mactime;
  prism_value channel;
  prism_value rssi;
  prism_value sq;
  prism_value signal;
  prism_value noise;
  prism_value rate;
  prism_value istx;
  prism_value frmlen;
};

map<string,int> mac_count[num_channels+1][4];

void handleMAC(const u_char * mac, int pos) {
  char mac_c_str[13];
  mac_c_str[0] = 0;
  for ( int i = 0 ; i < 6 ; i++ ) {
    sprintf(mac_c_str,"%s%02X",mac_c_str,mac[i]);
  }
  string mac_str(mac_c_str);
  mac_count[current_channel][pos][mac_str]++;
  debug("MAC %d : %s",pos,mac_c_str);
}

void handlePacket(const u_char* packet) {
  if ( datalink ==	DLT_PRISM_HEADER ) {
    prism_header* rth1 = (prism_header*)(packet);
    packet = packet + rth1->msglen;
  }

  // TODO: Check if the +4 should come after this line or before (during the PRISM skip)

  for ( int i = 0 ; i < 4 ; i++ ) {
    handleMAC(packet+4+(i*6),i);
  }

  channel_packets[current_channel]++;
}

class Timer {
  timespec start_time;

  float diff(timespec start, timespec end) {
	  timespec temp;
	  if ((end.tv_nsec-start.tv_nsec)<0) {
		  temp.tv_sec = end.tv_sec-start.tv_sec-1;
		  temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	  } else {
		  temp.tv_sec = end.tv_sec-start.tv_sec;
		  temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	  }
    return (float)temp.tv_sec + 1e-9 * temp.tv_nsec;
  }

public:
  void reset() { clock_gettime(CLOCK_MONOTONIC_COARSE,&start_time); }
  float get_time() {
    timespec temp;
    clock_gettime(CLOCK_MONOTONIC_COARSE,&temp);
    return diff(start_time,temp);
  }
  Timer() { reset(); }
};

void change_channel(int channel) {
  if ( channel < 1 || channel > num_channels ) {
    error("Impossible to switch to channel %d. Quitting.",channel);
    abort();
  }
  current_channel = channel;
  char channel_no[3];
  sprintf(channel_no,"%d",channel);
  char * const argv[] = {(char*)"iwconfig",interface,(char*)"channel",channel_no,0};
  run_command(argv);
  verbose("Changed to channel %d",channel);
}

bool switch_to_next_channel() {
  bool ret = (current_channel==num_channels);
  static Timer ch_time;
  channel_time[current_channel]+=ch_time.get_time();
  change_channel((current_channel % num_channels) + 1);
  ch_time.reset();
  return ret;
}

void recalculate_probs() {
  const float min_speed_adder = 0.01;
  float speed[num_channels+1];
  float total_speed = 0;
  for ( int i = 1 ; i <= num_channels ; i++ ) {
    debug("Packets on channel %02d = %d",i,channel_packets);
    speed[i] = channel_packets[i]/channel_time[i];
    speed[i] += min_speed_adder;
    total_speed += speed[i];
  }

  for ( int i = 1 ; i <= num_channels ; i++ ) {
    channel_prob[i] = speed[i] / total_speed;
  }
}

void capture_packets() {
  Timer timer;
  Timer channel_timer;
  switch_to_next_channel();
  while ( timer.get_time() < max_time ) {
    pcap_pkthdr header;
    handlePacket(pcap_next(handle, &header));
    debug("<<<Channel timer: %f; Total timer: %f>>>",channel_timer.get_time(),timer.get_time());
    bool is_round_over;
    if ( channel_timer.get_time() > channel_prob[current_channel] * round_time ) {
      is_round_over = switch_to_next_channel();
      channel_timer.reset();
    }
    if ( is_round_over ) {
      recalculate_probs();
    }
  }
}
<commit_msg>Change times<commit_after>#include "sniffer.h"

#include "util.h"
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <string>
#include <pcap.h>
#include <map>

using namespace std;

static pcap_t *handle = NULL;
static int datalink;
char * interface;

const int num_channels = 12;
int current_channel = 0;

void set_monitor_mode(char * iface) {
  interface = iface;
  char * const argv[] = {(char*)("iwconfig"),iface,(char*)("mode"),(char*)("monitor"),0};
  run_command(argv);
}

const float max_time = 60;
const float round_time = 12;

float channel_prob[num_channels+1];
float channel_time[num_channels+1];
int channel_packets[num_channels+1];

void initialize(char * interface) {
  if ( handle ) {
    error("Trying to reinitialize using interface %s",interface);
    abort();
  }

  char errbuf[BUFSIZ];

  set_monitor_mode(interface);

  handle = pcap_open_live(interface, BUFSIZ, 1, 1000, errbuf);
  if (handle == NULL) {
    error("Couldn't open interface %s. Error: %s",interface,errbuf);
    abort();
  }

  datalink = pcap_datalink(handle);

  verbose("Opened interface %s.",interface);
  debug("Datalink is %d.", datalink);

  for ( int i = 1 ; i <= num_channels ; i++ ) {
    channel_prob[i] = 1.0/num_channels;
    channel_time[i] = 0;
    channel_packets[i] = 0;
  }
}

struct ieee80211_radiotap_header {
        u_int8_t        it_version;     /* set to 0 */
        u_int8_t        it_pad;
        u_int16_t       it_len;         /* entire length */
        u_int32_t       it_present;     /* fields present */
} __attribute__((__packed__));

struct prism_value{
  u_int32_t did;
  u_int16_t status;
  u_int16_t len;
  u_int32_t data;
};

struct prism_header{
  u_int32_t msgcode;
  u_int32_t msglen;
  prism_value hosttime;
  prism_value mactime;
  prism_value channel;
  prism_value rssi;
  prism_value sq;
  prism_value signal;
  prism_value noise;
  prism_value rate;
  prism_value istx;
  prism_value frmlen;
};

map<string,int> mac_count[num_channels+1][4];

void handleMAC(const u_char * mac, int pos) {
  char mac_c_str[13];
  mac_c_str[0] = 0;
  for ( int i = 0 ; i < 6 ; i++ ) {
    sprintf(mac_c_str,"%s%02X",mac_c_str,mac[i]);
  }
  string mac_str(mac_c_str);
  mac_count[current_channel][pos][mac_str]++;
  debug("MAC %d : %s",pos,mac_c_str);
}

void handlePacket(const u_char* packet) {
  if ( datalink ==	DLT_PRISM_HEADER ) {
    prism_header* rth1 = (prism_header*)(packet);
    packet = packet + rth1->msglen;
  }

  // TODO: Check if the +4 should come after this line or before (during the PRISM skip)

  for ( int i = 0 ; i < 4 ; i++ ) {
    handleMAC(packet+4+(i*6),i);
  }

  channel_packets[current_channel]++;
}

class Timer {
  timespec start_time;

  float diff(timespec start, timespec end) {
	  timespec temp;
	  if ((end.tv_nsec-start.tv_nsec)<0) {
		  temp.tv_sec = end.tv_sec-start.tv_sec-1;
		  temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
	  } else {
		  temp.tv_sec = end.tv_sec-start.tv_sec;
		  temp.tv_nsec = end.tv_nsec-start.tv_nsec;
	  }
    return (float)temp.tv_sec + 1e-9 * temp.tv_nsec;
  }

public:
  void reset() { clock_gettime(CLOCK_MONOTONIC_COARSE,&start_time); }
  float get_time() {
    timespec temp;
    clock_gettime(CLOCK_MONOTONIC_COARSE,&temp);
    return diff(start_time,temp);
  }
  Timer() { reset(); }
};

void change_channel(int channel) {
  if ( channel < 1 || channel > num_channels ) {
    error("Impossible to switch to channel %d. Quitting.",channel);
    abort();
  }
  current_channel = channel;
  char channel_no[3];
  sprintf(channel_no,"%d",channel);
  char * const argv[] = {(char*)"iwconfig",interface,(char*)"channel",channel_no,0};
  run_command(argv);
  verbose("Changed to channel %d",channel);
}

bool switch_to_next_channel() {
  bool ret = (current_channel==num_channels);
  static Timer ch_time;
  channel_time[current_channel]+=ch_time.get_time();
  change_channel((current_channel % num_channels) + 1);
  ch_time.reset();
  return ret;
}

void recalculate_probs() {
  const float min_speed_adder = 0.01;
  float speed[num_channels+1];
  float total_speed = 0;
  for ( int i = 1 ; i <= num_channels ; i++ ) {
    debug("Packets on channel %02d = %d",i,channel_packets);
    speed[i] = channel_packets[i]/channel_time[i];
    speed[i] += min_speed_adder;
    total_speed += speed[i];
  }

  for ( int i = 1 ; i <= num_channels ; i++ ) {
    channel_prob[i] = speed[i] / total_speed;
  }
}

void capture_packets() {
  Timer timer;
  Timer channel_timer;
  switch_to_next_channel();
  while ( timer.get_time() < max_time ) {
    pcap_pkthdr header;
    handlePacket(pcap_next(handle, &header));
    debug("<<<Channel timer: %f; Total timer: %f>>>",channel_timer.get_time(),timer.get_time());
    bool is_round_over;
    if ( channel_timer.get_time() > channel_prob[current_channel] * round_time ) {
      is_round_over = switch_to_next_channel();
      channel_timer.reset();
    }
    if ( is_round_over ) {
      recalculate_probs();
    }
  }
}

// TODO: Use only one timer for the channels
// TODO: Make sure that pcap_next doesn't take too long
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 * Object hierarchy for describing the traces in memory.
 */

#ifndef _TRACE_MODEL_HPP_
#define _TRACE_MODEL_HPP_

#include <cassert>

#include <string>
#include <map>
#include <list>
#include <vector>
#include <iostream>

namespace Trace {

class Visitor;
class Dumper;
class UInt;

class Value
{
public:
    virtual ~Value() {}
    virtual void visit(Visitor &visitor) = 0;

    virtual operator bool (void) const = 0;
    virtual operator signed long long (void) const;
    virtual operator unsigned long long (void) const;
    virtual operator double (void) const;

    virtual void *blob(void) const;
    const char *string(void) const;

    inline operator signed char (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned char (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator signed short (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned short (void) const {
        return static_cast<unsigned long long>(*this);
    }

    inline operator signed (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned (void) const {
        return static_cast<unsigned long long>(*this);
    }

    inline operator signed long (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned long (void) const {
        return static_cast<unsigned long long>(*this);
    }

    inline operator float (void) const {
        return static_cast<double>(*this);
    }

    const Value & operator[](size_t index) const;
};

class Null : public Value
{
public:
    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void *blob(void) const;
    void visit(Visitor &visitor);
};

class Bool : public Value
{
public:
    Bool(bool _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    bool value;
};

class SInt : public Value
{
public:
    SInt(signed long long _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    signed long long value;
};

class UInt : public Value
{
public:
    UInt(unsigned long long _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    unsigned long long value;
};

class Float : public Value
{
public:
    Float(double _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    double value;
};

class String : public Value
{
public:
    String(std::string _value) : value(_value) {}

    operator bool (void) const;
    void visit(Visitor &visitor);

    std::string value;
};

class Enum : public Value
{
public:
    struct Signature : public std::pair<std::string, Value *>
    {
        Signature()
            : std::pair<std::string, Value *>()
        {}
        Signature(const std::string &n, Trace::Value *val)
            : std::pair<std::string, Value *>(n, val)
        {}
        ~Signature()
        {
            delete second;
        }
    };

    Enum(const Signature *_sig) : sig(_sig) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    const Signature *sig;
};

class Bitmask : public UInt
{
public:
    typedef std::pair<std::string, unsigned long long> Pair;
    typedef std::vector<Pair> Signature;

    Bitmask(const Signature *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}

    void visit(Visitor &visitor);

    const Signature *sig;
};

class Struct : public Value
{
public:
    struct Signature {
        std::string name;
        std::vector<std::string> member_names;
    };

    Struct(Signature *_sig) : sig(_sig), members(_sig->member_names.size()) { }
    ~Struct();

    operator bool (void) const;
    void visit(Visitor &visitor);

    const Signature *sig;
    std::vector<Value *> members;
};

class Array : public Value
{
public:
    Array(size_t len) : values(len) {}
    ~Array();

    operator bool (void) const;
    void visit(Visitor &visitor);

    std::vector<Value *> values;
};

class Blob : public Value
{
public:
    Blob(size_t _size) {
        size = _size;
        buf = new char[_size];
    }

    ~Blob();

    operator bool (void) const;
    void *blob(void) const;
    void visit(Visitor &visitor);

    size_t size;
    char *buf;
};

class Pointer : public UInt
{
public:
    Pointer(unsigned long long value) : UInt(value) {}

    operator bool (void) const;
    void *blob(void) const;
    void visit(Visitor &visitor);
};

class Visitor
{
public:
    virtual void visit(Null *);
    virtual void visit(Bool *);
    virtual void visit(SInt *);
    virtual void visit(UInt *);
    virtual void visit(Float *);
    virtual void visit(String *);
    virtual void visit(Enum *);
    virtual void visit(Bitmask *);
    virtual void visit(Struct *);
    virtual void visit(Array *);
    virtual void visit(Blob *);
    virtual void visit(Pointer *);

protected:
    inline void _visit(Value *value) {
        if (value) {
            value->visit(*this);
        }
    }
};

std::ostream & operator <<(std::ostream &os, Value *value);

signed long long asSInt(const Value &node);
unsigned long long asUInt(const Value &node);
double asFloat(const Value &node);

class Call
{
public:
    struct Signature {
        std::string name;
        std::vector<std::string> arg_names;
    };

    unsigned no;
    const Signature *sig;
    std::vector<Value *> args;
    Value *ret;

    Call(Signature *_sig) : sig(_sig), args(_sig->arg_names.size()), ret(0) { }
    ~Call();

    inline const std::string name(void) const {
        return sig->name;
    }

    inline Value & arg(unsigned index) {
        return *(args[index]);
    }
};

std::ostream & operator <<(std::ostream &os, Call &call);

} /* namespace Trace */

#endif /* _TRACE_MODEL_HPP_ */
<commit_msg>Fix replay on MSVC.<commit_after>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 **************************************************************************/

/*
 * Object hierarchy for describing the traces in memory.
 */

#ifndef _TRACE_MODEL_HPP_
#define _TRACE_MODEL_HPP_

#include <cassert>

#include <string>
#include <map>
#include <list>
#include <vector>
#include <iostream>

namespace Trace {

class Visitor;
class Dumper;
class UInt;

class Value
{
public:
    virtual ~Value() {}
    virtual void visit(Visitor &visitor) = 0;

    virtual operator bool (void) const = 0;
    virtual operator signed long long (void) const;
    virtual operator unsigned long long (void) const;
    virtual operator double (void) const;

    virtual void *blob(void) const;
    const char *string(void) const;

    inline operator signed char (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned char (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator signed short (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned short (void) const {
        return static_cast<unsigned long long>(*this);
    }

    inline operator signed (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned (void) const {
        return static_cast<unsigned long long>(*this);
    }

    inline operator signed long (void) const {
        return static_cast<signed long long>(*this);
    }

    inline operator unsigned long (void) const {
        return static_cast<unsigned long long>(*this);
    }

    inline operator float (void) const {
        return static_cast<double>(*this);
    }

    const Value & operator[](size_t index) const;
};

class Null : public Value
{
public:
    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void *blob(void) const;
    void visit(Visitor &visitor);
};

class Bool : public Value
{
public:
    Bool(bool _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    bool value;
};

class SInt : public Value
{
public:
    SInt(signed long long _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    signed long long value;
};

class UInt : public Value
{
public:
    UInt(unsigned long long _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    unsigned long long value;
};

class Float : public Value
{
public:
    Float(double _value) : value(_value) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    double value;
};

class String : public Value
{
public:
    String(std::string _value) : value(_value) {}

    operator bool (void) const;
    void visit(Visitor &visitor);

    std::string value;
};

class Enum : public Value
{
public:
    struct Signature : public std::pair<std::string, Value *>
    {
        Signature()
            : std::pair<std::string, Value *>()
        {}
        Signature(const std::string &n, Trace::Value *val)
            : std::pair<std::string, Value *>(n, val)
        {}
        ~Signature()
        {
            delete second;
        }
    };

    Enum(const Signature *_sig) : sig(_sig) {}

    operator bool (void) const;
    operator signed long long (void) const;
    operator unsigned long long (void) const;
    operator double (void) const;
    void visit(Visitor &visitor);

    const Signature *sig;
};

class Bitmask : public UInt
{
public:
    typedef std::pair<std::string, unsigned long long> Pair;
    typedef std::vector<Pair> Signature;

    Bitmask(const Signature *_sig, unsigned long long _value) : UInt(_value), sig(_sig) {}

    void visit(Visitor &visitor);

    const Signature *sig;
};

class Struct : public Value
{
public:
    struct Signature {
        std::string name;
        std::vector<std::string> member_names;
    };

    Struct(Signature *_sig) : sig(_sig), members(_sig->member_names.size()) { }
    ~Struct();

    operator bool (void) const;
    void visit(Visitor &visitor);

    const Signature *sig;
    std::vector<Value *> members;
};

class Array : public Value
{
public:
    Array(size_t len) : values(len) {}
    ~Array();

    operator bool (void) const;
    void visit(Visitor &visitor);

    std::vector<Value *> values;
};

class Blob : public Value
{
public:
    Blob(size_t _size) {
        size = _size;
        buf = new char[_size];
    }

    ~Blob();

    operator bool (void) const;
    void *blob(void) const;
    void visit(Visitor &visitor);

    size_t size;
    char *buf;
};

class Pointer : public UInt
{
public:
    Pointer(unsigned long long value) : UInt(value) {}

    operator bool (void) const;
    void *blob(void) const;
    void visit(Visitor &visitor);
};

class Visitor
{
public:
    virtual void visit(Null *);
    virtual void visit(Bool *);
    virtual void visit(SInt *);
    virtual void visit(UInt *);
    virtual void visit(Float *);
    virtual void visit(String *);
    virtual void visit(Enum *);
    virtual void visit(Bitmask *);
    virtual void visit(Struct *);
    virtual void visit(Array *);
    virtual void visit(Blob *);
    virtual void visit(Pointer *);

protected:
    inline void _visit(Value *value) {
        if (value) {
            value->visit(*this);
        }
    }
};

std::ostream & operator <<(std::ostream &os, Value *value);

signed long long asSInt(const Value &node);
unsigned long long asUInt(const Value &node);
double asFloat(const Value &node);

class Call
{
public:
    struct Signature {
        std::string name;
        std::vector<std::string> arg_names;
    };

    unsigned no;
    const Signature *sig;
    std::vector<Value *> args;
    Value *ret;

    Call(Signature *_sig) : sig(_sig), args(_sig->arg_names.size()), ret(0) { }
    ~Call();

    inline const std::string & name(void) const {
        return sig->name;
    }

    inline Value & arg(unsigned index) {
        return *(args[index]);
    }
};

std::ostream & operator <<(std::ostream &os, Call &call);

} /* namespace Trace */

#endif /* _TRACE_MODEL_HPP_ */
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Determine coverage of font given its raw "cmap" OpenType table

#ifdef PRINTF_DEBUG
#include <stdio.h>
#endif

#include <vector>
using std::vector;

#include <minikin/SparseBitSet.h>
#include <minikin/CmapCoverage.h>

namespace android {

// These could perhaps be optimized to use __builtin_bswap16 and friends.
static uint32_t readU16(const uint8_t* data, size_t offset) {
    return data[offset] << 8 | data[offset + 1];
}

static uint32_t readU32(const uint8_t* data, size_t offset) {
    return data[offset] << 24 | data[offset + 1] << 16 | data[offset + 2] << 8 | data[offset + 3];
}

static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
#ifdef PRINTF_DEBUG
    printf("adding range %d-%d\n", start, end);
#endif
    if (coverage.empty() || coverage.back() < start) {
        coverage.push_back(start);
        coverage.push_back(end);
    } else {
        coverage.back() = end;
    }
}

// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kSegCountOffset = 6;
    const size_t kEndCountOffset = 14;
    const size_t kHeaderSize = 16;
    const size_t kSegmentSize = 8;  // total size of array elements for one segment
    if (kEndCountOffset > size) {
        return false;
    }
    size_t segCount = readU16(data, kSegCountOffset) >> 1;
    if (kHeaderSize + segCount * kSegmentSize > size) {
        return false;
    }
    for (size_t i = 0; i < segCount; i++) {
        int end = readU16(data, kEndCountOffset + 2 * i);
        int start = readU16(data, kHeaderSize + 2 * (segCount + i));
        int rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
        if (rangeOffset == 0) {
            int delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
            if (((end + delta) & 0xffff) > end - start) {
                addRange(coverage, start, end + 1);
            } else {
                for (int j = start; j < end + 1; j++) {
                    if (((j + delta) & 0xffff) != 0) {
                        addRange(coverage, j, j + 1);
                    }
                }
            }
        } else {
            for (int j = start; j < end + 1; j++) {
                uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
                    (i + j - start) * 2;
                if (actualRangeOffset + 2 > size) {
                    return false;
                }
                int glyphId = readU16(data, actualRangeOffset);
                if (glyphId != 0) {
                    addRange(coverage, j, j + 1);
                }
            }
        }
    }
    return true;
}

// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kNGroupsOffset = 12;
    const size_t kFirstGroupOffset = 16;
    const size_t kGroupSize = 12;
    const size_t kStartCharCodeOffset = 0;
    const size_t kEndCharCodeOffset = 4;
    if (kFirstGroupOffset > size) {
        return false;
    }
    uint32_t nGroups = readU32(data, kNGroupsOffset);
    if (kFirstGroupOffset + nGroups * kGroupSize > size) {
        return false;
    }
    for (uint32_t i = 0; i < nGroups; i++) {
        uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
        uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
        uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
    }
    return true;
}

bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size) {
    vector<uint32_t> coverageVec;
    const size_t kHeaderSize = 4;
    const size_t kNumTablesOffset = 2;
    const size_t kTableSize = 8;
    const size_t kPlatformIdOffset = 0;
    const size_t kEncodingIdOffset = 2;
    const size_t kOffsetOffset = 4;
    const int kMicrosoftPlatformId = 3;
    const int kUnicodeBmpEncodingId = 1;
    const int kUnicodeUcs4EncodingId = 10;
    if (kHeaderSize > cmap_size) {
        return false;
    }
    int numTables = readU16(cmap_data, kNumTablesOffset);
    if (kHeaderSize + numTables * kTableSize > cmap_size) {
        return false;
    }
    int bestTable = -1;
    for (int i = 0; i < numTables; i++) {
        uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
        uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
        if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
            bestTable = i;
            break;
        } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) {
            bestTable = i;
        }
    }
#ifdef PRINTF_DEBUG
    printf("best table = %d\n", bestTable);
#endif
    if (bestTable < 0) {
        return false;
    }
    uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
    if (offset + 2 > cmap_size) {
        return false;
    }
    uint16_t format = readU16(cmap_data, offset);
    bool success = false;
    const uint8_t* tableData = cmap_data + offset;
    const size_t tableSize = cmap_size - offset;
    if (format == 4) {
        success = getCoverageFormat4(coverageVec, tableData, tableSize);
    } else if (format == 12) {
        success = getCoverageFormat12(coverageVec, tableData, tableSize);
    }
    if (success) {
        coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1);
    }
#ifdef PRINTF_DEBUG
    for (int i = 0; i < coverageVec.size(); i += 2) {
        printf("%x:%x\n", coverageVec[i], coverageVec[i + 1]);
    }
#endif
    return success;
}

}  // namespace android
<commit_msg>Avoid integer overflows in parsing fonts<commit_after>/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Determine coverage of font given its raw "cmap" OpenType table

#ifdef PRINTF_DEBUG
#include <stdio.h>
#endif

#include <vector>
using std::vector;

#include <minikin/SparseBitSet.h>
#include <minikin/CmapCoverage.h>

namespace android {

// These could perhaps be optimized to use __builtin_bswap16 and friends.
static uint32_t readU16(const uint8_t* data, size_t offset) {
    return ((uint32_t)data[offset]) << 8 | ((uint32_t)data[offset + 1]);
}

static uint32_t readU32(const uint8_t* data, size_t offset) {
    return ((uint32_t)data[offset]) << 24 | ((uint32_t)data[offset + 1]) << 16 |
        ((uint32_t)data[offset + 2]) << 8 | ((uint32_t)data[offset + 3]);
}

static void addRange(vector<uint32_t> &coverage, uint32_t start, uint32_t end) {
#ifdef PRINTF_DEBUG
    printf("adding range %d-%d\n", start, end);
#endif
    if (coverage.empty() || coverage.back() < start) {
        coverage.push_back(start);
        coverage.push_back(end);
    } else {
        coverage.back() = end;
    }
}

// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
static bool getCoverageFormat4(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kSegCountOffset = 6;
    const size_t kEndCountOffset = 14;
    const size_t kHeaderSize = 16;
    const size_t kSegmentSize = 8;  // total size of array elements for one segment
    if (kEndCountOffset > size) {
        return false;
    }
    size_t segCount = readU16(data, kSegCountOffset) >> 1;
    if (kHeaderSize + segCount * kSegmentSize > size) {
        return false;
    }
    for (size_t i = 0; i < segCount; i++) {
        int end = readU16(data, kEndCountOffset + 2 * i);
        int start = readU16(data, kHeaderSize + 2 * (segCount + i));
        int rangeOffset = readU16(data, kHeaderSize + 2 * (3 * segCount + i));
        if (rangeOffset == 0) {
            int delta = readU16(data, kHeaderSize + 2 * (2 * segCount + i));
            if (((end + delta) & 0xffff) > end - start) {
                addRange(coverage, start, end + 1);
            } else {
                for (int j = start; j < end + 1; j++) {
                    if (((j + delta) & 0xffff) != 0) {
                        addRange(coverage, j, j + 1);
                    }
                }
            }
        } else {
            for (int j = start; j < end + 1; j++) {
                uint32_t actualRangeOffset = kHeaderSize + 6 * segCount + rangeOffset +
                    (i + j - start) * 2;
                if (actualRangeOffset + 2 > size) {
                    return false;
                }
                int glyphId = readU16(data, actualRangeOffset);
                if (glyphId != 0) {
                    addRange(coverage, j, j + 1);
                }
            }
        }
    }
    return true;
}

// Get the coverage information out of a Format 12 subtable, storing it in the coverage vector
static bool getCoverageFormat12(vector<uint32_t>& coverage, const uint8_t* data, size_t size) {
    const size_t kNGroupsOffset = 12;
    const size_t kFirstGroupOffset = 16;
    const size_t kGroupSize = 12;
    const size_t kStartCharCodeOffset = 0;
    const size_t kEndCharCodeOffset = 4;
    const size_t kMaxNGroups = 0xfffffff0 / kGroupSize;  // protection against overflow
    // For all values < kMaxNGroups, kFirstGroupOffset + nGroups * kGroupSize fits in 32 bits.
    if (kFirstGroupOffset > size) {
        return false;
    }
    uint32_t nGroups = readU32(data, kNGroupsOffset);
    if (nGroups >= kMaxNGroups || kFirstGroupOffset + nGroups * kGroupSize > size) {
        return false;
    }
    for (uint32_t i = 0; i < nGroups; i++) {
        uint32_t groupOffset = kFirstGroupOffset + i * kGroupSize;
        uint32_t start = readU32(data, groupOffset + kStartCharCodeOffset);
        uint32_t end = readU32(data, groupOffset + kEndCharCodeOffset);
        addRange(coverage, start, end + 1);  // file is inclusive, vector is exclusive
    }
    return true;
}

bool CmapCoverage::getCoverage(SparseBitSet& coverage, const uint8_t* cmap_data, size_t cmap_size) {
    vector<uint32_t> coverageVec;
    const size_t kHeaderSize = 4;
    const size_t kNumTablesOffset = 2;
    const size_t kTableSize = 8;
    const size_t kPlatformIdOffset = 0;
    const size_t kEncodingIdOffset = 2;
    const size_t kOffsetOffset = 4;
    const int kMicrosoftPlatformId = 3;
    const int kUnicodeBmpEncodingId = 1;
    const int kUnicodeUcs4EncodingId = 10;
    if (kHeaderSize > cmap_size) {
        return false;
    }
    int numTables = readU16(cmap_data, kNumTablesOffset);
    if (kHeaderSize + numTables * kTableSize > cmap_size) {
        return false;
    }
    int bestTable = -1;
    for (int i = 0; i < numTables; i++) {
        uint16_t platformId = readU16(cmap_data, kHeaderSize + i * kTableSize + kPlatformIdOffset);
        uint16_t encodingId = readU16(cmap_data, kHeaderSize + i * kTableSize + kEncodingIdOffset);
        if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeUcs4EncodingId) {
            bestTable = i;
            break;
        } else if (platformId == kMicrosoftPlatformId && encodingId == kUnicodeBmpEncodingId) {
            bestTable = i;
        }
    }
#ifdef PRINTF_DEBUG
    printf("best table = %d\n", bestTable);
#endif
    if (bestTable < 0) {
        return false;
    }
    uint32_t offset = readU32(cmap_data, kHeaderSize + bestTable * kTableSize + kOffsetOffset);
    if (offset + 2 > cmap_size) {
        return false;
    }
    uint16_t format = readU16(cmap_data, offset);
    bool success = false;
    const uint8_t* tableData = cmap_data + offset;
    const size_t tableSize = cmap_size - offset;
    if (format == 4) {
        success = getCoverageFormat4(coverageVec, tableData, tableSize);
    } else if (format == 12) {
        success = getCoverageFormat12(coverageVec, tableData, tableSize);
    }
    if (success) {
        coverage.initFromRanges(&coverageVec.front(), coverageVec.size() >> 1);
    }
#ifdef PRINTF_DEBUG
    for (int i = 0; i < coverageVec.size(); i += 2) {
        printf("%x:%x\n", coverageVec[i], coverageVec[i + 1]);
    }
#endif
    return success;
}

}  // namespace android
<|endoftext|>


<commit_before>// RUN: rm -rf %t
// RUN: pp-trace -ignore FileChanged,MacroDefined %s -x objective-c++ -undef -target x86_64 -std=c++11 -fmodules -fcxx-modules -fmodules-cache-path=%t -I%S -I%S/Input | FileCheck --strict-whitespace %s

// CHECK: ---

@import Level1A;

// CHECK-NEXT: - Callback: moduleImport
// CHECK-NEXT:   ImportLoc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-3]]:2"
// CHECK-NEXT:   Path: [{Name: Level1A, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:9"}]
// CHECK-NEXT:   Imported: Level1A

@import Level1B.Level2B;

// CHECK-NEXT: - Callback: moduleImport
// CHECK-NEXT:   ImportLoc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-3]]:2"
// CHECK-NEXT:   Path: [{Name: Level1B, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:9"}, {Name: Level2B, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:17"}]
// CHECK-NEXT:   Imported: Level2B
// CHECK-NEXT: - Callback: EndOfMainFile
// CHECK-NEXT: ...
<commit_msg>Add a missing target requirement.<commit_after>// RUN: rm -rf %t
// RUN: pp-trace -ignore FileChanged,MacroDefined %s -x objective-c++ -undef -target x86_64 -std=c++11 -fmodules -fcxx-modules -fmodules-cache-path=%t -I%S -I%S/Input | FileCheck --strict-whitespace %s
// REQUIRES: x86-registered-target
// CHECK: ---

@import Level1A;

// CHECK-NEXT: - Callback: moduleImport
// CHECK-NEXT:   ImportLoc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-3]]:2"
// CHECK-NEXT:   Path: [{Name: Level1A, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:9"}]
// CHECK-NEXT:   Imported: Level1A

@import Level1B.Level2B;

// CHECK-NEXT: - Callback: moduleImport
// CHECK-NEXT:   ImportLoc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-3]]:2"
// CHECK-NEXT:   Path: [{Name: Level1B, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:9"}, {Name: Level2B, Loc: "{{.*}}{{[/\\]}}pp-trace-modules.cpp:[[@LINE-4]]:17"}]
// CHECK-NEXT:   Imported: Level2B
// CHECK-NEXT: - Callback: EndOfMainFile
// CHECK-NEXT: ...
<|endoftext|>


<commit_before>#include "spaghetti/logger.h"

namespace spaghetti::log {

Logger g_loggerConsole{};
Logger g_loggerFile{};

void init()
{
  if (!g_loggerConsole) g_loggerConsole = spdlog::stdout_color_mt("console");
  if (!g_loggerFile) g_loggerFile = spdlog::basic_logger_mt("file", "spaghetti.log");

  spdlog::set_pattern("[%Y.%m.%d %H:%M:%S.%e] [%n] [%L] %v");
}

Loggers get()
{
  return { g_loggerConsole, g_loggerFile };
}

} // namespace spaghetti::log
<commit_msg>Set console log level to debug<commit_after>#include "spaghetti/logger.h"

namespace spaghetti::log {

Logger g_loggerConsole{};
Logger g_loggerFile{};

void init()
{
  if (!g_loggerConsole) g_loggerConsole = spdlog::stdout_color_mt("console");
  if (!g_loggerFile) g_loggerFile = spdlog::basic_logger_mt("file", "spaghetti.log");

  spdlog::set_pattern("[%Y.%m.%d %H:%M:%S.%e] [%n] [%L] %v");

  g_loggerConsole->set_level(spdlog::level::debug);
}

Loggers get()
{
  return { g_loggerConsole, g_loggerFile };
}

} // namespace spaghetti::log
<|endoftext|>