/* copyop.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2026 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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 St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "listermode.h"
#include "worker.h"
#include "copyop.h"
#include "copyopwin.hh"
#include "nmspecialsourceext.hh"
#include "worker_locale.h"
#include "datei.h"
#include "dnd.h"
#include "aguix/choosebutton.h"
#include "aguix/cyclebutton.h"
#include "aguix/button.h"
#include "virtualdirmode.hh"

using namespace CopyParams;

const char *CopyOp::name="CopyOp";

CopyOp::CopyOp() : FunctionProto()
{
  follow_symlinks=false;
  move=false;
  do_rename=false;
  same_dir=false;
  request_dest=false;
  preserve_attr=true;
  vdir_preserve_dir_structure = false;
  adjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_NEVER;
  ensure_file_permissions = LEAVE_PERMISSIONS_UNMODIFIED;
  m_also_select_extension = false;
  hasConfigure = true;
    m_category = FunctionProto::CAT_FILEOPS;
    setRequestParameters( false );
}

CopyOp::~CopyOp()
{
}

CopyOp*
CopyOp::duplicate() const
{
  CopyOp *ta=new CopyOp();
  ta->follow_symlinks=follow_symlinks;
  ta->move=move;
  ta->do_rename=do_rename;
  ta->same_dir=same_dir;
  ta->request_dest=request_dest;
  ta->overwrite=overwrite;
  ta->preserve_attr=preserve_attr;
  ta->vdir_preserve_dir_structure = vdir_preserve_dir_structure;
  ta->adjust_relative_symlinks = adjust_relative_symlinks;
  ta->ensure_file_permissions = ensure_file_permissions;
  ta->m_also_select_extension = m_also_select_extension;
  ta->setRequestParameters( requestParameters() );
  return ta;
}

bool
CopyOp::isName(const char *str)
{
  if(strcmp(str,name)==0) return true; else return false;
}

const char *
CopyOp::getName()
{
  return name;
}

int
CopyOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
  ListerMode *lm1;
  if(msg->mode!=msg->AM_MODE_DNDACTION) {
    Lister *l1 = msg->getWorker()->getActiveLister();
    if(l1!=NULL) {
      startlister=l1;
      endlister = msg->getWorker()->getOtherLister(startlister);
      lm1=startlister->getActiveMode();
      if(lm1!=NULL) {
          if(dynamic_cast< VirtualDirMode * >( lm1 ) ) {
              normalmodecopy( msg );
          } else {
              lm1->not_supported();
          }
      }
    }
  } else {
    normalmodecopy( msg );
  }
  return 0;
}

bool
CopyOp::save(Datei *fh)
{
  if ( fh == NULL ) return false;
  fh->configPutPairBool( "followsymlinks", follow_symlinks );
  fh->configPutPairBool( "move", move );
  fh->configPutPairBool( "rename", do_rename );
  fh->configPutPairBool( "samedir", same_dir );
  fh->configPutPairBool( "requestdest", request_dest );
  fh->configPutPairBool( "requestflags", requestParameters() );
  switch(overwrite) {
    case copyorder::COPY_OVERWRITE_ALWAYS:
      fh->configPutPair( "overwrite", "always" );
      break;
    case copyorder::COPY_OVERWRITE_NEVER:
      fh->configPutPair( "overwrite", "never" );
      break;
    case copyorder::COPY_OVERWRITE_OLDER:
      fh->configPutPair( "overwrite", "older" );
      break;
    case copyorder::COPY_OVERWRITE_SMALLER:
      fh->configPutPair( "overwrite", "smaller" );
      break;
    case copyorder::COPY_OVERWRITE_DIFFERENT_SIZE:
      fh->configPutPair( "overwrite", "differentsize" );
      break;
    default:
      fh->configPutPair( "overwrite", "normal" );
      break;
  }
  fh->configPutPairBool( "preserveattr", preserve_attr );

  if ( vdir_preserve_dir_structure == true ) {
      fh->configPutPairBool( "vdirpreservedirstructure", vdir_preserve_dir_structure );
  }
  
  switch ( adjust_relative_symlinks ) {
      case COPYOP_ADJUST_SYMLINK_OUTSIDE:
          fh->configPutPair( "adjustrelativesymlinks", "outside" );
          break;
      case COPYOP_ADJUST_SYMLINK_ALWAYS:
          fh->configPutPair( "adjustrelativesymlinks", "always" );
          break;
      default:
          break;
  }

  switch ( ensure_file_permissions() ) {
      case ensure_mode_t::ENSURE_USER_RW_PERMISSION:
          fh->configPutPair( "ensure_file_permissions", "user_rw" );
          break;
      case ENSURE_USER_RW_GROUP_R_PERMISSION:
          fh->configPutPair( "ensure_file_permissions", "user_rw_group_r" );
          break;
      case ENSURE_USER_RW_ALL_R_PERMISSION:
          fh->configPutPair( "ensure_file_permissions", "user_rw_all_r" );
          break;
      default:
          break;
  }

  if ( m_also_select_extension == true ) {
      fh->configPutPairBool( "alsoselectextension", m_also_select_extension );
  }
  
  return true;
}

const char *
CopyOp::getDescription()
{
  return catalog.getLocale(1249);
}

int
CopyOp::normalmodecopy( ActionMessage *am )
{
  bool do_request,cont=true;
  std::string destination_directory;
  ListerMode *start_lm = NULL, *dest_lm = NULL;
  
  if(am->mode==am->AM_MODE_DNDACTION) {
      start_lm = am->dndmsg->getSourceMode();
      if ( start_lm == NULL ) return 1;

      dest_lm = am->dndmsg->getDestMode();
  } else {
      if ( startlister == NULL ) return 1;
      start_lm = startlister->getActiveMode();
      if ( start_lm == NULL ) return 1;

      if ( endlister != NULL ) {
          dest_lm = endlister->getActiveMode();
      }
  }
  
  if(requestParameters()==true) {
    if(doconfigure(1)!=0) cont=false;
  } else {
    // set values in t* variables
    tfollow_symlinks=follow_symlinks;
    tmove=move;
    trename=do_rename;
    tsame_dir=same_dir;
    trequest_dest=request_dest;
    toverwrite=overwrite;
    tpreserve_attr=preserve_attr;
    tvdir_preserve_dir_structure = vdir_preserve_dir_structure;
    tadjust_relative_symlinks = adjust_relative_symlinks;
    tensure_file_permissions = ensure_file_permissions;
    talso_select_extension = m_also_select_extension;

    if ( toverwrite != copyorder::COPY_OVERWRITE_NORMAL ) {
        std::string textstr;

        switch ( toverwrite ) {
            case copyorder::COPY_OVERWRITE_ALWAYS:
                textstr = catalog.getLocale( 1439 );
                break;
            case copyorder::COPY_OVERWRITE_NEVER:
                textstr = catalog.getLocale( 1440 );
                break;
            case copyorder::COPY_OVERWRITE_OLDER:
                textstr = catalog.getLocale( 1586 );
                break;
            case copyorder::COPY_OVERWRITE_SMALLER:
                textstr = catalog.getLocale( 1587 );
                break;
            case copyorder::COPY_OVERWRITE_DIFFERENT_SIZE:
                textstr = catalog.getLocale( 1588 );
                break;
            case copyorder::COPY_OVERWRITE_NORMAL:
                // will not happen, but to make compiler happy
                abort();
                break;
        }

        std::string buttonstr = catalog.getLocale( 629 );
        buttonstr += "|";
        buttonstr += catalog.getLocale( 8 );

        int erg = Worker::getRequester()->request( catalog.getLocale( 123 ),
                                                   textstr.c_str(),
                                                   buttonstr.c_str() );

        if ( erg != 0 ) {
            cont = false;
        }
    }
  }
  
  if ( ! cont ) {
      return 0;
  }

    std::shared_ptr< struct copyorder > co;

    co.reset( new copyorder );

    co->ignoreLosedAttr = false;
    // detect what to copy
    if(am->mode==am->AM_MODE_ONLYACTIVE)
      co->source=co->COPY_ONLYACTIVE;
    else if(am->mode==am->AM_MODE_DNDACTION) {
      // insert DND-element into list
      co->source=co->COPY_SPECIAL;
      co->sources.push_back( new NM_specialsourceExt( am->dndmsg->getFE() ) );
    } else if(am->mode==am->AM_MODE_SPECIAL) {
      co->source=co->COPY_SPECIAL;
      co->sources.push_back( new NM_specialsourceExt( am->getFE() ) );
    } else {
      co->source=co->COPY_ALLENTRIES;
    }

    /* now source defined
       next find destination
       
       Priority:
        1.Flag for requesting destination
        2.Flag for same dir
        3.When DNDAction destination of DND
        4.nonactive lister
       
       when no destination then also requesting
    */

    do_request = false;

    bool last_path_used = false;

    if ( trequest_dest == true ) {
        do_request = true;
    } else if ( tsame_dir == true ) {
        destination_directory = start_lm->getCurrentDirectory();
    } else if ( am->mode == am->AM_MODE_DNDACTION ) {
        std::string ddstr = am->dndmsg->getDestDir();
        if ( ! ddstr.empty() ) {
            destination_directory = ddstr;
        }
    } else {
        if ( dest_lm != NULL ) {
            destination_directory = dest_lm->getCurrentDirectory();

            if ( destination_directory.empty() ) {
                do_request = true;
            }

            if ( destination_directory.empty() ) {
                destination_directory = endlister->getLastPath();

                if ( ! destination_directory.empty() ) {
                    last_path_used = true;
                }
            }

            if ( auto vdm = dynamic_cast< VirtualDirMode * >( dest_lm ) ) {
                if ( ! destination_directory.empty() && ! vdm->currentDirIsReal() ) {
                    std::string textstr = AGUIXUtils::formatStringToString( catalog.getLocale( 1002 ),
                                                                            destination_directory.c_str() );
                    std::string buttonstr = catalog.getLocale( 629 );
                    buttonstr += "|";
                    buttonstr += catalog.getLocale( 8 );

                    int erg = Worker::getRequester()->request( catalog.getLocale( 123 ),
                                                               textstr.c_str(),
                                                               buttonstr.c_str() );

                    if ( erg == 1 ) {
                        do_request = false;
                        destination_directory.clear();
                    }
                }
            }
        } else {
            do_request=true;
        }
    }

    if ( last_path_used ) {
        int use_previous_if_same = 0;
        std::string previously_used_path;

        try {
            use_previous_if_same = Worker::getKVPStore().getIntValue( "copy_use_previous_if_same" );
            previously_used_path = Worker::getKVPStore().getStringValue( "copy_previous_destination" );

            if ( use_previous_if_same != 0 &&
                 previously_used_path == destination_directory ) {
                do_request = false;
            }
        } catch (...) {
        }
    }

    if ( do_request == true ) {
        std::string default_dir;
        char *tstr = NULL;

        if ( ! destination_directory.empty() ) {
            default_dir = destination_directory;
        } else {
            if ( dest_lm != NULL ) {
                default_dir = dest_lm->getCurrentDirectory();

                if ( default_dir.empty() ) {
                    default_dir = start_lm->getCurrentDirectory();
                }
            } else {
                default_dir = start_lm->getCurrentDirectory();
            }
        }
      
        bool ask_result = false;

        if ( requestdest( default_dir.c_str(), &tstr, last_path_used, ask_result ) != 0 ) {
            destination_directory.clear();
        } else {
            destination_directory = tstr;
            _freesafe( tstr );

            if ( last_path_used ) {
                Worker::getKVPStore().setIntValue( "copy_use_previous_if_same", ask_result ? 1 : 0 );
                Worker::getKVPStore().setStringValue( "copy_previous_destination",
                                                      destination_directory );
            }
        }
    }
    /* if dest==null nothing to do
       otherwise: */
    if ( ! destination_directory.empty() ) {
        /* if dest starts with no slash then take it as local dir
           so add currentDir */
        if ( destination_directory[0] != '/' ) {
            std::string tstr = start_lm->getCurrentDirectory();

            destination_directory = tstr + "/" + destination_directory;
        }
        /* now also destination determined
           next describing what to do */
        co->move=tmove;
        co->follow_symlinks=tfollow_symlinks;
        co->preserve_attr=tpreserve_attr;
        co->vdir_preserve_dir_structure = tvdir_preserve_dir_structure;
        co->also_select_extension = talso_select_extension;

        switch ( tadjust_relative_symlinks ) {
            case COPYOP_ADJUST_SYMLINK_OUTSIDE:
                co->adjust_relative_symlinks = co->COPY_ADJUST_SYMLINK_OUTSIDE;
                break;
            case COPYOP_ADJUST_SYMLINK_ALWAYS:
                co->adjust_relative_symlinks = co->COPY_ADJUST_SYMLINK_ALWAYS;
                break;
            default:                
                co->adjust_relative_symlinks = co->COPY_ADJUST_SYMLINK_NEVER;
                break;
        }

        co->ensure_file_permissions = tensure_file_permissions;

        co->do_rename=trename;
        co->overwrite = toverwrite;
        co->destdir = destination_directory.c_str();
        co->also_select_extension = talso_select_extension;
        // now start copy process
        co->cowin=new CopyOpWin( am->getWorker()->getAGUIX(),
                                       co->move );

        if ( VirtualDirMode *vdm = dynamic_cast< VirtualDirMode * >( start_lm ) ) {
            vdm->copy( co );
        }
    }

    return 0;
}

int
CopyOp::doconfigure(int mode)
{
  AGUIX *aguix = Worker::getAGUIX();
  AWindow *win;
  ChooseButton *fscb,*mcb,*rcb,*sdcb,*rfcb=NULL,*rdcb,*pacb;
//  CycleButton *ocyb,*fccyb;
  AGMessage *msg;
  int endmode=-1;
  Requester *req;
  char *tstr;
  const int cincw = AContainer::ACONT_MINH +
                    AContainer::ACONT_MINW +
                    AContainer::ACONT_MAXH;
  const int cincwnr = cincw +
                      AContainer::ACONT_NORESIZE;
  const int cfix = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW +
                   AContainer::ACONT_MAXH +
                   AContainer::ACONT_MAXW;
  
  req=new Requester(aguix);

  tstr=(char*)_allocsafe(strlen(catalog.getLocale(293))+strlen(getDescription())+1);
  sprintf(tstr,catalog.getLocale(293),getDescription());
  win = new AWindow( aguix, 10, 10, 10, 10, tstr, AWindow::AWINDOW_DIALOG );
  win->create();
  _freesafe(tstr);

  AContainer *ac1 = win->setContainer( new AContainer( win, 1, 13 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  ac1->add( new Text( aguix, 0, 0, getDescription() ), 0, 0, cincwnr );

  fscb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, 20, 20, ( follow_symlinks == true ) ? 1 : 0,
						    catalog.getLocale( 298 ), LABEL_RIGHT, 0 ), 0, 1, cincwnr );

  mcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, 20, 20, ( move == true ) ? 1 : 0,
						   catalog.getLocale( 299 ), LABEL_RIGHT, 0 ), 0, 2, cincwnr );

  AContainer *ac0_3 = ac1->add( new AContainer( win, 2, 1 ), 0, 3 );
  ac0_3->setMinSpace( 5 );
  ac0_3->setMaxSpace( 5 );
  ac0_3->setBorderWidth( 0 );

  rcb = ac0_3->addWidget( new ChooseButton( aguix, 0, 0, 20, 20, ( do_rename == true ) ? 1 : 0,
                                            catalog.getLocale( 300 ), LABEL_RIGHT, 0 ), 0, 0, cincwnr );
  auto also_select_extension_cb = ac0_3->addWidget( new ChooseButton( aguix, 0, 0, 20, 20, m_also_select_extension,
                                                                      catalog.getLocale( 1564 ), LABEL_RIGHT, 0 ), 1, 0, cincwnr );


  sdcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, 20, 20, ( same_dir == true ) ? 1 : 0,
						    catalog.getLocale( 301 ), LABEL_RIGHT, 0 ), 0, 4, cincwnr );

  rdcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, 20, 20, ( request_dest == true ) ? 1 : 0,
						    catalog.getLocale( 302 ), LABEL_RIGHT, 0 ), 0, 5, cincwnr );

  pacb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, 20, 20, ( preserve_attr == true ) ? 1 : 0,
						    catalog.getLocale( 150 ), LABEL_RIGHT, 0 ), 0, 6, cincwnr );

  AContainer *ac1_1 = ac1->add( new AContainer( win, 2, 1 ), 0, 7 );
  ac1_1->setMinSpace( 5 );
  ac1_1->setMaxSpace( 5 );
  ac1_1->setBorderWidth( 0 );

  ac1_1->addWidget( new Text( aguix, 0, 0, catalog.getLocale( 1088 ) ),
                    0, 0, cfix );
  CycleButton *ars_cyb = ac1_1->addWidget( new CycleButton( aguix, 0, 0, 100, 0 ),
                                           1, 0, cincwnr );
  ars_cyb->addOption( catalog.getLocale( 306 ) );
  ars_cyb->addOption( catalog.getLocale( 1089 ) );
  ars_cyb->addOption( catalog.getLocale( 305 ) );
  ars_cyb->resize( ars_cyb->getMaxSize(),
                   ars_cyb->getHeight() );
  ac1_1->readLimits();

  switch ( adjust_relative_symlinks ) {
    case COPYOP_ADJUST_SYMLINK_OUTSIDE:
      ars_cyb->setOption( 1 );
      break;
    case COPYOP_ADJUST_SYMLINK_ALWAYS:
      ars_cyb->setOption( 2 );
      break;
    default:
      ars_cyb->setOption( 0 );
      break;
  }

  AContainer *ac1_ens_perm = ac1->add( new AContainer( win, 2, 1 ), 0, 8 );
  ac1_ens_perm->setMinSpace( 5 );
  ac1_ens_perm->setMaxSpace( 5 );
  ac1_ens_perm->setBorderWidth( 0 );

  ac1_ens_perm->addWidget( new Text( aguix, 0, 0, catalog.getLocale( 1097 ) ),
                           0, 0, cfix );
  CycleButton *ep_cyb = ac1_ens_perm->addWidget( new CycleButton( aguix, 0, 0, 100, 0 ),
                                                 1, 0, cincwnr );
  ep_cyb->addOption( catalog.getLocale( 1098 ) );
  ep_cyb->addOption( catalog.getLocale( 1099 ) );
  ep_cyb->addOption( catalog.getLocale( 1100 ) );
  ep_cyb->addOption( catalog.getLocale( 1101 ) );
  ep_cyb->resize( ep_cyb->getMaxSize(),
                  ep_cyb->getHeight() );
  ac1_ens_perm->readLimits();

  switch ( ensure_file_permissions() ) {
    case ENSURE_USER_RW_PERMISSION:
      ep_cyb->setOption( 1 );
      break;
    case ENSURE_USER_RW_GROUP_R_PERMISSION:
      ep_cyb->setOption( 2 );
      break;
    case ENSURE_USER_RW_ALL_R_PERMISSION:
      ep_cyb->setOption( 3 );
      break;
    default:
      ep_cyb->setOption( 0 );
      break;
  }

/*  ttext=(Text*)win->add(new Text(aguix,x,y,catalog.getLocale(303),1));
  x+=ttext->getWidth()+5;
  ocyb=(CycleButton*)win->add(new CycleButton(aguix,x,y,100,1,0,0));
  ocyb->addOption(catalog.getLocale(304));
  ocyb->addOption(catalog.getLocale(305));
  ocyb->addOption(catalog.getLocale(306));
  ocyb->resize(ocyb->getMaxSize(),ocyb->getHeight());
  switch(overwrite) {
    case COPYOP_OVERWRITE_ALWAYS:
      ocyb->setOption(1);
      break;
    case COPYOP_OVERWRITE_NEVER:
      ocyb->setOption(2);
      break;
    default:
      ocyb->setOption(0);
      break;
  }
  
  y+=ocyb->getHeight()+5;
  tw=x+ocyb->getWidth()+5;
  if(tw>w) w=tw;
  x=5;*/

  auto vdirpreserve_cb = ac1->addWidget( new ChooseButton( aguix, 0, 0, 20, 20, ( vdir_preserve_dir_structure == true ) ? 1 : 0,
                                                           catalog.getLocale( 1209 ), LABEL_RIGHT, 0 ), 0, 9, cincwnr );

  AContainer *ac1_overwrite_mode = ac1->add( new AContainer( win, 2, 1 ), 0, 10 );
  ac1_overwrite_mode->setMinSpace( 5 );
  ac1_overwrite_mode->setMaxSpace( 5 );
  ac1_overwrite_mode->setBorderWidth( 0 );

  ac1_overwrite_mode->addWidget( new Text( aguix, 0, 0, catalog.getLocale( 303 ) ),
                                 0, 0, cfix );
  CycleButton *overwritemode_cyb = ac1_overwrite_mode->addWidget( new CycleButton( aguix, 0, 0, 100, 0 ),
                                                                  1, 0, cincwnr );
  overwritemode_cyb->addOption( catalog.getLocale( 304 ) );
  overwritemode_cyb->addOption( catalog.getLocale( 305 ) );
  overwritemode_cyb->addOption( catalog.getLocale( 306 ) );
  overwritemode_cyb->addOption( catalog.getLocale( 1589 ) );
  overwritemode_cyb->addOption( catalog.getLocale( 1590 ) );
  overwritemode_cyb->addOption( catalog.getLocale( 1591 ) );
  overwritemode_cyb->resize( overwritemode_cyb->getMaxSize(),
                             overwritemode_cyb->getHeight() );
  ac1_overwrite_mode->readLimits();

  switch ( overwrite ) {
      case copyorder::COPY_OVERWRITE_ALWAYS:
          overwritemode_cyb->setOption( 1 );
          break;
      case copyorder::COPY_OVERWRITE_NEVER:
          overwritemode_cyb->setOption( 2 );
          break;
      case copyorder::COPY_OVERWRITE_OLDER:
          overwritemode_cyb->setOption( 3 );
          break;
      case copyorder::COPY_OVERWRITE_SMALLER:
          overwritemode_cyb->setOption( 4 );
          break;
      case copyorder::COPY_OVERWRITE_DIFFERENT_SIZE:
          overwritemode_cyb->setOption( 5 );
          break;
      default:
          overwritemode_cyb->setOption( 0 );
          break;
  }

  if(mode==0) {
    rfcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, 20, 20, ( requestParameters() == true ) ? 1 : 0,
						      catalog.getLocale( 294 ), LABEL_RIGHT, 0 ), 0, 11, cincwnr );
  }

  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 12 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( -1 );
  ac1_2->setBorderWidth( 0 );
  Button *okb =(Button*)ac1_2->add( new Button( aguix,
                                                0,
                                                0,
                                                catalog.getLocale( 11 ),
                                                0 ), 0, 0, cfix );
  Button *cb = (Button*)ac1_2->add( new Button( aguix,
						0,
						0,
						catalog.getLocale( 8 ),
						0 ), 1, 0, cfix );
  
  okb->takeFocus();
  win->setDoTabCycling( true );
  win->contMaximize( true );
  win->show();
  for(;endmode==-1;) {
    msg=aguix->WaitMessage(win);
    if(msg!=NULL) {
      switch(msg->type) {
        case AG_CLOSEWINDOW:
          if(msg->closewindow.window==win->getWindow()) endmode=1;
          break;
        case AG_BUTTONCLICKED:
          if(msg->button.button==okb) {
            endmode = 0;
          } else if(msg->button.button==cb) endmode=1;
          break;
        case AG_KEYPRESSED:
          if(win->isParent(msg->key.window,false)==true) {
            switch(msg->key.key) {
              case XK_1:
                fscb->setState((fscb->getState() == true ) ? false : true);
                break;
              case XK_2:
                mcb->setState((mcb->getState() == true ) ? false : true);
                break;
              case XK_3:
                rcb->setState((rcb->getState() == true ) ? false : true);
                break;
              case XK_4:
                sdcb->setState((sdcb->getState() == true ) ? false : true);
                break;
              case XK_5:
                rdcb->setState((rdcb->getState() == true ) ? false : true);
                break;
              case XK_6:
                pacb->setState( ( pacb->getState() == true ) ? false : true );
                break;
              case XK_7:
                  ars_cyb->setOption( ( ars_cyb->getSelectedOption() + 1 ) % 3 );
                  break;
              case XK_8:
                  ep_cyb->setOption( ( ep_cyb->getSelectedOption() + 1 ) % 4 );
                  break;
              case XK_9:
                  vdirpreserve_cb->setState( ( vdirpreserve_cb->getState() == true ) ? false : true );
                  break;
              case XK_0:
                  overwritemode_cyb->setOption( ( overwritemode_cyb->getSelectedOption() + 1 ) % overwritemode_cyb->getNrOfOptions() );
                  break;
              case XK_Return:
                if ( cb->getHasFocus() == false ) {
                  endmode = 0;
                }
                break;
              case XK_Escape:
                endmode=1;
                break;
            }
          }
          break;
      }
      aguix->ReplyMessage(msg);
    }
  }
  
  if(endmode==0) {
    // ok
    if(mode==1) {
      // store in t-variables
      tfollow_symlinks = fscb->getState();
      tmove = mcb->getState();
      trename = rcb->getState();
      tsame_dir = sdcb->getState();
      trequest_dest = rdcb->getState();
      tpreserve_attr = pacb->getState();
      tvdir_preserve_dir_structure = vdirpreserve_cb->getState();

      switch ( ars_cyb->getSelectedOption() ) {
          case 1:
              tadjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_OUTSIDE;
              break;
          case 2:
              tadjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_ALWAYS;
              break;
          default:
              tadjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_NEVER;
              break;
      }

      switch ( ep_cyb->getSelectedOption() ) {
          case 1:
              tensure_file_permissions = ENSURE_USER_RW_PERMISSION;
              break;
          case 2:
              tensure_file_permissions = ENSURE_USER_RW_GROUP_R_PERMISSION;
              break;
          case 3:
              tensure_file_permissions = ENSURE_USER_RW_ALL_R_PERMISSION;
              break;
          default:
              tensure_file_permissions = LEAVE_PERMISSIONS_UNMODIFIED;
              break;
      }

      toverwrite=copyorder::COPY_OVERWRITE_NORMAL;
      switch ( overwritemode_cyb->getSelectedOption() ) {
          case 1:
              toverwrite = copyorder::COPY_OVERWRITE_ALWAYS;
              break;
          case 2:
              toverwrite = copyorder::COPY_OVERWRITE_NEVER;
              break;
          case 3:
              toverwrite = copyorder::COPY_OVERWRITE_OLDER;
              break;
          case 4:
              toverwrite = copyorder::COPY_OVERWRITE_SMALLER;
              break;
          case 5:
              toverwrite = copyorder::COPY_OVERWRITE_DIFFERENT_SIZE;
              break;
          default:
              toverwrite = copyorder::COPY_OVERWRITE_NORMAL;
              break;
      }

      talso_select_extension = also_select_extension_cb->getState();
    } else {
      // store in normal variables
      follow_symlinks = fscb->getState();
      move = mcb->getState();
      do_rename = rcb->getState();
      same_dir = sdcb->getState();
      request_dest = rdcb->getState();
      setRequestParameters( rfcb->getState() );
      preserve_attr = pacb->getState();
      vdir_preserve_dir_structure = vdirpreserve_cb->getState();

      switch ( ars_cyb->getSelectedOption() ) {
          case 1:
              adjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_OUTSIDE;
              break;
          case 2:
              adjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_ALWAYS;
              break;
          default:
              adjust_relative_symlinks = COPYOP_ADJUST_SYMLINK_NEVER;
              break;
      }

      switch ( ep_cyb->getSelectedOption() ) {
          case 1:
              ensure_file_permissions = ENSURE_USER_RW_PERMISSION;
              break;
          case 2:
              ensure_file_permissions = ENSURE_USER_RW_GROUP_R_PERMISSION;
              break;
          case 3:
              ensure_file_permissions = ENSURE_USER_RW_ALL_R_PERMISSION;
              break;
          default:
              ensure_file_permissions = LEAVE_PERMISSIONS_UNMODIFIED;
              break;
      }

      overwrite=copyorder::COPY_OVERWRITE_NORMAL;
      switch ( overwritemode_cyb->getSelectedOption() ) {
          case 1:
              overwrite = copyorder::COPY_OVERWRITE_ALWAYS;
              break;
          case 2:
              overwrite = copyorder::COPY_OVERWRITE_NEVER;
              break;
          case 3:
              overwrite = copyorder::COPY_OVERWRITE_OLDER;
              break;
          case 4:
              overwrite = copyorder::COPY_OVERWRITE_SMALLER;
              break;
          case 5:
              overwrite = copyorder::COPY_OVERWRITE_DIFFERENT_SIZE;
              break;
          default:
              overwrite = copyorder::COPY_OVERWRITE_NORMAL;
              break;
      }

      m_also_select_extension = also_select_extension_cb->getState();
    }
  }
  
  delete win;
  delete req;

  return endmode;
}

int
CopyOp::configure()
{
  return doconfigure(0);
}

int
CopyOp::requestdest( const char *defaultstr, char **dest,
                     bool show_do_not_ask, bool &do_not_ask_return )
{
  Requester *req=new Requester( Worker::getAGUIX());
  char *buttonstr;
  const char *textstr;
  int erg;
  
  textstr=catalog.getLocale(212);
  buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(11))+1+
                              strlen(catalog.getLocale(8))+1);
  sprintf(buttonstr,"%s|%s",catalog.getLocale(11),
                            catalog.getLocale(8));

  if ( show_do_not_ask ) {
      bool v = false;

      erg = req->string_request_choose( catalog.getLocale( 123 ),
                                        textstr,
                                        ( defaultstr != NULL ) ? defaultstr : "",
                                        catalog.getLocale( 1062 ),
                                        v,
                                        buttonstr,
                                        dest,
                                        Requester::REQUEST_SELECTALL );

      do_not_ask_return = v;
  } else {
      erg = req->string_request( catalog.getLocale( 123 ),
                                 textstr,
                                 ( defaultstr != NULL ) ? defaultstr : "",
                                 buttonstr,
                                 dest,
                                 Requester::REQUEST_SELECTALL );
  }

  _freesafe(buttonstr);
  delete req;
  return erg;
}

void CopyOp::setFollowSymlinks(bool nv)
{
  follow_symlinks=nv;
}

void CopyOp::setMove(bool nv)
{
  move=nv;
}

void CopyOp::setRename(bool nv)
{
  do_rename=nv;
}

void CopyOp::setSameDir(bool nv)
{
  same_dir=nv;
}

void CopyOp::setRequestDest(bool nv)
{
  request_dest=nv;
}

void CopyOp::setOverwrite(copyorder::overwrite_type nv)
{
  overwrite=nv;
}

void CopyOp::setPreserveAttr(bool nv)
{
  preserve_attr=nv;
}

void CopyOp::setVdirPreserveDirStructure(bool nv)
{
  vdir_preserve_dir_structure = nv;
}

void CopyOp::setAdjustRelativeSymlinks( adjust_relative_symlinks_t nv )
{
    adjust_relative_symlinks = nv;
}

void CopyOp::setEnsureFilePermissions( const CopyParams::EnsureFilePermissions &nv )
{
    ensure_file_permissions = nv;
}

bool CopyOp::isInteractiveRun() const
{
    return true;
}

void CopyOp::setInteractiveRun()
{
    setRequestParameters( true );
}

void CopyOp::setAlsoSelectExtension(bool nv)
{
    m_also_select_extension = nv;
}
