/* ownop.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2023 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 "ownop.h"
#include "worker.h"
#include "filereq.h"
#include "datei.h"
#include "aguix/lowlevelfunc.h"
#include "aguix/button.h"
#include "aguix/fieldlistview.h"
#include "aguix/stringgadget.h"
#include "aguix/cyclebutton.h"
#include "aguix/choosebutton.h"
#include "aguix/acontainer.h"
#include "aguix/awindow.h"
#include "worker_locale.h"
#include "dnd.h"
#include "wpucontext.h"
#include "processexitaction.hh"
#include "execlass.h"
#include "wconfig.h"
#include "listermode.h"
#include "textviewmode.hh"
#include "virtualdirmode.hh"

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

OwnOp::OwnOp() : FunctionProto()
{
  separate_each_entry=false;
  recursive=false;
  inbackground = false;
  take_dirs = false;

  ownstart=OWNOP_START_NORMAL;

  com_str=dupstring("");
  view_str=dupstring("");
  hasConfigure = true;
  
  dontcd = false;

  m_use_virtual_temp_copies = true;
  m_flags_are_relative_to_base_dir = true;
}

OwnOp::~OwnOp()
{
  _freesafe(com_str);
  _freesafe(view_str);
}

OwnOp*
OwnOp::duplicate() const
{
  OwnOp *ta=new OwnOp();
  ta->separate_each_entry=separate_each_entry;
  ta->recursive=recursive;
  ta->inbackground = inbackground;
  ta->take_dirs = take_dirs;
  ta->dontcd = dontcd;
  ta->m_use_virtual_temp_copies = m_use_virtual_temp_copies;
  ta->m_flags_are_relative_to_base_dir = m_flags_are_relative_to_base_dir;
  ta->m_follow_active = m_follow_active;
  ta->m_watch_file = m_watch_file;

  ta->ownstart=ownstart;

  _freesafe(ta->com_str);
  _freesafe(ta->view_str);
  ta->com_str=dupstring(com_str);
  ta->view_str=dupstring(view_str);
  return ta;
}

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

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

int
OwnOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
  externprog( wpu, msg );

  return 0;
}

bool
OwnOp::save(Datei *fh)
{
  if ( fh == NULL ) return false;

  fh->configPutPairBool( "separateeachentry", separate_each_entry );
  fh->configPutPairBool( "recursive", recursive );
  switch ( ownstart ) {
    case OWNOP_START_IN_TERMINAL:
      fh->configPutPair( "start", "terminal" );
      break;
    case OWNOP_START_IN_TERMINAL_AND_WAIT4KEY:
      fh->configPutPair( "start", "terminalwait" );
      break;
    case OWNOP_SHOW_OUTPUT:
      fh->configPutPair( "start", "showoutput" );
      break;
    case OWNOP_SHOW_OUTPUT_INT:
      fh->configPutPair( "start", "showoutputint" );
      break;
    case OWNOP_SHOW_OUTPUT_OTHER_SIDE:
      fh->configPutPair( "start", "showoutputotherside" );
      break;
    case OWNOP_SHOW_OUTPUT_CUSTOM_ATTRIBUTE:
      fh->configPutPair( "start", "showoutputcustomattribute" );
      break;
    default:
      fh->configPutPair( "start", "normal" );
      break;
  }
  fh->configPutPairString( "com", com_str );
  fh->configPutPairString( "viewstr", view_str );
  
  fh->configPutPairBool( "inbackground", inbackground );
  fh->configPutPairBool( "takedirs", take_dirs );
  fh->configPutPairBool( "dontcd", dontcd );

  if ( m_use_virtual_temp_copies != true ) {
      fh->configPutPairBool( "usevirtualtempcopies", m_use_virtual_temp_copies );
  }

  if ( m_flags_are_relative_to_base_dir != true ) {
      fh->configPutPairBool( "flagsarerelativetobasedir", m_flags_are_relative_to_base_dir );
  }

  if ( m_follow_active ) {
      fh->configPutPairBool( "followactive", m_follow_active );
  }
  if ( m_watch_file ) {
      fh->configPutPairBool( "watchfile", m_watch_file );
  }

  return true;
}

const char *
OwnOp::getDescription()
{
  return catalog.getLocale(1269);
}

static bool isCorrectViewProg( const char *str )
{
    const char *pos;
    if ( strlen( str ) < 1 ) return true;
    pos = strstr( str, "%s" );
    if ( pos != NULL ) return true;
    return false;
}

static void updateVisibility( int option,
                              ChooseButton *scb,
                              ChooseButton *rcb,
                              ChooseButton *ibcb,
                              ChooseButton *tdcb,
                              ChooseButton *dcdcb,
                              ChooseButton *virtualcb,
                              ChooseButton* relflagscb,
                              ChooseButton *follow_active_cb,
                              ChooseButton *watch_file_cb )
{
    if ( option == 5 ) {
        scb->hide();
        rcb->hide();
        ibcb->hide();
        tdcb->hide();
        dcdcb->hide();
        virtualcb->hide();
        relflagscb->hide();
        follow_active_cb->show();
        watch_file_cb->show();
    } else if ( option == 6 ) {
        scb->show();
        rcb->hide();
        ibcb->hide();
        tdcb->hide();
        dcdcb->show();
        virtualcb->show();
        relflagscb->show();
        follow_active_cb->hide();
        watch_file_cb->hide();
    } else {
        scb->show();
        rcb->show();
        ibcb->show();
        tdcb->show();
        dcdcb->show();
        virtualcb->show();
        relflagscb->show();
        follow_active_cb->hide();
        watch_file_cb->hide();
    }
}

int
OwnOp::configure()
{
  AGUIX *aguix = Worker::getAGUIX();
  Button *fb, *comreqb, *comreqb2;
  StringGadget *sg[2];
  AWindow *win;
  ChooseButton *scb,*rcb, *ibcb, *tdcb, *dcdcb;
  CycleButton *cyb;
  AGMessage *msg;
  int endmode=-1;
  Requester *req;
  FileRequester *freq;
  const char *textstr;
  char *buttonstr,*tstr;
  int erg;
  std::string str1;
  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);
  freq = new FileRequester( 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 );

  scb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( separate_each_entry == true ) ? 1 : 0,
						   catalog.getLocale( 329 ), LABEL_RIGHT, 0 ), 0, 0, cincwnr );

  rcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( recursive == true ) ? 1 : 0,
						   catalog.getLocale( 330 ), LABEL_RIGHT, 0 ), 0, 1, cincwnr );

  tdcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( take_dirs == true ) ? 1 : 0,
                                                    catalog.getLocale( 513 ), LABEL_RIGHT, 0 ), 0, 2, cincwnr );

  dcdcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( dontcd == true ) ? 1 : 0,
						     catalog.getLocale( 617 ), LABEL_RIGHT, 0 ), 0, 3, cincwnr );

  ChooseButton* virtualcb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( m_use_virtual_temp_copies == true ) ? 1 : 0,
                                                                       catalog.getLocale( 964 ), LABEL_RIGHT, 0 ), 0, 4, cincwnr );

  ChooseButton* relflagscb = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( m_flags_are_relative_to_base_dir == true ) ? 1 : 0,
                                                                        catalog.getLocale( 1001 ), LABEL_RIGHT, 0 ), 0, 5, cincwnr );

  ibcb = (ChooseButton*)ac1->add( new ChooseButton( aguix,
                                                    0,
                                                    0,
                                                    ( inbackground == true ) ? 1 : 0,
                                                    catalog.getLocale( 435 ),
                                                    LABEL_RIGHT,
                                                    0 ), 0, 6, cincwnr );

  ChooseButton *follow_active_cb = ac1->addWidget( new ChooseButton( aguix,
                                                                     0,
                                                                     0,
                                                                     ( m_follow_active == true ) ? 1 : 0,
                                                                     catalog.getLocale( 1184 ),
                                                                     LABEL_RIGHT,
                                                                     0 ), 0, 7, cincwnr );
  ChooseButton *watch_file_cb = ac1->addWidget( new ChooseButton( aguix,
                                                                  0,
                                                                  0,
                                                                  ( m_watch_file == true ) ? 1 : 0,
                                                                  catalog.getLocale( 1183 ),
                                                                  LABEL_RIGHT,
                                                                  0 ), 0, 8, cincwnr );

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

  ac1_1->add( new Text( aguix, 0, 0, catalog.getLocale( 331 ) ), 0, 0, cfix );
  cyb = (CycleButton*)ac1_1->add( new CycleButton( aguix, 0, 0, 100, 0 ), 1, 0, cincw );
  cyb->addOption(catalog.getLocale(332));
  cyb->addOption(catalog.getLocale(333));
  cyb->addOption(catalog.getLocale(334));
  cyb->addOption(catalog.getLocale(335));
  cyb->addOption( catalog.getLocale( 911 ) );
  cyb->addOption( catalog.getLocale( 1512 ) );
  cyb->addOption( catalog.getLocale( 1535 ) );
  cyb->resize(cyb->getMaxSize(),cyb->getHeight());
  ac1_1->readLimits();
  switch(ownstart) {
    case OWNOP_START_IN_TERMINAL:
      cyb->setOption(1);
      break;
    case OWNOP_START_IN_TERMINAL_AND_WAIT4KEY:
      cyb->setOption(2);
      break;
    case OWNOP_SHOW_OUTPUT:
      cyb->setOption(3);
      break;
    case OWNOP_SHOW_OUTPUT_INT:
      cyb->setOption( 4 );
      break;
    case OWNOP_SHOW_OUTPUT_OTHER_SIDE:
      cyb->setOption( 5 );
      break;
    case OWNOP_SHOW_OUTPUT_CUSTOM_ATTRIBUTE:
      cyb->setOption( 6 );
      break;
    default:
      cyb->setOption(0);
      break;
  }
  
  AContainer *ac1_2 = ac1->add( new AContainer( win, 5, 1 ), 0, 10 );
  ac1_2->setMinSpace( 0 );
  ac1_2->setMaxSpace( 0 );
  ac1_2->setBorderWidth( 0 );

  ac1_2->add( new Text( aguix, 0, 0, catalog.getLocale( 336 ) ), 0, 0, cfix );
  ac1_2->setMinWidth( 5, 1, 0 );
  ac1_2->setMaxWidth( 5, 1, 0 );

  comreqb = (Button*)ac1_2->add( new Button( aguix, 0, 0, catalog.getLocale( 458 ), 0 ), 2, 0, cfix );

  sg[0] = (StringGadget*)ac1_2->add( new StringGadget( aguix, 0, 0, 100, com_str, 0 ), 3, 0, cincw );
  
  fb = (Button*)ac1_2->add( new Button( aguix, 0, 0, "O", 0 ), 4, 0, cfix );
  fb->setBubbleHelpText( catalog.getLocale( 1132 ) );
  
  AContainer *ac1_3 = ac1->add( new AContainer( win, 5, 1 ), 0, 11 );
  ac1_3->setMinSpace( 0 );
  ac1_3->setMaxSpace( 0 );
  ac1_3->setBorderWidth( 0 );

  Text *view_text = (Text*)ac1_3->add( new Text( aguix, 0, 0, catalog.getLocale( 337 ) ), 0, 0, cfix );
  ac1_3->setMinWidth( 5, 1, 0 );
  ac1_3->setMaxWidth( 5, 1, 0 );
  comreqb2 = (Button*)ac1_3->add( new Button( aguix, 0, 0, catalog.getLocale( 458 ), 0 ), 2, 0, cfix );
  sg[1] = (StringGadget*)ac1_3->add( new StringGadget( aguix, 0, 0, 100, view_str, 0 ), 3, 0, cincw );
  auto view_help_b = ac1_3->addWidget( new Button( aguix, 0, 0, "?", 0 ), 4, 0, cfix );
  
  if ( cyb->getSelectedOption() == 3 ) {
      sg[1]->show();
      comreqb2->show();
      view_text->show();
      view_help_b->show();
  } else {
      sg[1]->hide();
      comreqb2->hide();
      view_text->hide();
      view_help_b->hide();
  }
  updateVisibility( cyb->getSelectedOption(),
                    scb, rcb, ibcb, tdcb, dcdcb,
                    virtualcb, relflagscb,
                    follow_active_cb, watch_file_cb );
  
  AContainer *ac1_4 = ac1->add( new AContainer( win, 2, 1 ), 0, 12 );
  ac1_4->setMinSpace( 5 );
  ac1_4->setMaxSpace( -1 );
  ac1_4->setBorderWidth( 0 );
  Button *okb =(Button*)ac1_4->add( new Button( aguix,
                                                0,
                                                0,
                                                catalog.getLocale( 11 ),
                                                0 ), 0, 0, cfix );
  Button *cb = (Button*)ac1_4->add( new Button( aguix,
						0,
						0,
						catalog.getLocale( 8 ),
						0 ), 1, 0, cfix );
  
  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) {
            if ( isCorrectViewProg( sg[1]->getText() ) == false ) {
              // show requester
              textstr=catalog.getLocale(312);
              buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(313))+1+
                                          strlen(catalog.getLocale(314))+1);
              sprintf(buttonstr,"%s|%s",catalog.getLocale(313),
                                        catalog.getLocale(314));
              erg=req->request(catalog.getLocale(125),textstr,buttonstr);
              _freesafe(buttonstr);
              if(erg==0) {
                sg[0]->deactivate();
                sg[1]->activate();
              } else {
                sg[1]->setText("");
              }
            } else endmode=0;
          } else if(msg->button.button==cb) endmode=1;
          else if(msg->button.button==fb) {
            tstr=getFlag();
            if(tstr!=NULL) {
              const char *newstr1=sg[0]->getText();
              char *newstr2;
              int pos=sg[0]->getCursor();
              newstr2=(char*)_allocsafe(strlen(newstr1)+strlen(tstr)+1);
              strncpy(newstr2,newstr1,pos);
              strcpy(newstr2+pos,tstr);
              strcpy(newstr2+pos+strlen(tstr),newstr1+pos);
              sg[0]->setText(newstr2);
              _freesafe(newstr2);
              _freesafe(tstr);
            }
          } else if ( msg->button.button == comreqb ) {
            if ( freq->request_entry( catalog.getLocale( 265 ),
                                      NULL,
                                      catalog.getLocale( 11 ),
                                      catalog.getLocale( 8 ),
                                      catalog.getLocale( 265 ),
                                      true ) > 0 ) {
              str1 = freq->getLastEntryStr();
              if ( str1.length() > 0 ) {
                const char *newstr1 = sg[ 0 ]->getText();
                char *newstr2;
                int pos = sg[ 0 ]->getCursor();

                newstr2 = (char*)_allocsafe( strlen( newstr1 ) + strlen( str1.c_str() ) + 1 );
                strncpy( newstr2, newstr1, pos );
                strcpy( newstr2 + pos, str1.c_str() );
                strcpy( newstr2 + pos + strlen( str1.c_str() ), newstr1 + pos );
                sg[ 0 ]->setText( newstr2 );
                _freesafe( newstr2 );
              }
            }
          } else if ( msg->button.button == comreqb2 ) {
            if ( freq->request_entry( catalog.getLocale( 265 ),
                                      NULL,
                                      catalog.getLocale( 11 ),
                                      catalog.getLocale( 8 ),
                                      catalog.getLocale( 265 ),
                                      true ) > 0 ) {
              str1 = freq->getLastEntryStr();
              if ( str1.length() > 0 ) {
                const char *newstr1 = sg[ 1 ]->getText();
                char *newstr2;
                int pos = sg[ 1 ]->getCursor();

                newstr2 = (char*)_allocsafe( strlen( newstr1 ) + strlen( str1.c_str() ) + 1 );
                strncpy( newstr2, newstr1, pos );
                strcpy( newstr2 + pos, str1.c_str() );
                strcpy( newstr2 + pos + strlen( str1.c_str() ), newstr1 + pos );
                sg[ 1 ]->setText( newstr2 );
                _freesafe( newstr2 );
              }
            }
          } else if ( msg->button.button == view_help_b ) {
              req->request( catalog.getLocale( 125 ),
                            catalog.getLocale( 1399 ),
                            catalog.getLocale( 11 ) );
          }
          break;
	case AG_STRINGGADGET_DEACTIVATE:
          if(msg->stringgadget.sg==sg[1]) {
            if ( isCorrectViewProg( sg[1]->getText() ) == false ) {
              // show requester
              textstr=catalog.getLocale(312);
              buttonstr=(char*)_allocsafe(strlen(catalog.getLocale(313))+1+
                                          strlen(catalog.getLocale(314))+1);
              sprintf(buttonstr,"%s|%s",catalog.getLocale(313),
                                        catalog.getLocale(314));
              erg=req->request(catalog.getLocale(125),textstr,buttonstr);
              _freesafe(buttonstr);
              if(erg==0) {
                sg[0]->deactivate();
                sg[1]->activate();
              } else {
                sg[1]->setText("");
              }
            }
          }
	  break;
        case AG_CYCLEBUTTONCLICKED:
            if ( msg->cyclebutton.cyclebutton == cyb ) {
                if ( cyb->getSelectedOption() == 3 ) {
                    sg[1]->show();
                    comreqb2->show();
                    view_text->show();
                    view_help_b->show();
                } else {
                    sg[1]->hide();
                    comreqb2->hide();
                    view_text->hide();
                    view_help_b->hide();
                }
                updateVisibility( cyb->getSelectedOption(),
                                  scb, rcb, ibcb, tdcb, dcdcb,
                                  virtualcb, relflagscb,
                                  follow_active_cb, watch_file_cb );
                aguix->Flush();
            }
            break;
          case AG_KEYPRESSED:
              if ( win->isParent( msg->key.window, false ) == true ) {
                  switch ( msg->key.key ) {
                      case XK_Escape:
                          endmode = 1;
                          break;
                  }
              }
              break;
      }
      aguix->ReplyMessage(msg);
    }
  }
  
  if(endmode==0) {
    // ok
    separate_each_entry = scb->getState();
    recursive = rcb->getState();
    take_dirs = tdcb->getState();
    dontcd = dcdcb->getState();
    m_use_virtual_temp_copies = virtualcb->getState();
    m_flags_are_relative_to_base_dir = relflagscb->getState();
    inbackground = ibcb->getState();
    _freesafe(com_str);
    _freesafe(view_str);
    com_str=dupstring(sg[0]->getText());
    view_str=dupstring(sg[1]->getText());
    switch(cyb->getSelectedOption()) {
      case 1:
        ownstart=OWNOP_START_IN_TERMINAL;
        break;
      case 2:
        ownstart=OWNOP_START_IN_TERMINAL_AND_WAIT4KEY;
        break;
      case 3:
        ownstart=OWNOP_SHOW_OUTPUT;
        break;
      case 4:
        ownstart = OWNOP_SHOW_OUTPUT_INT;
        break;
      case 5:
          ownstart = OWNOP_SHOW_OUTPUT_OTHER_SIDE;
          break;
      case 6:
          ownstart = OWNOP_SHOW_OUTPUT_CUSTOM_ATTRIBUTE;
          break;
      default:
        ownstart=OWNOP_START_NORMAL;
        break;
    }
    m_follow_active = follow_active_cb->getState();
    m_watch_file = watch_file_cb->getState();
  }
  
  delete win;
  delete req;
  delete freq;

  return endmode;
}

char*
OwnOp::getFlag()
{
  AGUIX *aguix = Worker::getAGUIX();
  Button *okb,*cb;
  AWindow *win;
  FieldListView *lv;
  AGMessage *msg;
  int endmode=-1;
  char *returnstr;
  int i, trow, nr;
  const int cmin = AContainer::ACONT_MINH +
                   AContainer::ACONT_MINW;
  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;
  
  win = new AWindow( aguix, 10, 10, 10, 10, catalog.getLocale( 338 ), AWindow::AWINDOW_DIALOG );
  win->create();

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

  ac1->add( new Text( aguix, 0, 0, catalog.getLocale( 338 ) ), 0, 0, cincwnr );

  lv = (FieldListView*)ac1->add( new FieldListView( aguix,
                                                    0,
                                                    0,
                                                    300,
                                                    200,
                                                    0 ), 0, 1, cmin );
  lv->setHBarState(2);
  lv->setVBarState(2);

  lv->setNrOfFields( 3 );
  lv->setFieldWidth( 1, 3 );
  
  nr = sizeof( ownop_flags ) / sizeof( ownop_flags[0] );

  for( i=0;i<nr;i++) {
    trow = lv->addRow();
    lv->setText( trow, 0, ownop_flags[ i ].flag );
    lv->setText( trow, 2, catalog.getLocaleFlag( ownop_flags[ i ].catcode ) );
    lv->setPreColors( trow, FieldListView::PRECOLOR_ONLYACTIVE );
    lv->setData( trow, i );
  }

  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 2 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( -1 );
  ac1_2->setBorderWidth( 0 );
  okb = (Button*)ac1_2->add( new Button( aguix,
					 0,
					 0,
					 catalog.getLocale( 11 ),
					 0 ), 0, 0, cfix );
  cb = (Button*)ac1_2->add( new Button( aguix,
					0,
					0,
					catalog.getLocale( 8 ),
					0 ), 1, 0, cfix );
  win->contMaximize( true );
  win->setDoTabCycling( 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;
      }
      aguix->ReplyMessage(msg);
    }
  }
  
  returnstr=NULL;
  if(endmode==0) {
    // ok
    trow = lv->getActiveRow();
    if ( lv->isValidRow( trow ) == true ) {
      nr = lv->getData( trow, 0 );
      returnstr = dupstring( ownop_flags[nr].flag );
    }
  }
  
  delete win;

  return returnstr;
}

void OwnOp::setSeparateEachEntry(bool nv)
{
  separate_each_entry=nv;
}

void OwnOp::setRecursive(bool nv)
{
  recursive=nv;
}

void OwnOp::setOwnStart(ownstart_t nv)
{
  ownstart=nv;
}

void OwnOp::setComStr(const char* nv)
{
  if ( nv == NULL ) return;
  _freesafe(com_str);
  com_str=dupstring(nv);
}

void OwnOp::setViewStr( const char* nv )
{
  if ( nv == NULL ) return;
  _freesafe( view_str );
  view_str = dupstring( nv );
}

void OwnOp::setInBackground( bool nv )
{
  inbackground = nv;
}

void OwnOp::setTakeDirs( bool nv )
{
  take_dirs = nv;
}

void OwnOp::setDontCD( bool nv )
{
  dontcd = nv;
}

void OwnOp::setUseVirtualTempCopies( bool nv )
{
    m_use_virtual_temp_copies = nv;
}

void OwnOp::setFlagsAreRelativeToBaseDir( bool nv )
{
    m_flags_are_relative_to_base_dir = nv;
}

void OwnOp::setFollowActive( bool nv )
{
    m_follow_active = nv;
}

void OwnOp::setWatchFile( bool nv )
{
    m_watch_file = nv;
}

void OwnOp::externprog( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
    char *tmpname, *tmpoutput, *tstr;
    Datei *fp;
    bool useint;
    bool cancel = false;
    bool oldrec, oldtd;
    std::string string1;
    bool removeTMPFiles;

    if ( com_str == NULL ) return;  // nothing to do
    if ( wpu == NULL ) return;

    if ( ownstart == OWNOP_SHOW_OUTPUT_OTHER_SIDE ) {
        Lister *activelister = msg->getWorker()->getActiveLister();
        if ( activelister ) {
            Lister *inactivelister = msg->getWorker()->getOtherLister( activelister );
            if ( inactivelister ) {
                inactivelister->switch2Mode( 3 );
                auto tvm = dynamic_cast< TextViewMode * >( inactivelister->getActiveMode() );
                if ( tvm ) {
                    uint32_t options = 0;
                    if ( m_follow_active ) {
                        options |= TextViewMode::FOLLOW_ACTIVE;
                    }
                    if ( m_watch_file ) {
                        options |= TextViewMode::WATCH_FILE;
                    }
                    tvm->setCommandString( com_str,
                                           wpu->getBaseDir(),
                                           options );
                }
            }
        }

        return;
    } else if ( ownstart == OWNOP_SHOW_OUTPUT_CUSTOM_ATTRIBUTE ) {
        Lister *activelister = msg->getWorker()->getActiveLister();
        if ( activelister ) {
            auto vdm = dynamic_cast< VirtualDirMode * >( activelister->getActiveMode() );
            if ( vdm ) {
                oldrec = wpu->getRecursive();
                oldtd = wpu->getTakeDirs();
                wpu->setRecursive( false );
                wpu->setTakeDirs( false );
                wpu->setUseVirtualTempCopies( m_use_virtual_temp_copies );
                wpu->setUseExtendedBasename( m_flags_are_relative_to_base_dir );

                vdm->processCustomAttribute( msg,
                                             { .command_str = com_str,
                                               .dont_cd = dontcd,
                                               .global_command = true,
                                               .separate_each_entry = separate_each_entry
                                             },
                                             NULL,
                                             -1 );

                wpu->setRecursive( oldrec );
                wpu->setTakeDirs( oldtd );
            }
        }
        return;
    }

    oldrec = wpu->getRecursive();
    oldtd = wpu->getTakeDirs();
    wpu->setRecursive( recursive );
    wpu->setTakeDirs( take_dirs );
    wpu->setUseVirtualTempCopies( m_use_virtual_temp_copies );
    wpu->setUseExtendedBasename( m_flags_are_relative_to_base_dir );

    tmpname = Datei::createTMPName();
    tmpoutput = Datei::createTMPName();

    if ( tmpname != NULL && tmpoutput != NULL ) {
        // runCommand will remove the tmpfiles but if we do runCommand
        // (because of an error) remove them here
        removeTMPFiles = true;

        std::string tmpoutput_lnk;

        RefCount< GenericCallbackArg< void, int > > pea( NULL );
      
        if ( ownstart == OWNOP_SHOW_OUTPUT_INT ) {
            tmpoutput_lnk = Datei::createTMPHardlink( tmpoutput );
            pea.reset( new ProcessExitAction( true,
                                              tmpoutput_lnk,
                                              msg->getWorker(), wpu ) );
        } else {
            pea.reset( new ProcessExitAction( false,
                                              "",
                                              msg->getWorker(), wpu ) );
        }

        fp = new Datei();
        if ( fp->open( tmpname, "w" ) == 0 ) {
            fp->putString( "#! /bin/sh\n" );
            if ( wpu->getBaseDir() != NULL ) {
                if ( ( worker_islocal( wpu->getBaseDir() ) == 1 ) &&
                     ( dontcd == false ) ) {
                    tstr = AGUIX_catTrustedAndUnTrusted( "cd ", wpu->getBaseDir() );
                    fp->putString( tstr );
                    _freesafe( tstr );
                    fp->putString( "\n" );
                }
            }

            std::string quoted_tmpoutput = AGUIX_catTrustedAndUnTrusted2( "", tmpoutput );

            for ( int loopnr = 1;; loopnr++ ) {
                std::string res_str;
                if ( wpu->parse( com_str, res_str, EXE_STRING_LEN - quoted_tmpoutput.size() - 4,
                                 true, WPUContext::PERSIST_FLAGS ) == WPUContext::PARSE_SUCCESS ) {
                    string1 = Worker_secureCommandForShell( res_str.c_str() );
                    if ( string1.length() > 0 ) {
                        if ( ownstart == OWNOP_SHOW_OUTPUT ||
                             ownstart == OWNOP_SHOW_OUTPUT_INT ) {
                            std::string tstr2 = string1;
                            if ( loopnr == 1 ) tstr2 += " >";
                            else tstr2 += " >>";
                            tstr2 += quoted_tmpoutput;
                            fp->putString( tstr2.c_str() );
                        } else {
                            fp->putString( string1.c_str() );
                        }
                        fp->putString( "\n" );
                    }

                    msg->getWorker()->storePathPers( wpu->getPathDBFilename(),
                                                     res_str,
                                                     time( NULL ) );
                    
                    if ( separate_each_entry == false ) break;
                    if ( wpu->filelistEmpty( false ) ) break;
                    if ( ! wpu->filelistModified( false, true ) ) {
                        // endless loop
                        //TODO: requester
                        break;
                    }
                } else {
                    cancel = true;
                    break;
                }
            }
            if(  cancel == false ) {
                std::string exestr;
                bool remove_after_exec = true;

                if ( ( ownstart == OWNOP_START_IN_TERMINAL_AND_WAIT4KEY ) ||
                     ( ownstart == OWNOP_START_IN_TERMINAL ) ) {
                    /* in terminal starten */
                    if ( ownstart == OWNOP_START_IN_TERMINAL_AND_WAIT4KEY ) {
                        fp->putStringExt( "echo %s\n", catalog.getLocale( 201 ) );
                        fp->putString( "read x\n" );
                    }
                    exestr = Worker::getTerminalCommand( tmpname, tmpoutput, remove_after_exec );
                } else {
                    exestr = AGUIXUtils::replace_percent_s_quoted( "/bin/sh %s", tmpname, NULL );
                }
                if ( ownstart == OWNOP_SHOW_OUTPUT ) {
                    useint = true;
                    if ( view_str != NULL ) {
                        if ( strlen( view_str ) > 2 ) {
                            if ( strstr( view_str, "%s" ) != NULL ) useint = false;
                        }
                    }

                    std::string real_view_str;

                    if ( useint == true ) {
                        real_view_str = AGUIXUtils::replace_percent_s_quoted( OUTPUT_BIN, tmpoutput, NULL );
                    } else {
                        real_view_str = AGUIXUtils::replace_percent_s_quoted( view_str, tmpoutput, NULL );
                    }
                    fp->putString( real_view_str.c_str() );
                    fp->putString( "\n" );
                }
                fp->close();
      
                if ( fp->errors() == 0 ) {
                    worker_chmod( tmpname, 0700 );
                    removeTMPFiles = false;
                    msg->getWorker()->runCommand( exestr.c_str(),
                                                  remove_after_exec ? tmpname : NULL,
                                                  remove_after_exec ? tmpoutput : NULL,
                                                  inbackground, pea );
                } else {
                    std::string text = AGUIXUtils::formatStringToString( catalog.getLocale( 647 ), tmpname );
                    std::string button = catalog.getLocale( 11 );
                    Worker::getRequester()->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
                }
            } else fp->close();
        }
        delete fp;
        if ( removeTMPFiles == true ) {
            worker_unlink( tmpname );
            worker_unlink( tmpoutput );

            if ( pea.get() != NULL ) {
                pea->callback( 0 );
            }
        }
    } else {
        std::string text = AGUIXUtils::formatStringToString( catalog.getLocale( 647 ), "" );
        std::string button = catalog.getLocale( 11 );
        Worker::getRequester()->request( catalog.getLocale( 347 ), text.c_str(), button.c_str() );
    }
  
    if ( tmpname != NULL ) _freesafe(tmpname);
    if ( tmpoutput != NULL ) _freesafe(tmpoutput);

    wpu->setRecursive( oldrec );
    wpu->setTakeDirs( oldtd );
}

std::string OwnOp::getStringRepresentation()
{
    return com_str;
}
