Blame src/misc.cc

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