<commit_before>/*
    Copyright (c) 2007 <NAME> <<EMAIL>>
                  2008 <NAME> <<EMAIL>>

    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 "nepomukcontactfeeder.h"

#include <kabc/addressee.h>

#include <akonadi/changerecorder.h>
#include <akonadi/item.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/collectionfetchjob.h>

#include <nepomuk/resource.h>
#include <nepomuk/resourcemanager.h>
#include <nepomuk/variant.h>
#include <kurl.h>

#include <Soprano/Model>

// ontology includes
#include "bbsnumber.h"
#include "carphonenumber.h"
#include "cellphonenumber.h"
#include "emailaddress.h"
#include "faxnumber.h"
#include "isdnnumber.h"
#include "messagingnumber.h"
#include "modemnumber.h"
#include "pagernumber.h"
#include "personcontact.h"
#include "pcsnumber.h"
#include "postaladdress.h"
#include "videotelephonenumber.h"
#include "voicephonenumber.h"

#include <QtCore/QTimer>
#include <QtDBus/QDBusConnection>

#include <KDebug>


namespace Akonadi {

NepomukContactFeeder::NepomukContactFeeder( const QString &id )
  : AgentBase( id ),
    mForceUpdate( false )
{
  changeRecorder()->itemFetchScope().fetchFullPayload();
  changeRecorder()->setMimeTypeMonitored( "text/directory" );
  changeRecorder()->setChangeRecordingEnabled( false );

  // do the initial scan to make sure all items have been fed to nepomuk
  QTimer::singleShot( 0, this, SLOT( slotInitialItemScan() ) );

  // The line below is not necessary anymore once AgentBase also exports scriptable slots
  QDBusConnection::sessionBus().registerObject( "/nepomukcontactfeeder", this, QDBusConnection::ExportScriptableSlots );
}

void NepomukContactFeeder::itemAdded( const Akonadi::Item &item, const Akonadi::Collection& )
{
  itemChanged( item, QSet<QByteArray>() );
}

void NepomukContactFeeder::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
{
  if ( item.hasPayload<KABC::Addressee>() )
    updateItem( item );
}

void NepomukContactFeeder::itemRemoved( const Akonadi::Item &item )
{
  Nepomuk::PersonContact contact( item.url() );

  QList<Nepomuk::PhoneNumber> numbers = contact.phoneNumbers();
  Q_FOREACH( Nepomuk::PhoneNumber number, numbers ) {
    number.remove();
  }

  QList<Nepomuk::EmailAddress> emails = contact.emailAddresses();
  Q_FOREACH( Nepomuk::EmailAddress email, emails ) {
    email.remove();
  }

  QList<Nepomuk::PostalAddress> addresses = contact.postalAddresses();
  Q_FOREACH( Nepomuk::PostalAddress address, addresses ) {
    address.remove();
  }

  contact.remove();
}

void NepomukContactFeeder::slotInitialItemScan()
{
  kDebug();
  updateAll( false );
}

void NepomukContactFeeder::updateAll( bool force )
{
  mForceUpdate = force;

  CollectionFetchJob *collectionFetch = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
  if ( collectionFetch->exec() ) {
    Collection::List collections = collectionFetch->collections();

    foreach( const Collection &collection, collections) {
      kDebug() << "checking collection" << collection.name();
      if ( collection.contentMimeTypes().contains( QLatin1String( "text/directory" ) ) ) {
        kDebug() << "fetching items from collection" << collection.name();
        ItemFetchJob *itemFetch = new ItemFetchJob( collection );
        itemFetch->fetchScope().fetchFullPayload();
        connect( itemFetch, SIGNAL( itemsReceived( Akonadi::Item::List ) ),
                 this, SLOT( slotItemsReceivedForInitialScan( Akonadi::Item::List ) ) );
      }
    }
  }
}

void NepomukContactFeeder::slotItemsReceivedForInitialScan( const Akonadi::Item::List& items )
{
  kDebug() << items.count();
  foreach( const Item &item, items ) {
    // only update the item if it does not exist
    if ( mForceUpdate ||
         !Nepomuk::ResourceManager::instance()->mainModel()->containsAnyStatement( item.url(), Soprano::Node(), Soprano::Node() ) ) {
      // FIXME: the idea is that we only fetch the full payload for items that need updating
      //        However, the code below always returns an empty list!
//       ItemFetchJob *itemFetch = new ItemFetchJob( item );
//       itemFetch->fetchScope().fetchFullPayload();
//       if ( itemFetch->exec() ) {
//         Akonadi::Item::List fullItems = itemFetch->items();
//         if ( fullItems.isEmpty() ) {
//           kDebug() << "Failed to get full payload for item" << item.url();
//         }
//         else {
//           updateItem( itemFetch->items().first() );
//         }
//       }
      updateItem( item );
    }
  }
  kDebug() << "done";
}

namespace {
  QStringList listFromString( const QString& s ) {
    if ( s.isEmpty() )
      return QStringList();
    else
      return QStringList( s );
  }
}


void NepomukContactFeeder::updateItem( const Akonadi::Item &item )
{
  if ( !item.hasPayload() )
    return;

  const KABC::Addressee addressee = item.payload<KABC::Addressee>();
<commit_msg>Better use hasPayload() with template arguments here. Also, add a kDebug() when no payload was found.<commit_after>/*
    Copyright (c) 2007 <NAME> <<EMAIL>>
                  2008 <NAME> <<EMAIL>>

    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 "nepomukcontactfeeder.h"

#include <kabc/addressee.h>

#include <akonadi/changerecorder.h>
#include <akonadi/item.h>
#include <akonadi/itemfetchscope.h>
#include <akonadi/itemfetchjob.h>
#include <akonadi/collectionfetchjob.h>

#include <nepomuk/resource.h>
#include <nepomuk/resourcemanager.h>
#include <nepomuk/variant.h>
#include <kurl.h>

#include <Soprano/Model>

// ontology includes
#include "bbsnumber.h"
#include "carphonenumber.h"
#include "cellphonenumber.h"
#include "emailaddress.h"
#include "faxnumber.h"
#include "isdnnumber.h"
#include "messagingnumber.h"
#include "modemnumber.h"
#include "pagernumber.h"
#include "personcontact.h"
#include "pcsnumber.h"
#include "postaladdress.h"
#include "videotelephonenumber.h"
#include "voicephonenumber.h"

#include <QtCore/QTimer>
#include <QtDBus/QDBusConnection>

#include <KDebug>


namespace Akonadi {

NepomukContactFeeder::NepomukContactFeeder( const QString &id )
  : AgentBase( id ),
    mForceUpdate( false )
{
  changeRecorder()->itemFetchScope().fetchFullPayload();
  changeRecorder()->setMimeTypeMonitored( "text/directory" );
  changeRecorder()->setChangeRecordingEnabled( false );

  // do the initial scan to make sure all items have been fed to nepomuk
  QTimer::singleShot( 0, this, SLOT( slotInitialItemScan() ) );

  // The line below is not necessary anymore once AgentBase also exports scriptable slots
  QDBusConnection::sessionBus().registerObject( "/nepomukcontactfeeder", this, QDBusConnection::ExportScriptableSlots );
}

void NepomukContactFeeder::itemAdded( const Akonadi::Item &item, const Akonadi::Collection& )
{
  itemChanged( item, QSet<QByteArray>() );
}

void NepomukContactFeeder::itemChanged( const Akonadi::Item &item, const QSet<QByteArray>& )
{
  if ( item.hasPayload<KABC::Addressee>() )
    updateItem( item );
}

void NepomukContactFeeder::itemRemoved( const Akonadi::Item &item )
{
  Nepomuk::PersonContact contact( item.url() );

  QList<Nepomuk::PhoneNumber> numbers = contact.phoneNumbers();
  Q_FOREACH( Nepomuk::PhoneNumber number, numbers ) {
    number.remove();
  }

  QList<Nepomuk::EmailAddress> emails = contact.emailAddresses();
  Q_FOREACH( Nepomuk::EmailAddress email, emails ) {
    email.remove();
  }

  QList<Nepomuk::PostalAddress> addresses = contact.postalAddresses();
  Q_FOREACH( Nepomuk::PostalAddress address, addresses ) {
    address.remove();
  }

  contact.remove();
}

void NepomukContactFeeder::slotInitialItemScan()
{
  kDebug();
  updateAll( false );
}

void NepomukContactFeeder::updateAll( bool force )
{
  mForceUpdate = force;

  CollectionFetchJob *collectionFetch = new CollectionFetchJob( Collection::root(), CollectionFetchJob::Recursive );
  if ( collectionFetch->exec() ) {
    Collection::List collections = collectionFetch->collections();

    foreach( const Collection &collection, collections) {
      kDebug() << "checking collection" << collection.name();
      if ( collection.contentMimeTypes().contains( QLatin1String( "text/directory" ) ) ) {
        kDebug() << "fetching items from collection" << collection.name();
        ItemFetchJob *itemFetch = new ItemFetchJob( collection );
        itemFetch->fetchScope().fetchFullPayload();
        connect( itemFetch, SIGNAL( itemsReceived( Akonadi::Item::List ) ),
                 this, SLOT( slotItemsReceivedForInitialScan( Akonadi::Item::List ) ) );
      }
    }
  }
}

void NepomukContactFeeder::slotItemsReceivedForInitialScan( const Akonadi::Item::List& items )
{
  kDebug() << items.count();
  foreach( const Item &item, items ) {
    // only update the item if it does not exist
    if ( mForceUpdate ||
         !Nepomuk::ResourceManager::instance()->mainModel()->containsAnyStatement( item.url(), Soprano::Node(), Soprano::Node() ) ) {
      // FIXME: the idea is that we only fetch the full payload for items that need updating
      //        However, the code below always returns an empty list!
//       ItemFetchJob *itemFetch = new ItemFetchJob( item );
//       itemFetch->fetchScope().fetchFullPayload();
//       if ( itemFetch->exec() ) {
//         Akonadi::Item::List fullItems = itemFetch->items();
//         if ( fullItems.isEmpty() ) {
//           kDebug() << "Failed to get full payload for item" << item.url();
//         }
//         else {
//           updateItem( itemFetch->items().first() );
//         }
//       }
      updateItem( item );
    }
  }
  kDebug() << "done";
}

namespace {
  QStringList listFromString( const QString& s ) {
    if ( s.isEmpty() )
      return QStringList();
    else
      return QStringList( s );
  }
}


void NepomukContactFeeder::updateItem( const Akonadi::Item &item )
{
  if ( !item.hasPayload<KABC::Addressee>() ) {
    kDebug() << "Got item without payload. Mimetype:" << item.mimeType()
             << "Id:" << item.id();
    return;
  }

  const KABC::Addressee addressee = item.payload<KABC::Addressee>();

{'fraction_non_alphanumeric': 0.12504332755632583, 'fraction_numerical': 0.0038128249566724438, 'mean_word_length': 3.9468495499357052, 'pattern_counts': {'":': 0, '<': 98, '<?xml version=': 0, '>': 82, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4503663', 'n_tokens_mistral': 3594, 'n_tokens_neox': 3503, 'n_words': 938}