<commit_before>/***************************************************************************
 *   Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org>                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "store.h"

#include "akonadi.h"
#include "akonadiconnection.h"
#include "handlerhelper.h"
#include "response.h"
#include "storage/datastore.h"
#include "storage/transaction.h"
#include "storage/itemqueryhelper.h"
#include "storage/selectquerybuilder.h"
#include "storage/parthelper.h"
#include "storage/dbconfig.h"
#include "storage/itemretriever.h"

#include "libs/imapparser_p.h"
#include "libs/protocol_p.h"
#include "imapstreamparser.h"

#include <QtCore/QStringList>
#include <QLocale>
#include <QDebug>
#include <QFile>

#include <algorithm>
#include <functional>

using namespace Akonadi;

Store::Store( Scope::SelectionScope scope )
  : Handler()
  , mScope( scope )
  , mPos( 0 )
  , mPreviousRevision( -1 )
  , mSize( 0 )
  , mCheckRevision( false )
{
}

bool Store::replaceFlags( const PimItem &item, const QList<QByteArray> &flags )
{
  Flag::List flagList = HandlerHelper::resolveFlags( flags );
  DataStore *store = connection()->storageBackend();

  Flag::List currentFlags = item.flags();
  std::sort( flagList.begin(), flagList.end(), _detail::ById<std::less>() );
  std::sort( currentFlags.begin(), currentFlags.end(), _detail::ById<std::less>() );

  if ( flagList == currentFlags )
    return false;

  if ( !store->setItemFlags( item, flagList ) )
    throw HandlerException( "Store::replaceFlags: Unable to set new item flags" );

  return true;
}

bool Store::addFlags( const PimItem &item, const QList<QByteArray> &flags, bool& flagsChanged )
{
  const Flag::List flagList = HandlerHelper::resolveFlags( flags );
  DataStore *store = connection()->storageBackend();

  if ( !store->appendItemFlags( item, flagList, flagsChanged ) ) {
    qDebug( "Store::addFlags: Unable to add new item flags" );
    return false;
  }
  return true;
}

bool Store::deleteFlags( const PimItem &item, const QList<QByteArray> &flags )
{
  DataStore *store = connection()->storageBackend();

  QVector<Flag> flagList;
  flagList.reserve( flags.size() );
  for ( int i = 0; i < flags.count(); ++i ) {
    Flag flag = Flag::retrieveByName( QString::fromUtf8( flags[ i ] ) );
    if ( !flag.isValid() )
      continue;

    flagList.append( flag );
  }

  if ( !store->removeItemFlags( item, flagList ) ) {
    qDebug( "Store::deleteFlags: Unable to remove item flags" );
    return false;
  }
  return true;
}

bool Store::parseStream()
{
  parseCommand();
  DataStore *store = connection()->storageBackend();
  Transaction transaction( store );
   // Set the same modification time for each item.
  const QDateTime modificationtime = QDateTime::currentDateTime().toUTC();

  // retrieve selected items
  SelectQueryBuilder<PimItem> qb;
  ItemQueryHelper::scopeToQuery( mScope, connection(), qb );
  if ( !qb.exec() )
    return failureResponse( "Unable to retrieve items" );
  PimItem::List pimItems = qb.result();
  if ( pimItems.isEmpty() )
    return failureResponse( "No items found" );

  for ( int i = 0; i < pimItems.size(); ++i ) {
    if ( mCheckRevision ) {
      // check for conflicts if a resources tries to overwrite an item with dirty payload
      // FIXME: STORE is also used to mark items as no longer dirty by the resource!
/*      if ( connection()->isOwnerResource( pimItems.at( i ) ) ) {
        if ( pimItems.at( i ).dirty() )
          throw HandlerException( "[LRCONFLICT] Resource tries to modify item with dirty payload, aborting STORE." );
      }*/

      // check and update revisions
      if ( pimItems.at( i ).rev() != (int)mPreviousRevision )
        throw HandlerException( "[LLCONFLICT] Item was modified elsewhere, aborting STORE." );
    }
    pimItems[ i ].setRev( pimItems[ i ].rev() + 1 );
  }

  QSet<QByteArray> changes;
  qint64 partSizes = 0;
  bool invalidateCache = false;

  // apply modifications
  m_streamParser->beginList();
  while ( !m_streamParser->atListEnd() ) {
    // parse the command
    QByteArray command = m_streamParser->readString();
    if ( command.isEmpty() )
      throw HandlerException( "Syntax error" );
    Operation op = Replace;
    bool silent = false;
    if ( command.startsWith( '+' ) ) {
      op = Add;
      command = command.mid( 1 );
    } else if ( command.startsWith( '-' ) ) {
      op = Delete;
      command = command.mid( 1 );
    }
    if ( command.endsWith( ".SILENT" ) ) {
      command.chop( 7 );
      silent = true;
    }
//     qDebug() << "STORE: handling command: " << command;

    // handle commands that can be applied to more than one item
    if ( command == AKONADI_PARAM_FLAGS ) {
      bool flagsChanged = true;
      const QList<QByteArray> flags = m_streamParser->readParenthesizedList();
      // TODO move this iteration to an SQL query.
      for ( int i = 0; i < pimItems.count(); ++i ) {
        if ( op == Replace ) {
          flagsChanged = replaceFlags( pimItems[ i ], flags );
        } else if ( op == Add ) {
          if ( !addFlags( pimItems[ i ], flags, flagsChanged ) )
            return failureResponse( "Unable to add item flags." );
        } else if ( op == Delete ) {
          if ( !deleteFlags( pimItems[ i ], flags ) )
            return failureResponse( "Unable to remove item flags." );
        }
        // TODO what is this about?
        if ( !silent ) {
          sendPimItemResponse( pimItems[i] );
        }
      }

      if ( flagsChanged )
        changes << AKONADI_PARAM_FLAGS;
      continue;
    }

    // handle commands that can only be applied to one item
    if ( pimItems.size() > 1 )
      throw HandlerException( "This Modification can only be applied to a single item" );
    PimItem &item = pimItems.first();
    if ( !item.isValid() )
      throw HandlerException( "Invalid item in query result!?" );

    if ( command == AKONADI_PARAM_REMOTEID ) {
      const QString rid = m_streamParser->readUtf8String();
      if ( item.remoteId() != rid ) {
        if ( !connection()->isOwnerResource( item ) )
          throw HandlerException( "Only resources can modify remote identifiers" );
        item.setRemoteId( rid );
        changes << AKONADI_PARAM_REMOTEID;
      }
    }

    else if ( command == AKONADI_PARAM_REMOTEREVISION ) {
      const QString remoteRevision = m_streamParser->readUtf8String();
      if ( item.remoteRevision() != remoteRevision ) {
        if ( !connection()->isOwnerResource( item ) )
          throw HandlerException( "Only resources can modify remote revisions" );
        item.setRemoteRevision( remoteRevision );
        changes << AKONADI_PARAM_REMOTEREVISION;
      }
    }

    else if ( command == AKONADI_PARAM_UNDIRTY ) {
      m_streamParser->readString(); // read the 'false' string
      item.setDirty( false );
    }

    else if ( command == AKONADI_PARAM_INVALIDATECACHE ) {
      invalidateCache = true;
    }

    else if ( command == AKONADI_PARAM_SIZE ) {
      mSize = m_streamParser->readNumber();
      changes << AKONADI_PARAM_SIZE;
    }

    else if ( command == "PARTS" ) {
      const QList<QByteArray> parts = m_streamParser->readParenthesizedList();
      if ( op == Delete ) {
        if ( !store->removeItemParts( item, parts ) )
          return failureResponse( "Unable to remove item parts." );
        changes += QSet<QByteArray>::fromList( parts );
      }
    }

    else if ( command == "COLLECTION" ) {
      throw HandlerException( "Item moving via STORE is deprecated, update your Akonadi client" );
    }

    // parts/attributes
    else {
      // obtain and configure the part object
      int partVersion = 0;
      QByteArray partName;
      ImapParser::splitVersionedKey( command, partName, partVersion );

      SelectQueryBuilder<Part> qb;
      qb.addValueCondition( Part::pimItemIdColumn(), Query::Equals, item.id() );
      qb.addValueCondition( Part::nameColumn(), Query::Equals, QString::fromUtf8( partName ) );
      if ( !qb.exec() )
        return failureResponse( "Unable to check item part existence" );
      Part::List result = qb.result();
      Part part;
      if ( !result.isEmpty() )
        part = result.first();
      part.setName( QString::fromUtf8( partName ) );
      part.setVersion( partVersion );
      part.setPimItemId( item.id() );

      QByteArray value;
      if ( m_streamParser->hasLiteral() ) {
        const qint64 dataSize = m_streamParser->remainingLiteralSize();
        partSizes += dataSize;
        const bool storeInFile = ( DbConfig::configuredDatabase()->useExternalPayloadFile() && dataSize > DbConfig::configuredDatabase()->sizeThreshold() );
        //actual case when streaming storage is used: external payload is enabled, data is big enough in a literal
        if ( storeInFile ) {
          // use first part as value for the initial insert into / update to the database.
          // this will give us a proper filename to stream the rest of the parts contents into
          // NOTE: we have to set the correct size (== dataSize) directly
          value = m_streamParser->readLiteralPart();
         // qDebug() << Q_FUNC_INFO << "VALUE in STORE: " << value << value.size() << dataSize;

          if ( part.isValid() ) {
            PartHelper::update( &part, value, dataSize );
          } else {
//             qDebug() << "insert from Store::handleLine";
            part.setData( value );
            part.setDatasize( dataSize );
            if ( !PartHelper::insert( &part ) )
              return failureResponse( "Unable to add item part" );
          }

          //the actual streaming code for the remaining parts:
          // reads from the parser, writes immediately to the file
          // ### move this entire block to part helper? should be useful for append as well
          const QString fileName = QString::fromUtf8( part.data() );
          QFile file( fileName );
          if ( file.open( QIODevice::WriteOnly | QIODevice::Append ) ) {
            while ( !m_streamParser->atLiteralEnd() ) {
              value = m_streamParser->readLiteralPart();
              file.write( value ); // ### error handling?
            }
            file.close();
          } else {
            return failureResponse( "Unable to update item part" );
          }

          changes << partName;
          continue;
        } else { // not store in file
          //don't write in streaming way as the data goes to the database
          while (!m_streamParser->atLiteralEnd()) {
            value += m_streamParser->readLiteralPart();
          }
        }
      } else { //not a literal
        value = m_streamParser->readString();
        partSizes += value.size();
      }

      // only relevant for non-literals or non-external literals
      const QByteArray origData = PartHelper::translateData( part );
      if ( origData != value ) {
        if ( part.isValid() ) {
          PartHelper::update( &part, value, value.size() );
        } else {
//           qDebug() << "insert from Store::handleLine: " << value.left(100);
          part.setData( value );
          part.setDatasize( value.size() );
          if ( !PartHelper::insert( &part ) )
            return failureResponse( "Unable to add item part" );
        }
        changes << partName;
      }

    } // parts/attribute modification
  }

  QString datetime;
  if ( !changes.isEmpty() ) {
    // update item size
    if ( pimItems.size() == 1 && (mSize > 0 || partSizes > 0) )
      pimItems.first().setSize( qMax( mSize, partSizes ) );

    // run update query and prepare change notifications
    for ( int i = 0; i < pimItems.count(); ++i ) {
      PimItem &item = pimItems[ i ];
      item.setDatetime( modificationtime );
      item.setAtime( modificationtime );
      if ( !connection()->isOwnerResource( item ) )
        item.setDirty( true );
      if ( !item.update() )
        throw HandlerException( "Unable to write item changes into the database" );

      if ( invalidateCache ) {
        if ( !store->invalidateItemCache( item ) ) {
          throw HandlerException( "Unable to invalidate item cache in the database" );
        }
      }

      store->notificationCollector()->itemChanged( item, changes );
    }

    if ( !transaction.commit() )
      return failureResponse( "Cannot commit transaction." );

    datetime = QLocale::c().toString( modificationtime, QLatin1String( "dd-MMM-yyyy hh:mm:ss +0000" ) );
  } else {
    datetime = QLocale::c().toString( pimItems.first().datetime(), QLatin1String( "dd-MMM-yyyy hh:mm:ss +0000" ) );
  }

  // TODO: When implementing support for modifying multiple items at once, the revisions of the items should be in the responses.
  // or only modified items should appear in the repsponse.
  Response response;
  response.setTag( tag() );
  response.setSuccess();
  response.setString( "DATETIME " + ImapParser::quote( datetime.toUtf8() ) + " STORE completed" );

  emit responseAvailable( response );
  return true;
}

void Store::parseCommand()
{
  mScope.parseScope( m_streamParser );

  // parse the stuff before the modification list
  while ( !m_streamParser->hasList() ) {
    const QByteArray command = m_streamParser->readString();
    if ( command.isEmpty() ) { // ie. we are at command end
      throw HandlerException( "No modification list provided in STORE command" );
    } else if ( command == AKONADI_PARAM_REVISION ) {
      mPreviousRevision = m_streamParser->readNumber();
      mCheckRevision = true;
    } else if ( command == AKONADI_PARAM_SIZE ) {
      mSize = m_streamParser->readNumber();
    }
  }
}

void Store::sendPimItemResponse( const PimItem &pimItem )
{
  const QVector<Flag> flags = pimItem.flags();
  QStringList flagList;
  for ( int j = 0; j < flags.count(); ++j )
    flagList.append( flags[ j ].name() );

  Response response;
  response.setUntagged();
        // IMAP protocol violation: should actually be the sequence number
  response.setString( QByteArray::number( pimItem.id() ) + " FETCH (FLAGS (" + flagList.join( QLatin1String(" ") ).toUtf8() + "))" );
  emit responseAvailable( response );
}

#include "store.moc"
<commit_msg>Enable the conflict detection for resources again.<commit_after>/***************************************************************************
 *   Copyright (C) 2006 by Tobias Koenig <tokoe@kde.org>                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU Library General Public License as       *
 *   published by the Free Software Foundation; either version 2 of the    *
 *   License, or (at your option) any later version.                       *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this program; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
 ***************************************************************************/

#include "store.h"

#include "akonadi.h"
#include "akonadiconnection.h"
#include "handlerhelper.h"
#include "response.h"
#include "storage/datastore.h"
#include "storage/transaction.h"
#include "storage/itemqueryhelper.h"
#include "storage/selectquerybuilder.h"
#include "storage/parthelper.h"
#include "storage/dbconfig.h"
#include "storage/itemretriever.h"

#include "libs/imapparser_p.h"
#include "libs/protocol_p.h"
#include "imapstreamparser.h"

#include <QtCore/QStringList>
#include <QLocale>
#include <QDebug>
#include <QFile>

#include <algorithm>
#include <functional>

using namespace Akonadi;

Store::Store( Scope::SelectionScope scope )
  : Handler()
  , mScope( scope )
  , mPos( 0 )
  , mPreviousRevision( -1 )
  , mSize( 0 )
  , mCheckRevision( false )
{
}

bool Store::replaceFlags( const PimItem &item, const QList<QByteArray> &flags )
{
  Flag::List flagList = HandlerHelper::resolveFlags( flags );
  DataStore *store = connection()->storageBackend();

  Flag::List currentFlags = item.flags();
  std::sort( flagList.begin(), flagList.end(), _detail::ById<std::less>() );
  std::sort( currentFlags.begin(), currentFlags.end(), _detail::ById<std::less>() );

  if ( flagList == currentFlags )
    return false;

  if ( !store->setItemFlags( item, flagList ) )
    throw HandlerException( "Store::replaceFlags: Unable to set new item flags" );

  return true;
}

bool Store::addFlags( const PimItem &item, const QList<QByteArray> &flags, bool& flagsChanged )
{
  const Flag::List flagList = HandlerHelper::resolveFlags( flags );
  DataStore *store = connection()->storageBackend();

  if ( !store->appendItemFlags( item, flagList, flagsChanged ) ) {
    qDebug( "Store::addFlags: Unable to add new item flags" );
    return false;
  }
  return true;
}

bool Store::deleteFlags( const PimItem &item, const QList<QByteArray> &flags )
{
  DataStore *store = connection()->storageBackend();

  QVector<Flag> flagList;
  flagList.reserve( flags.size() );
  for ( int i = 0; i < flags.count(); ++i ) {
    Flag flag = Flag::retrieveByName( QString::fromUtf8( flags[ i ] ) );
    if ( !flag.isValid() )
      continue;

    flagList.append( flag );
  }

  if ( !store->removeItemFlags( item, flagList ) ) {
    qDebug( "Store::deleteFlags: Unable to remove item flags" );
    return false;
  }
  return true;
}

bool Store::parseStream()
{
  parseCommand();
  DataStore *store = connection()->storageBackend();
  Transaction transaction( store );
   // Set the same modification time for each item.
  const QDateTime modificationtime = QDateTime::currentDateTime().toUTC();

  // retrieve selected items
  SelectQueryBuilder<PimItem> qb;
  ItemQueryHelper::scopeToQuery( mScope, connection(), qb );
  if ( !qb.exec() )
    return failureResponse( "Unable to retrieve items" );
  PimItem::List pimItems = qb.result();
  if ( pimItems.isEmpty() )
    return failureResponse( "No items found" );

  for ( int i = 0; i < pimItems.size(); ++i ) {
    if ( mCheckRevision ) {
      // check for conflicts if a resources tries to overwrite an item with dirty payload
      if ( connection()->isOwnerResource( pimItems.at( i ) ) ) {
        if ( pimItems.at( i ).dirty() )
          throw HandlerException( "[LRCONFLICT] Resource tries to modify item with dirty payload, aborting STORE." );
      }

      // check and update revisions
      if ( pimItems.at( i ).rev() != (int)mPreviousRevision )
        throw HandlerException( "[LLCONFLICT] Item was modified elsewhere, aborting STORE." );
    }
    pimItems[ i ].setRev( pimItems[ i ].rev() + 1 );
  }

  QSet<QByteArray> changes;
  qint64 partSizes = 0;
  bool invalidateCache = false;

  // apply modifications
  m_streamParser->beginList();
  while ( !m_streamParser->atListEnd() ) {
    // parse the command
    QByteArray command = m_streamParser->readString();
    if ( command.isEmpty() )
      throw HandlerException( "Syntax error" );
    Operation op = Replace;
    bool silent = false;
    if ( command.startsWith( '+' ) ) {
      op = Add;
      command = command.mid( 1 );
    } else if ( command.startsWith( '-' ) ) {
      op = Delete;
      command = command.mid( 1 );
    }
    if ( command.endsWith( ".SILENT" ) ) {
      command.chop( 7 );
      silent = true;
    }
//     qDebug() << "STORE: handling command: " << command;

    // handle commands that can be applied to more than one item
    if ( command == AKONADI_PARAM_FLAGS ) {
      bool flagsChanged = true;
      const QList<QByteArray> flags = m_streamParser->readParenthesizedList();
      // TODO move this iteration to an SQL query.
      for ( int i = 0; i < pimItems.count(); ++i ) {
        if ( op == Replace ) {
          flagsChanged = replaceFlags( pimItems[ i ], flags );
        } else if ( op == Add ) {
          if ( !addFlags( pimItems[ i ], flags, flagsChanged ) )
            return failureResponse( "Unable to add item flags." );
        } else if ( op == Delete ) {
          if ( !deleteFlags( pimItems[ i ], flags ) )
            return failureResponse( "Unable to remove item flags." );
        }
        // TODO what is this about?
        if ( !silent ) {
          sendPimItemResponse( pimItems[i] );
        }
      }

      if ( flagsChanged )
        changes << AKONADI_PARAM_FLAGS;
      continue;
    }

    // handle commands that can only be applied to one item
    if ( pimItems.size() > 1 )
      throw HandlerException( "This Modification can only be applied to a single item" );
    PimItem &item = pimItems.first();
    if ( !item.isValid() )
      throw HandlerException( "Invalid item in query result!?" );

    if ( command == AKONADI_PARAM_REMOTEID ) {
      const QString rid = m_streamParser->readUtf8String();
      if ( item.remoteId() != rid ) {
        if ( !connection()->isOwnerResource( item ) )
          throw HandlerException( "Only resources can modify remote identifiers" );
        item.setRemoteId( rid );
        changes << AKONADI_PARAM_REMOTEID;
      }
    }

    else if ( command == AKONADI_PARAM_REMOTEREVISION ) {
      const QString remoteRevision = m_streamParser->readUtf8String();
      if ( item.remoteRevision() != remoteRevision ) {
        if ( !connection()->isOwnerResource( item ) )
          throw HandlerException( "Only resources can modify remote revisions" );
        item.setRemoteRevision( remoteRevision );
        changes << AKONADI_PARAM_REMOTEREVISION;
      }
    }

    else if ( command == AKONADI_PARAM_UNDIRTY ) {
      m_streamParser->readString(); // read the 'false' string
      item.setDirty( false );
    }

    else if ( command == AKONADI_PARAM_INVALIDATECACHE ) {
      invalidateCache = true;
    }

    else if ( command == AKONADI_PARAM_SIZE ) {
      mSize = m_streamParser->readNumber();
      changes << AKONADI_PARAM_SIZE;
    }

    else if ( command == "PARTS" ) {
      const QList<QByteArray> parts = m_streamParser->readParenthesizedList();
      if ( op == Delete ) {
        if ( !store->removeItemParts( item, parts ) )
          return failureResponse( "Unable to remove item parts." );
        changes += QSet<QByteArray>::fromList( parts );
      }
    }

    else if ( command == "COLLECTION" ) {
      throw HandlerException( "Item moving via STORE is deprecated, update your Akonadi client" );
    }

    // parts/attributes
    else {
      // obtain and configure the part object
      int partVersion = 0;
      QByteArray partName;
      ImapParser::splitVersionedKey( command, partName, partVersion );

      SelectQueryBuilder<Part> qb;
      qb.addValueCondition( Part::pimItemIdColumn(), Query::Equals, item.id() );
      qb.addValueCondition( Part::nameColumn(), Query::Equals, QString::fromUtf8( partName ) );
      if ( !qb.exec() )
        return failureResponse( "Unable to check item part existence" );
      Part::List result = qb.result();
      Part part;
      if ( !result.isEmpty() )
        part = result.first();
      part.setName( QString::fromUtf8( partName ) );
      part.setVersion( partVersion );
      part.setPimItemId( item.id() );

      QByteArray value;
      if ( m_streamParser->hasLiteral() ) {
        const qint64 dataSize = m_streamParser->remainingLiteralSize();
        partSizes += dataSize;
        const bool storeInFile = ( DbConfig::configuredDatabase()->useExternalPayloadFile() && dataSize > DbConfig::configuredDatabase()->sizeThreshold() );
        //actual case when streaming storage is used: external payload is enabled, data is big enough in a literal
        if ( storeInFile ) {
          // use first part as value for the initial insert into / update to the database.
          // this will give us a proper filename to stream the rest of the parts contents into
          // NOTE: we have to set the correct size (== dataSize) directly
          value = m_streamParser->readLiteralPart();
         // qDebug() << Q_FUNC_INFO << "VALUE in STORE: " << value << value.size() << dataSize;

          if ( part.isValid() ) {
            PartHelper::update( &part, value, dataSize );
          } else {
//             qDebug() << "insert from Store::handleLine";
            part.setData( value );
            part.setDatasize( dataSize );
            if ( !PartHelper::insert( &part ) )
              return failureResponse( "Unable to add item part" );
          }

          //the actual streaming code for the remaining parts:
          // reads from the parser, writes immediately to the file
          // ### move this entire block to part helper? should be useful for append as well
          const QString fileName = QString::fromUtf8( part.data() );
          QFile file( fileName );
          if ( file.open( QIODevice::WriteOnly | QIODevice::Append ) ) {
            while ( !m_streamParser->atLiteralEnd() ) {
              value = m_streamParser->readLiteralPart();
              file.write( value ); // ### error handling?
            }
            file.close();
          } else {
            return failureResponse( "Unable to update item part" );
          }

          changes << partName;
          continue;
        } else { // not store in file
          //don't write in streaming way as the data goes to the database
          while (!m_streamParser->atLiteralEnd()) {
            value += m_streamParser->readLiteralPart();
          }
        }
      } else { //not a literal
        value = m_streamParser->readString();
        partSizes += value.size();
      }

      // only relevant for non-literals or non-external literals
      const QByteArray origData = PartHelper::translateData( part );
      if ( origData != value ) {
        if ( part.isValid() ) {
          PartHelper::update( &part, value, value.size() );
        } else {
//           qDebug() << "insert from Store::handleLine: " << value.left(100);
          part.setData( value );
          part.setDatasize( value.size() );
          if ( !PartHelper::insert( &part ) )
            return failureResponse( "Unable to add item part" );
        }
        changes << partName;
      }

    } // parts/attribute modification
  }

  QString datetime;
  if ( !changes.isEmpty() ) {
    // update item size
    if ( pimItems.size() == 1 && (mSize > 0 || partSizes > 0) )
      pimItems.first().setSize( qMax( mSize, partSizes ) );

    // run update query and prepare change notifications
    for ( int i = 0; i < pimItems.count(); ++i ) {
      PimItem &item = pimItems[ i ];
      item.setDatetime( modificationtime );
      item.setAtime( modificationtime );
      if ( !connection()->isOwnerResource( item ) )
        item.setDirty( true );
      if ( !item.update() )
        throw HandlerException( "Unable to write item changes into the database" );

      if ( invalidateCache ) {
        if ( !store->invalidateItemCache( item ) ) {
          throw HandlerException( "Unable to invalidate item cache in the database" );
        }
      }

      store->notificationCollector()->itemChanged( item, changes );
    }

    if ( !transaction.commit() )
      return failureResponse( "Cannot commit transaction." );

    datetime = QLocale::c().toString( modificationtime, QLatin1String( "dd-MMM-yyyy hh:mm:ss +0000" ) );
  } else {
    datetime = QLocale::c().toString( pimItems.first().datetime(), QLatin1String( "dd-MMM-yyyy hh:mm:ss +0000" ) );
  }

  // TODO: When implementing support for modifying multiple items at once, the revisions of the items should be in the responses.
  // or only modified items should appear in the repsponse.
  Response response;
  response.setTag( tag() );
  response.setSuccess();
  response.setString( "DATETIME " + ImapParser::quote( datetime.toUtf8() ) + " STORE completed" );

  emit responseAvailable( response );
  return true;
}

void Store::parseCommand()
{
  mScope.parseScope( m_streamParser );

  // parse the stuff before the modification list
  while ( !m_streamParser->hasList() ) {
    const QByteArray command = m_streamParser->readString();
    if ( command.isEmpty() ) { // ie. we are at command end
      throw HandlerException( "No modification list provided in STORE command" );
    } else if ( command == AKONADI_PARAM_REVISION ) {
      mPreviousRevision = m_streamParser->readNumber();
      mCheckRevision = true;
    } else if ( command == AKONADI_PARAM_SIZE ) {
      mSize = m_streamParser->readNumber();
    }
  }
}

void Store::sendPimItemResponse( const PimItem &pimItem )
{
  const QVector<Flag> flags = pimItem.flags();
  QStringList flagList;
  for ( int j = 0; j < flags.count(); ++j )
    flagList.append( flags[ j ].name() );

  Response response;
  response.setUntagged();
        // IMAP protocol violation: should actually be the sequence number
  response.setString( QByteArray::number( pimItem.id() ) + " FETCH (FLAGS (" + flagList.join( QLatin1String(" ") ).toUtf8() + "))" );
  emit responseAvailable( response );
}

#include "store.moc"
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: options.hxx,v $
 *
 *  $Revision: 1.20 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-19 23:24:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONFIGMGR_MISC_OPTIONS_HXX_
#define CONFIGMGR_MISC_OPTIONS_HXX_

#ifndef CONFIGMGR_MISC_REQUESTOPTIONS_HXX_
#include "requestoptions.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef _SALHELPER_SIMPLEREFERENCEOBJECT_HXX_
#include <salhelper/simplereferenceobject.hxx>
#endif
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif

namespace configmgr
{
    namespace css  = ::com::sun::star;

    /**
       class OOptions is created one time per Configuration[update]Access
       all important options should stored in this class.
       The object will be forwarded to all other objects so we only
       need to extend this classobject and all other class can work with
       the new options or important options etc.
    */

    class OOptions : public salhelper::SimpleReferenceObject
    {
        RequestOptions  m_aRequestOptions;  // current options to use

    public:
        typedef RequestOptions::Locale Locale;
        typedef RequestOptions::LocaleString LocaleString;
        typedef RequestOptions::Entity Entity;

        OOptions()
        : m_aRequestOptions()
        {}

        explicit
        OOptions(const RequestOptions& _aDefaultOptions)
        : m_aRequestOptions(_aDefaultOptions)
        {
        }

        OOptions(const OOptions& _aOtherOptions)
        : salhelper::SimpleReferenceObject()
        , m_aRequestOptions(_aOtherOptions.m_aRequestOptions)
        {
        }

        bool isForSessionUser()     const { return ! m_aRequestOptions.hasEntity(); }

        LocaleString    getLocale() const { return m_aRequestOptions.getLocale(); }
        Entity          getUser()   const { return m_aRequestOptions.getEntity(); }

        RequestOptions const & getRequestOptions() const
        { return m_aRequestOptions; }

        void setUser(const Entity & _rUser)
        { m_aRequestOptions.setEntity(_rUser); }

        void setLocale(const Locale & _rLocale)
        { m_aRequestOptions.setLocale(_rLocale); }

        void setMultiLocaleMode()
        { m_aRequestOptions.setAllLocales(); }

        void enableAsync(bool _bEnable)
        { m_aRequestOptions.enableAsync(_bEnable); }
    };
    typedef vos::ORef<OOptions> OptionsRef;

    struct ltOptions
    {
        lessRequestOptions ltData;
        bool operator()(OptionsRef const &o1, OptionsRef const &o2) const
        {
            return ltData(o1->getRequestOptions(),o2->getRequestOptions());
        }
    };
} // namespace

#endif
<commit_msg>INTEGRATION: CWS configrefactor01 (1.20.42); FILE MERGED 2007/01/11 20:16:01 mmeeks 1.20.42.1: Submitted by: mmeeks More re-factoring, lots of locking rationalized, drastically reduced the mutex count, also removed ~300k interlocked increments with a non-interlocking SimpleReferencedObject base<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: options.hxx,v $
 *
 *  $Revision: 1.21 $
 *
 *  last change: $Author: ihi $ $Date: 2007-11-23 14:22:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef CONFIGMGR_MISC_OPTIONS_HXX_
#define CONFIGMGR_MISC_OPTIONS_HXX_

#ifndef CONFIGMGR_MISC_REQUESTOPTIONS_HXX_
#include "requestoptions.hxx"
#endif

#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif

#ifndef CONFIGMGR_UTILITY_HXX_
#include "utility.hxx"
#endif
#ifndef _VOS_REF_HXX_
#include <vos/ref.hxx>
#endif

namespace configmgr
{
    namespace css  = ::com::sun::star;

    /**
       class OOptions is created one time per Configuration[update]Access
       all important options should stored in this class.
       The object will be forwarded to all other objects so we only
       need to extend this classobject and all other class can work with
       the new options or important options etc.
    */

    class OOptions : public configmgr::SimpleReferenceObject
    {
        RequestOptions  m_aRequestOptions;  // current options to use

    public:
        typedef RequestOptions::Locale Locale;
        typedef RequestOptions::LocaleString LocaleString;
        typedef RequestOptions::Entity Entity;

        OOptions()
        : m_aRequestOptions()
        {}

        explicit
        OOptions(const RequestOptions& _aDefaultOptions)
        : m_aRequestOptions(_aDefaultOptions)
        {
        }

        OOptions(const OOptions& _aOtherOptions)
        : configmgr::SimpleReferenceObject()
        , m_aRequestOptions(_aOtherOptions.m_aRequestOptions)
        {
        }

        bool isForSessionUser()     const { return ! m_aRequestOptions.hasEntity(); }

        LocaleString    getLocale() const { return m_aRequestOptions.getLocale(); }
        Entity          getUser()   const { return m_aRequestOptions.getEntity(); }

        RequestOptions const & getRequestOptions() const
        { return m_aRequestOptions; }

        void setUser(const Entity & _rUser)
        { m_aRequestOptions.setEntity(_rUser); }

        void setLocale(const Locale & _rLocale)
        { m_aRequestOptions.setLocale(_rLocale); }

        void setMultiLocaleMode()
        { m_aRequestOptions.setAllLocales(); }

        void enableAsync(bool _bEnable)
        { m_aRequestOptions.enableAsync(_bEnable); }
    };
    typedef vos::ORef<OOptions> OptionsRef;

    struct ltOptions
    {
        lessRequestOptions ltData;
        bool operator()(OptionsRef const &o1, OptionsRef const &o2) const
        {
            return ltData(o1->getRequestOptions(),o2->getRequestOptions());
        }
    };
} // namespace

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: tracer.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: hr $ $Date: 2000-11-07 12:14:37 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// SUNPRO5 does not like the following to be done after including stdio.h, that's why it's here at the very
// beginning of the file
#undef _TIME_T_DEFINED
#include <time.h>
#include <rtl/string.hxx>
#include <map>

namespace configmgr
{
    typedef ::std::map< ::rtl::OString, void*, ::std::less< ::rtl::OString > > VirtualDevices;
}

#ifndef _CONFIGMGR_TRACER_HXX_
#include "tracer.hxx"
#endif

#ifdef CFG_ENABLE_TRACING

#include <cstdarg>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#define INFO    1
#define WARNING 2
#define ERROR   4

namespace configmgr
{

struct OTracerSetup
{
    sal_Int32       s_nTraceMask;
    sal_Int32       s_nIndentDepth;
    FILE*           s_pOutputMedium;
    sal_Bool        s_bInitialized;

    VirtualDevices  s_aDevices;

    OTracerSetup()
        :s_nTraceMask(INFO | WARNING | ERROR)
        ,s_nIndentDepth(0)
        ,s_pOutputMedium(NULL)
        ,s_bInitialized(sal_False)
    {
    }
};

//==========================================================================
//= OConfigTracer
//==========================================================================
::osl::Mutex    OConfigTracer::s_aMutex;
OTracerSetup*   OConfigTracer::s_pImpl = NULL;

//--------------------------------------------------------------------------
void OConfigTracer::ensureData()
{
    if (s_pImpl)
        return;
    s_pImpl = new OTracerSetup;
}

//--------------------------------------------------------------------------
void OConfigTracer::inc()
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    ++s_pImpl->s_nIndentDepth;
}

//--------------------------------------------------------------------------
void OConfigTracer::dec()
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    --s_pImpl->s_nIndentDepth;
}

//--------------------------------------------------------------------------
void OConfigTracer::traceInfo(const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    if (s_pImpl->s_nTraceMask & INFO)
    {
        va_list args;
        va_start(args, _pFormat);
        implTrace("info    : ", _pFormat, args);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
void OConfigTracer::traceWarning(const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    if (s_pImpl->s_nTraceMask & WARNING)
    {
        va_list args;
        va_start(args, _pFormat);
        implTrace("warning : ", _pFormat, args);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
void OConfigTracer::traceError(const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    if (s_pImpl->s_nTraceMask & ERROR)
    {
        va_list args;
        va_start(args, _pFormat);
        implTrace("error   : ", _pFormat, args);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
void OConfigTracer::indent()
{
    for (sal_Int32 i=0; i<s_pImpl->s_nIndentDepth; ++i)
        fprintf(s_pImpl->s_pOutputMedium, " ");
}

//--------------------------------------------------------------------------
FILE* disambiguate(const ::rtl::OString& _rFileName)
{
    FILE* pExistenceCheck = NULL;
    sal_Int32 i = 1;
    ::rtl::OString sLoop;
    while (i <= 256)
    {
        sLoop = _rFileName;
        sLoop += ".";
        sLoop += ::rtl::OString::valueOf(i);

        pExistenceCheck = fopen(sLoop.getStr(), "r");
        if (!pExistenceCheck)
            // does not exist
            return fopen(sLoop.getStr(), "w+");

        // already exists, try the next name
        fclose(pExistenceCheck);
        ++i;
    }

    // could not open such a file
    return NULL;
}

//--------------------------------------------------------------------------
void OConfigTracer::ensureInitalized()
{
    if (s_pImpl->s_bInitialized)
        return;

    s_pImpl->s_bInitialized = sal_True;

    char* pSettings = getenv("ENVCFGFLAGS");
    if (!pSettings)
        return;

    /*  currently recognized structure :
        + switches have to be separated by whitespaces
        + valid switches are:
            -m[e|o|f<file>] -   output to stderr (e), stdout (o) or a file (f). In the latter case the whole rest
                                of the param ('til the next one, means 'til the next whitespace) is the filename
            -t{i,w,e}*      -   type of output : i includes infos, w includes warnings, e includes errors
    */

    s_pImpl->s_pOutputMedium = stderr;
    s_pImpl->s_nTraceMask = 0;

    char* pParamLoop = pSettings;
    while (*pParamLoop)
    {
        while (!isspace(*pParamLoop) && *pParamLoop)
            ++pParamLoop;

        sal_Int32 nLen = pParamLoop - pSettings;
        if ((nLen > 1) && (*pSettings == '-'))
        {
            ++pSettings;
            switch (*pSettings)
            {
                case 'm':
                case 'w':
                    if (nLen > 2)
                    {
                        ++pSettings;
                        switch (*pSettings)
                        {
                            case 'e':
                                s_pImpl->s_pOutputMedium = stderr;
                                break;
                            case 'o':
                                s_pImpl->s_pOutputMedium = stdout;
                                break;
                            case 'f':
                            {
                                ++pSettings;
                                // copy the filename into an own buffer
                                ::rtl::OString sFileName(pSettings, pParamLoop - pSettings);

                                // open the file
                                s_pImpl->s_pOutputMedium = disambiguate(sFileName);

                                break;
                            }
                        }
                    }
                    break;
                case 'd':
                {   // assign a virtual device
                    // copy the device assingment description
                    ::rtl::OString sDescription(pSettings + 1, pParamLoop - pSettings - 1);
                    sal_Int32 nSep = sDescription.indexOf(':');
                    if (-1 == nSep)
                        break;  // invalid format

                    ::rtl::OString sVirtualDeviceName, sFileName;
                    sVirtualDeviceName = sDescription.copy(0, nSep);
                    sFileName = sDescription.copy(nSep + 1);

                    FILE* pVirtualDevice = disambiguate(sFileName);
                    if (pVirtualDevice)
                        s_pImpl->s_aDevices[sVirtualDeviceName] = pVirtualDevice;
                }
                case 't':
                {
                    ++pSettings;
                    while (pSettings != pParamLoop)
                    {
                        switch (*pSettings)
                        {
                            case 'i':   s_pImpl->s_nTraceMask |= INFO; break;
                            case 'w':   s_pImpl->s_nTraceMask |= WARNING; break;
                            case 'e':   s_pImpl->s_nTraceMask |= ERROR; break;
                        }
                        ++pSettings;
                    }
                }
            }
        }

        if (!*pParamLoop)
            break;

        ++pParamLoop;
        pSettings = pParamLoop;
    }
}
//--------------------------------------------------------------------------
void OConfigTracer::traceToVirtualDevice(const sal_Char* _pDeviceName, const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    ensureInitalized();

    VirtualDevices::const_iterator aDeviceMediumPos = s_pImpl->s_aDevices.find(::rtl::OString(_pDeviceName));
    if (aDeviceMediumPos != s_pImpl->s_aDevices.end())
    {
        FILE* pDeviceMedium = (FILE*)aDeviceMediumPos->second;

        va_list args;
        va_start(args, _pFormat);
        vfprintf(pDeviceMedium, _pFormat, args);
        fflush(pDeviceMedium);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
::rtl::OString OConfigTracer::getTimeStamp()
{
    time_t aTime = time(NULL);
    tm* pStructuredTime = gmtime(&aTime);
    ::rtl::OString sTimeStamp(asctime(pStructuredTime));
    // cut the trainling linefeed (asctime is defined to contain such a line feed)
    sal_Int32 nStampLen = sTimeStamp.getLength();
    if ((0 != nStampLen) && ('\n' == sTimeStamp.getStr()[nStampLen - 1]))
        sTimeStamp = sTimeStamp.copy(0, nStampLen - 1);

    return sTimeStamp;
}

//--------------------------------------------------------------------------
void OConfigTracer::implTrace(const sal_Char* _pType, const sal_Char* _pFormat, va_list args)
{
    ensureInitalized();
    if (!s_pImpl->s_pOutputMedium)
        // no tracing enabled
        return;

    fprintf(s_pImpl->s_pOutputMedium, "%s", _pType);
    indent();
    vfprintf(s_pImpl->s_pOutputMedium, _pFormat, args);
    fprintf(s_pImpl->s_pOutputMedium,"\n");
    fflush(s_pImpl->s_pOutputMedium);
}

}   // namespace configmgr

#endif // defined(DEBUG) || defined(_DEBUG)

//**************************************************************************
// history:
//  $Log: not supported by cvs2svn $
//  Revision 1.1.1.1  2000/09/18 16:13:41  hr
//  initial import
//
//  Revision 1.7  2000/09/15 09:51:51  willem.vandorp
//  OpenOffice header added
//
//  Revision 1.6  2000/08/31 10:00:21  fs
//  time_t unknown
//
//  Revision 1.5  2000/08/30 14:34:09  fs
//  getTimeStamp
//
//  Revision 1.4  2000/08/20 12:55:42  fs
//  #77860# introduced an impl class; introduces virtual trace devices
//
//  Revision 1.3  2000/08/17 07:18:02  lla
//  im/export
//
//  Revision 1.2  2000/08/10 06:53:45  fs
//  read settings from the ENVCFGFLAGS environment variable
//
//  Revision 1.1  2000/08/09 18:52:46  fs
//  helper classes for tracing
//
//
//  Revision 1.0 09.08.00 13:10:05  fs
//**************************************************************************

<commit_msg>#80122# additional traces upon initialization (process id / executable name)<commit_after>/*************************************************************************
 *
 *  $RCSfile: tracer.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: fs $ $Date: 2000-11-29 12:45:31 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

// SUNPRO5 does not like the following to be done after including stdio.h, that's why it's here at the very
// beginning of the file
#undef _TIME_T_DEFINED
#include <time.h>
#include <rtl/string.hxx>
#include <map>

namespace configmgr
{
    typedef ::std::map< ::rtl::OString, void*, ::std::less< ::rtl::OString > > VirtualDevices;
}

#ifndef _CONFIGMGR_TRACER_HXX_
#include "tracer.hxx"
#endif

#ifdef CFG_ENABLE_TRACING

#include <cstdarg>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>

#include <osl/process.h>
#include <rtl/ustring.hxx>

#define INFO    1
#define WARNING 2
#define ERROR   4

namespace configmgr
{

struct OTracerSetup
{
    sal_Int32       s_nTraceMask;
    sal_Int32       s_nIndentDepth;
    FILE*           s_pOutputMedium;
    sal_Bool        s_bInitialized;

    VirtualDevices  s_aDevices;

    OTracerSetup()
        :s_nTraceMask(INFO | WARNING | ERROR)
        ,s_nIndentDepth(0)
        ,s_pOutputMedium(NULL)
        ,s_bInitialized(sal_False)
    {
    }
};

//==========================================================================
//= OConfigTracer
//==========================================================================
::osl::Mutex    OConfigTracer::s_aMutex;
OTracerSetup*   OConfigTracer::s_pImpl = NULL;

//--------------------------------------------------------------------------
void OConfigTracer::ensureData()
{
    if (s_pImpl)
        return;
    s_pImpl = new OTracerSetup;
}

//--------------------------------------------------------------------------
void OConfigTracer::inc()
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    ++s_pImpl->s_nIndentDepth;
}

//--------------------------------------------------------------------------
void OConfigTracer::dec()
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    --s_pImpl->s_nIndentDepth;
}

//--------------------------------------------------------------------------
void OConfigTracer::traceInfo(const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    if (s_pImpl->s_nTraceMask & INFO)
    {
        va_list args;
        va_start(args, _pFormat);
        implTrace("info    : ", _pFormat, args);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
void OConfigTracer::traceWarning(const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    if (s_pImpl->s_nTraceMask & WARNING)
    {
        va_list args;
        va_start(args, _pFormat);
        implTrace("warning : ", _pFormat, args);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
void OConfigTracer::traceError(const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    if (s_pImpl->s_nTraceMask & ERROR)
    {
        va_list args;
        va_start(args, _pFormat);
        implTrace("error   : ", _pFormat, args);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
void OConfigTracer::indent()
{
    for (sal_Int32 i=0; i<s_pImpl->s_nIndentDepth; ++i)
        fprintf(s_pImpl->s_pOutputMedium, " ");
}

//--------------------------------------------------------------------------
FILE* disambiguate(const ::rtl::OString& _rFileName)
{
    FILE* pExistenceCheck = NULL;
    sal_Int32 i = 1;
    ::rtl::OString sLoop;
    while (i <= 256)
    {
        sLoop = _rFileName;
        sLoop += ".";
        sLoop += ::rtl::OString::valueOf(i);

        pExistenceCheck = fopen(sLoop.getStr(), "r");
        if (!pExistenceCheck)
            // does not exist
            return fopen(sLoop.getStr(), "w+");

        // already exists, try the next name
        fclose(pExistenceCheck);
        ++i;
    }

    // could not open such a file
    return NULL;
}

//--------------------------------------------------------------------------
void OConfigTracer::ensureInitalized()
{
    if (s_pImpl->s_bInitialized)
        return;

    s_pImpl->s_bInitialized = sal_True;

    char* pSettings = getenv("ENVCFGFLAGS");
    if (!pSettings)
        return;

    /*  currently recognized structure :
        + switches have to be separated by whitespaces
        + valid switches are:
            -m[e|o|f<file>] -   output to stderr (e), stdout (o) or a file (f). In the latter case the whole rest
                                of the param ('til the next one, means 'til the next whitespace) is the filename
            -t{i,w,e}*      -   type of output : i includes infos, w includes warnings, e includes errors
    */

    s_pImpl->s_pOutputMedium = stderr;
    s_pImpl->s_nTraceMask = 0;

    char* pParamLoop = pSettings;
    while (*pParamLoop)
    {
        while (!isspace(*pParamLoop) && *pParamLoop)
            ++pParamLoop;

        sal_Int32 nLen = pParamLoop - pSettings;
        if ((nLen > 1) && (*pSettings == '-'))
        {
            ++pSettings;
            switch (*pSettings)
            {
                case 'm':
                case 'w':
                    if (nLen > 2)
                    {
                        ++pSettings;
                        switch (*pSettings)
                        {
                            case 'e':
                                s_pImpl->s_pOutputMedium = stderr;
                                break;
                            case 'o':
                                s_pImpl->s_pOutputMedium = stdout;
                                break;
                            case 'f':
                            {
                                ++pSettings;
                                // copy the filename into an own buffer
                                ::rtl::OString sFileName(pSettings, pParamLoop - pSettings);

                                // open the file
                                s_pImpl->s_pOutputMedium = disambiguate(sFileName);

                                break;
                            }
                        }
                    }
                    break;
                case 'd':
                {   // assign a virtual device
                    // copy the device assingment description
                    ::rtl::OString sDescription(pSettings + 1, pParamLoop - pSettings - 1);
                    sal_Int32 nSep = sDescription.indexOf(':');
                    if (-1 == nSep)
                        break;  // invalid format

                    ::rtl::OString sVirtualDeviceName, sFileName;
                    sVirtualDeviceName = sDescription.copy(0, nSep);
                    sFileName = sDescription.copy(nSep + 1);

                    FILE* pVirtualDevice = disambiguate(sFileName);
                    if (pVirtualDevice)
                        s_pImpl->s_aDevices[sVirtualDeviceName] = pVirtualDevice;
                }
                case 't':
                {
                    ++pSettings;
                    while (pSettings != pParamLoop)
                    {
                        switch (*pSettings)
                        {
                            case 'i':   s_pImpl->s_nTraceMask |= INFO; break;
                            case 'w':   s_pImpl->s_nTraceMask |= WARNING; break;
                            case 'e':   s_pImpl->s_nTraceMask |= ERROR; break;
                        }
                        ++pSettings;
                    }
                }
            }
        }

        if (!*pParamLoop)
            break;

        ++pParamLoop;
        pSettings = pParamLoop;
    }

    // trace some initial information
    CFG_TRACE_INFO_NI("initialization: process id: 0x%08X", osl_getProcess(0));
    ::rtl::OUString sExecutable;
    osl_getExecutableFile(&sExecutable.pData);
    CFG_TRACE_INFO_NI("initialization: executable file name: %s", OUSTRING2ASCII(sExecutable));
}

//--------------------------------------------------------------------------
void OConfigTracer::traceToVirtualDevice(const sal_Char* _pDeviceName, const sal_Char* _pFormat, ...)
{
    ::osl::MutexGuard aGuard(s_aMutex);
    ensureData();
    ensureInitalized();

    VirtualDevices::const_iterator aDeviceMediumPos = s_pImpl->s_aDevices.find(::rtl::OString(_pDeviceName));
    if (aDeviceMediumPos != s_pImpl->s_aDevices.end())
    {
        FILE* pDeviceMedium = (FILE*)aDeviceMediumPos->second;

        va_list args;
        va_start(args, _pFormat);
        vfprintf(pDeviceMedium, _pFormat, args);
        fflush(pDeviceMedium);
        va_end(args);
    }
}

//--------------------------------------------------------------------------
::rtl::OString OConfigTracer::getTimeStamp()
{
    time_t aTime = time(NULL);
    tm* pStructuredTime = gmtime(&aTime);
    ::rtl::OString sTimeStamp(asctime(pStructuredTime));
    // cut the trainling linefeed (asctime is defined to contain such a line feed)
    sal_Int32 nStampLen = sTimeStamp.getLength();
    if ((0 != nStampLen) && ('\n' == sTimeStamp.getStr()[nStampLen - 1]))
        sTimeStamp = sTimeStamp.copy(0, nStampLen - 1);

    return sTimeStamp;
}

//--------------------------------------------------------------------------
void OConfigTracer::implTrace(const sal_Char* _pType, const sal_Char* _pFormat, va_list args)
{
    ensureInitalized();
    if (!s_pImpl->s_pOutputMedium)
        // no tracing enabled
        return;

    fprintf(s_pImpl->s_pOutputMedium, "%s", _pType);
    indent();
    vfprintf(s_pImpl->s_pOutputMedium, _pFormat, args);
    fprintf(s_pImpl->s_pOutputMedium,"\n");
    fflush(s_pImpl->s_pOutputMedium);
}

}   // namespace configmgr

#endif // defined(DEBUG) || defined(_DEBUG)

//**************************************************************************
// history:
//  $Log: not supported by cvs2svn $
//  Revision 1.2  2000/11/07 12:14:37  hr
//  #65293#: includes
//
//  Revision 1.1.1.1  2000/09/18 16:13:41  hr
//  initial import
//
//  Revision 1.7  2000/09/15 09:51:51  willem.vandorp
//  OpenOffice header added
//
//  Revision 1.6  2000/08/31 10:00:21  fs
//  time_t unknown
//
//  Revision 1.5  2000/08/30 14:34:09  fs
//  getTimeStamp
//
//  Revision 1.4  2000/08/20 12:55:42  fs
//  #77860# introduced an impl class; introduces virtual trace devices
//
//  Revision 1.3  2000/08/17 07:18:02  lla
//  im/export
//
//  Revision 1.2  2000/08/10 06:53:45  fs
//  read settings from the ENVCFGFLAGS environment variable
//
//  Revision 1.1  2000/08/09 18:52:46  fs
//  helper classes for tracing
//
//
//  Revision 1.0 09.08.00 13:10:05  fs
//**************************************************************************

<|endoftext|>


<commit_before>/*
    Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QUrl>

#include "nepomuksearch.h"

#include "search/result.h"

using namespace Akonadi;

static qint64 uriToItemId( const QUrl &url )
{
  bool ok = false;

  const qint64 id = url.queryItemValue( QLatin1String( "item" ) ).toLongLong( &ok );

  if ( !ok )
    return -1;
  else
    return id;
}

NepomukSearch::NepomukSearch( QObject* parent )
  : QObject( parent ), mSearchService( 0 )
{
  if ( !Nepomuk::Search::QueryServiceClient::serviceAvailable() ) {
    qWarning() << "Nepomuk QueryServer interface not available!";
  } else {
    mSearchService = new Nepomuk::Search::QueryServiceClient( this );
    connect( mSearchService, SIGNAL( newEntries( const QList<Nepomuk::Search::Result>& ) ),
             this, SLOT( hitsAdded( const QList<Nepomuk::Search::Result>& ) ) );
  }
}

NepomukSearch::~NepomukSearch()
{
  if ( mSearchService ) {
    mSearchService->close();
    delete mSearchService;
  }
}

QStringList NepomukSearch::search( const QString &query )
{
  if ( !mSearchService ) {
    qWarning() << "Nepomuk search service not available!";
    return QStringList();
  }

  mSearchService->blockingQuery( query );

  return mMatchingUIDs.toList();
}

void NepomukSearch::hitsAdded( const QList<Nepomuk::Search::Result>& entries )
{
  if ( !mSearchService ) {
    qWarning() << "Nepomuk search service not available!";
    return;
  }

  Q_FOREACH( const Nepomuk::Search::Result &result, entries ) {
    const qint64 itemId = uriToItemId( result.resourceUri() );

    if ( itemId == -1 ) {
      qWarning() << "Nepomuk QueryServer: Retrieved invalid item id from server!";
      continue;
    }

    mMatchingUIDs.insert( QString::number( itemId ) );
  }
}

#include "nepomuksearch.moc"
<commit_msg>Finding objects not handled by Akonadi is perfectly normal here, so no need to warn about that.<commit_after>/*
    Copyright (c) 2009 Tobias Koenig <tokoe@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include <QtCore/QDebug>
#include <QtCore/QStringList>
#include <QtCore/QUrl>

#include "nepomuksearch.h"

#include "search/result.h"

using namespace Akonadi;

static qint64 uriToItemId( const QUrl &url )
{
  bool ok = false;

  const qint64 id = url.queryItemValue( QLatin1String( "item" ) ).toLongLong( &ok );

  if ( !ok )
    return -1;
  else
    return id;
}

NepomukSearch::NepomukSearch( QObject* parent )
  : QObject( parent ), mSearchService( 0 )
{
  if ( !Nepomuk::Search::QueryServiceClient::serviceAvailable() ) {
    qWarning() << "Nepomuk QueryServer interface not available!";
  } else {
    mSearchService = new Nepomuk::Search::QueryServiceClient( this );
    connect( mSearchService, SIGNAL( newEntries( const QList<Nepomuk::Search::Result>& ) ),
             this, SLOT( hitsAdded( const QList<Nepomuk::Search::Result>& ) ) );
  }
}

NepomukSearch::~NepomukSearch()
{
  if ( mSearchService ) {
    mSearchService->close();
    delete mSearchService;
  }
}

QStringList NepomukSearch::search( const QString &query )
{
  if ( !mSearchService ) {
    qWarning() << "Nepomuk search service not available!";
    return QStringList();
  }

  mSearchService->blockingQuery( query );

  return mMatchingUIDs.toList();
}

void NepomukSearch::hitsAdded( const QList<Nepomuk::Search::Result>& entries )
{
  if ( !mSearchService ) {
    qWarning() << "Nepomuk search service not available!";
    return;
  }

  Q_FOREACH( const Nepomuk::Search::Result &result, entries ) {
    const qint64 itemId = uriToItemId( result.resourceUri() );

    if ( itemId == -1 )
      continue;

    mMatchingUIDs.insert( QString::number( itemId ) );
  }
}

#include "nepomuksearch.moc"
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cmtree.cxx,v $
 *
 *  $Revision: 1.36 $
 *
 *  last change: $Author: ihi $ $Date: 2006-08-24 10:42:17 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include <stdio.h>

#include "subtree.hxx"
#ifndef CONFIGMGR_CHANGE_HXX
#include "change.hxx"
#endif
#ifndef CONFIGMGR_TREECHANGELIST_HXX
#include "treechangelist.hxx"
#endif

#ifndef CONFIGMGR_TREEPROVIDER_HXX
#include "treeprovider.hxx"
#endif

//#include "treeactions.hxx"

#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef INCLUDED_DEQUE
#include <deque>
#define INCLUDED_DEQUE
#endif
#ifndef INCLUDED_VECTOR
#include <vector>
#define INCLUDED_VECTOR
#endif
#ifndef INCLUDED_IOSTREAM
#include <iostream>
#define INCLUDED_IOSTREAM
#endif
#ifndef INCLUDED_EXCEPTION
#include <exception>
#define INCLUDED_EXCEPTION
#endif
#ifndef INCLUDED_SET
#include <set>
#define INCLUDED_SET
#endif

using namespace std;
using namespace rtl;
using namespace com::sun::star::uno;

namespace configmgr
{

// ------------------------ ChildListSet implementations ------------------------
    ChildListSet::ChildListSet(ChildListSet const& aSet, treeop::DeepChildCopy)
    {
        for(ChildList::iterator it = aSet.GetSet().begin();
            it != aSet.GetSet().end();
            ++it)
        {
            INode* pOrg = *it;
            std::auto_ptr<INode> aCopy = pOrg->clone();
            m_aChildList.insert(m_aChildList.end(), aCopy.release());
        }
    }
    ChildListSet::~ChildListSet()
    {
        for(ChildList::iterator it = m_aChildList.begin();
            it != m_aChildList.end();
            ++it)
            delete *it;
    }

// ---------------------------- Node implementation ----------------------------

    INode::INode(node::Attributes _aAttr):m_aAttributes(_aAttr){}
    INode::INode(OUString const& aName, node::Attributes _aAttr)
          :m_aName(aName)
          ,m_aAttributes(_aAttr){}
    // CopyCTor will be create automatically

    INode::~INode() {}

    ISubtree*         INode::asISubtree(){return NULL;}
    ISubtree const*   INode::asISubtree() const {return NULL;}
    ValueNode*       INode::asValueNode() {return NULL;}
    ValueNode const* INode::asValueNode() const {return NULL;}

    void INode::modifyState(node::State _eNewState)
    {
        m_aAttributes.setState(_eNewState);
    }

    void INode::modifyAccess(node::Access _aAccessLevel)
    {
        OSL_ENSURE( node::accessWritable <= _aAccessLevel && _aAccessLevel <= node::accessReadonly,"Invalid access level for Node");

        m_aAttributes.setAccess(_aAccessLevel);
    }

    void INode::markMandatory()
    {
        m_aAttributes.markMandatory();
    }

    void INode::markRemovable()
    {
        m_aAttributes.markRemovable();
    }

    void INode::promoteAccessToDefault()
      {
        if (m_aAttributes.isFinalized())
            m_aAttributes.setAccess(node::accessReadonly);

        if ( m_aAttributes.isMandatory())
            m_aAttributes.setRemovability(false,false);
    }

    void INode::forceReadonlyToFinalized()
      {
        if (m_aAttributes.isReadonly())
        {
            m_aAttributes.setAccess(node::accessFinal);
        }
    }

// ------------------------- SearchNode implementation -------------------------
    SearchNode::SearchNode():INode(node::Attributes()){}
    SearchNode::SearchNode(OUString const& aName)
        :INode(aName, node::Attributes()){}

    std::auto_ptr<INode> SearchNode::clone() const {return std::auto_ptr<INode>(new SearchNode(*this));}

    SearchNode::~SearchNode(){}

    //==========================================================================
    //= OPropagateLevels
    //==========================================================================
    /** fills a subtree with the correct level informations
    */
    struct OPropagateLevels : public NodeModification
    {
    public:
        typedef sal_Int16 Level;
        OPropagateLevels(Level _nParentLevel, Level _nParentDefaultLevel)
        : m_nLevel          ( childLevel(_nParentLevel) )
        , m_nDefaultLevel   ( childLevel(_nParentDefaultLevel) )
        {
        }
        virtual void handle(ValueNode&) { /* not interested in value nodes */ }
        virtual void handle(ISubtree& _rSubtree)
        {
            _rSubtree.setLevels(m_nLevel, m_nDefaultLevel);
        }

        static Level childLevel(Level _nLevel)
        {
            OSL_ASSERT(0 > treeop::ALL_LEVELS);
            return (_nLevel > 0) ? _nLevel-1 : _nLevel;
        }
    protected:
        Level   m_nLevel;
        Level   m_nDefaultLevel;
    };

// -------------------------- ISubtree implementation --------------------------
    ISubtree* ISubtree::asISubtree() {return this;}
    ISubtree const* ISubtree::asISubtree() const {return this;}

    //--------------------------------------------------------------------------
    static inline bool adjustLevel(sal_Int16& _rLevel, sal_Int16 _nNewLevel)
    {
        if (_rLevel == treeop::ALL_LEVELS)   return false;
        if (_nNewLevel <= _rLevel &&
            _nNewLevel != treeop::ALL_LEVELS) return false;

        _rLevel = _nNewLevel;
        return true;
    }

    //--------------------------------------------------------------------------
    void ISubtree::setLevels(sal_Int16 _nLevel, sal_Int16 _nDefaultLevels)
    {
        bool bActive = false;

        if (_nLevel && adjustLevel(m_nLevel, _nLevel))
            bActive = true;

        if (_nDefaultLevels && adjustLevel(m_nDefaultLevels, _nDefaultLevels))
            bActive = true;

        // forward the level numbers to any child subtrees we have
        if (bActive)
        {
            OPropagateLevels aPropagate(_nLevel,_nDefaultLevels);
            aPropagate.applyToChildren(*this);
        }
    }

// --------------------------- Subtree implementation ---------------------------
    std::auto_ptr<INode> Subtree::clone() const
    {
        return std::auto_ptr<INode>(new Subtree(*this, treeop::DeepChildCopy()));
    }

    INode* Subtree::doGetChild(OUString const& aName) const
    {
        SearchNode searchObj(aName);

#if OSL_DEBUG_LEVEL > 1
        for (ChildList::iterator it2 = m_aChildren.GetSet().begin();
            it2 != m_aChildren.GetSet().end();
            ++it2)
        {
            INode* pINode = *it2;
            OUString aName2 = pINode->getName();
            volatile int dummy;
            dummy = 0;
        }
#endif

        ChildList::iterator it = m_aChildren.GetSet().find(&searchObj);
        if (it == m_aChildren.GetSet().end())
            return NULL;
        else
            return *it;
    }

    INode* Subtree::addChild(std::auto_ptr<INode> aNode)    // takes ownership
    {
        OUString aName = aNode->getName();
        std::pair<ChildList::iterator, bool> aInserted =
            m_aChildren.GetSet().insert(aNode.get());
        if (aInserted.second)
            aNode.release();
        return *aInserted.first;
    }

    ::std::auto_ptr<INode> Subtree::removeChild(OUString const& aName)
    {
        SearchNode searchObj(aName);
        ChildList::const_iterator it = m_aChildren.GetSet().find(&searchObj);

        ::std::auto_ptr<INode> aReturn;
        if (m_aChildren.GetSet().end() != it)
        {
            aReturn = ::std::auto_ptr<INode>(*it);
            m_aChildren.GetSet().erase(it);
        }
        return aReturn;
    }
//  // -------------------------- ValueNode implementation --------------------------

    void Subtree::forEachChild(NodeAction& anAction) const
    {
        for(ChildList::const_iterator it = m_aChildren.GetSet().begin();
            it != m_aChildren.GetSet().end();
            ++it)
            (**it).dispatch(anAction);
    }

    void Subtree::forEachChild(NodeModification& anAction)
    {
        ChildList::iterator it = m_aChildren.GetSet().begin();
        while( it != m_aChildren.GetSet().end() )
        {
            // modification-safe iteration
            (**it++).dispatch(anAction);
        }
      }

//  // -------------------------- ValueNode implementation --------------------------
    bool ValueNode::setValueType(uno::Type const& _aType)
    {
        if (_aType == this->getValueType()) return true;

        if (!this->isNull()) return false;

        uno::TypeClass eTC = this->getValueType().getTypeClass();
        if (eTC != uno::TypeClass_VOID && eTC != uno::TypeClass_ANY)
            return false;

        m_aValuePair = AnyPair(_aType);

        OSL_ASSERT(_aType == this->getValueType());

        return true;
    }
    bool ValueNode::setValue(Any const& _aValue)
    {
        sal_Bool bRet = m_aValuePair.setFirst(_aValue);
        if (bRet) this->markAsDefault(false);
        return !! bRet;
    }

    bool ValueNode::changeDefault(Any const& _aValue)
    {
        return !! m_aValuePair.setSecond(_aValue);
    }

    void ValueNode::setDefault()
    {
        OSL_PRECOND( hasUsableDefault(), "No default value to set for value node");
        m_aValuePair.clear( selectValue() );
        this->markAsDefault();
        OSL_POSTCOND( isDefault(), "Could not set value node to default");
    }

    void ValueNode::promoteToDefault()
    {
        if (!isDefault())
        {
            if (m_aValuePair.hasFirst())
            {
                OSL_VERIFY( m_aValuePair.setSecond(m_aValuePair.getFirst()) );
                m_aValuePair.clear( selectValue() );
            }
            else
            {
                m_aValuePair.clear( selectDeflt() );
                OSL_ASSERT( m_aValuePair.isNull() );
            }

            this->markAsDefault();

            OSL_ENSURE( !m_aValuePair.hasFirst(), "Leaving orphaned value in after promoting to default");
        }
        else
            OSL_ENSURE( !m_aValuePair.hasFirst(), "Orphaned value in default node won't be promoted");

        OSL_POSTCOND( isDefault(), "Could not promote value node to default");
    }

    std::auto_ptr<INode> ValueNode::clone() const
    {
        return std::auto_ptr<INode>(new ValueNode(*this));
    }

    ValueNode* ValueNode::asValueNode() {return this;}
    ValueNode const* ValueNode::asValueNode() const {return this;}

} // namespace configmgr

<commit_msg>INTEGRATION: CWS pchfix02 (1.35.60); FILE MERGED 2006/09/01 17:20:42 kaib 1.35.60.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cmtree.cxx,v $
 *
 *  $Revision: 1.37 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 15:20:21 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"

#include <stdio.h>

#include "subtree.hxx"
#ifndef CONFIGMGR_CHANGE_HXX
#include "change.hxx"
#endif
#ifndef CONFIGMGR_TREECHANGELIST_HXX
#include "treechangelist.hxx"
#endif

#ifndef CONFIGMGR_TREEPROVIDER_HXX
#include "treeprovider.hxx"
#endif

//#include "treeactions.hxx"

#ifndef _RTL_STRING_HXX_
#include <rtl/string.hxx>
#endif
#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef INCLUDED_DEQUE
#include <deque>
#define INCLUDED_DEQUE
#endif
#ifndef INCLUDED_VECTOR
#include <vector>
#define INCLUDED_VECTOR
#endif
#ifndef INCLUDED_IOSTREAM
#include <iostream>
#define INCLUDED_IOSTREAM
#endif
#ifndef INCLUDED_EXCEPTION
#include <exception>
#define INCLUDED_EXCEPTION
#endif
#ifndef INCLUDED_SET
#include <set>
#define INCLUDED_SET
#endif

using namespace std;
using namespace rtl;
using namespace com::sun::star::uno;

namespace configmgr
{

// ------------------------ ChildListSet implementations ------------------------
    ChildListSet::ChildListSet(ChildListSet const& aSet, treeop::DeepChildCopy)
    {
        for(ChildList::iterator it = aSet.GetSet().begin();
            it != aSet.GetSet().end();
            ++it)
        {
            INode* pOrg = *it;
            std::auto_ptr<INode> aCopy = pOrg->clone();
            m_aChildList.insert(m_aChildList.end(), aCopy.release());
        }
    }
    ChildListSet::~ChildListSet()
    {
        for(ChildList::iterator it = m_aChildList.begin();
            it != m_aChildList.end();
            ++it)
            delete *it;
    }

// ---------------------------- Node implementation ----------------------------

    INode::INode(node::Attributes _aAttr):m_aAttributes(_aAttr){}
    INode::INode(OUString const& aName, node::Attributes _aAttr)
          :m_aName(aName)
          ,m_aAttributes(_aAttr){}
    // CopyCTor will be create automatically

    INode::~INode() {}

    ISubtree*         INode::asISubtree(){return NULL;}
    ISubtree const*   INode::asISubtree() const {return NULL;}
    ValueNode*       INode::asValueNode() {return NULL;}
    ValueNode const* INode::asValueNode() const {return NULL;}

    void INode::modifyState(node::State _eNewState)
    {
        m_aAttributes.setState(_eNewState);
    }

    void INode::modifyAccess(node::Access _aAccessLevel)
    {
        OSL_ENSURE( node::accessWritable <= _aAccessLevel && _aAccessLevel <= node::accessReadonly,"Invalid access level for Node");

        m_aAttributes.setAccess(_aAccessLevel);
    }

    void INode::markMandatory()
    {
        m_aAttributes.markMandatory();
    }

    void INode::markRemovable()
    {
        m_aAttributes.markRemovable();
    }

    void INode::promoteAccessToDefault()
      {
        if (m_aAttributes.isFinalized())
            m_aAttributes.setAccess(node::accessReadonly);

        if ( m_aAttributes.isMandatory())
            m_aAttributes.setRemovability(false,false);
    }

    void INode::forceReadonlyToFinalized()
      {
        if (m_aAttributes.isReadonly())
        {
            m_aAttributes.setAccess(node::accessFinal);
        }
    }

// ------------------------- SearchNode implementation -------------------------
    SearchNode::SearchNode():INode(node::Attributes()){}
    SearchNode::SearchNode(OUString const& aName)
        :INode(aName, node::Attributes()){}

    std::auto_ptr<INode> SearchNode::clone() const {return std::auto_ptr<INode>(new SearchNode(*this));}

    SearchNode::~SearchNode(){}

    //==========================================================================
    //= OPropagateLevels
    //==========================================================================
    /** fills a subtree with the correct level informations
    */
    struct OPropagateLevels : public NodeModification
    {
    public:
        typedef sal_Int16 Level;
        OPropagateLevels(Level _nParentLevel, Level _nParentDefaultLevel)
        : m_nLevel          ( childLevel(_nParentLevel) )
        , m_nDefaultLevel   ( childLevel(_nParentDefaultLevel) )
        {
        }
        virtual void handle(ValueNode&) { /* not interested in value nodes */ }
        virtual void handle(ISubtree& _rSubtree)
        {
            _rSubtree.setLevels(m_nLevel, m_nDefaultLevel);
        }

        static Level childLevel(Level _nLevel)
        {
            OSL_ASSERT(0 > treeop::ALL_LEVELS);
            return (_nLevel > 0) ? _nLevel-1 : _nLevel;
        }
    protected:
        Level   m_nLevel;
        Level   m_nDefaultLevel;
    };

// -------------------------- ISubtree implementation --------------------------
    ISubtree* ISubtree::asISubtree() {return this;}
    ISubtree const* ISubtree::asISubtree() const {return this;}

    //--------------------------------------------------------------------------
    static inline bool adjustLevel(sal_Int16& _rLevel, sal_Int16 _nNewLevel)
    {
        if (_rLevel == treeop::ALL_LEVELS)   return false;
        if (_nNewLevel <= _rLevel &&
            _nNewLevel != treeop::ALL_LEVELS) return false;

        _rLevel = _nNewLevel;
        return true;
    }

    //--------------------------------------------------------------------------
    void ISubtree::setLevels(sal_Int16 _nLevel, sal_Int16 _nDefaultLevels)
    {
        bool bActive = false;

        if (_nLevel && adjustLevel(m_nLevel, _nLevel))
            bActive = true;

        if (_nDefaultLevels && adjustLevel(m_nDefaultLevels, _nDefaultLevels))
            bActive = true;

        // forward the level numbers to any child subtrees we have
        if (bActive)
        {
            OPropagateLevels aPropagate(_nLevel,_nDefaultLevels);
            aPropagate.applyToChildren(*this);
        }
    }

// --------------------------- Subtree implementation ---------------------------
    std::auto_ptr<INode> Subtree::clone() const
    {
        return std::auto_ptr<INode>(new Subtree(*this, treeop::DeepChildCopy()));
    }

    INode* Subtree::doGetChild(OUString const& aName) const
    {
        SearchNode searchObj(aName);

#if OSL_DEBUG_LEVEL > 1
        for (ChildList::iterator it2 = m_aChildren.GetSet().begin();
            it2 != m_aChildren.GetSet().end();
            ++it2)
        {
            INode* pINode = *it2;
            OUString aName2 = pINode->getName();
            volatile int dummy;
            dummy = 0;
        }
#endif

        ChildList::iterator it = m_aChildren.GetSet().find(&searchObj);
        if (it == m_aChildren.GetSet().end())
            return NULL;
        else
            return *it;
    }

    INode* Subtree::addChild(std::auto_ptr<INode> aNode)    // takes ownership
    {
        OUString aName = aNode->getName();
        std::pair<ChildList::iterator, bool> aInserted =
            m_aChildren.GetSet().insert(aNode.get());
        if (aInserted.second)
            aNode.release();
        return *aInserted.first;
    }

    ::std::auto_ptr<INode> Subtree::removeChild(OUString const& aName)
    {
        SearchNode searchObj(aName);
        ChildList::const_iterator it = m_aChildren.GetSet().find(&searchObj);

        ::std::auto_ptr<INode> aReturn;
        if (m_aChildren.GetSet().end() != it)
        {
            aReturn = ::std::auto_ptr<INode>(*it);
            m_aChildren.GetSet().erase(it);
        }
        return aReturn;
    }
//  // -------------------------- ValueNode implementation --------------------------

    void Subtree::forEachChild(NodeAction& anAction) const
    {
        for(ChildList::const_iterator it = m_aChildren.GetSet().begin();
            it != m_aChildren.GetSet().end();
            ++it)
            (**it).dispatch(anAction);
    }

    void Subtree::forEachChild(NodeModification& anAction)
    {
        ChildList::iterator it = m_aChildren.GetSet().begin();
        while( it != m_aChildren.GetSet().end() )
        {
            // modification-safe iteration
            (**it++).dispatch(anAction);
        }
      }

//  // -------------------------- ValueNode implementation --------------------------
    bool ValueNode::setValueType(uno::Type const& _aType)
    {
        if (_aType == this->getValueType()) return true;

        if (!this->isNull()) return false;

        uno::TypeClass eTC = this->getValueType().getTypeClass();
        if (eTC != uno::TypeClass_VOID && eTC != uno::TypeClass_ANY)
            return false;

        m_aValuePair = AnyPair(_aType);

        OSL_ASSERT(_aType == this->getValueType());

        return true;
    }
    bool ValueNode::setValue(Any const& _aValue)
    {
        sal_Bool bRet = m_aValuePair.setFirst(_aValue);
        if (bRet) this->markAsDefault(false);
        return !! bRet;
    }

    bool ValueNode::changeDefault(Any const& _aValue)
    {
        return !! m_aValuePair.setSecond(_aValue);
    }

    void ValueNode::setDefault()
    {
        OSL_PRECOND( hasUsableDefault(), "No default value to set for value node");
        m_aValuePair.clear( selectValue() );
        this->markAsDefault();
        OSL_POSTCOND( isDefault(), "Could not set value node to default");
    }

    void ValueNode::promoteToDefault()
    {
        if (!isDefault())
        {
            if (m_aValuePair.hasFirst())
            {
                OSL_VERIFY( m_aValuePair.setSecond(m_aValuePair.getFirst()) );
                m_aValuePair.clear( selectValue() );
            }
            else
            {
                m_aValuePair.clear( selectDeflt() );
                OSL_ASSERT( m_aValuePair.isNull() );
            }

            this->markAsDefault();

            OSL_ENSURE( !m_aValuePair.hasFirst(), "Leaving orphaned value in after promoting to default");
        }
        else
            OSL_ENSURE( !m_aValuePair.hasFirst(), "Orphaned value in default node won't be promoted");

        OSL_POSTCOND( isDefault(), "Could not promote value node to default");
    }

    std::auto_ptr<INode> ValueNode::clone() const
    {
        return std::auto_ptr<INode>(new ValueNode(*this));
    }

    ValueNode* ValueNode::asValueNode() {return this;}
    ValueNode const* ValueNode::asValueNode() const {return this;}

} // namespace configmgr

<|endoftext|>