/*
  This file is part of KDE-Pim/Pi.
  Copyright (c) 2004 Ulf Schenk

  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., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.
*/

// $Id$

#include "ksyncmanager.h"

#include <stdlib.h>

#ifndef _WIN32_
#include <unistd.h>
#endif


#include "ksyncprofile.h"
#include "ksyncprefsdialog.h"
#include "kpimprefs.h"
#include <kmessagebox.h>

#include <qdir.h>
#include <qprogressbar.h>
#include <qpopupmenu.h>
#include <qpushbutton.h>
#include <qradiobutton.h>
#include <qbuttongroup.h>
#include <qtimer.h>
#include <qmessagebox.h>
#include <qapplication.h>
#include <qlineedit.h>
#include <qdialog.h>
#include <qlayout.h>
#include <qtextcodec.h>
#include <qlabel.h>
#include <qcheckbox.h>

#include <klocale.h>
#include <kglobal.h>
#include <kconfig.h>
#include <kfiledialog.h>

KSyncManager::KSyncManager(QWidget* parent, KSyncInterface* implementation, TargetApp ta, KPimPrefs* prefs, QPopupMenu* syncmenu)
    : QObject(), mParent(parent), mImplementation(implementation), mTargetApp(ta), mPrefs(prefs ),mSyncMenu(syncmenu)
{
    mServerSocket = 0;
    bar = new QProgressBar ( 1, 0 );
    bar->setCaption ("");
    
    int w = 300;
    if ( QApplication::desktop()->width() < 320 )
        w = 220;
    int h = bar->sizeHint().height() ;
    int dw = QApplication::desktop()->width();
    int dh = QApplication::desktop()->height();
    bar->setGeometry( (dw-w)/2, (dh - h )/2 ,w,h );
    if ( mPrefs->mPassiveSyncAutoStart )
      enableQuick( false );

}

KSyncManager::~KSyncManager()
{
    delete bar;
}


void KSyncManager::fillSyncMenu()
{
    if ( mSyncMenu->count() )
        mSyncMenu->clear();
    
    mSyncMenu->insertItem( i18n("Configure..."), 0 );
    mSyncMenu->insertSeparator();
    if ( mServerSocket == 0 ) {
        mSyncMenu->insertItem( i18n("Enable Pi-Sync"), 2 );
    } else {
        mSyncMenu->insertItem( i18n("Disable Pi-Sync"), 3 );
    }
    mSyncMenu->insertSeparator();
    mSyncMenu->insertItem( i18n("Multiple sync"), 1 );
    mSyncMenu->insertSeparator();
    
    KConfig config ( locateLocal( "config","ksyncprofilesrc"  ) );
    config.setGroup("General");
    QStringList prof = config.readListEntry("SyncProfileNames");
    mLocalMachineName = config.readEntry("LocalMachineName","undefined");
    if ( prof.count() < 2 ) {
        prof.clear();
        QString externalName;
#ifdef DESKTOP_VERSION
#ifdef _WIN32_
        externalName = "OutLook(not_implemented)";
#else
        externalName = "KDE_Desktop";
#endif
#else
        externalName = "Sharp_DTM";
#endif
        prof << externalName;
        prof << i18n("Local_file");
        prof << i18n("Last_file");
        KSyncProfile* temp = new KSyncProfile ();
        temp->setName( prof[0] );
        temp->writeConfig(&config);
        temp->setName( prof[1] );
        temp->writeConfig(&config);
        temp->setName( prof[2] );
        temp->writeConfig(&config);
        config.setGroup("General");
        config.writeEntry("SyncProfileNames",prof);
        config.writeEntry("ExternSyncProfiles",externalName);
        config.sync();
        delete temp;
    }
    mExternSyncProfiles = config.readListEntry("ExternSyncProfiles");
    mSyncProfileNames = prof;
    unsigned int i;
    for ( i = 0; i < prof.count(); ++i ) {
        mSyncMenu->insertItem(  prof[i], 1000+i );
        if ( i == 2 )
            mSyncMenu->insertSeparator();
    }
    QDir app_dir;
    //US do not display SharpDTM if app is pwmpi, or no sharpfiles available
    if ( mTargetApp == PWMPI) {
        mSyncMenu->removeItem( 1000 );
    }
#ifndef DESKTOP_VERSION
    else if (!app_dir.exists(QDir::homeDirPath()+"/Applications/dtm" ) ) {
        mSyncMenu->removeItem( 1000 );
    }
#endif
    mSyncMenu->removeItem( 1002 );
}

void KSyncManager::slotSyncMenu( int action )
{
    qDebug("syncaction %d ", action);
    if ( action == 0 ) {

        // seems to be a Qt2 event handling bug
        // syncmenu.clear causes a segfault at first time
        // when we call it after the main event loop, it is ok
        // same behaviour when calling OM/Pi via QCOP for the first time
        QTimer::singleShot ( 1, this, SLOT ( confSync() ) ); 
        //confSync();

        return;
    }
    if ( action == 1 ) {
        multiSync( true );
        return;
    }
    if ( action == 2 ) {
        enableQuick();
        QTimer::singleShot ( 1, this, SLOT ( fillSyncMenu() ) ); 
        return;
    }
    if ( action == 3 ) {
        delete mServerSocket;
        mServerSocket = 0;
        QTimer::singleShot ( 1, this, SLOT ( fillSyncMenu() ) ); 
        return;
    }

    if (blockSave())
        return;

    setBlockSave(true);
    bool silent = false;
    if ( action == 999 ) {
        //special mode for silent syncing
        action = 1000;
        silent = true;
    }

    mCurrentSyncProfile = action - 1000 ;
    mCurrentSyncDevice = mSyncProfileNames[mCurrentSyncProfile] ;
    mCurrentSyncName =  mLocalMachineName ;
    KConfig config ( locateLocal( "config","ksyncprofilesrc"  ) );
    KSyncProfile* temp = new KSyncProfile ();
    temp->setName(mSyncProfileNames[mCurrentSyncProfile]);
    temp->readConfig(&config);
    if (silent) {
        mAskForPreferences = false;
        mShowSyncSummary = false;
        mWriteBackFile = true;
        mSyncAlgoPrefs = 2;// take newest
    }
    else {
        mAskForPreferences = temp->getAskForPreferences();
        mShowSyncSummary = temp->getShowSummaryAfterSync();
        mWriteBackFile = temp->getWriteBackFile();
        mSyncAlgoPrefs = temp->getSyncPrefs();
    }
    mWriteBackExistingOnly = temp->getWriteBackExisting();
    mIsKapiFile = temp->getIsKapiFile();
    mWriteBackInFuture = 0;
    if ( temp->getWriteBackFuture() )
        mWriteBackInFuture =  temp->getWriteBackFutureWeeks( );
   
    if ( action == 1000  ) {
#ifdef DESKTOP_VERSION
        syncKDE();
#else
        syncSharp();
#endif
    
    } else if ( action == 1001 ) {
        syncLocalFile();

    } else if ( action == 1002 ) {
        mWriteBackFile = false;
        mAskForPreferences = false;
        mShowSyncSummary = false; 
        mSyncAlgoPrefs = 3; 
        quickSyncLocalFile();

    } else if ( action >= 1003  ) {
        if ( temp->getIsLocalFileSync() ) {
            switch(mTargetApp)
                {
                case (KAPI):
                    if ( syncWithFile( temp->getRemoteFileNameAB( ), false ) )
                        mPrefs->mLastSyncedLocalFile = temp->getRemoteFileNameAB();
                    break;
                case (KOPI):
                    if ( syncWithFile( temp->getRemoteFileName( ), false ) )
                        mPrefs->mLastSyncedLocalFile = temp->getRemoteFileName();
                    break;
                case (PWMPI):
                    if ( syncWithFile( temp->getRemoteFileNamePWM( ), false ) )
                        mPrefs->mLastSyncedLocalFile = temp->getRemoteFileNamePWM();
                    break;
                default:
                    qDebug("KSyncManager::slotSyncMenu: invalid apptype selected");
                    break;
	      
                }
        } else {
            if (  temp->getIsPhoneSync() ) {
                mPhoneDevice = temp->getPhoneDevice( ) ;
                mPhoneConnection = temp->getPhoneConnection( );
                mPhoneModel = temp->getPhoneModel( );
                syncPhone();
            } else if (  temp->getIsPiSync() ) {
                if ( mTargetApp == KAPI ) {
                    mPassWordPiSync = temp->getRemotePwAB();
                    mActiveSyncPort = temp->getRemotePortAB();
                    mActiveSyncIP = temp->getRemoteIPAB();
                } else if ( mTargetApp == KOPI ) {
                    mPassWordPiSync = temp->getRemotePw();
                    mActiveSyncPort = temp->getRemotePort();
                    mActiveSyncIP = temp->getRemoteIP();
                } else  {
                    mPassWordPiSync = temp->getRemotePwPWM();
                    mActiveSyncPort = temp->getRemotePortPWM();
                    mActiveSyncIP = temp->getRemoteIPPWM();
                } 
                syncPi();
                while ( !mPisyncFinished ) {
                    //qDebug("waiting ");
                    qApp->processEvents();
                }
            } else
                syncRemote( temp );

        }
    }
    delete temp;
    setBlockSave(false);
}

void KSyncManager::enableQuick( bool ask )
{
    bool autoStart;
    bool changed = false;
    if ( ask ) {
        QDialog dia ( 0, "input-dialog", true );
        QLineEdit lab ( &dia );
        QVBoxLayout lay( &dia );
        lab.setText( mPrefs->mPassiveSyncPort );
        lay.setMargin(7);
        lay.setSpacing(7);
        int po = 9197+mTargetApp;
        QLabel label ( i18n("Port number (Default: %1)").arg(po), &dia );
        lay.addWidget( &label);
        lay.addWidget( &lab);

        QLineEdit lepw ( &dia );
        lepw.setText( mPrefs->mPassiveSyncPw );
        QLabel label2 ( i18n("Password to enable\naccess from remote:"), &dia );
        lay.addWidget( &label2);
        lay.addWidget( &lepw);
        QCheckBox autostart(i18n("Automatically start\nat application startup"), &dia );
        lay.addWidget( &autostart);
        autostart.setChecked( mPrefs->mPassiveSyncAutoStart );
#ifdef DESKTOP_VERSION
#ifdef _WIN32_
        QCheckBox syncdesktop( i18n("Automatically sync with Outlook\nwhen receiving sync request"),&dia );
#else
        QCheckBox syncdesktop( i18n("Automatically sync with KDE-Desktop\nwhen receiving sync request"),&dia );
#endif
        lay.addWidget( &syncdesktop);
#else
        mPrefs->mPassiveSyncWithDesktop = false;
        QCheckBox syncdesktop( i18n("Automatically sync\nwith KDE-Desktop"),&dia );
        syncdesktop.hide();
#endif
        syncdesktop.setChecked( mPrefs->mPassiveSyncWithDesktop );

        dia.setFixedSize( 230,120 );
        dia.setCaption( i18n("Enter port for Pi-Sync") );
        QPushButton pb ( "OK",  &dia);
        lay.addWidget( &pb );
        connect(&pb, SIGNAL( clicked() ), &dia, SLOT ( accept() ) );
        dia.show();
        if ( ! dia.exec() )
            return;
        dia.hide();
        qApp->processEvents();
        if ( mPrefs->mPassiveSyncPw != lepw.text() ) {
            changed = true;
            mPrefs->mPassiveSyncPw = lepw.text();
        }
        if ( mPrefs->mPassiveSyncPort != lab.text() ) {
            mPrefs->mPassiveSyncPort = lab.text();
            changed = true;
        }
        autoStart = autostart.isChecked();
        if (mPrefs->mPassiveSyncWithDesktop != syncdesktop.isChecked() ) {
            changed = true;
            mPrefs->mPassiveSyncWithDesktop = syncdesktop.isChecked();
        }
    }
    else
        autoStart = mPrefs->mPassiveSyncAutoStart;
    if ( autoStart != mPrefs->mPassiveSyncAutoStart )
        changed =  true;
    bool ok;
    mPrefs->mPassiveSyncAutoStart = false;
    Q_UINT16 port = mPrefs->mPassiveSyncPort.toUInt(&ok);
    if ( ! ok ) {
        KMessageBox::information( 0, i18n("No valid port"));
        return;
    }
    //qDebug("port %d ", port);
    mServerSocket = new KServerSocket ( mPrefs->mPassiveSyncPw, port ,1 );
    mServerSocket->setFileName( defaultFileName() );
    //qDebug("connected ");
    if ( !mServerSocket->ok() ) {
        KMessageBox::information( 0, i18n("Failed to bind or\nlisten to the port!"));
        delete mServerSocket;
        mServerSocket = 0;
        return;
    }
    mPrefs->mPassiveSyncAutoStart = autoStart;
    if ( changed ) {
        mPrefs->writeConfig();
    }
    connect( mServerSocket, SIGNAL ( request_file() ),this, SIGNAL  ( request_file() ) );
    connect( mServerSocket, SIGNAL ( file_received( bool ) ), this,  SIGNAL  ( getFile( bool ) ) );
}

void KSyncManager::syncLocalFile()
{

    QString fn =mPrefs->mLastSyncedLocalFile;
    QString ext;

    switch(mTargetApp)
        {
	    case (KAPI):
            ext = "(*.vcf)";
            break;
	    case (KOPI):
            ext = "(*.ics/*.vcs)";
            break;
	    case (PWMPI):
            ext = "(*.pwm)";
            break;
	    default:
            qDebug("KSyncManager::syncLocalFile: invalid apptype selected");
            break;
	      
        }

    fn =KFileDialog:: getOpenFileName( fn, i18n("Sync filename"+ext), mParent );
    if ( fn == "" )
        return;
    if (  syncWithFile(  fn, false ) ) {
        qDebug("syncLocalFile() successful ");
    }

}

bool  KSyncManager::syncWithFile( QString fn , bool quick )
{
    bool ret = false;
    QFileInfo info;
    info.setFile( fn );
    QString mess;
    bool loadbup = true;
    if ( !info. exists() ) {
        mess =  i18n( "Sync file \n...%1\ndoes not exist!\nNothing synced!\n").arg(fn.right( 30) );
        int result = QMessageBox::warning( mParent, i18n("Warning!"),
                                           mess );
        return ret;
    }
    int result = 0;
    if ( !quick ) {
        mess =  i18n("Sync with file \n...%1\nfrom:\n%2\n").arg(fn.right( 25)).arg(KGlobal::locale()->formatDateTime(info.lastModified (), true, false ));
        result = QMessageBox::warning( mParent, i18n("Warning!"),
                                       mess,
                                       i18n("Sync"), i18n("Cancel"), 0,
                                       0, 1 );
        if ( result )
            return false;
    }
    if ( mAskForPreferences )
        if ( !edit_sync_options()) {
            mParent->topLevelWidget()->setCaption( i18n("Syncing aborted. Nothing synced.") );
            return false;
        }
    if ( result == 0 ) {
        //qDebug("Now sycing ... ");
        if ( ret = mImplementation->sync( this, fn, mSyncAlgoPrefs ) )
            mParent->topLevelWidget()->setCaption( i18n("Synchronization successful") );
        else
            mParent->topLevelWidget()->setCaption( i18n("Sync cancelled or failed. Nothing synced.") );
        if ( ! quick )
            mPrefs->mLastSyncedLocalFile = fn;
    }
    return ret;
}

void KSyncManager::quickSyncLocalFile()
{
    
    if ( syncWithFile( mPrefs->mLastSyncedLocalFile, true ) ) {
        qDebug("quick syncLocalFile() successful ");
      
    }
}

void KSyncManager::multiSync( bool askforPrefs  )
{
    if (blockSave())
        return;
    setBlockSave(true);
    QString question = i18n("Do you really want\nto multiple sync\nwith all checked profiles?\nSyncing takes some\ntime - all profiles\nare synced twice!");
    if ( QMessageBox::information( mParent, i18n("KDE-Pim Sync"),
                                   question,
                                   i18n("Yes"), i18n("No"),
                                   0, 0 ) != 0 ) {
        setBlockSave(false);
        mParent->topLevelWidget()->setCaption(i18n("Aborted! Nothing synced!"));
        return;
    }
    mCurrentSyncDevice = i18n("Multiple profiles") ;
    mSyncAlgoPrefs = mPrefs->mRingSyncAlgoPrefs;
    if ( askforPrefs ) {
        if ( !edit_sync_options()) {
            mParent->topLevelWidget()->setCaption( i18n("Syncing aborted. Nothing synced.") );
            return;
        }
        mPrefs->mRingSyncAlgoPrefs = mSyncAlgoPrefs;
    }
    mParent->topLevelWidget()->setCaption(i18n("Multiple sync started.") );
    qApp->processEvents();
    int num = ringSync() ;
    if (  num > 1 )
        ringSync();
    setBlockSave(false);
    if ( num )
        emit save();
    if ( num )
        mParent->topLevelWidget()->setCaption(i18n("%1 profiles synced. Multiple sync complete!").arg(num) );
    else
        mParent->topLevelWidget()->setCaption(i18n("Nothing synced! No profiles defined for multisync!"));
    return;
}

int KSyncManager::ringSync()
{
    int syncedProfiles = 0;
    unsigned int i;
    QTime timer;
    KConfig config ( locateLocal( "config","ksyncprofilesrc"  ) );
    QStringList syncProfileNames = mSyncProfileNames;
    KSyncProfile* temp = new KSyncProfile ();
    mAskForPreferences = false;
    for ( i = 0; i < syncProfileNames.count(); ++i ) {
        mCurrentSyncProfile = i;
        temp->setName(syncProfileNames[mCurrentSyncProfile]);
        temp->readConfig(&config);

        bool includeInRingSync;
        switch(mTargetApp)
            {
            case (KAPI):
                includeInRingSync = temp->getIncludeInRingSyncAB();
                break;
            case (KOPI):
                includeInRingSync = temp->getIncludeInRingSync();
                break;
            case (PWMPI):
                includeInRingSync = temp->getIncludeInRingSyncPWM();
                break;
            default:
                qDebug("KSyncManager::ringSync: invalid apptype selected");
                break;
	      
            }
        
	
        if ( includeInRingSync && ( i < 1 || i > 2  )) {
            mParent->topLevelWidget()->setCaption(i18n("Profile ")+syncProfileNames[mCurrentSyncProfile]+ i18n(" is synced ... "));
            ++syncedProfiles;
            // mAskForPreferences = temp->getAskForPreferences();
            mWriteBackFile = temp->getWriteBackFile();
            mWriteBackExistingOnly = temp->getWriteBackExisting();
            mWriteBackInFuture = 0;
            if ( temp->getWriteBackFuture() )
                mWriteBackInFuture =  temp->getWriteBackFutureWeeks( );
            mShowSyncSummary = false;
            mCurrentSyncDevice = syncProfileNames[i] ;
            mCurrentSyncName = mLocalMachineName;
            if ( i == 0 ) {
#ifdef DESKTOP_VERSION
                syncKDE();
#else
                syncSharp();
#endif
            } else {
                if ( temp->getIsLocalFileSync() ) {
                    switch(mTargetApp)
                        {
                        case (KAPI):
                            if ( syncWithFile( temp->getRemoteFileNameAB( ), false ) )
                                mPrefs->mLastSyncedLocalFile = temp->getRemoteFileNameAB();
                            break;
                        case (KOPI):
                            if ( syncWithFile( temp->getRemoteFileName( ), false ) )
                                mPrefs->mLastSyncedLocalFile = temp->getRemoteFileName();
                            break;
                        case (PWMPI):
                            if ( syncWithFile( temp->getRemoteFileNamePWM( ), false ) )
                                mPrefs->mLastSyncedLocalFile = temp->getRemoteFileNamePWM();
                            break;
                        default:
                            qDebug("KSyncManager::slotSyncMenu: invalid apptype selected");
                            break;
                        }
                } else {
                    if (  temp->getIsPhoneSync() ) {
                        mPhoneDevice = temp->getPhoneDevice( ) ;
                        mPhoneConnection = temp->getPhoneConnection( );
                        mPhoneModel = temp->getPhoneModel( );
                        syncPhone();
                    } else if (  temp->getIsPiSync() ) {
                        if ( mTargetApp == KAPI ) {
                            mPassWordPiSync = temp->getRemotePwAB();
                            mActiveSyncPort = temp->getRemotePortAB();
                            mActiveSyncIP = temp->getRemoteIPAB();
                        } else if ( mTargetApp == KOPI ) {
                            mPassWordPiSync = temp->getRemotePw();
                            mActiveSyncPort = temp->getRemotePort();
                            mActiveSyncIP = temp->getRemoteIP();
                        } else  {
                            mPassWordPiSync = temp->getRemotePwPWM();
                            mActiveSyncPort = temp->getRemotePortPWM();
                            mActiveSyncIP = temp->getRemoteIPPWM();
                        } 
                        syncPi();
                        while ( !mPisyncFinished ) {
                            //qDebug("waiting ");
                            qApp->processEvents();
                        }
                        timer.start(); 
                        while ( timer.elapsed () < 2000 ) {
                            qApp->processEvents();
                        }
                    } else
                        syncRemote( temp, false );

                }
            }
            timer.start();
            mParent->topLevelWidget()->setCaption(i18n("Multiple sync in progress ... please wait!") );
            while ( timer.elapsed () < 2000 ) {
                qApp->processEvents();
#ifndef _WIN32_
                sleep (1);
#endif
            }

        }

    }
    delete temp;
    return syncedProfiles;
}

void KSyncManager::syncRemote( KSyncProfile* prof,  bool ask)
{
    QString question;
    if ( ask ) {
        question = i18n("Do you really want\nto remote sync\nwith profile \n")+ prof->getName()+" ?\n";
        if ( QMessageBox::information( mParent, i18n("Sync"),
                                       question,
                                       i18n("Yes"), i18n("No"),
                                       0, 0 ) != 0 )
            return;
    }

    QString preCommand;
    QString localTempFile;
    QString postCommand;

    switch(mTargetApp)
        {
        case (KAPI):
            preCommand = prof->getPreSyncCommandAB();
            postCommand = prof->getPostSyncCommandAB();
            localTempFile = prof->getLocalTempFileAB();
            break;
        case (KOPI):
            preCommand = prof->getPreSyncCommand();
            postCommand = prof->getPostSyncCommand();
            localTempFile = prof->getLocalTempFile();
            break;
        case (PWMPI):
            preCommand = prof->getPreSyncCommandPWM();
            postCommand = prof->getPostSyncCommandPWM();
            localTempFile = prof->getLocalTempFilePWM();
            break;
        default:
            qDebug("KSyncManager::syncRemote: invalid apptype selected");
            break;
        }


    int fi;
    if ( (fi = preCommand.find("$PWD$")) > 0 ) {
        QString pwd = getPassword();
        preCommand = preCommand.left( fi )+ pwd + preCommand.mid( fi+5 );

    }
    int maxlen = 30;
    if ( QApplication::desktop()->width() > 320 )
        maxlen += 25;
    mParent->topLevelWidget()->setCaption ( i18n( "Copy remote file to local machine..." ) );
    int fileSize = 0;
    int result = system ( preCommand );
    // 0 : okay
    // 256: no such file or dir
    //
    qDebug("Sync: Remote copy result(0 = okay): %d ",result );
    if ( result != 0 ) {
        unsigned int len = maxlen;
        while ( len <  preCommand.length() ) {
            preCommand.insert( len , "\n" );
            len += maxlen +2;
        }
        question = i18n("Sorry, the copy command failed!\nCommand was:\n%1\n \nTry command on console to get more\ndetailed info about the reason.\n").arg (preCommand) ;
        QMessageBox::information( mParent, i18n("Sync - ERROR"),
                                  question,
                                  i18n("Okay!")) ;
        mParent->topLevelWidget()->setCaption ("KDE-Pim");
        return;
    }
    mParent->topLevelWidget()->setCaption ( i18n( "Copying succeed." ) );
    //qDebug(" file **%s** ",prof->getLocalTempFile().latin1() );

    if ( syncWithFile( localTempFile, true ) ) {

        if ( mWriteBackFile ) {
            int fi;
            if ( (fi = postCommand.find("$PWD$")) > 0 ) {
                QString pwd = getPassword();
                postCommand = postCommand.left( fi )+ pwd + postCommand.mid( fi+5 );
                
            }
            mParent->topLevelWidget()->setCaption ( i18n( "Writing back file ..." ) );
            result = system ( postCommand );
            qDebug("Sync:Writing back file result: %d ", result);
            if ( result != 0 ) {
                mParent->topLevelWidget()->setCaption ( i18n( "Writing back file result: " )+QString::number( result ) );
                return;
            } else {
                mParent->topLevelWidget()->setCaption ( i18n( "Syncronization sucessfully completed" ) );
            }
        }
    }
    return;
}
bool KSyncManager::edit_pisync_options()
{
    QDialog dia( mParent, "dia", true );
    dia.setCaption( i18n("Pi-Sync options for device: " ) +mCurrentSyncDevice );
    QVBoxLayout lay ( &dia );
    lay.setSpacing( 5 );
    lay.setMargin( 3 );
    QLabel lab1 ( i18n("Password for remote access:"), &dia); 
    lay.addWidget( &lab1 );
    QLineEdit le1 (&dia );
    lay.addWidget( &le1 );
    QLabel lab2 ( i18n("Remote IP address:"), &dia);
    lay.addWidget( &lab2 );
    QLineEdit le2 (&dia );
    lay.addWidget( &le2 );
    QLabel lab3 ( i18n("Remote port number:"), &dia);
    lay.addWidget( &lab3 );
    QLineEdit le3 (&dia );
    lay.addWidget( &le3 );
    QPushButton pb ( "OK",  &dia); 
    lay.addWidget( &pb );
    connect(&pb, SIGNAL( clicked() ), &dia, SLOT ( accept() ) ); 
    le1.setText( mPassWordPiSync );
    le2.setText( mActiveSyncIP  );
    le3.setText( mActiveSyncPort );
    if ( dia.exec() ) {
        mPassWordPiSync = le1.text();
        mActiveSyncPort = le3.text();
        mActiveSyncIP = le2.text();
        return true;
    }
    return false;
}
bool KSyncManager::edit_sync_options()
{

    QDialog dia( mParent, "dia", true );
    dia.setCaption( i18n("Device: " ) +mCurrentSyncDevice );
    QButtonGroup gr ( 1,  Qt::Horizontal, i18n("Sync preferences"), &dia);
    QVBoxLayout lay ( &dia );
    lay.setSpacing( 2 );
    lay.setMargin( 3 );
    lay.addWidget(&gr);
    QRadioButton loc ( i18n("Take local entry on conflict"), &gr );
    QRadioButton rem ( i18n("Take remote entry on conflict"), &gr );
    QRadioButton newest( i18n("Take newest entry on conflict"), &gr );
    QRadioButton ask( i18n("Ask for every entry on conflict"), &gr );
    QRadioButton f_loc( i18n("Force: Take local entry always"), &gr );
    QRadioButton f_rem( i18n("Force: Take remote entry always"), &gr );
    //QRadioButton both( i18n("Take both on conflict"), &gr );
    QPushButton pb ( "OK",  &dia); 
    lay.addWidget( &pb );
    connect(&pb, SIGNAL( clicked() ), &dia, SLOT ( accept() ) ); 
    switch ( mSyncAlgoPrefs ) {
    case 0:
        loc.setChecked( true);
        break;
    case 1:
        rem.setChecked( true );
        break;
    case 2:
        newest.setChecked( true);
        break;
    case 3:
        ask.setChecked( true);
        break;
    case 4:
        f_loc.setChecked( true);
        break;
    case 5:
        f_rem.setChecked( true);
        break;
    case 6:
        // both.setChecked( true);
        break; 
    default:
        break;
    }
    if ( dia.exec() ) {
        mSyncAlgoPrefs = rem.isChecked()*1+newest.isChecked()*2+  ask.isChecked()*3+  f_loc.isChecked()*4+  f_rem.isChecked()*5;//+  both.isChecked()*6 ;
        return true;
    }
    return false;
}

QString  KSyncManager::getPassword( )
{
    QString retfile = "";
    QDialog dia ( mParent, "input-dialog", true );
    QLineEdit lab ( &dia );
    lab.setEchoMode( QLineEdit::Password );
    QVBoxLayout lay( &dia );
    lay.setMargin(7);
    lay.setSpacing(7);
    lay.addWidget( &lab);
    dia.setFixedSize( 230,50 );
    dia.setCaption( i18n("Enter password") );
    QPushButton pb ( "OK",  &dia);
    lay.addWidget( &pb );
    connect(&pb, SIGNAL( clicked() ), &dia, SLOT ( accept() ) );
    dia.show();
    int res = dia.exec();
    if ( res )
        retfile = lab.text();
    dia.hide();
    qApp->processEvents();
    return retfile;

}


void KSyncManager::confSync()
{ 
    static KSyncPrefsDialog* sp = 0;
    if ( ! sp ) {
        sp = new KSyncPrefsDialog( mParent, "syncprefs", true );
    }
    sp->usrReadConfig();
#ifndef DESKTOP_VERSION
    sp->showMaximized();
#else
    sp->show();
#endif
    sp->exec();
    mSyncProfileNames = sp->getSyncProfileNames();
    mLocalMachineName = sp->getLocalMachineName ();
    QTimer::singleShot ( 1, this, SLOT ( fillSyncMenu() ) ); 
}
void KSyncManager::syncKDE()
{
    emit save();
    switch(mTargetApp)
        {
        case (KAPI):

            break;
        case (KOPI):
            {
#ifdef DESKTOP_VERSION
                QString command = qApp->applicationDirPath () + "/kdecaldump"; 
#else
                QString command = "kdecaldump"; 
#endif
                if ( ! QFile::exists ( command ) )
                    command = "kdecaldump";  
                QString fileName = QDir::homeDirPath ()+"/.kdecalendardump.ics";
                system (  command.latin1());
                    if ( syncWithFile( fileName,true ) ) {
                        if ( mWriteBackFile ) {
                            command += " --read";
                            system (  command.latin1());
                        }
                    }
                
            }
            break;
        case (PWMPI):

            break;
        default:
            qDebug("KSyncManager::slotSyncMenu: invalid apptype selected");
            break;
	      
        }
}

void KSyncManager::syncSharp()
{

    if ( ! syncExternalApplication("sharp") )
        qDebug("ERROR sync sharp  ");
}

bool KSyncManager::syncExternalApplication(QString  resource)
{
   
    emit save();

    if ( mAskForPreferences )  
        if ( !edit_sync_options()) {
            mParent->topLevelWidget()->setCaption( i18n("Syncing aborted. Nothing synced.") );
            return false;
        }

    qDebug("Sync extern %s", resource.latin1());

    bool syncOK = mImplementation->syncExternal(this, resource);

    return syncOK;

}

void KSyncManager::syncPhone()
{

    syncExternalApplication("phone");

}

void KSyncManager::showProgressBar(int percentage, QString caption, int total)
{
    if (!bar->isVisible())
        {
            bar->setCaption (caption); 
            bar->setTotalSteps (  total  ) ;

            bar->show();
        }

    bar->setProgress( percentage );
}

void KSyncManager::hideProgressBar()
{
    bar->hide();
}

bool KSyncManager::isProgressBarCanceled()
{
    return !bar->isVisible();
}

QString KSyncManager::syncFileName()
{

    QString fn = "tempfile";
    switch(mTargetApp)
        {
        case (KAPI):
            fn = "tempsyncab.vcf";
            break;
        case (KOPI):
            fn = "tempsynccal.ics";
            break;
        case (PWMPI):
            fn = "tempsyncpw.pwm";
            break;
        default:
            break;
        }
#ifdef _WIN32_
    return  locateLocal( "tmp", fn );
#else
    return (QString( "/tmp/" )+ fn );
#endif
}

void KSyncManager::syncPi()
{
    mPisyncFinished = false;
    qApp->processEvents();
    if ( mAskForPreferences )
        if ( !edit_pisync_options()) {
            mParent->topLevelWidget()->setCaption( i18n("Syncing aborted. Nothing synced.") );
            return;
        }
    bool ok;
    Q_UINT16 port = mActiveSyncPort.toUInt(&ok);
    if ( ! ok ) {
        mParent->topLevelWidget()->setCaption( i18n("Sorry, no valid port.Syncing cancelled.") );
        return;
    }
    KCommandSocket* commandSocket = new KCommandSocket( mPassWordPiSync, port, mActiveSyncIP, this );
    connect( commandSocket, SIGNAL(commandFinished( KCommandSocket*, int )), this, SLOT(deleteCommandSocket(KCommandSocket*, int)) );
    mParent->topLevelWidget()->setCaption( i18n("Sending request for remote file ...") );
    commandSocket->readFile(  syncFileName() );
}

void KSyncManager::deleteCommandSocket(KCommandSocket*s, int state)
{
    //enum { success, errorW, errorR, quiet };
    if ( state == KCommandSocket::errorR ||state == KCommandSocket::errorTO ) {
        mParent->topLevelWidget()->setCaption( i18n("ERROR: Receiving remote file failed.") );
        delete s;
        if ( state == KCommandSocket::errorR ) {
            KCommandSocket* commandSocket = new KCommandSocket( mPassWordPiSync, mActiveSyncPort.toUInt(), mActiveSyncIP, this );
            connect( commandSocket, SIGNAL(commandFinished( KCommandSocket*, int)), this, SLOT(deleteCommandSocket(KCommandSocket*, int )) );
            commandSocket->sendStop();
        }
        mPisyncFinished = true;
        return;
        
    } else  if ( state == KCommandSocket::errorW ) {
        mParent->topLevelWidget()->setCaption( i18n("ERROR:Writing back file failed.") );
        mPisyncFinished = true;

    } else  if ( state == KCommandSocket::successR ) {
        QTimer::singleShot( 1, this , SLOT ( readFileFromSocket()));

    } else  if ( state == KCommandSocket::successW ) {
        mParent->topLevelWidget()->setCaption( i18n("Pi-Sync succesful!") );
        mPisyncFinished = true;
    }

    delete s;
}

void KSyncManager::readFileFromSocket()
{
    QString fileName = syncFileName();
    mParent->topLevelWidget()->setCaption( i18n("Remote file saved to temp file.") );
    if ( ! syncWithFile( fileName , true ) ) {
        mParent->topLevelWidget()->setCaption( i18n("Syncing failed.") );
        mPisyncFinished = true;
        return;
    }
    KCommandSocket* commandSocket = new KCommandSocket( mPassWordPiSync, mActiveSyncPort.toUInt(), mActiveSyncIP, this );
    connect( commandSocket, SIGNAL(commandFinished( KCommandSocket*, int)), this, SLOT(deleteCommandSocket(KCommandSocket*, int )) );
    if ( mWriteBackFile ) 
        commandSocket->writeFile(  fileName );
    else {
        commandSocket->sendStop();
        mParent->topLevelWidget()->setCaption( i18n("Pi-Sync succesful!") );
        mPisyncFinished = true;
    }
}

KServerSocket:: KServerSocket ( QString pw, Q_UINT16 port, int backlog, QObject * parent, const char * name ) : QServerSocket( port, backlog, parent, name )
{
    mPassWord = pw;
    mSocket = 0;
    mSyncActionDialog = 0;
    blockRC = false;
};

void KServerSocket::newConnection ( int socket ) 
{
    // qDebug("KServerSocket:New connection %d ", socket); 
    if ( mSocket ) {
        qDebug("KServerSocket::newConnection Socket deleted! ");
        delete mSocket;
        mSocket = 0;
    }
    mSocket = new QSocket( this );
    connect( mSocket , SIGNAL(readyRead()), this, SLOT(readClient()) );
    connect( mSocket , SIGNAL(delayedCloseFinished()), this, SLOT(discardClient()) );
    mSocket->setSocket( socket );
}

void KServerSocket::discardClient()
{
    //qDebug(" KServerSocket::discardClient()");
    if ( mSocket ) {
        delete mSocket;
        mSocket = 0;
    }
    //emit endConnect();
}
void KServerSocket::readClient()
{
    if ( blockRC )
        return;
    if ( mSocket == 0 ) {
        qDebug("ERROR::KServerSocket::readClient(): mSocket == 0  ");
        return;
    }
    //qDebug("KServerSocket::readClient()");
    if ( mSocket->canReadLine() ) {
        QString line = mSocket->readLine();
        //qDebug("KServerSocket readline: %s ", line.latin1());
        QStringList tokens = QStringList::split( QRegExp("[ \r\n][ \r\n]*"), line );
        if ( tokens[0] == "GET" ) {
            if (  tokens[1] == mPassWord )
                //emit sendFile( mSocket );
                send_file();
            else {
                KMessageBox::error( 0, i18n("Got send file request\nwith invalid password"));
                //qDebug("password %s, invalid password %s ",mPassWord.latin1(), tokens[1].latin1() );
            }
        } 
        if ( tokens[0] == "PUT" ) {
            if (  tokens[1] == mPassWord ) {
                //emit getFile( mSocket );
                blockRC = true;
                get_file();
            }
            else {
                KMessageBox::error( 0, i18n("Got receive file request\nwith invalid password"));
                //qDebug("password %s, invalid password %s ",mPassWord.latin1(), tokens[1].latin1() );
            }
        } 
        if ( tokens[0] == "STOP" ) {
            //emit endConnect();
            end_connect();
        }
    }
}
void KServerSocket::end_connect()
{
    delete mSyncActionDialog;
    mSyncActionDialog = 0;
}
void KServerSocket::send_file()
{
    //qDebug("MainWindow::sendFile(QSocket* s) ");
    if ( mSyncActionDialog )
        delete mSyncActionDialog;
    mSyncActionDialog = new QDialog ( 0, "input-dialog", true );
    mSyncActionDialog->setCaption(i18n("Received sync request"));
    QLabel* label = new QLabel( i18n("Synchronizing from remote ...\n\nDo not use this application!\n\nIf syncing fails\nyou can close this dialog."), mSyncActionDialog );
    QVBoxLayout* lay = new QVBoxLayout( mSyncActionDialog );
    lay->addWidget( label);
    lay->setMargin(7);
    lay->setSpacing(7);
    mSyncActionDialog->setFixedSize( 230, 120);
    mSyncActionDialog->show();
    mSyncActionDialog->raise();
    emit request_file();
    qApp->processEvents();
    QString fileName = mFileName;
    QFile file( fileName );
    if (!file.open( IO_ReadOnly ) ) {
        delete mSyncActionDialog;
        mSyncActionDialog = 0;
        qDebug("KSS::error open file ");
        mSocket->close();
        if ( mSocket->state() == QSocket::Idle )
            QTimer::singleShot( 10, this , SLOT ( discardClient()));
        return ;
        
    } 
    mSyncActionDialog->setCaption( i18n("Sending file...") );
    QTextStream ts( &file );
    ts.setEncoding( QTextStream::Latin1 );

    QTextStream os( mSocket );
    os.setEncoding( QTextStream::Latin1 );
    while ( ! ts.atEnd() ) {
        os << ts.readLine() << "\r\n";
    }
    //os << ts.read();
    file.close();
    mSyncActionDialog->setCaption( i18n("Waiting for synced file...") );
    mSocket->close();
    if ( mSocket->state() == QSocket::Idle )
        QTimer::singleShot( 10, this , SLOT ( discardClient()));
}
void KServerSocket::get_file()
{
    mSyncActionDialog->setCaption( i18n("Receiving synced file...") );
   
    piTime.start();
    piFileString = "";
    QTimer::singleShot( 1, this , SLOT (readBackFileFromSocket( ) ));
}


void KServerSocket::readBackFileFromSocket()
{
    //qDebug("readBackFileFromSocket() %d ", piTime.elapsed ());
    while ( mSocket->canReadLine ()  ) {
        piTime.restart();
        QString line = mSocket->readLine ();
        piFileString += line;
        //qDebug("readline: %s ", line.latin1());
        mSyncActionDialog->setCaption( i18n("Received %1 bytes").arg( piFileString.length()  ) );

    }
    if ( piTime.elapsed () < 3000 ) {
        // wait for more 
        //qDebug("waitformore ");
        QTimer::singleShot( 100, this , SLOT (readBackFileFromSocket( ) ));
        return;
    }
    QString fileName = mFileName;
    QFile file ( fileName );
    if (!file.open( IO_WriteOnly ) ) {
        delete mSyncActionDialog;
        mSyncActionDialog = 0;
        qDebug("KSS:Error open read back file ");
        piFileString = "";
        emit file_received( false );
        blockRC = false;
        return ;
                    
    } 

    // mView->setLoadedFileVersion(QDateTime::currentDateTime().addSecs( -1));
    QTextStream ts ( &file );
    ts.setEncoding( QTextStream::Latin1 );
    mSyncActionDialog->setCaption( i18n("Writing file to disk...") );
    ts << piFileString;
    mSocket->close();
    if ( mSocket->state() == QSocket::Idle )
        QTimer::singleShot( 10, this , SLOT ( discardClient()));
    file.close(); 
    piFileString = "";
    emit file_received( true );
    delete mSyncActionDialog;
    mSyncActionDialog = 0;
    blockRC = false;

}

KCommandSocket::KCommandSocket (  QString password, Q_UINT16 port, QString host, QObject * parent, const char * name ): QObject( parent, name )
{
    mPassWord = password;
    mSocket = 0;
    mPort = port;
    mHost = host;

    mRetVal = quiet;
    mTimerSocket = new QTimer ( this );
    connect( mTimerSocket, SIGNAL ( timeout () ), this, SLOT ( deleteSocket()  ) );
}
void KCommandSocket::readFile( QString fn )
{
    if ( !mSocket ) {
        mSocket = new QSocket( this );
        connect( mSocket, SIGNAL(readyRead()), this, SLOT(startReadFileFromSocket()) );
        connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) );
    }
    mFileString = "";
    mFileName = fn;
    mFirst = true;
    mSocket->connectToHost( mHost, mPort ); 
    QTextStream os( mSocket );
    os.setEncoding( QTextStream::Latin1 );
    os << "GET " << mPassWord << "\r\n";
    mTimerSocket->start( 20000 );
}

void KCommandSocket::writeFile( QString fileName  )
{
    if ( !mSocket ) {
        mSocket = new QSocket( this );
        connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) );
        connect( mSocket, SIGNAL(connected ()), this, SLOT(writeFileToSocket()) );
    }
    mFileName = fileName ;
    mSocket->connectToHost( mHost, mPort ); 
}
void KCommandSocket::writeFileToSocket()
{
    QFile file2( mFileName );
    if (!file2.open( IO_ReadOnly ) ) {
        mRetVal= errorW;
        mSocket->close();
        if ( mSocket->state() == QSocket::Idle )
            QTimer::singleShot( 10, this , SLOT ( deleteSocket()));
        return ;
    }  
    QTextStream ts2( &file2 );
    ts2.setEncoding( QTextStream::Latin1 );
    QTextStream os2( mSocket );
    os2.setEncoding( QTextStream::Latin1 );
    os2 << "PUT " << mPassWord << "\r\n";;
    while ( ! ts2.atEnd() ) {
        os2 << ts2.readLine() << "\r\n";
    }
    mRetVal= successW;
    file2.close();
    mSocket->close();
    if ( mSocket->state() == QSocket::Idle )
        QTimer::singleShot( 10, this , SLOT ( deleteSocket()));
}
void KCommandSocket::sendStop()
{
    if ( !mSocket ) {
        mSocket = new QSocket( this );
        connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) );
    }
    mSocket->connectToHost( mHost, mPort ); 
    QTextStream os2( mSocket );
    os2.setEncoding( QTextStream::Latin1 );
    os2 << "STOP\r\n";
    mSocket->close();
    if ( mSocket->state() == QSocket::Idle )
        QTimer::singleShot( 10, this , SLOT ( deleteSocket()));
}

void KCommandSocket::startReadFileFromSocket()
{
    if ( ! mFirst )
        return;
    mFirst = false;
    mTimerSocket->stop();
    mFileString = "";
    mTime.start();
    QTimer::singleShot( 1, this , SLOT (readFileFromSocket( ) ));

}
void KCommandSocket::readFileFromSocket()
{
    //qDebug("readBackFileFromSocket() %d ", mTime.elapsed ());
    while ( mSocket->canReadLine ()  ) {
        mTime.restart();
        QString line = mSocket->readLine ();
        mFileString += line;
        //qDebug("readline: %s ", line.latin1());
    }
    if ( mTime.elapsed () < 3000 ) {
        // wait for more 
        //qDebug("waitformore ");
        QTimer::singleShot( 100, this , SLOT (readFileFromSocket( ) ));
        return;
    }
    QString fileName = mFileName;
    QFile file ( fileName );
    if (!file.open( IO_WriteOnly ) ) {
        mFileString = "";
        mRetVal = errorR;
        qDebug("KSS:Error open temp sync file for writing: %s",fileName.latin1() );
        deleteSocket();
        return ;
                    
    } 
    // mView->setLoadedFileVersion(QDateTime::currentDateTime().addSecs( -1));
    QTextStream ts ( &file );
    ts.setEncoding( QTextStream::Latin1 );
    ts << mFileString;
    file.close();  
    mFileString = "";
    mRetVal = successR;
    mSocket->close();
    // if state is not idle, deleteSocket(); is called via 
    //  connect( mSocket, SIGNAL(delayedCloseFinished ()), this, SLOT(deleteSocket()) );
    if ( mSocket->state() == QSocket::Idle )
        deleteSocket();
}

void KCommandSocket::deleteSocket()
{
    //qDebug("KCommandSocket::deleteSocket() ");
    if ( mTimerSocket->isActive () ) {
        mTimerSocket->stop();
        mRetVal = errorTO;
        qDebug("Connection to remote host timed out");
        if ( mSocket ) {
            mSocket->close();
            //if ( mSocket->state() == QSocket::Idle )
            //   deleteSocket();
            delete mSocket;
            mSocket = 0;
        }
        KMessageBox::error( 0, i18n("Connection to remote\nhost timed out!\nDid you forgot to enable\nsyncing on remote host? "));
        emit commandFinished( this, mRetVal );
        return;      
    }
    //qDebug("KCommandSocket::deleteSocket() %d", mRetVal ); 
    if ( mSocket)
        delete mSocket;
    mSocket = 0; 
    emit commandFinished( this, mRetVal );
}