Blame src/misc.cc

Packit Service a2489d
/*
Packit Service a2489d
 * lftp - file transfer program
Packit Service a2489d
 *
Packit Service a2489d
 * Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
Packit Service a2489d
 *
Packit Service a2489d
 * This program is free software; you can redistribute it and/or modify
Packit Service a2489d
 * it under the terms of the GNU General Public License as published by
Packit Service a2489d
 * the Free Software Foundation; either version 3 of the License, or
Packit Service a2489d
 * (at your option) any later version.
Packit Service a2489d
 *
Packit Service a2489d
 * This program is distributed in the hope that it will be useful,
Packit Service a2489d
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service a2489d
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service a2489d
 * GNU General Public License for more details.
Packit Service a2489d
 *
Packit Service a2489d
 * You should have received a copy of the GNU General Public License
Packit Service a2489d
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service a2489d
 */
Packit Service a2489d
Packit Service a2489d
#include <config.h>
Packit Service a2489d
#include "xmalloc.h"
Packit Service a2489d
#include "xstring.h"
Packit Service a2489d
#include "trio.h"
Packit Service a2489d
#include <pwd.h>
Packit Service a2489d
#include <unistd.h>
Packit Service a2489d
#include <errno.h>
Packit Service a2489d
#include <sys/types.h>
Packit Service a2489d
#include <sys/stat.h>
Packit Service a2489d
#include <time.h>
Packit Service a2489d
#include <ctype.h>
Packit Service a2489d
#include <sys/ioctl.h>
Packit Service a2489d
#include <fcntl.h>
Packit Service a2489d
#include <pwd.h>
Packit Service a2489d
#include <sys/socket.h>
Packit Service a2489d
#include <netinet/in.h>
Packit Service a2489d
#include <arpa/inet.h>
Packit Service a2489d
Packit Service a2489d
#ifdef HAVE_TERMIOS_H
Packit Service a2489d
#include <termios.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#ifdef TIME_WITH_SYS_TIME
Packit Service a2489d
# include <sys/time.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#if LIBIDN2
Packit Service a2489d
# include <idn2.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
#ifdef HAVE_DLFCN_H
Packit Service a2489d
# include <dlfcn.h>
Packit Service a2489d
#endif
Packit Service a2489d
Packit Service a2489d
CDECL_BEGIN
Packit Service a2489d
#include "regex.h"
Packit Service a2489d
#include "human.h"
Packit Service a2489d
CDECL_END
Packit Service a2489d
#include "misc.h"
Packit Service a2489d
#include "ProcWait.h"
Packit Service a2489d
#include "SignalHook.h"
Packit Service a2489d
#include "url.h"
Packit Service a2489d
#include "ResMgr.h"
Packit Service a2489d
#include <mbswidth.h>
Packit Service a2489d
#include "strftime.h"
Packit Service a2489d
Packit Service a2489d
const char *dir_file(const char *dir,const char *file)
Packit Service a2489d
{
Packit Service a2489d
   if(dir==0 || dir[0]==0)
Packit Service a2489d
      return file?file:dir;
Packit Service a2489d
   if(file==0 || file[0]==0)
Packit Service a2489d
      return dir;
Packit Service a2489d
   if(file[0]=='/')
Packit Service a2489d
      return file;
Packit Service a2489d
   if(file[0]=='.' && file[1]=='/')
Packit Service a2489d
      file+=2;
Packit Service a2489d
Packit Service a2489d
   xstring& buf=xstring::get_tmp();
Packit Service a2489d
   size_t len=strlen(dir);
Packit Service a2489d
   if(len==0)
Packit Service a2489d
      return buf.set(file);
Packit Service a2489d
   if(dir[len-1]=='/')
Packit Service a2489d
      return buf.vset(dir,file,NULL);
Packit Service a2489d
   return buf.vset(dir,"/",file,NULL);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *url_file(const char *url,const char *file)
Packit Service a2489d
{
Packit Service a2489d
   static xstring buf;
Packit Service a2489d
Packit Service a2489d
   if(buf && url==buf) // it is possible to url_file(url_file(url,dir),file)
Packit Service a2489d
      url=alloca_strdup(url);
Packit Service a2489d
Packit Service a2489d
   if(!url || url[0]==0)
Packit Service a2489d
   {
Packit Service a2489d
      buf.set(file?file:"");
Packit Service a2489d
      return buf;
Packit Service a2489d
   }
Packit Service a2489d
   ParsedURL u(url);
Packit Service a2489d
   if(!u.proto)
Packit Service a2489d
   {
Packit Service a2489d
      buf.set(dir_file(url,file));
Packit Service a2489d
      return buf;
Packit Service a2489d
   }
Packit Service a2489d
   if(file && file[0]=='~')
Packit Service a2489d
      u.path.set(file);
Packit Service a2489d
   else
Packit Service a2489d
      u.path.set(dir_file(u.path,file));
Packit Service a2489d
   buf.truncate();
Packit Service a2489d
   return u.CombineTo(buf);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *output_file_name(const char *src,const char *dst,bool dst_local,
Packit Service a2489d
			     const char *dst_base,bool make_dirs)
Packit Service a2489d
{
Packit Service a2489d
   bool dst_is_dir=false;
Packit Service a2489d
   if(dst)
Packit Service a2489d
   {
Packit Service a2489d
      if(dst_base)
Packit Service a2489d
	 dst=url_file(dst_base,dst);
Packit Service a2489d
      ParsedURL u_dst(dst,true);
Packit Service a2489d
      if(u_dst.proto)
Packit Service a2489d
	 dst_local=false;
Packit Service a2489d
      if(dst_local)
Packit Service a2489d
      {
Packit Service a2489d
	 dst=expand_home_relative(dst);
Packit Service a2489d
	 struct stat st;
Packit Service a2489d
	 if(stat(dst,&st)!=-1 && S_ISDIR(st.st_mode))
Packit Service a2489d
	    dst_is_dir=true;
Packit Service a2489d
      }
Packit Service a2489d
      else
Packit Service a2489d
      {
Packit Service a2489d
	 int len=xstrlen(u_dst.path);
Packit Service a2489d
	 if(len>0 && u_dst.path[len-1]=='/')
Packit Service a2489d
	    dst_is_dir=true;
Packit Service a2489d
      }
Packit Service a2489d
      if(!dst_is_dir)
Packit Service a2489d
	 return dst;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   ParsedURL u_src(src,true);
Packit Service a2489d
   if(u_src.proto)
Packit Service a2489d
      src=u_src.path;
Packit Service a2489d
   if(!src)
Packit Service a2489d
      return "";  // there will be error anyway.
Packit Service a2489d
   const char *base=basename_ptr(src);
Packit Service a2489d
   if(make_dirs && !dst)
Packit Service a2489d
   {
Packit Service a2489d
      base=src;
Packit Service a2489d
      if(base[0]=='~')
Packit Service a2489d
      {
Packit Service a2489d
	 base=strchr(base,'/');
Packit Service a2489d
	 if(!base)
Packit Service a2489d
	    base="";
Packit Service a2489d
      }
Packit Service a2489d
      while(*base=='/')
Packit Service a2489d
	 base++;
Packit Service a2489d
   }
Packit Service a2489d
   return url_file(dst?dst:dst_base,base);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *basename_ptr(const char *s)
Packit Service a2489d
{
Packit Service a2489d
   const char *s1=s+strlen(s);
Packit Service a2489d
   while(s1>s && s1[-1]=='/')
Packit Service a2489d
      s1--;
Packit Service a2489d
   while(s1>s && s1[-1]!='/')
Packit Service a2489d
      s1--;
Packit Service a2489d
   return s1;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *expand_home_relative(const char *s)
Packit Service a2489d
{
Packit Service a2489d
   if(s[0]!='~')
Packit Service a2489d
      return s;
Packit Service a2489d
Packit Service a2489d
   const char *home=0;
Packit Service a2489d
   const char *sl=strchr(s+1,'/');
Packit Service a2489d
   static xstring ret_path;
Packit Service a2489d
Packit Service a2489d
   if(s[1]==0 || s[1]=='/')
Packit Service a2489d
   {
Packit Service a2489d
      home=get_home();
Packit Service a2489d
   }
Packit Service a2489d
   else
Packit Service a2489d
   {
Packit Service a2489d
      // extract user name and find the home
Packit Service a2489d
      int name_len=(sl?sl-s-1:strlen(s+1));
Packit Service a2489d
      struct passwd *pw=getpwnam(xstring::get_tmp(s+1,name_len));
Packit Service a2489d
      if(pw)
Packit Service a2489d
	 home=pw->pw_dir;
Packit Service a2489d
   }
Packit Service a2489d
   if(home==0)
Packit Service a2489d
      return s;
Packit Service a2489d
Packit Service a2489d
   if(sl)
Packit Service a2489d
      return ret_path.vset(home,sl,NULL);
Packit Service a2489d
   return home;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int   create_directories(char *path)
Packit Service a2489d
{
Packit Service a2489d
   char  *sl=path;
Packit Service a2489d
   int	 res;
Packit Service a2489d
Packit Service a2489d
   if(access(path,0)==0)
Packit Service a2489d
      return 0;
Packit Service a2489d
Packit Service a2489d
   for(;;)
Packit Service a2489d
   {
Packit Service a2489d
      sl=strchr(sl,'/');
Packit Service a2489d
      if(sl==path)
Packit Service a2489d
      {
Packit Service a2489d
	 sl++;
Packit Service a2489d
	 continue;
Packit Service a2489d
      }
Packit Service a2489d
      if(sl)
Packit Service a2489d
	 *sl=0;
Packit Service a2489d
      if(access(path,0)==-1)
Packit Service a2489d
      {
Packit Service a2489d
	 res=mkdir(path,0777);
Packit Service a2489d
	 if(res==-1)
Packit Service a2489d
	 {
Packit Service a2489d
	    if(errno!=EEXIST)
Packit Service a2489d
	    {
Packit Service a2489d
	       fprintf(stderr,"mkdir(%s): %s\n",path,strerror(errno));
Packit Service a2489d
	       if(sl)
Packit Service a2489d
		  *sl='/';
Packit Service a2489d
	       return(-1);
Packit Service a2489d
	    }
Packit Service a2489d
	 }
Packit Service a2489d
      }
Packit Service a2489d
      if(sl)
Packit Service a2489d
	 *sl++='/';
Packit Service a2489d
      else
Packit Service a2489d
	 break;
Packit Service a2489d
   }
Packit Service a2489d
   return 0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void  truncate_file_tree(const char *dir)
Packit Service a2489d
{
Packit Service a2489d
   fflush(stderr);
Packit Service a2489d
   pid_t pid;
Packit Service a2489d
   switch(pid=fork())
Packit Service a2489d
   {
Packit Service a2489d
   case(0): // child
Packit Service a2489d
      SignalHook::Ignore(SIGINT);
Packit Service a2489d
      SignalHook::Ignore(SIGTSTP);
Packit Service a2489d
      SignalHook::Ignore(SIGQUIT);
Packit Service a2489d
      SignalHook::Ignore(SIGHUP);
Packit Service a2489d
      execlp("rm","rm","-rf",dir,(char*)NULL);
Packit Service a2489d
      perror("execlp(rm)");
Packit Service a2489d
      fflush(stderr);
Packit Service a2489d
      _exit(1);
Packit Service a2489d
   case(-1):   // error
Packit Service a2489d
      perror("fork()");
Packit Service a2489d
      return;
Packit Service a2489d
   default: // parent
Packit Service a2489d
      (new ProcWait(pid))->Auto();  // don't wait for termination
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int fd_width(int fd)
Packit Service a2489d
{
Packit Service a2489d
   if(fd == -1) return -1;
Packit Service a2489d
   if(!isatty(fd)) return 0;
Packit Service a2489d
Packit Service a2489d
#ifdef TIOCGWINSZ
Packit Service a2489d
   struct winsize sz;
Packit Service a2489d
   sz.ws_col=sz.ws_row=0;
Packit Service a2489d
   ioctl(fd,TIOCGWINSZ,&sz);
Packit Service a2489d
   if(sz.ws_col==0)
Packit Service a2489d
      sz.ws_col=80;
Packit Service a2489d
   return(sz.ws_col);
Packit Service a2489d
#else /* !TIOCGWINSZ */
Packit Service a2489d
   return 80;
Packit Service a2489d
#endif
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
char *xgetcwd()
Packit Service a2489d
{
Packit Service a2489d
   char *cwd=getcwd(0,0); // glibc extension
Packit Service a2489d
   if(cwd) {
Packit Service a2489d
      xmalloc_register_block(cwd);
Packit Service a2489d
      return cwd;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   int size=256;
Packit Service a2489d
   cwd=(char*)xmalloc(size);
Packit Service a2489d
   for(;;)
Packit Service a2489d
   {
Packit Service a2489d
      if(getcwd(cwd,size))
Packit Service a2489d
	 return cwd;
Packit Service a2489d
      if(errno!=ERANGE)
Packit Service a2489d
	 return strcpy(cwd,".");
Packit Service a2489d
      cwd=(char*)xrealloc(cwd,size*=2);
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void xgetcwd_to(xstring& s)
Packit Service a2489d
{
Packit Service a2489d
   int size=256;
Packit Service a2489d
   for(;;) {
Packit Service a2489d
      s.get_space(size);
Packit Service a2489d
      if(getcwd(s.get_non_const(),size)) {
Packit Service a2489d
	 s.set_length(strlen(s.get()));
Packit Service a2489d
	 return;
Packit Service a2489d
      }
Packit Service a2489d
      if(errno!=ERANGE) {
Packit Service a2489d
	 s.set(".");
Packit Service a2489d
	 return;
Packit Service a2489d
      }
Packit Service a2489d
      size*=2;
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int parse_perms(const char *s)
Packit Service a2489d
{
Packit Service a2489d
   int p=0;
Packit Service a2489d
Packit Service a2489d
   if(strlen(s)!=9
Packit Service a2489d
   && !(strlen(s)==10 && s[9]=='+'))   // ACL tag
Packit Service a2489d
      bad: return -1;
Packit Service a2489d
Packit Service a2489d
   switch(s[0])
Packit Service a2489d
   {
Packit Service a2489d
   case('r'): p|=S_IRUSR; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   switch(s[1])
Packit Service a2489d
   {
Packit Service a2489d
   case('w'): p|=S_IWUSR; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   switch(s[2])
Packit Service a2489d
   {
Packit Service a2489d
   case('S'): p|=S_ISUID; break;
Packit Service a2489d
   case('s'): p|=S_ISUID; // fall-through
Packit Service a2489d
   case('x'): p|=S_IXUSR; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   s+=3;
Packit Service a2489d
   switch(s[0])
Packit Service a2489d
   {
Packit Service a2489d
   case('r'): p|=S_IRGRP; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   switch(s[1])
Packit Service a2489d
   {
Packit Service a2489d
   case('w'): p|=S_IWGRP; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   switch(s[2])
Packit Service a2489d
   {
Packit Service a2489d
   case('S'): p|=S_ISGID; break;
Packit Service a2489d
   case('s'): p|=S_ISGID; // fall-through
Packit Service a2489d
   case('x'): p|=S_IXGRP; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   s+=3;
Packit Service a2489d
   switch(s[0])
Packit Service a2489d
   {
Packit Service a2489d
   case('r'): p|=S_IROTH; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   switch(s[1])
Packit Service a2489d
   {
Packit Service a2489d
   case('w'): p|=S_IWOTH; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
   switch(s[2])
Packit Service a2489d
   {
Packit Service a2489d
   case('T'): p|=S_ISVTX; break;
Packit Service a2489d
   case('t'): p|=S_ISVTX; // fall-through
Packit Service a2489d
   case('x'): p|=S_IXOTH; break;
Packit Service a2489d
   case('l'): case('L'): p|=S_ISGID; p&=~S_IXGRP; break;
Packit Service a2489d
   case('-'): break;
Packit Service a2489d
   default: goto bad;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   return p;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
// it does not prepend file type.
Packit Service a2489d
const char *format_perms(int p)
Packit Service a2489d
{
Packit Service a2489d
   static char s[10];
Packit Service a2489d
   memset(s,'-',9);
Packit Service a2489d
   if(p&0400) s[0]='r';
Packit Service a2489d
   if(p&0200) s[1]='w';
Packit Service a2489d
   if(p&0100) s[2]='x';
Packit Service a2489d
   if(p&0040) s[3]='r';
Packit Service a2489d
   if(p&0020) s[4]='w';
Packit Service a2489d
   if(p&0010) s[5]='x';
Packit Service a2489d
   if(p&0004) s[6]='r';
Packit Service a2489d
   if(p&0002) s[7]='w';
Packit Service a2489d
   if(p&0001) s[8]='x';
Packit Service a2489d
   if(p&01000) s[8]=(p&0001?'t':'T');
Packit Service a2489d
   if(p&02000) s[5]=(p&0010?'s':'S');
Packit Service a2489d
   if(p&04000) s[2]=(p&0100?'s':'S');
Packit Service a2489d
   return s;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char month_names[][4]={
Packit Service a2489d
   "Jan","Feb","Mar","Apr","May","Jun",
Packit Service a2489d
   "Jul","Aug","Sep","Oct","Nov","Dec",
Packit Service a2489d
   ""
Packit Service a2489d
};
Packit Service a2489d
int parse_month(const char *m)
Packit Service a2489d
{
Packit Service a2489d
   for(int i=0; month_names[i][0]; i++)
Packit Service a2489d
      if(!strcasecmp(month_names[i],m))
Packit Service a2489d
	 return(i%12);
Packit Service a2489d
   return -1;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int parse_year_or_time(const char *year_or_time,int *year,int *hour,int *minute)
Packit Service a2489d
{
Packit Service a2489d
   if(year_or_time[2]==':')
Packit Service a2489d
   {
Packit Service a2489d
      if(2!=sscanf(year_or_time,"%2d:%2d",hour,minute))
Packit Service a2489d
	 return -1;
Packit Service a2489d
      *year=-1;
Packit Service a2489d
   }
Packit Service a2489d
   else
Packit Service a2489d
   {
Packit Service a2489d
      if(1!=sscanf(year_or_time,"%d",year))
Packit Service a2489d
	 return -1;;
Packit Service a2489d
      *hour=*minute=0;
Packit Service a2489d
   }
Packit Service a2489d
   return 0;
Packit Service a2489d
}
Packit Service a2489d
int guess_year(int month,int day,int hour,int minute)
Packit Service a2489d
{
Packit Service a2489d
   const struct tm &now=SMTask::now;
Packit Service a2489d
   int year=now.tm_year+1900;
Packit Service a2489d
   if(month     *32+        day
Packit Service a2489d
    > now.tm_mon*32+now.tm_mday+6)
Packit Service a2489d
      year--;
Packit Service a2489d
   return year;
Packit Service a2489d
}
Packit Service a2489d
int percent(off_t offset,off_t size)
Packit Service a2489d
{
Packit Service a2489d
   if(offset>=size)
Packit Service a2489d
      return 100;
Packit Service a2489d
   // use floating point to avoid integer overflow.
Packit Service a2489d
   return int(double(offset)*100/size);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *squeeze_file_name(const char *name,int w)
Packit Service a2489d
{
Packit Service a2489d
   static xstring buf;
Packit Service a2489d
   int mbflags=0;
Packit Service a2489d
Packit Service a2489d
   name=url::remove_password(name);
Packit Service a2489d
Packit Service a2489d
   int name_width=mbswidth(name,mbflags);
Packit Service a2489d
   if(name_width<=w)
Packit Service a2489d
      return name;
Packit Service a2489d
Packit Service a2489d
   const char *b=basename_ptr(name);
Packit Service a2489d
   int b_width=name_width-mbsnwidth(name,b-name,mbflags);
Packit Service a2489d
   if(b_width<=w-4 && b_width>w-15)
Packit Service a2489d
      return buf.vset(".../",b,NULL);
Packit Service a2489d
   int b_len=strlen(b);
Packit Service a2489d
   while(b_width>(w<3?w-1:w-3) && b_len>0)
Packit Service a2489d
   {
Packit Service a2489d
      int ch_len=mblen(b,b_len);
Packit Service a2489d
      if(ch_len<1)
Packit Service a2489d
	 ch_len=1;
Packit Service a2489d
      b_width-=mbsnwidth(b,ch_len,mbflags);
Packit Service a2489d
      b+=ch_len;
Packit Service a2489d
      b_len-=ch_len;
Packit Service a2489d
   }
Packit Service a2489d
   if(w>=6)
Packit Service a2489d
      buf.set("...");
Packit Service a2489d
   else
Packit Service a2489d
      buf.set("<");
Packit Service a2489d
   return buf.append(b);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* Converts struct tm to time_t, assuming the data in tm is UTC rather
Packit Service a2489d
   than local timezone (mktime assumes the latter).
Packit Service a2489d
Packit Service a2489d
   Contributed by Roger Beeman <beeman@cisco.com>, with the help of
Packit Service a2489d
   Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO.  */
Packit Service a2489d
time_t
Packit Service a2489d
mktime_from_utc (const struct tm *t)
Packit Service a2489d
{
Packit Service a2489d
   struct tm tc;
Packit Service a2489d
   memcpy(&tc, t, sizeof(struct tm));
Packit Service a2489d
Packit Service a2489d
   /* UTC times are never DST; if we say -1, we'll introduce odd localtime-
Packit Service a2489d
    * dependant errors. */
Packit Service a2489d
Packit Service a2489d
   tc.tm_isdst = 0;
Packit Service a2489d
Packit Service a2489d
   time_t tl = mktime (&tc);
Packit Service a2489d
   if (tl == -1)
Packit Service a2489d
      return -1;
Packit Service a2489d
   time_t tb = mktime (gmtime (&tl));
Packit Service a2489d
Packit Service a2489d
   return (tl <= tb ? (tl + (tl - tb)) : (tl - (tb - tl)));
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
static void set_tz(const char *tz)
Packit Service a2489d
{
Packit Service a2489d
   static char *put_tz;
Packit Service a2489d
   static int put_tz_alloc;
Packit Service a2489d
Packit Service a2489d
   if(!tz)
Packit Service a2489d
   {
Packit Service a2489d
      unsetenv("TZ");
Packit Service a2489d
Packit Service a2489d
      xfree(put_tz);
Packit Service a2489d
      put_tz=0;
Packit Service a2489d
      put_tz_alloc=0;
Packit Service a2489d
Packit Service a2489d
      tzset();
Packit Service a2489d
      return;
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   int tz_len=strlen(tz)+4;
Packit Service a2489d
   char *new_tz=put_tz;
Packit Service a2489d
   if(tz_len>put_tz_alloc)
Packit Service a2489d
      new_tz=(char*)xmalloc(put_tz_alloc=tz_len);
Packit Service a2489d
   snprintf(new_tz,tz_len,"TZ=%s",tz);
Packit Service a2489d
   if(new_tz!=put_tz)
Packit Service a2489d
   {
Packit Service a2489d
      putenv(new_tz);
Packit Service a2489d
      xfree(put_tz);
Packit Service a2489d
      put_tz=new_tz;
Packit Service a2489d
   }
Packit Service a2489d
   // now initialize libc variables from env TZ.
Packit Service a2489d
   tzset();
Packit Service a2489d
}
Packit Service a2489d
static char *saved_tz=0;
Packit Service a2489d
static void save_tz()
Packit Service a2489d
{
Packit Service a2489d
   xstrset(saved_tz,getenv("TZ"));
Packit Service a2489d
}
Packit Service a2489d
static void restore_tz()
Packit Service a2489d
{
Packit Service a2489d
   set_tz(saved_tz);
Packit Service a2489d
}
Packit Service a2489d
time_t mktime_from_tz(struct tm *t,const char *tz)
Packit Service a2489d
{
Packit Service a2489d
   if(!tz || !*tz)
Packit Service a2489d
      return mktime(t);
Packit Service a2489d
   if(!strcasecmp(tz,"GMT"))
Packit Service a2489d
      return mktime_from_utc(t);
Packit Service a2489d
   if(isdigit((unsigned char)*tz) || *tz=='+' || *tz=='-')
Packit Service a2489d
   {
Packit Service a2489d
      int tz1_len=strlen(tz)+4;
Packit Service a2489d
      char *tz1=string_alloca(tz1_len);
Packit Service a2489d
      snprintf(tz1,tz1_len,"GMT%s",tz);
Packit Service a2489d
      tz=tz1;
Packit Service a2489d
   }
Packit Service a2489d
   save_tz();
Packit Service a2489d
   set_tz(tz);
Packit Service a2489d
   time_t res=mktime(t);
Packit Service a2489d
   restore_tz();
Packit Service a2489d
   return res;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool re_match(const char *line,const char *a,int flags)
Packit Service a2489d
{
Packit Service a2489d
   if(!a || !*a)
Packit Service a2489d
      return false;
Packit Service a2489d
   regex_t re;
Packit Service a2489d
   if(regcomp(&re,a,REG_EXTENDED|REG_NOSUB|flags))
Packit Service a2489d
      return false;
Packit Service a2489d
   bool res=(0==regexec(&re,line,0,0,0));
Packit Service a2489d
   regfree(&re);
Packit Service a2489d
   return res;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
xstring& SubstTo(xstring& buf,const char *txt, const subst_t *s)
Packit Service a2489d
{
Packit Service a2489d
   buf.nset("",0);
Packit Service a2489d
Packit Service a2489d
   char str[3];
Packit Service a2489d
   bool last_subst_empty=true;
Packit Service a2489d
Packit Service a2489d
   while(*txt)
Packit Service a2489d
   {
Packit Service a2489d
      char ch = *txt++;
Packit Service a2489d
      const char *to_add = NULL;
Packit Service a2489d
      if(ch=='\\' && *txt && *txt!='\\')
Packit Service a2489d
      {
Packit Service a2489d
	 ch=*txt++;
Packit Service a2489d
	 if(ch >= '0' && ch < '8') {
Packit Service a2489d
	    int len;
Packit Service a2489d
	    unsigned code;
Packit Service a2489d
	    txt--;
Packit Service a2489d
	    if(sscanf(txt,"%3o%n",&code,&len)!=1)
Packit Service a2489d
	       continue; // should never happen.
Packit Service a2489d
	    ch=code;
Packit Service a2489d
	    txt+=len;
Packit Service a2489d
	    str[0]=ch;
Packit Service a2489d
	    str[1]=0;
Packit Service a2489d
	    to_add=str;
Packit Service a2489d
	 } else {
Packit Service a2489d
	    if(ch=='?')
Packit Service a2489d
	    {
Packit Service a2489d
	       if(last_subst_empty)
Packit Service a2489d
		  txt++;
Packit Service a2489d
	       to_add="";
Packit Service a2489d
	    }
Packit Service a2489d
	    for(int i = 0; s[i].from; i++) {
Packit Service a2489d
	       if(s[i].from != ch)
Packit Service a2489d
		  continue;
Packit Service a2489d
	       to_add=s[i].to;
Packit Service a2489d
	       if(!to_add)
Packit Service a2489d
		  to_add = "";
Packit Service a2489d
	       last_subst_empty = (*to_add==0);
Packit Service a2489d
	    }
Packit Service a2489d
	    if(!to_add) {
Packit Service a2489d
	       str[0]='\\';
Packit Service a2489d
	       str[1]=ch;
Packit Service a2489d
	       str[2]=0;
Packit Service a2489d
	       to_add=str;
Packit Service a2489d
	    }
Packit Service a2489d
	 }
Packit Service a2489d
      }
Packit Service a2489d
      else
Packit Service a2489d
      {
Packit Service a2489d
	 if(ch=='\\' && *txt=='\\')
Packit Service a2489d
	    txt++;
Packit Service a2489d
	 str[0]=ch;
Packit Service a2489d
	 str[1]=0;
Packit Service a2489d
	 to_add=str;
Packit Service a2489d
      }
Packit Service a2489d
Packit Service a2489d
      if(to_add==0)
Packit Service a2489d
	 continue;
Packit Service a2489d
Packit Service a2489d
      buf.append(to_add);
Packit Service a2489d
   }
Packit Service a2489d
   return(buf);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void xgettimeofday(time_t *sec, int *usec)
Packit Service a2489d
{
Packit Service a2489d
#ifdef HAVE_GETTIMEOFDAY
Packit Service a2489d
   struct timeval tv;
Packit Service a2489d
   gettimeofday(&tv,0);
Packit Service a2489d
   if(sec) *sec = tv.tv_sec;
Packit Service a2489d
   if(usec) *usec = tv.tv_usec;
Packit Service a2489d
#else
Packit Service a2489d
   if(sec) time(sec);
Packit Service a2489d
   if(usec) *usec = 0;
Packit Service a2489d
#endif
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
char *xstrftime(const char *format, const struct tm *tm)
Packit Service a2489d
{
Packit Service a2489d
   char *ret = NULL;
Packit Service a2489d
   int siz = 32;
Packit Service a2489d
Packit Service a2489d
   struct tm dummy;
Packit Service a2489d
   memset(&dummy, 0, sizeof(dummy));
Packit Service a2489d
   if(tm == NULL)
Packit Service a2489d
      tm = &dummy;
Packit Service a2489d
Packit Service a2489d
   for(;;)
Packit Service a2489d
   {
Packit Service a2489d
      ret = (char *) xrealloc(ret, siz);
Packit Service a2489d
      int res=strftime(ret, siz, format, tm);
Packit Service a2489d
      if(res>0 && res
Packit Service a2489d
	 return ret; /* success */
Packit Service a2489d
      /* more space */
Packit Service a2489d
      siz*=2;
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* /file/name -> /file
Packit Service a2489d
 * /file -> /
Packit Service a2489d
 * file/name -> "file"
Packit Service a2489d
 * file/name/ -> "file"
Packit Service a2489d
 * file -> ""
Packit Service a2489d
 * note: the last differs from dirname(1) (which would return ".")
Packit Service a2489d
 *
Packit Service a2489d
 */
Packit Service a2489d
void strip_trailing_slashes(xstring& ret)
Packit Service a2489d
{
Packit Service a2489d
   int len=ret.length();
Packit Service a2489d
   while(len>0 && ret[len-1]=='/')
Packit Service a2489d
      len--;
Packit Service a2489d
   if(len==0 && ret[0]=='/')
Packit Service a2489d
      len=1+(ret[1]=='/');
Packit Service a2489d
   if(len>0)
Packit Service a2489d
      ret.truncate(len);
Packit Service a2489d
}
Packit Service a2489d
xstring& dirname_modify(xstring &ret)
Packit Service a2489d
{
Packit Service a2489d
   strip_trailing_slashes(ret);
Packit Service a2489d
   const char *slash=strrchr(ret,'/');
Packit Service a2489d
   if(!slash)
Packit Service a2489d
      ret.truncate(0); /* file with no path */
Packit Service a2489d
   else if(slash==ret)
Packit Service a2489d
      ret.truncate(1); /* the slash is the first character */
Packit Service a2489d
   else
Packit Service a2489d
      ret.truncate(slash-ret);
Packit Service a2489d
   return ret;
Packit Service a2489d
}
Packit Service a2489d
xstring& dirname(const char *path)
Packit Service a2489d
{
Packit Service a2489d
   return dirname_modify(xstring::get_tmp(path));
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
char last_char(const char *str)
Packit Service a2489d
{
Packit Service a2489d
   int len=strlen(str);
Packit Service a2489d
   return str[len-(len>0)];
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* How many bytes it will take to store LEN bytes in base64.  */
Packit Service a2489d
int
Packit Service a2489d
base64_length(int len)
Packit Service a2489d
{
Packit Service a2489d
  return (4 * (((len) + 2) / 3));
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
/* Encode the string S of length LENGTH to base64 format and place it
Packit Service a2489d
   to STORE.  STORE will be 0-terminated, and must point to a writable
Packit Service a2489d
   buffer of at least 1+BASE64_LENGTH(length) bytes.  */
Packit Service a2489d
void
Packit Service a2489d
base64_encode (const char *s, char *store, int length)
Packit Service a2489d
{
Packit Service a2489d
  /* Conversion table.  */
Packit Service a2489d
  static const char tbl[64] = {
Packit Service a2489d
    'A','B','C','D','E','F','G','H',
Packit Service a2489d
    'I','J','K','L','M','N','O','P',
Packit Service a2489d
    'Q','R','S','T','U','V','W','X',
Packit Service a2489d
    'Y','Z','a','b','c','d','e','f',
Packit Service a2489d
    'g','h','i','j','k','l','m','n',
Packit Service a2489d
    'o','p','q','r','s','t','u','v',
Packit Service a2489d
    'w','x','y','z','0','1','2','3',
Packit Service a2489d
    '4','5','6','7','8','9','+','/'
Packit Service a2489d
  };
Packit Service a2489d
  int i;
Packit Service a2489d
  unsigned char *p = (unsigned char *)store;
Packit Service a2489d
Packit Service a2489d
  /* Transform the 3x8 bits to 4x6 bits, as required by base64.  */
Packit Service a2489d
  for (i = 0; i < length; i += 3)
Packit Service a2489d
    {
Packit Service a2489d
      *p++ = tbl[s[0] >> 2];
Packit Service a2489d
      *p++ = tbl[((s[0] & 3) << 4) + (s[1] >> 4)];
Packit Service a2489d
      *p++ = tbl[((s[1] & 0xf) << 2) + (s[2] >> 6)];
Packit Service a2489d
      *p++ = tbl[s[2] & 0x3f];
Packit Service a2489d
      s += 3;
Packit Service a2489d
    }
Packit Service a2489d
  /* Pad the result if necessary...  */
Packit Service a2489d
  if (i == length + 1)
Packit Service a2489d
    *(p - 1) = '=';
Packit Service a2489d
  else if (i == length + 2)
Packit Service a2489d
    *(p - 1) = *(p - 2) = '=';
Packit Service a2489d
  /* ...and zero-terminate it.  */
Packit Service a2489d
  *p = '\0';
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool temporary_network_error(int err)
Packit Service a2489d
{
Packit Service a2489d
   switch(err)
Packit Service a2489d
   {
Packit Service a2489d
   case(EPIPE):
Packit Service a2489d
   case(EIO):
Packit Service a2489d
   case(ETIMEDOUT):
Packit Service a2489d
#ifdef ECONNRESET
Packit Service a2489d
   case(ECONNRESET):
Packit Service a2489d
#endif
Packit Service a2489d
   case(ECONNREFUSED):
Packit Service a2489d
#ifdef EHOSTUNREACH
Packit Service a2489d
   case(EHOSTUNREACH):
Packit Service a2489d
#endif
Packit Service a2489d
#ifdef EHOSTDOWN
Packit Service a2489d
   case(EHOSTDOWN):
Packit Service a2489d
#endif
Packit Service a2489d
#ifdef ENETRESET
Packit Service a2489d
   case(ENETRESET):
Packit Service a2489d
#endif
Packit Service a2489d
#ifdef ENETUNREACH
Packit Service a2489d
   case(ENETUNREACH):
Packit Service a2489d
#endif
Packit Service a2489d
#ifdef ENETDOWN
Packit Service a2489d
   case(ENETDOWN):
Packit Service a2489d
#endif
Packit Service a2489d
#ifdef ECONNABORTED
Packit Service a2489d
   case(ECONNABORTED):
Packit Service a2489d
#endif
Packit Service a2489d
#ifdef EADDRNOTAVAIL
Packit Service a2489d
   case(EADDRNOTAVAIL):
Packit Service a2489d
#endif
Packit Service a2489d
      return true;
Packit Service a2489d
   }
Packit Service a2489d
   return false;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *get_home()
Packit Service a2489d
{
Packit Service a2489d
   static char *home=NULL;
Packit Service a2489d
   if(home)
Packit Service a2489d
      return home;
Packit Service a2489d
   home=getenv("HOME");
Packit Service a2489d
   if(home)
Packit Service a2489d
      return home;
Packit Service a2489d
   struct passwd *pw=getpwuid(getuid());
Packit Service a2489d
   if(pw && pw->pw_dir)
Packit Service a2489d
      return home=pw->pw_dir;
Packit Service a2489d
   return NULL;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *get_lftp_home_nocreate()
Packit Service a2489d
{
Packit Service a2489d
   static char *lftp_home=NULL;
Packit Service a2489d
Packit Service a2489d
   if(lftp_home)
Packit Service a2489d
      return *lftp_home?lftp_home:NULL;
Packit Service a2489d
Packit Service a2489d
   lftp_home=getenv("LFTP_HOME");
Packit Service a2489d
   if(!lftp_home)
Packit Service a2489d
   {
Packit Service a2489d
      const char *h=get_home();
Packit Service a2489d
      if(h)
Packit Service a2489d
         lftp_home=xstring::cat(h,"/.lftp",NULL).borrow();
Packit Service a2489d
      else
Packit Service a2489d
         return NULL;
Packit Service a2489d
   }
Packit Service a2489d
   else
Packit Service a2489d
      lftp_home=xstrdup(lftp_home);
Packit Service a2489d
Packit Service a2489d
   return *lftp_home?lftp_home:NULL;
Packit Service a2489d
}
Packit Service a2489d
const char *get_lftp_home_if_exists()
Packit Service a2489d
{
Packit Service a2489d
   const char *home=get_lftp_home_nocreate();
Packit Service a2489d
   struct stat st;
Packit Service a2489d
   if(stat(home,&st)==-1 || !S_ISDIR(st.st_mode))
Packit Service a2489d
      return NULL;
Packit Service a2489d
   return home;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
// new XDG directories
Packit Service a2489d
const char *get_lftp_dir(char *&cached_dir,const char *env,const char *def)
Packit Service a2489d
{
Packit Service a2489d
   if(cached_dir)
Packit Service a2489d
      return cached_dir;
Packit Service a2489d
Packit Service a2489d
   // use old existing directory for compatibility
Packit Service a2489d
   const char *dir=get_lftp_home_if_exists();
Packit Service a2489d
   if(dir)
Packit Service a2489d
      return cached_dir=xstrdup(dir);
Packit Service a2489d
Packit Service a2489d
   // use explicit directory if specified, otherwise use default under home
Packit Service a2489d
   const char *home=getenv(env);
Packit Service a2489d
   if(home) {
Packit Service a2489d
      // explicit XDG dir
Packit Service a2489d
      (void)mkdir(home,0755);
Packit Service a2489d
      dir=xstring::cat(home,"/lftp",NULL);
Packit Service a2489d
   } else {
Packit Service a2489d
      home=get_home();
Packit Service a2489d
      if(!home)
Packit Service a2489d
	 return NULL;
Packit Service a2489d
      xstring& path=xstring::get_tmp(home);
Packit Service a2489d
      path.append('/');
Packit Service a2489d
      const char *slash=strchr(def,'/');
Packit Service a2489d
      if(slash) {
Packit Service a2489d
	 path.append(def,slash-def);
Packit Service a2489d
	 (void)mkdir(path,0755);
Packit Service a2489d
	 path.append(slash);
Packit Service a2489d
      } else {
Packit Service a2489d
	 path.append(def);
Packit Service a2489d
      }
Packit Service a2489d
      (void)mkdir(path,0755);
Packit Service a2489d
      dir=path.append("/lftp");
Packit Service a2489d
   }
Packit Service a2489d
   (void)mkdir(dir,0755);
Packit Service a2489d
   return cached_dir=xstrdup(dir);
Packit Service a2489d
}
Packit Service a2489d
const char *get_lftp_config_dir()
Packit Service a2489d
{
Packit Service a2489d
   static char *config_dir;
Packit Service a2489d
   return get_lftp_dir(config_dir,"XDG_CONFIG_HOME",".config");
Packit Service a2489d
}
Packit Service a2489d
const char *get_lftp_data_dir()
Packit Service a2489d
{
Packit Service a2489d
   static char *data_dir;
Packit Service a2489d
   return get_lftp_dir(data_dir,"XDG_DATA_HOME",".local/share");
Packit Service a2489d
}
Packit Service a2489d
const char *get_lftp_cache_dir()
Packit Service a2489d
{
Packit Service a2489d
   static char *cache_dir;
Packit Service a2489d
   return get_lftp_dir(cache_dir,"XDG_CACHE_HOME",".cache");
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *memrchr(const char *buf,char c,size_t len)
Packit Service a2489d
{
Packit Service a2489d
   buf+=len;
Packit Service a2489d
   while(len-->0)
Packit Service a2489d
      if(*--buf==c)
Packit Service a2489d
	 return buf;
Packit Service a2489d
   return 0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool is_shell_special(char c)
Packit Service a2489d
{
Packit Service a2489d
   switch (c)
Packit Service a2489d
   {
Packit Service a2489d
   case '\'':
Packit Service a2489d
   case '(': case ')':
Packit Service a2489d
   case '!': case '{': case '}':		/* reserved words */
Packit Service a2489d
   case '^':
Packit Service a2489d
   case '$': case '`':			/* expansion chars */
Packit Service a2489d
   case '*': case '[': case '?': case ']':	/* globbing chars */
Packit Service a2489d
   case ' ': case '\t': case '\n':		/* IFS white space */
Packit Service a2489d
   case '"': case '\\':		/* quoting chars */
Packit Service a2489d
   case '|': case '&': case ';':		/* shell metacharacters */
Packit Service a2489d
   case '<': case '>':
Packit Service a2489d
   case '#':				/* comment char */
Packit Service a2489d
      return true;
Packit Service a2489d
   }
Packit Service a2489d
   return false;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const xstring& shell_encode(const char *string,int len)
Packit Service a2489d
{
Packit Service a2489d
   if(!string)
Packit Service a2489d
      return xstring::null;
Packit Service a2489d
Packit Service a2489d
   static xstring result;
Packit Service a2489d
Packit Service a2489d
   result.get_space(2 + 2 * len);
Packit Service a2489d
   char *r = result.get_non_const();
Packit Service a2489d
Packit Service a2489d
   if(string[0]=='-' || string[0]=='~')
Packit Service a2489d
   {
Packit Service a2489d
      *r++='.';
Packit Service a2489d
      *r++='/';
Packit Service a2489d
   }
Packit Service a2489d
Packit Service a2489d
   int c;
Packit Service a2489d
   for (const char *s = string; s && (c = *s); s++)
Packit Service a2489d
   {
Packit Service a2489d
      if (is_shell_special(c))
Packit Service a2489d
	 *r++ = '\\';
Packit Service a2489d
      *r++ = c;
Packit Service a2489d
   }
Packit Service a2489d
   result.set_length(r-result);
Packit Service a2489d
   return (result);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void remove_tags(char *buf)
Packit Service a2489d
{
Packit Service a2489d
   int len=strlen(buf);
Packit Service a2489d
   for(;;)
Packit Service a2489d
   {
Packit Service a2489d
      char *less=strchr(buf,'<');
Packit Service a2489d
      char *amp=strstr(buf," ");
Packit Service a2489d
      if(!less && !amp)
Packit Service a2489d
	 break;
Packit Service a2489d
      if(amp && (!less || amp
Packit Service a2489d
      {
Packit Service a2489d
	 amp[0]=' ';
Packit Service a2489d
	 memmove(amp+1,amp+6,len-(amp+6-buf)+1);
Packit Service a2489d
	 len-=amp+6-buf;
Packit Service a2489d
	 buf=amp+1;
Packit Service a2489d
	 continue;
Packit Service a2489d
      }
Packit Service a2489d
      char *more=strchr(less+1,'>');
Packit Service a2489d
      if(!more)
Packit Service a2489d
	 break;
Packit Service a2489d
      memmove(less,more+1,len-(more+1-buf)+1);
Packit Service a2489d
      len-=more+1-buf;
Packit Service a2489d
      buf=less;
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
void rtrim(char *s)
Packit Service a2489d
{
Packit Service a2489d
   int len=strlen(s);
Packit Service a2489d
   while(len>0 && (s[len-1]==' ' || s[len-1]=='\t' || s[len-1]=='\r'))
Packit Service a2489d
      s[--len]=0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool in_foreground_pgrp()
Packit Service a2489d
{
Packit Service a2489d
   static int tty_fd;
Packit Service a2489d
   if(tty_fd==-1)
Packit Service a2489d
      return true;
Packit Service a2489d
   pid_t pg=tcgetpgrp(tty_fd);
Packit Service a2489d
   if(pg==(pid_t)-1 && !isatty(tty_fd)) {
Packit Service a2489d
      tty_fd=open("/dev/tty",O_RDONLY);
Packit Service a2489d
      if(tty_fd==-1)
Packit Service a2489d
	 return true;
Packit Service a2489d
      pg=tcgetpgrp(tty_fd);
Packit Service a2489d
   }
Packit Service a2489d
   if(pg==(pid_t)-1 || pg==getpgrp())
Packit Service a2489d
      return true;
Packit Service a2489d
   return false;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void random_init()
Packit Service a2489d
{
Packit Service a2489d
   static bool init;
Packit Service a2489d
   if(!init)
Packit Service a2489d
   {
Packit Service a2489d
      srandom(time(NULL)+getpid());
Packit Service a2489d
      init=true;
Packit Service a2489d
   }
Packit Service a2489d
}
Packit Service a2489d
double random01()
Packit Service a2489d
{
Packit Service a2489d
   return random()/2147483648.0;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
#include <sys/utsname.h>
Packit Service a2489d
const char *get_nodename()
Packit Service a2489d
{
Packit Service a2489d
   static struct utsname u;
Packit Service a2489d
   if(uname(&u)==0)
Packit Service a2489d
      return u.nodename;
Packit Service a2489d
   return "NODE";
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *xhuman(long long n)
Packit Service a2489d
{
Packit Service a2489d
   char *buf=xstring::tmp_buf(LONGEST_HUMAN_READABLE + 1);
Packit Service a2489d
   return human_readable(n, buf, human_autoscale|human_SI, 1, 1);
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
const char *xidna_to_ascii(const char *name)
Packit Service a2489d
{
Packit Service a2489d
#if LIBIDN2
Packit Service a2489d
   if(!name)
Packit Service a2489d
      return 0;
Packit Service a2489d
   static xstring_c name_ace_tmp;
Packit Service a2489d
   name_ace_tmp.unset();
Packit Service a2489d
   if(idn2_to_ascii_lz(name,name_ace_tmp.buf_ptr(),0)==IDN2_OK) {
Packit Service a2489d
      xmalloc_register_block((void*)name_ace_tmp.get());
Packit Service a2489d
      return name_ace_tmp;
Packit Service a2489d
   }
Packit Service a2489d
#endif//LIBIDN2
Packit Service a2489d
   return name;
Packit Service a2489d
}
Packit Service a2489d
bool xtld_name_ok(const char *name)
Packit Service a2489d
{
Packit Service a2489d
#if LIBIDN2
Packit Service a2489d
   if(mbswidth(name,MBSW_REJECT_INVALID|MBSW_REJECT_UNPRINTABLE)<=0)
Packit Service a2489d
      return false;
Packit Service a2489d
   if(idn2_lookup_ul(name,NULL,0)==IDN2_OK)
Packit Service a2489d
      return true;
Packit Service a2489d
#endif//LIBIDN2
Packit Service a2489d
   return false;
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
bool is_ipv4_address(const char *s)
Packit Service a2489d
{
Packit Service a2489d
   struct in_addr addr;
Packit Service a2489d
   return inet_pton(AF_INET,s,&addr)>0;
Packit Service a2489d
}
Packit Service a2489d
bool is_ipv6_address(const char *s)
Packit Service a2489d
{
Packit Service a2489d
#if INET6
Packit Service a2489d
   struct in6_addr addr;
Packit Service a2489d
   return inet_pton(AF_INET6,s,&addr)>0;
Packit Service a2489d
#else
Packit Service a2489d
   return false;
Packit Service a2489d
#endif
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
int lftp_fallocate(int fd,off_t sz)
Packit Service a2489d
{
Packit Service a2489d
#if defined(HAVE_FALLOCATE)
Packit Service a2489d
   return fallocate(fd,0,0,sz);
Packit Service a2489d
#elif defined(HAVE_POSIX_FALLOCATE)
Packit Service a2489d
   return posix_fallocate(fd,0,sz);
Packit Service a2489d
#else
Packit Service a2489d
   errno=ENOSYS;
Packit Service a2489d
   return -1;
Packit Service a2489d
#endif
Packit Service a2489d
}
Packit Service a2489d
Packit Service a2489d
void call_dynamic_hook(const char *name) {
Packit Service a2489d
#if defined(HAVE_DLOPEN) && defined(RTLD_DEFAULT)
Packit Service a2489d
   typedef void (*func)();
Packit Service a2489d
   func f=(func)dlsym(RTLD_DEFAULT,name);
Packit Service a2489d
   if(f) f();
Packit Service a2489d
#endif
Packit Service a2489d
}