/*
    This file is part of KDE.

    Copyright (C) 2007 Trolltech ASA. All rights reserved.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU 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 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 <tqapplication.h>
#include <tqeventloop.h>

#include <tdeapplication.h>
#include <tdecmdlineargs.h>
#include <kdebug.h>
#include <tdeio/global.h>
#include <tdelocale.h>

#include <tdemacros.h>

#include <stdlib.h>

#include "scalix.h"

extern "C" {
  TDE_EXPORT int kdemain( int argc, char **argv );
}

static const TDECmdLineOptions options[] =
{
  { "+protocol", I18N_NOOP( "Protocol name" ), 0 },
  { "+pool", I18N_NOOP( "Socket name" ), 0 },
  { "+app", I18N_NOOP( "Socket name" ), 0 },
  TDECmdLineLastOption
};

int kdemain( int argc, char **argv )
{
  putenv( strdup( "SESSION_MANAGER=" ) );
  TDEApplication::disableAutoDcopRegistration();

  TDECmdLineArgs::init( argc, argv, "tdeio_scalix", 0, 0, 0, 0 );
  TDECmdLineArgs::addCmdLineOptions( options );
  TDEApplication app( false, false );

  TDECmdLineArgs *args = TDECmdLineArgs::parsedArgs();
  Scalix slave( args->arg( 0 ), args->arg( 1 ), args->arg( 2 ) );
  slave.dispatchLoop();

  return 0;
}

Scalix::Scalix( const TQCString &protocol, const TQCString &pool, const TQCString &app )
  : SlaveBase( protocol, pool, app )
{
}

void Scalix::get( const KURL &url )
{
  mimeType( "text/plain" );

  TQString path = url.path();

  if ( path.contains( "/freebusy/" ) ) {
    retrieveFreeBusy( url );
  } else {
    error( TDEIO::ERR_SLAVE_DEFINED, i18n( "Unknown path. Known path is '/freebusy/'" ) );
  }
}

void Scalix::put( const KURL& url, int, bool, bool )
{
  TQString path = url.path();

  if ( path.contains( "/freebusy/" ) ) {
    publishFreeBusy( url );
  } else {
    error( TDEIO::ERR_SLAVE_DEFINED, i18n( "Unknown path. Known path is '/freebusy/'" ) );
  }
}

void Scalix::retrieveFreeBusy( const KURL &url )
{
  /**
   * The url is of the following form:
   *  scalix://user:password@host/freebusy/user@domain.ifb
   */

  // Extract user@domain (e.g. everything between '/freebusy/' and '.ifb')
  const TQString requestUser = url.path().mid( 10, url.path().length() - 14 );

  TQByteArray packedArgs;
  TQDataStream stream( packedArgs, IO_WriteOnly );

  const TQString argument = TQString( "BEGIN:VFREEBUSY\nATTENDEE:MAILTO:%1\nEND:VFREEBUSY" ).arg( requestUser );
  const TQString command = TQString( "X-GET-ICAL-FREEBUSY {%1}" ).arg( argument.length() );

  stream << (int) 'X' << 'E' << command << argument;

  TQString imapUrl = TQString( "imap://%1@%3/" ).arg( url.pass().isEmpty() ?
                                                   url.user() : url.user() + ":" + url.pass() )
                                                .arg( url.host() );

  mFreeBusyData = TQString();

  TDEIO::SimpleJob *job = TDEIO::special( imapUrl, packedArgs, false );
  connect( job, TQ_SIGNAL( infoMessage( TDEIO::Job*, const TQString& ) ),
           this, TQ_SLOT( slotInfoMessage( TDEIO::Job*, const TQString& ) ) );
  connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ),
           this, TQ_SLOT( slotRetrieveResult( TDEIO::Job* ) ) );

  tqApp->eventLoop()->enterLoop();
}

void Scalix::publishFreeBusy( const KURL &url )
{
  /**
   * The url is of the following form:
   *  scalix://user:password@host/freebusy/path/to/calendar/user@domain
   */
  TQString requestUser, calendar;
  TQString path = url.path();

  // extract user name
  int lastSlash = path.findRev( '/' );
  if ( lastSlash != -1 )
    requestUser = path.mid( lastSlash + 1 );

  // extract calendar name
  int secondSlash = path.find( '/', 1 );
  if ( secondSlash != -1 )
    calendar = path.mid( secondSlash + 1, lastSlash - secondSlash - 1 );

  if ( requestUser.isEmpty() || calendar.isEmpty() ) {
    error( TDEIO::ERR_SLAVE_DEFINED, i18n( "No user or calendar given!" ) );
    return;
  };

  // read freebusy information
  TQByteArray data;
  while ( true ) {
    dataReq();

    TQByteArray buffer;
    const int newSize = readData(buffer);
    if ( newSize < 0 ) {
      // read error: network in unknown state so disconnect
      error( TDEIO::ERR_COULD_NOT_READ, i18n("TDEIO data supply error.") );
      return;
    }

    if ( newSize == 0 )
      break;

    unsigned int oldSize = data.size();
    data.resize( oldSize + buffer.size() );
    memcpy( data.data() + oldSize, buffer.data(), buffer.size() );
  }

  TQByteArray packedArgs;
  TQDataStream stream( packedArgs, IO_WriteOnly );

  const TQString argument = TQString::fromUtf8( data );
  const TQString command = TQString( "X-PUT-ICAL-FREEBUSY Calendar {%1}" ).arg( argument.length() );

  stream << (int) 'X' << 'E' << command << argument;

  TQString imapUrl = TQString( "imap://%1@%3/" ).arg( url.pass().isEmpty() ?
                                                   url.user() : url.user() + ":" + url.pass() )
                                                .arg( url.host() );

  TDEIO::SimpleJob *job = TDEIO::special( imapUrl, packedArgs, false );
  connect( job, TQ_SIGNAL( result( TDEIO::Job* ) ),
           this, TQ_SLOT( slotPublishResult( TDEIO::Job* ) ) );

  tqApp->eventLoop()->enterLoop();
}

void Scalix::slotInfoMessage( TDEIO::Job *job, const TQString &data )
{
  if ( job->error() ) {
    // error is handled in slotResult
    return;
  }

  mFreeBusyData = data;
}


void Scalix::slotRetrieveResult( TDEIO::Job *job )
{
  if ( job->error() ) {
    error( TDEIO::ERR_SLAVE_DEFINED, job->errorString() );
  } else {
    data( mFreeBusyData.utf8() );
    finished();
  }

  tqApp->eventLoop()->exitLoop();
}

void Scalix::slotPublishResult( TDEIO::Job *job )
{
  if ( job->error() ) {
    error( TDEIO::ERR_SLAVE_DEFINED, job->errorString() );
  } else {
    finished();
  }

  tqApp->eventLoop()->exitLoop();
}

#include "scalix.moc"
