Blame src/SleepJob.cc

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
#include <config.h>
Packit 8f70b4
#include <ctype.h>
Packit 8f70b4
#include <stddef.h>
Packit 8f70b4
#include "SleepJob.h"
Packit 8f70b4
#include "CmdExec.h"
Packit 8f70b4
#include "misc.h"
Packit 8f70b4
#include "LocalDir.h"
Packit 8f70b4
Packit 8f70b4
SleepJob::SleepJob(const TimeInterval &when,FileAccess *s,LocalDirectory *cwd,char *what)
Packit 8f70b4
   : SessionJob(s), Timer(when), saved_cwd(cwd)
Packit 8f70b4
{
Packit 8f70b4
   cmd.set_allocated(what);
Packit 8f70b4
   exit_code=0;
Packit 8f70b4
   done=false;
Packit 8f70b4
   repeat=false;
Packit 8f70b4
   weak=false;
Packit 8f70b4
   repeat_count=0;
Packit 8f70b4
   max_repeat_count=0;
Packit 8f70b4
   continue_code=-1;
Packit 8f70b4
   break_code=-1;
Packit 8f70b4
}
Packit 8f70b4
SleepJob::~SleepJob()
Packit 8f70b4
{
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
int SleepJob::Do()
Packit 8f70b4
{
Packit 8f70b4
   int m=STALL;
Packit 8f70b4
   if(Done())
Packit 8f70b4
      return m;
Packit 8f70b4
Packit 8f70b4
   if(waiting.count()>0)
Packit 8f70b4
   {
Packit 8f70b4
      Job *j=FindDoneAwaitedJob();
Packit 8f70b4
      if(!j)
Packit 8f70b4
	 return m;
Packit 8f70b4
      exit_code=j->ExitCode();
Packit 8f70b4
      if(!repeat || (++repeat_count>=max_repeat_count && max_repeat_count)
Packit 8f70b4
      || exit_code==break_code || (continue_code!=-1 && exit_code!=continue_code))
Packit 8f70b4
      {
Packit 8f70b4
	 RemoveWaiting(j);
Packit 8f70b4
	 Delete(j);
Packit 8f70b4
	 exec=0;
Packit 8f70b4
	 done=true;
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      Reset();
Packit 8f70b4
      exec=(CmdExec*)j; // we are sure it is CmdExec.
Packit 8f70b4
      RemoveWaiting(j);
Packit 8f70b4
      m=MOVED;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(Stopped())
Packit 8f70b4
   {
Packit 8f70b4
      if(cmd)
Packit 8f70b4
      {
Packit 8f70b4
	 if(!exec)
Packit 8f70b4
	 {
Packit 8f70b4
	    exec=new CmdExec(session.borrow(),saved_cwd.borrow());
Packit 8f70b4
	    exec->AllocJobno();
Packit 8f70b4
	    exec->cmdline.vset("(",cmd.get(),")",NULL);
Packit 8f70b4
	 }
Packit 8f70b4
	 exec->FeedCmd(cmd);
Packit 8f70b4
	 exec->FeedCmd("\n");
Packit 8f70b4
	 AddWaiting(exec.borrow());
Packit 8f70b4
	 return MOVED;
Packit 8f70b4
      }
Packit 8f70b4
      done=true;
Packit 8f70b4
      return MOVED;
Packit 8f70b4
   }
Packit 8f70b4
   return m;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
const char *SleepJob::Status()
Packit 8f70b4
{
Packit 8f70b4
   if(Stopped() || TimeLeft().Seconds()<=1)
Packit 8f70b4
      return "";
Packit 8f70b4
Packit 8f70b4
   if(IsInfty())
Packit 8f70b4
      return(_("Sleeping forever"));
Packit 8f70b4
   return xstring::cat(_("Sleep time left: "),
Packit 8f70b4
      TimeLeft().toString(TimeInterval::TO_STR_TRANSLATE),
Packit 8f70b4
      NULL);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
xstring& SleepJob::FormatStatus(xstring& buf,int,const char *prefix)
Packit 8f70b4
{
Packit 8f70b4
   if(repeat)
Packit 8f70b4
      buf.appendf(_("\tRepeat count: %d\n"),repeat_count);
Packit 8f70b4
   const char *s=Status();
Packit 8f70b4
   if(s[0])
Packit 8f70b4
      buf.appendf("\t%s\n",s);
Packit 8f70b4
   return buf;
Packit 8f70b4
}
Packit 8f70b4
void SleepJob::ShowRunStatus(const SMTaskRef<StatusLine>& s)
Packit 8f70b4
{
Packit 8f70b4
   if(Stopped())
Packit 8f70b4
      Job::ShowRunStatus(s);
Packit 8f70b4
   else
Packit 8f70b4
   {
Packit 8f70b4
      s->Show("%s",Status());
Packit 8f70b4
      current->TimeoutS(1);
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
void SleepJob::lftpMovesToBackground()
Packit 8f70b4
{
Packit 8f70b4
   if(weak || IsInfty() || (repeat && cmd[0]==0))
Packit 8f70b4
   {
Packit 8f70b4
      // terminate
Packit 8f70b4
      done=true;
Packit 8f70b4
   }
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
#define args (parent->args)
Packit 8f70b4
#define eprintf parent->eprintf
Packit 8f70b4
#define session (parent->session)
Packit 8f70b4
Job *cmd_sleep(CmdExec *parent)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   if(args->count()!=2)
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: argument required. "),op);
Packit 8f70b4
   err:
Packit 8f70b4
      eprintf(_("Try `help %s' for more information.\n"),op);
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   const char *t=args->getarg(1);
Packit 8f70b4
   TimeIntervalR delay(t);
Packit 8f70b4
   if(delay.Error())
Packit 8f70b4
   {
Packit 8f70b4
      eprintf("%s: %s: %s. ",op,t,delay.ErrorText());
Packit 8f70b4
      goto err;
Packit 8f70b4
   }
Packit 8f70b4
   return new SleepJob(delay);
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
Job *cmd_repeat(CmdExec *parent)
Packit 8f70b4
{
Packit 8f70b4
   const char *op=args->a0();
Packit 8f70b4
   int cmd_start=1;
Packit 8f70b4
   TimeIntervalR delay(1);
Packit 8f70b4
   int max_count=0;
Packit 8f70b4
   const char *delay_str=0;
Packit 8f70b4
   bool while_ok=false;
Packit 8f70b4
   bool until_ok=false;
Packit 8f70b4
   bool weak=false;
Packit 8f70b4
   int opt;
Packit 8f70b4
Packit 8f70b4
   static struct option repeat_opts[]=
Packit 8f70b4
   {
Packit 8f70b4
      {"delay",required_argument,0,'d'},
Packit 8f70b4
      {"count",required_argument,0,'c'},
Packit 8f70b4
      {"while-ok",no_argument,0,'o'},
Packit 8f70b4
      {"until-ok",no_argument,0,'O'},
Packit 8f70b4
      {"weak",no_argument,0,'w'},
Packit 8f70b4
      {0},
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   args->rewind();
Packit 8f70b4
   while((opt=args->getopt_long("+c:d:",repeat_opts,0))!=EOF)
Packit 8f70b4
   {
Packit 8f70b4
      switch(opt)
Packit 8f70b4
      {
Packit 8f70b4
      case('c'):
Packit 8f70b4
	 max_count=atoi(optarg);
Packit 8f70b4
	 break;
Packit 8f70b4
      case('d'):
Packit 8f70b4
	 delay_str=optarg;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('o'):
Packit 8f70b4
	 while_ok=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('O'):
Packit 8f70b4
	 until_ok=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('w'):
Packit 8f70b4
	 weak=true;
Packit 8f70b4
	 break;
Packit 8f70b4
      case('?'):
Packit 8f70b4
	 eprintf(_("Try `help %s' for more information.\n"),args->a0());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   if(!delay_str)
Packit 8f70b4
   {
Packit 8f70b4
      const char *t=args->getcurr();
Packit 8f70b4
      if(t && isdigit((unsigned char)t[0]))
Packit 8f70b4
      {
Packit 8f70b4
	 args->getnext();
Packit 8f70b4
	 delay_str=t;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
   cmd_start=args->getindex();
Packit 8f70b4
Packit 8f70b4
   if(delay_str)
Packit 8f70b4
   {
Packit 8f70b4
      delay.Set(delay_str);
Packit 8f70b4
      if(delay.Error())
Packit 8f70b4
      {
Packit 8f70b4
	 eprintf("%s: %s: %s.\n",op,delay_str,delay.ErrorText());
Packit 8f70b4
	 return 0;
Packit 8f70b4
      }
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   char *cmd = (args->count()==cmd_start+1
Packit 8f70b4
	        ? args->Combine(cmd_start) : args->CombineQuoted(cmd_start));
Packit 8f70b4
   SleepJob *s=new SleepJob(delay,session->Clone(),parent->cwd->Clone(),cmd);
Packit 8f70b4
   s->Repeat(max_count);
Packit 8f70b4
   s->SetWeak(weak);
Packit 8f70b4
   if(while_ok)
Packit 8f70b4
      s->ContinueCode(0);
Packit 8f70b4
   if(until_ok)
Packit 8f70b4
      s->BreakCode(0);
Packit 8f70b4
   return s;
Packit 8f70b4
}
Packit 8f70b4
Packit 8f70b4
extern "C" {
Packit 8f70b4
#include "parse-datetime.h"
Packit 8f70b4
}
Packit 8f70b4
Job *cmd_at(CmdExec *parent)
Packit 8f70b4
{
Packit 8f70b4
   int count=1;
Packit 8f70b4
   int cmd_start=0;
Packit 8f70b4
   xstring date;
Packit 8f70b4
   for(;;)
Packit 8f70b4
   {
Packit 8f70b4
      const char *arg=args->getnext();
Packit 8f70b4
      if(arg==0)
Packit 8f70b4
	 break;
Packit 8f70b4
      if(!strcmp(arg,"--"))
Packit 8f70b4
      {
Packit 8f70b4
	 cmd_start=count+1;
Packit 8f70b4
	 break;
Packit 8f70b4
      }
Packit 8f70b4
      if(date)
Packit 8f70b4
	 date.append(' ');
Packit 8f70b4
      date.append(arg);
Packit 8f70b4
      count++;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!date) {
Packit 8f70b4
      eprintf(_("%s: date-time specification missed\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   struct timespec ts;
Packit 8f70b4
   if(!parse_datetime(&ts,date,0))
Packit 8f70b4
   {
Packit 8f70b4
      eprintf(_("%s: date-time parse error\n"),args->a0());
Packit 8f70b4
      return 0;
Packit 8f70b4
   }
Packit 8f70b4
   time_t when=ts.tv_sec;
Packit 8f70b4
   if(when
Packit 8f70b4
      when+=86400;
Packit 8f70b4
Packit 8f70b4
   char *cmd=0;
Packit 8f70b4
   if(cmd_start)
Packit 8f70b4
   {
Packit 8f70b4
      // two cases:
Packit 8f70b4
      //  1. at time -- "cmd; cmd..." (one argument)
Packit 8f70b4
      //  2. at time -- shell "cmd; cmd..." (several args)
Packit 8f70b4
      if(cmd_start==args->count()-1)
Packit 8f70b4
	 cmd=args->Combine(cmd_start);
Packit 8f70b4
      else
Packit 8f70b4
	 cmd=args->CombineQuoted(cmd_start);
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   if(!cmd)
Packit 8f70b4
      return new SleepJob(Time(when,0)-SMTask::now);
Packit 8f70b4
Packit 8f70b4
   return new SleepJob(Time(when,0)-SMTask::now,
Packit 8f70b4
			session->Clone(), parent->cwd->Clone(), cmd);
Packit 8f70b4
}
Packit 8f70b4
#undef args
Packit 8f70b4
Packit 8f70b4
#include "modconfig.h"
Packit 8f70b4
#ifndef MODULE_CMD_SLEEP
Packit 8f70b4
# define module_init cmd_sleep_module_init
Packit 8f70b4
#endif
Packit 8f70b4
CDECL void module_init()
Packit 8f70b4
{
Packit 8f70b4
   CmdExec::RegisterCommand("sleep",cmd_sleep,0,
Packit 8f70b4
	 N_("Usage: sleep <time>[unit]\n"
Packit 8f70b4
	 "Sleep for given amount of time. The time argument can be optionally\n"
Packit 8f70b4
	 "followed by unit specifier: d - days, h - hours, m - minutes, s - seconds.\n"
Packit 8f70b4
	 "By default time is assumed to be seconds.\n")
Packit 8f70b4
   );
Packit 8f70b4
   CmdExec::RegisterCommand("at",cmd_at);
Packit 8f70b4
   CmdExec::RegisterCommand("repeat",cmd_repeat,0,
Packit 8f70b4
	 N_("Repeat specified command with a delay between iterations.\n"
Packit 8f70b4
	 "Default delay is one second, default command is empty.\n"
Packit 8f70b4
	 " -c <count>  maximum number of iterations\n"
Packit 8f70b4
	 " -d <delay>  delay between iterations\n"
Packit 8f70b4
	 " --while-ok  stop when command exits with non-zero code\n"
Packit 8f70b4
	 " --until-ok  stop when command exits with zero code\n"
Packit 8f70b4
	 " --weak      stop when lftp moves to background.\n")
Packit 8f70b4
   );
Packit 8f70b4
}