/* goftpop.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2005-2021 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 "goftpop.h"
#include "listermode.h"
#include "worker.h"
#include "avfssupport.hh"
#include "worker_locale.h"
#include "datei.h"
#include "aguix/stringgadget.h"
#include "aguix/choosebutton.h"
#include "aguix/cyclebutton.h"
#include "aguix/button.h"
#include "argclass.hh"
#include "virtualdirmode.hh"

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

GoFTPOp::GoFTPOp() : FunctionProto()
{
  dontenterftp = false;
  always_store_pw = false;
  host = "";
  user = "";
  pass = "";
  avfs_module = "ftp";
  hasConfigure = true;
  setRequestParameters( true );
}

GoFTPOp::~GoFTPOp()
{
}

GoFTPOp*
GoFTPOp::duplicate() const
{
  GoFTPOp *ta=new GoFTPOp();
  ta->setRequestParameters( requestParameters() );
  ta->setDontEnterFTP( dontenterftp );
  ta->setHost( host );
  ta->setUser( user );
  ta->setPass( pass );
  ta->setAVFSModule( avfs_module );
  ta->setAlwaysStorePW( always_store_pw );
  return ta;
}

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

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

int
GoFTPOp::run( std::shared_ptr< WPUContext > wpu, ActionMessage *msg )
{
  Requester *req = Worker::getRequester();
  std::string str1;
  bool cont = true;
  ListerMode *lm1=NULL;
  Lister *l1;

  if ( requestParameters() == true ) {
    if ( doconfigure( 1 ) != 0 ) cont = false;
  } else {
    tdontenterftp = dontenterftp;
    thost = host;
    tuser = user;
    tpass = pass;
    tavfs_module = avfs_module;
    talways_store_pw = always_store_pw;
  }
  
  if ( cont == true ) {
    if ( ( thost.length() < 1 ) ||
	 ( tuser.length() < 1 ) ) {
      req->request( catalog.getLocale( 124 ), catalog.getLocale( 625 ), catalog.getLocale( 11 ) );
    } else {
      std::string key = tuser;
      key += "@";
      key += thost;

      if ( pw_stored.count( key ) < 1 ||
           pw_stored[key] == false ||
           talways_store_pw == true ) {
        str1 = "/#";
        str1 += tavfs_module;
        str1 += "_ctl:";
	str1 += tuser;
	str1 += "@";
	str1 += thost;
	str1 += "/password";
	
	Datei d;
	d.open( str1.c_str(), "w" );
	d.putString( tpass.c_str() );
	d.putString( "\n" );
	d.close();
	pw_stored[key] = true;
      }

      if ( tdontenterftp == false ) {
        str1 = "/#";
        str1 += tavfs_module;
	str1 += ":";
	str1 += tuser;
	str1 += "@";
	str1 += thost;
	str1 += "/";

	l1 = msg->getWorker()->getActiveLister();
	if ( l1 != NULL ) {
            if ( l1->getActiveMode() == NULL ||
                 ! ( dynamic_cast< VirtualDirMode *>( l1->getActiveMode() ) ) ) {
                l1->switch2Mode( 0 );
            }
            lm1 = l1->getActiveMode();
            if ( lm1 != NULL ) {
                std::list< RefCount< ArgClass > > args;

                args.push_back( RefCount< ArgClass >( new StringArg( str1 ) ) );
                lm1->runCommand( "enter_dir", args );
            }
	}
      }
    }
  }
  tpass = "";

  return 0;
}

bool
GoFTPOp::save(Datei *fh)
{
  if ( fh == NULL ) return false;
  fh->configPutPairBool( "requestflags", requestParameters() );
  fh->configPutPairBool( "dontenterftp", dontenterftp );
  fh->configPutPairString( "hostname", host.c_str() );
  fh->configPutPairString( "username", user.c_str() );
  fh->configPutPairString( "password", pass.c_str() );
  fh->configPutPairBool( "alwaysstorepw", always_store_pw );
  fh->configPutPairString( "avfsmodule", avfs_module.c_str() );
  return true;
}

const char *
GoFTPOp::getDescription()
{
  return catalog.getLocale( 1289 );
}

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

int
GoFTPOp::doconfigure(int mode)
{
  AGUIX *aguix = Worker::getAGUIX();
  Button *okb,*cancelb;
  AWindow *win;
  ChooseButton *cb1,*rfcb=NULL, *cb2, *cb_anon;
  StringGadget *sgh, *sgu, *sgp;
  AGMessage *msg;
  int endmode=-1;
  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;
  Requester *req = Worker::getRequester();
  std::vector<std::string> module_list;
  CycleButton *cycb_avfs = NULL;
  
  module_list = getAvailModules();

  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, 9 ), true );
  ac1->setMinSpace( 5 );
  ac1->setMaxSpace( 5 );

  AContainer *ac1_2 = ac1->add( new AContainer( win, 2, 1 ), 0, 0 );
  ac1_2->setMinSpace( 5 );
  ac1_2->setMaxSpace( 5 );
  ac1_2->setBorderWidth( 0 );
  ac1_2->add( new Text( aguix, 0, 0, catalog.getLocale( 620 ) ), 0, 0, cfix );
  sgh = (StringGadget*)ac1_2->add( new StringGadget( aguix, 0, 0, 100, host.c_str(), 0 ),
				   1, 0, cincw );

  AContainer *ac1_3 = ac1->add( new AContainer( win, 2, 1 ), 0, 1 );
  ac1_3->setMinSpace( 5 );
  ac1_3->setMaxSpace( 5 );
  ac1_3->setBorderWidth( 0 );
  ac1_3->add( new Text( aguix, 0, 0, catalog.getLocale( 621 ) ), 0, 0, cfix );
  sgu = (StringGadget*)ac1_3->add( new StringGadget( aguix, 0, 0, 100, user.c_str(), 0 ),
				   1, 0, cincw );

  AContainer *ac1_4 = ac1->add( new AContainer( win, 2, 1 ), 0, 2 );
  ac1_4->setMinSpace( 5 );
  ac1_4->setMaxSpace( 5 );
  ac1_4->setBorderWidth( 0 );
  ac1_4->add( new Text( aguix, 0, 0, catalog.getLocale( 622 ) ), 0, 0, cfix );
  sgp = (StringGadget*)ac1_4->add( new StringGadget( aguix, 0, 0, 100, "", 0 ),
				   1, 0, cincw );
  sgp->setPasswordMode( true );
  sgp->setText( pass.c_str() );

  cb_anon = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, false,
                                                       catalog.getLocale( 755 ), LABEL_RIGHT, 0 ),
                                     0, 3, cincwnr );

  cb1 = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( dontenterftp == true ) ? 1 : 0,
						   catalog.getLocale( 623 ), LABEL_RIGHT, 0 ),
				 0, 4, cincwnr );
  cb2 = (ChooseButton*)ac1->add( new ChooseButton( aguix, 0, 0, ( always_store_pw == true ) ? 1 : 0,
						   catalog.getLocale( 627 ), LABEL_RIGHT, 0 ),
				 0, 5, cincwnr );

  if ( module_list.size() > 1 ) {
      AContainer *ac1_6 = ac1->add( new AContainer( win, 2, 1 ), 0, 6 );
      ac1_6->setMinSpace( 5 );
      ac1_6->setMaxSpace( 5 );
      ac1_6->setBorderWidth( 0 );
      ac1_6->add( new Text( aguix, 0, 0, catalog.getLocale( 933 ) ), 0, 0, cfix );
      cycb_avfs = (CycleButton*)ac1_6->add( new CycleButton( aguix, 0, 0, 50, 0 ),
                                                         1, 0, AContainer::CO_INCWNR );

      int pos = 0;
      for ( std::vector<std::string>::const_iterator it1 = module_list.begin();
            it1 != module_list.end();
            it1++, pos++ ) {
          cycb_avfs->addOption( it1->c_str() );

          if ( it1->c_str() == avfs_module ) {
              cycb_avfs->setOption( pos );
          }
      }
      cycb_avfs->resize( cycb_avfs->getMaxSize(), cycb_avfs->getHeight() );
      ac1_6->readLimits();
  }

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

  AContainer *ac1_5 = ac1->add( new AContainer( win, 2, 1 ), 0, 8 );
  ac1_5->setMinSpace( 5 );
  ac1_5->setMaxSpace( -1 );
  ac1_5->setBorderWidth( 0 );
  okb = (Button*)ac1_5->add( new Button( aguix,
					 0,
					 0,
					 catalog.getLocale( 11 ),
					 0 ), 0, 0, cfix );
  cancelb = (Button*)ac1_5->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 == cancelb ) endmode = 1;
          break;
        case AG_KEYPRESSED:
          if ( win->isParent( msg->key.window, false ) == true ) {
            switch ( msg->key.key ) {
              case XK_Return:
                if ( cancelb->getHasFocus() == true ) {
		  endmode = 1;
		} else {
                  endmode=0;
                }
                break;
              case XK_Escape:
                endmode = 1;
                break;
            }
          }
          break;
        case AG_CHOOSECLICKED:
            if ( msg->choose.button == cb_anon ) {
                if ( msg->choose.state == true ) {
                    sgu->setText( "anonymous" );
                    sgp->setText( "ano@nym.ous" );
                    sgp->setPasswordMode( false );
                } else {
                    sgp->setPasswordMode( true );
                }
            }
            break;
        case AG_STRINGGADGET_CONTENTCHANGE:
            if ( msg->stringgadget.sg == sgu ) {
                sgp->setPasswordMode( true );
                cb_anon->setState( false );
            }
            break;
      }
      aguix->ReplyMessage( msg );
    }
  }
  
  if ( endmode == 0 ) {
    // ok
    if ( mode == 1 ) {
      tdontenterftp = cb1->getState();
      talways_store_pw = cb2->getState();
      thost = sgh->getText();
      tuser = sgu->getText();
      tpass = sgp->getText();

      tavfs_module = "ftp";
      if ( cycb_avfs != NULL ) {
          if ( cycb_avfs->getSelectedOption() >= 0 &&
               cycb_avfs->getSelectedOption() < static_cast<int>( module_list.size() ) ) {
              tavfs_module = module_list[ cycb_avfs->getSelectedOption() ];
          }
      }
      sgp->setText( "" );
    } else {
      dontenterftp = cb1->getState();
      always_store_pw = cb2->getState();
      if ( rfcb != NULL ) setRequestParameters( rfcb->getState() );
      setHost( sgh->getText() );
      setUser( sgu->getText() );
      if ( sgp->getText() != NULL ) {
	if ( strlen( sgp->getText() ) > 0 ) {
	  std::string str1;
	  
	  str1 = catalog.getLocale( 11 );
	  str1 += "|";
	  str1 += catalog.getLocale( 8 );
	  if ( req->request( catalog.getLocale( 347 ), catalog.getLocale( 624 ), str1.c_str() ) == 0 ) {
	    setPass( sgp->getText() );
	  }
	}
      }

      std::string str2 = "ftp";
      if ( cycb_avfs != NULL ) {
          if ( cycb_avfs->getSelectedOption() >= 0 &&
               cycb_avfs->getSelectedOption() < static_cast<int>( module_list.size() ) ) {
              str2 = module_list[ cycb_avfs->getSelectedOption() ];
          }
      }
      setAVFSModule( str2 );
      sgp->setText( "" );
    }
  }
  delete win;

  return endmode;
}

void GoFTPOp::setDontEnterFTP( bool nv )
{
  dontenterftp = nv;
}

void GoFTPOp::setHost( std::string s1 )
{
  host = s1;
}

void GoFTPOp::setUser( std::string s1 )
{
  user = s1;
}

void GoFTPOp::setPass( std::string s1 )
{
  pass = s1;
}

void GoFTPOp::setAVFSModule( const std::string &s1 )
{
  avfs_module = s1;
}

void GoFTPOp::setAlwaysStorePW( bool nv )
{
  always_store_pw = nv;
}

std::vector<std::string> GoFTPOp::getAvailModules()
{
    std::vector<std::string> l, avail_modules;
    std::vector<std::string>::iterator it1;
    
    // ftp is always available
    l.push_back( "ftp" );

    avail_modules = AVFSSupport::getAVFSModules();
    
    for ( it1 = avail_modules.begin();
          it1 != avail_modules.end();
          it1++ ) {
        if ( *it1 == "ucftp" ) {
            l.push_back( "ucftp" );
            break;
        }
    }
    
    return l;
}

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

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