/* * File: fetchfile.c * * Author: Ulli Horlacher (framstag@rus.uni-stuttgart.de) * * Contrib.: Michael Neumayer (eumel@42.org) * * History: * * 1997-09-28 Framstag initial version * 1997-10-03 Framstag added -r autoreceive option * 1997-10-05 Framstag better pgp error handling * 1997-10-24 Framstag added check for pgp key files * 1997-12-11 Eumel fixed pgp my_ID problem * 1997-12-19 Framstag default key length is now 1024 bit * 1998-01-03 Framstag config options id and server merged to o-saft * 1998-03-11 Framstag new default user configuration directory * 2001-02-04 Framstag added secure mktmpdir() * * The fetchfile client of the sendfile package. * Lists or gets files from a SAFT server to put them into the local spool. * * Copyright © 1997,1998 Ulli Horlacher * This file is covered by the GNU General Public License */ #include "config.h" /* autoconf header */ #include #include #include #include #include #include #include #include #include #include #include #include #include "string.h" /* extended string functions */ #include "net.h" /* the network routines */ #include "io.h" /* (socket) read/write */ #include "message.h" /* information, warning and error messages */ #include "spool.h" /* operations on files in the sendfile spool */ #include "utf7.h" /* UTF-7 coding */ #include "address.h" /* address checking */ #include "getline.h" /* get a line of text from stdin */ #if defined(HAVE_GETOPT_H) #include #else int getopt(int, char * const *, const char *); extern int opterr; extern int optind; extern int optopt; extern char *optarg; #endif #if defined(SOLARIS2) int gethostname(char *, int); #endif #if defined(LINUX) int gethostname(char *, size_t); int symlink(const char *, const char *); #endif #ifndef AIX #ifndef CONVEXOS FILE *popen(const char *, const char *); #endif int pclose(FILE *); #endif #ifdef NEXT int shutdown(int, int); #endif #if defined(AIX3) || defined(ULTRIX) #include "bsd.h" #endif /* print short help usage text */ int usage(); /* get file list from server */ int get_list(int, const char *, const char *, FILE *); /* get file from server */ int get_file(int, int, int); /* delete a file from the server */ int delete_file(int, int); /* clean termination routine */ void cleanexit(); /* delete tmp-file */ void cleanup(); /* delete tmp-file */ void init(); /* test local sendfiled */ int sendfiled_test(const char *); /* exit wit receive evaluation */ void rexit(int); /* global variables */ int verbose=0, /* flag for verbose mode */ client=1, /* flag to determine client or server */ quiet=0, /* quiet mode */ ignore=0, /* ignore testing flag */ packet_size=0; /* packet size */ char *prg, /* name of the game */ *tmpdir, /* directory for temporary files */ swd[MAXLEN], /* start working directory */ rfilen[MAXLEN], /* receive files for -R option */ userspool[MAXLEN], /* user spool directory */ userconfig[MAXLEN],/* user configuration directory */ listfile[MAXLEN], /* file with list command output */ pgp_bin[MAXLEN], /* the pgp binary */ pgptmp[MAXLEN]; /* name of pgp temporary file */ struct passwd *pwe; /* password entry */ struct senderlist *sls; /* sender list start */ int main(int argc, char *argv[]) { int i, /* simple loop counter */ n, /* number of files on the server */ pid, /* current proccess id */ sockfd, /* socket file descriptor */ opt, /* option to test for */ number, /* file number */ wconf, /* flag for writing config file (0=reading) */ del, /* flag for deleting previous sent files */ all, /* flag for specifying all files */ numbers, /* flag for specifying file numbers */ ptso, /* flag for "pipe to standard output" */ keep, /* flag for keeping files on server */ list; /* flag for listing files in outgoing spool */ char *cp, /* simple string pointer */ *argp, /* argument string pointer */ *user, /* sending user pattern */ id[FLEN], /* user identication for SAFT server */ server[FLEN], /* SAFT server */ alternate[MAXLEN], /* alternate user and/or SAFT server */ cmd[MAXLEN], /* cmd string for system-call */ line[MAXLEN], /* one line of text */ from[MAXLEN], /* sender address */ fname[MAXLEN], /* file name */ conffile[MAXLEN], /* config file name */ response[MAXLEN], /* signed response to authorization challenge */ tmp[3*MAXLEN]; /* temporary string */ FILE *pp, /* pipe */ *listf, /* list command output file */ *inf, /* input file */ *outf; /* output file */ struct stat finfo; /* information about a file */ n=0; del=0; all=0; ptso=0; list=0; keep=0; sockfd=0; verbose=0; numbers=0; *id=0; *server=0; *rfilen=0; *conffile=0; *response=0; *alternate=0; user="*"; listf=NULL; pid=(int)getpid(); getcwd(MAXS(swd)); prg=argv[0]; if ((cp=strrchr(prg,'/'))) prg=cp+1; /* protect all tmp-files */ umask(~(S_IRUSR|S_IWUSR)); /* support programs defaults */ strcpy(pgp_bin,PGP); /* look for environment variables */ if ((cp=getenv("SF_PGP"))) strcpy(pgp_bin,cp); /* do the support programs really exist? */ if (access(pgp_bin,X_OK)<0) strcpy(pgp_bin,"pgp"); /* get the own user name and tmpdir */ if ((pwe=getpwuid(getuid())) == NULL) message(prg,'F',"cannot access user system informations"); tmpdir=mktmpdir(verbose); /* set various file names and check user spool and configuration directory */ snprintf(MAXS(pgptmp),"%s/fetchfile.pgp",tmpdir); snprintf(MAXS(userspool),SPOOL"/%s",pwe->pw_name); if (stat(userspool,&finfo)<0) sendfiled_test(pwe->pw_name); snprintf(MAXS(userconfig),"%s/.sendfile",pwe->pw_dir); snprintf(MAXS(tmp),"%s/config",userspool); if (stat(userconfig,&finfo)<0 && stat(userspool,&finfo)==0) symlink(tmp,userconfig); snprintf(MAXS(tmp),"%s/.sfspool",pwe->pw_dir); if (stat(tmp,&finfo)==0 && finfo.st_mode&S_IFDIR) strcpy(userspool,tmp); /* scan the command line on options */ while ((opt=getopt(argc, argv, "vVqQ?hrPIliadkns:f:C:")) > 0) { switch (opt) { case ':': case 'h': case '?': exit(usage()); case 'r': strcpy(rfilen,"receive -n "); break; case 's': strcpy(alternate,optarg); break; case 'C': strcpy(conffile,optarg); break; case 'f': user=optarg; break; case 'd': del=1; break; case 'k': keep=1; break; case 'P': ptso=1; break; case 'i': ignore=1; break; case 'n': numbers=1; break; case 'a': all=1; break; case 'l': list=1; break; case 'q': quiet=1; break; case 'Q': quiet=2; break; case 'v': verbose=1; break; case 'V': message(prg,'I',"version "VERSION" revision "REVISION); exit(0); case 'I': init(); exit(0); } } /* too few arguments? */ if (argc-optind<1 && !all && !list && !*conffile) exit(usage()); /* incompatible options? */ if (*conffile && (del || keep || all || list || numbers)) { errno=0; message(prg,'F',"you cannot mix -C with any other option"); } if (del && keep) { errno=0; message(prg,'F',"you cannot delete and keep a file at the same time"); } if (ptso && *rfilen) { errno=0; message(prg,'F',"you cannot auto-receive and pipe to stdout (-R and -n options)"); } if (list && (del || keep || all || *rfilen || ptso)) { errno=0; message(prg,'F',"you cannot not specify any other option with -l"); } if (all && argc>optind) { errno=0; message(prg,'F',"you cannot specify file names or numbers " "together with -a option"); } /* alternate user or server specified? */ if (*alternate) { if (str_beq_nocase(alternate,"saft://")) saft2rfc822(alternate); if ((cp=strchr(alternate,'@'))) { *cp=0; strcpy(id,alternate); strcpy(server,cp+1); } else { strcpy(server,alternate); } } /* check tmp files */ unlink(pgptmp); if (stat(pgptmp,&finfo)==0) { snprintf(MAXS(tmp), "tmp-file %s does already exist and cannot be deleted",pgptmp); message(prg,'F',tmp); } /* parse the global config-file */ if ((inf=rfopen(CONFIG,"r"))) { while (fgetl(line,inf)) { /* prepare line to be parsed */ if ((cp=strchr(line,'#'))) *cp=0; if ((cp=strchr(line,'='))) *cp=' '; str_tolower(str_trim(line)); /* is there an option and an argument? */ if ((argp=strchr(line,' '))) { *argp=0; argp++; if (str_eq(line,"packet")) { packet_size=atoi(argp); continue; } } } fclose(inf); } /* check pgp key files */ snprintf(MAXS(tmp),"%s/private.pgp",userconfig); if (stat(tmp,&finfo)<0) { snprintf(MAXS(line),"no access to %s (try 'fetchfile -I' first)",tmp); message(prg,'F',line); } snprintf(MAXS(tmp),"%s/public.pgp",userconfig); if (stat(tmp,&finfo)<0) { snprintf(MAXS(line),"no access to %s (try 'fetchfile -I' first)",tmp); message(prg,'F',line); } /* parse the user config-file */ snprintf(MAXS(tmp),"%s/config",userconfig); if ((inf=rfopen(tmp,"r"))) { while (fgetl(line,inf)) { /* prepare line to be parsed */ if ((cp=strchr(line,'#'))) *cp=0; if ((cp=strchr(line,'='))) *cp=' '; str_tolower(str_trim(line)); /* is there an option and an argument? */ if ((argp=strchr(line,' '))) { *argp=0; argp++; if (str_eq(line,"id") && !*id) { /* depreciated */ strcpy(id,argp); continue; } if (str_eq(line,"server") && !*server) { /* depreciated */ strcpy(server,argp); continue; } if (str_eq(line,"o-saft") && !*server) { if (str_beq_nocase(argp,"saft://")) saft2rfc822(argp); if ((cp=strchr(argp,'@'))) { *cp=0; strcpy(id,argp); strcpy(server,cp+1); } else { strcpy(id,pwe->pw_name); strcpy(server,argp); } } } } fclose(inf); } if (!*id) strcpy(id,pwe->pw_name); if (!*server) strcpy(server,"localhost"); snprintf(MAXS(listfile),"%s/%s@%s:fetch.lis",userspool,id,server); /* initiate the connection to the server */ if (!*server) { errno=0; message(prg,'F',"no SAFT server is defined"); } snprintf(MAXS(tmp),"connecting to SAFT server %s",server); if (quiet<2) message(prg,'I',tmp); sockfd=open_connection(server,SAFT); if (sockfd==-1) snprintf(MAXS(tmp),"cannot create a network socket"); if (sockfd==-2) snprintf(MAXS(tmp),"cannot open connection to %s",server); if (sockfd==-3) snprintf(MAXS(tmp),"%s is unknown",server); if (sockfd<0) { errno=0; message(prg,'F',tmp); } /* no remote server or protocol error? */ sock_getline(sockfd,line); if (!str_beq(line,"220 ") || !strstr(line,"SAFT")) { errno=0; snprintf(MAXS(tmp),"No SAFT server on port %d at %s",SAFT,server); message(prg,'F',tmp); } /* send ID */ snprintf(MAXS(tmp),"ID %s",id); sock_putline(sockfd,tmp); sock_getline(sockfd,line); if (str_beq(line,"520")) { errno=0; snprintf(MAXS(tmp),"user %s is unknown on SAFT-server %s",id,server); message(prg,'F',tmp); } if (!str_beq(line,"331")) { errno=0; snprintf(MAXS(tmp),"server error: %s",line+4); message(prg,'F',tmp); } str_trim(line); cp=strrchr(line,' '); if (!cp) { errno=0; message(prg,'F',"bad answer from server"); } outf=rfopen(pgptmp,"w"); if (!outf) { errno=0; snprintf(MAXS(tmp),"cannot open/write to %s",pgptmp); message(prg,'F',tmp); } fprintf(outf,"%s",cp+1); fclose(outf); /* goto user spool directory */ if (chdir(userspool)<0) { snprintf(MAXS(tmp),"cannot change to %s",userspool); message(prg,'F',tmp); } /* call pgp */ /* DONT REMOVE 2>/dev/null IN THE FOLLOWING LINE! */ snprintf(MAXS(cmd),"cd %s; PGPPATH='.' %s -sbaf " "+secring=private.pgp +pubring=public.pgp <%s 2>/dev/null", userconfig,pgp_bin,pgptmp); if (verbose) printf("call: %s\n",cmd); if (!(pp=popen(cmd,"r"))) message(prg,'F',"call to pgp failed"); while (fgetl(line,pp) && strlen(response)+strlen(line)+3 < sizeof(response)) { if ((cp=strchr(line,'\n'))) *cp=0; strcat(response,line); strcat(response,"\r\n"); } pclose(pp); /* wrong pgp output? */ if (!strstr(response,"BEGIN PGP MESSAGE")) { errno=0; message(prg,'E',"corrupt pgp reply:"); cp=strrchr(cmd,'2'); *cp=0; system(cmd); message(prg,'F',"corrupt pgp reply"); } iso2utf(tmp,response); snprintf(MAXS(response),"AUTH %s",tmp); sendheader(sockfd,response); /* config file transfer? */ if (*conffile) { if (*conffile=='w') wconf=1; else wconf=0; /* extract real file name */ if (!(cp=strchr(conffile+1,'='))) cp=conffile; strcpy(tmp,cp+1); if (*tmp == '/') strcpy(conffile,tmp); else snprintf(MAXS(conffile),"%s/%s",swd,tmp); /* write config file */ if (wconf) { if ((cp=strrchr(conffile,'/'))) cp++; else cp=conffile; snprintf(MAXS(tmp),"CONF WRITE %s",cp); sock_putline(sockfd,tmp); sock_getline(sockfd,line); if (!str_beq(line,"302 ") && !str_beq(line,"200 ")) { errno=0; snprintf(MAXS(tmp),"server error: %s",line+4); message(prg,'F',tmp); } inf=rfopen(conffile,"r"); if (!inf) { snprintf(MAXS(tmp),"cannot open %s",conffile); message(prg,'F',tmp); } if (quiet<2) { snprintf(MAXS(tmp),"transfering %s",conffile); message(prg,'I',tmp); } /* send the file */ while (fgetl(line,inf)) { if ((cp=strchr(line,'\n'))) *cp=0; sock_putline(sockfd,line); } sock_putline(sockfd,"\004"); /* End Of Transmission */ fclose(inf); sock_getline(sockfd,line); if (!str_beq(line,"201 ")) { errno=0; snprintf(MAXS(tmp),"server error: %s",line+4); message(prg,'F',tmp); } } else { /* read config file */ if ((cp=strrchr(conffile,'/'))) cp++; else cp=conffile; snprintf(MAXS(tmp),"CONF READ %s",cp); sock_putline(sockfd,tmp); while (sock_getline(sockfd,line)) { if (!str_beq(line,"250")) { errno=0; snprintf(MAXS(tmp),"server error: %s",line+4); message(prg,'F',tmp); } if (str_beq("250 ",line)) break; utf2iso(0,NULL,tmp,NULL,line+4); printf("%s\n",tmp); } } sock_putline(sockfd,"QUIT"); getreply(sockfd); close(sockfd); cleanup(); exit(0); } /* enable simple interrupt handler */ signal(SIGTERM,cleanexit); signal(SIGABRT,cleanexit); signal(SIGQUIT,cleanexit); signal(SIGHUP,cleanexit); signal(SIGINT,cleanexit); /* list files in outgoing spool */ if (list) { n=get_list(sockfd,server,id,listf); sock_putline(sockfd,"QUIT"); getreply(sockfd); close(sockfd); cleanup(); exit(n); } /* set tcp packet length */ if (packet_size<1) packet_size=PACKET; /* scan local spool */ sls=scanspool(""); if (numbers) { for (i=optind; i0) { /* change back to starting directory */ if (chdir(swd)<0) { snprintf(MAXS(tmp),"cannot change back to %s",swd); message(prg,'E',tmp); } else if (verbose) printf("shell-call: %s\n",rfilen); /* call receive */ system(rfilen); } exit(n); } /* * delete_file - delete a file from the server * * INPUT: sockfd - socket file descriptor * number - spool file number * * RETURN: 0 on success, -1 on error */ int delete_file(int sockfd, int number) { char line[MAXLEN]; /* one line of text */ /* send LIST command */ snprintf(MAXS(line),"DEL %d",number); sock_putline(sockfd,line); sock_getline(sockfd,line); if (str_beq(line,"200 ")) return(0); else return(-1); } /* * get_list - get list of files from server * * INPUT: sockfd - socket file descriptor * server - server name * id - user name * listf - list command output file * * RETURN: number of files, -1 on error */ int get_list(int sockfd, const char *server, const char *id, FILE *listf) { int i, /* simple loop counter */ n, /* number of files */ number; /* file number */ unsigned long size; /* file size */ char *cp, /* simple string pointer */ tmp[MAXLEN], /* temporary string */ line[MAXLEN], /* one line of text */ from[MAXLEN]; /* address and name of sender */ char *flist[6]; /* file list elements */ n=0; *from=0; /* send LIST command */ sock_putline(sockfd,"LIST"); for (;;) { /* get one line of answer from server */ sock_getline(sockfd,line); str_trim(line); /* invalid answer? */ if (!str_beq(line,"250")) { errno=0; snprintf(MAXS(tmp),"invalid answer from server: %s",line+4); message(prg,'E',tmp); return(n); } /* last answer line? */ if (str_beq(line,"250 ")) { if (!listf) printf("\n"); return(n); } /* write only to list file? */ if (listf) { fprintf(listf,"%s\n",line+4); continue; } /* print server ID on top */ if (!*from) { sprintf(tmp,"Files on SAFT-server %s for user %s:",server,id); printf("\n%s\n",tmp); for (i=1; i<80 && i<=strlen(tmp); i++) printf("="); printf("\n"); } /* split file list */ cp=line+4; str_trim(cp); for(i=1;i<6;i++) { flist[i]=cp; if ((cp=strchr(cp,' '))) { *cp=0; cp++; } } /* new from? */ if (!str_eq(from,flist[3])) { strcpy(from,flist[3]); utf2iso(0,NULL,tmp,NULL,from); printf("\nFrom %s\n",tmp); for (i=1; i<80 && i<=strlen(tmp)+5; i++) printf("-"); printf("\n"); } /* build and print list line */ if ((cp=strrchr(flist[5],':')) > strchr(flist[5],':')) *cp=0; number=atoi(flist[1]); size=atol(flist[4]); size=(size+1023)/1024; sprintf(tmp,"%3d) %s %8lu kB %s",number,flist[5],size,flist[2]); utf2iso(1,NULL,line,NULL,tmp); printf("%s\n",line); n++; } } /* * get_file - get a file from the server * * INPUT: sockfd - socket file descriptor * number - file number * ptso - flag for "pipe to standard output" * * RETURN: 0 if ok, -1 on error */ int get_file(int sockfd, int number, int ptso) { int percent, /* what percentage of file has been transmitted */ chunk, /* number of bytes in one read chunk */ shfd, /* spool header file descriptor */ sdfd, /* spool data file descriptor */ id; /* local spool id */ unsigned long msec, /* milliseconds */ size, /* total file size */ rsize, /* rest file size */ offset, /* bytes that have been already transfered */ bytes; /* bytes to receive */ char *cp, /* simple string pointer */ date[DLEN], /* date string */ shfile[FLEN], /* spool header file */ sdfile[FLEN], /* spool data file */ packet[OVERSIZE], /* one line of text */ line[MAXLEN], /* one line of text */ from[MAXLEN], /* sender name (address) */ fname[MAXLEN], /* file name */ tmp[MAXLEN]; /* temporary string */ time_t sec1,sec2; /* unix time */ float thruput; /* net throughput */ struct filelist * flp; /* file list pointer */ struct senderlist *slp; /* sender list pointer */ struct timeval tv1,tv2; #if !defined(SOLARIS2) && !defined(IRIX) struct timezone tz; #endif id=0; shfd=0; sdfd=0; size=0; offset=0; *date=0; flp=NULL; /* get time normal */ #if defined(SOLARIS2) || defined(IRIX) #ifdef _SVID_GETTOD gettimeofday(&tv1); #else gettimeofday(&tv1,NULL); #endif #else gettimeofday(&tv1,&tz); #endif sec1=0; /* get next spool id */ if (!ptso) { id=spoolid(999999); if (!id) message(prg,'F',"cannot create local spool file"); /* open spool header and data files */ snprintf(MAXS(shfile),"%d.h",id); snprintf(MAXS(sdfile),"%d.d",id); sdfd=open(sdfile,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); shfd=open(shfile,O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR); if (shfd<0 || sdfd<0) message(prg,'F',"cannot create local spool file"); } snprintf(MAXS(tmp),"GET HEADER %d",number); sock_putline(sockfd,tmp); for (;;) { /* get one line of answer from server */ sock_getline(sockfd,line); str_trim(line); /* invalid answer? */ if (!str_beq(line,"250")) { if (!ptso) { close(sdfd); close(shfd); unlink(sdfile); unlink(shfile); } errno=0; snprintf(MAXS(tmp),"server-error: %s",line+4); message(prg,'E',tmp); return(-1); } /* last answer line? */ if (str_beq(line,"250 ")) break; /* make SAFT commands uppercase */ if ((cp=strchr(line+4,' '))) { *cp=0; str_toupper(line+4); *cp='\t'; } /* store attributes */ if (str_beq(line+4,"FILE")) strcpy(fname,line+9); if (str_beq(line+4,"SIZE")) size=atol(line+9); if (str_beq(line+4,"DATE")) utf2iso(1,date,NULL,NULL,line+9); if (str_beq(line+4,"FROM")) { if ((cp=strchr(line+10,' '))) { *cp=0; snprintf(MAXS(tmp),"%s (%s)",line+9,cp+1); *cp=' '; } else strcpy(tmp,line+9); utf2iso(1,from,NULL,NULL,tmp); } strcat(line,"\n"); if (ptso) printf("%s",line+4); else write(shfd,line+4,strlen(line+4)); } close(shfd); /* check if file has been already fetched and how much of it */ if (!ignore) { /* loop over sender list */ for (slp=sls, offset=0; slp!=NULL; slp=slp->next) { /* same sender? */ if (str_eq(slp->from,from)) { /* loop over files list */ for (flp=slp->flist; flp!=NULL; flp=flp->next) { /* same file? */ if (str_eq(flp->fname,fname) && flp->csize==size && (*date==0 || str_eq(flp->date,date))) { offset=flp->tsize; break; } } } /* leave loop if found */ if (offset) break; } } utf2iso(1,NULL,tmp,NULL,fname); strcpy(fname,tmp); if (quiet<2) { if (flp && flp->csize==offset) { snprintf(MAXS(tmp),"file %d (%s) has been already fetched",number,fname); message(prg,'I',tmp); } else { if (quiet==1) { if (offset) snprintf(MAXS(tmp),"resuming fetching file %d (%s) with %ld kB", number,fname,(size+1023)/1024); else snprintf(MAXS(tmp),"fetching file %d (%s) with %ld kB", number,fname,(size+1023)/1024); message(prg,'I',tmp); } } } if (flp && flp->csize==offset) { close(sdfd); unlink(sdfile); unlink(shfile); return(0); } snprintf(MAXS(tmp),"GET FILE %d %ld",number,offset); sock_putline(sockfd,tmp); sock_getline(sockfd,line); /* invalid answer? */ if (!str_beq(line,"231 ")) { if (!ptso) { close(sdfd); unlink(sdfile); unlink(shfile); } errno=0; snprintf(MAXS(tmp),"server-error: %s",line+4); message(prg,'E',tmp); return(-1); } if (ptso) printf("DATA\n"); fflush(stdout); rsize=atol(line+4); /* resend active? */ if (offset && quiet<2) { snprintf(MAXS(tmp),"resuming at byte %ld",offset); message("",'I',tmp); } bytes=0; while (bytessec1) { fprintf(stderr,"%s: %3d%% (%ld of %ld kB)\r", fname,percent,(bytes+offset-1)/1024+1,(size-1)/1024+1); fflush(stderr); sec1=sec2; } } write(sdfd,packet,chunk); } } if (!ptso) close(sdfd); /* note spool number for auto-receive */ if (*rfilen) { sprintf(tmp," %d",id); strcat(rfilen,tmp); } if (quiet<2) { /* get time difference */ #if defined(SOLARIS2) || defined(IRIX) #ifdef _SVID_GETTOD gettimeofday(&tv2); #else gettimeofday(&tv2,NULL); #endif #else gettimeofday(&tv2,&tz); #endif msec=(tv2.tv_usec-tv1.tv_usec)/1000+(tv2.tv_sec-tv1.tv_sec)*1000; if (msec<1) msec=1; thruput=bytes*1000.0/msec; /* print transfer statistics */ if (quiet==1) { if (thruput>9999) snprintf(MAXS(tmp), "transfer of %s completed: %.1f kB/s",fname,thruput/1024); else snprintf(MAXS(tmp), "transfer of %s completed: %d byte/s",fname,(int)thruput); message("",'I',tmp); } else { if (bytes>9999) fprintf(stderr,"%s: 100%% (%ld kB, ",fname,bytes/1024); else fprintf(stderr,"%s: 100%% (%ld byte, ",fname,bytes); if (thruput>9999) fprintf(stderr,"%.1f kB/s) \n",thruput/1024); else fprintf(stderr,"%d byte/s) \n",(int)thruput); fflush(stderr); } } return(0); } /* * reply - dummy function, only needed for linking */ void reply(int x) { } /* * init - initialize spool and pgp for fetchfile */ void init() { char answer[FLEN], /* answer string */ server[FLEN], /* SAFT server */ configf[MAXLEN], /* config file */ tmp[MAXLEN]; /* temporary string */ struct stat finfo; /* information about a file */ FILE *outf; /* file to create */ *server=0; sprintf(configf,"%s/config",userconfig); umask(~S_IRWXU); printf("\nThis is the init routine for %s.\n",prg); printf("It will create the necessary pgp files and the spool directory.\n"); printf("You can press Ctrl-C at any time to stop this procedure.\n\n"); snprintf(MAXS(userspool),SPOOL"/%s",pwe->pw_name); if (stat(userspool,&finfo)<0 || !(finfo.st_mode&S_IFDIR)) { printf("User spool %s does not exist.\n",userspool); snprintf(MAXS(userspool),"%s/.sfspool",pwe->pw_dir); printf("May I create local spool %s? ",userspool); fgetl(answer,stdin); if (*answer!='y' && *answer!='Y') { errno=0; message(prg,'F',"cannot continue with answer 'no'."); } unlink(userspool); if (mkdir(userspool,S_IRWXU)<0) { sprintf(tmp,"cannot create directory %s",userspool); message(prg,'F',tmp); } } if (stat(userconfig,&finfo)<0) { if (mkdir(userconfig,S_IRWXU)<0) { sprintf(tmp,"cannot create config directory %s",userconfig); message(prg,'F',tmp); } } if (chdir(userconfig)<0) { sprintf(tmp,"cannot change to directory %s",userconfig); message(prg,'F',tmp); } if (!(outf=rfopen(configf,"a"))) { snprintf(MAXS(tmp),"cannot open %s",configf); message(prg,'F',tmp); } printf("What is the address of your SAFT server where you want to " "poll your files?\n"); while (getpromptline(MAXS(server))==NULL || *server=='\n' || *server==0) printf("Illegal address! Please repeat: "); fprintf(outf,"\n# The address of your default SAFT-server for fetchfile\n"); fprintf(outf,"server = %s\n",server); fclose(outf); if (stat("public.pgp",&finfo)==0 || stat("private.pgp",&finfo)==0) { printf("There are already pgp files in your config directory %s\n",userconfig); printf("Overwrite them? "); fgetl(answer,stdin); if (*answer!='y' && *answer!='Y') { errno=0; message(prg,'F',"cannot continue with answer 'no'."); } } printf("\npgp will now be started to create a new sendfile-only key pair.\n"); printf("When asked, you can enter your normal e-mail address.\n\n"); printf("YOU MUST ENTER AN EMPTY PASS PHRASE, "); printf("OR FETCHFILE WILL NOT WORK!\n\n"); if (system("PGPPATH='.' " " pgp -kg +pubring=public.pgp +secring=private.pgp 1024")) message(prg,'F',"pgp call failed"); printf("\nYou should now send %s/public.pgp to\n",userconfig); printf("root@%s, because this file has to be stored in your\n",server); printf("sendfile spool on %s\n",server); printf("For example you can type:\n"); printf("sendfile -c 'this is my SAFT/fetchfile public key' \\\n"); printf(" %s/public.pgp root@%s\n\n",userconfig,server); printf("If you want to change your default SAFT server, then edit\n%s\n\n", configf); exit(0); } /* * sendfiled_test - test local sendfiled * * INPUT: user - user name * * RETURN: 0 if ok, -1 if failed */ int sendfiled_test(const char *user) { int sockfd; /* socket file descriptor */ char line[MAXLEN]; /* one line of text */ /* test the local sendfiled */ if (verbose) printf("testing local SAFT server:\n"); sockfd=open_connection("127.0.0.1",SAFT); sock_getline(sockfd,line); /* no local server? */ if (!str_beq(line,"220 ") || !strstr(line,"SAFT")) return(-1); /* test if you can receive messages */ snprintf(MAXS(line),"FROM %s",user); sock_putline(sockfd,line); sock_getline(sockfd,line); if (!str_beq(line,"200 ")) return(-1); snprintf(MAXS(line),"TO %s",user); sock_putline(sockfd,line); sock_getline(sockfd,line); if (!str_beq(line,"200 ")) return(-1); sock_putline(sockfd,"FILE test"); sock_getline(sockfd,line); if (!str_beq(line,"200 ")) return(-1); sock_putline(sockfd,"QUIT"); sock_getline(sockfd,line); close(sockfd); return(0); } /* * usage - print short help usage text */ int usage() { fprintf(stderr,"\n"); fprintf(stderr,"usage: %s [OPTIONS]\n",prg); fprintf(stderr," or: %s [OPTIONS] file [...]\n",prg); fprintf(stderr," or: %s [OPTIONS] -n file-number [...]\n",prg); fprintf(stderr,"options: -l only list files\n"); fprintf(stderr," -a fetch all files\n"); fprintf(stderr," -k keep file on SAFT-server after receiving\n"); fprintf(stderr," -d delete file on SAFT-server without receiving\n"); fprintf(stderr," -n fetch file number instead of file name\n"); fprintf(stderr," -P pipe file directly to stdout\n"); fprintf(stderr," -r call receive automatically\n"); fprintf(stderr," -i ignore testing if file has already been fetched\n"); fprintf(stderr," -q quiet mode 1: no information messages\n"); fprintf(stderr," -Q quiet mode 2: no information or transfer messages\n"); fprintf(stderr," -v verbose output\n"); fprintf(stderr," -V show version information\n"); fprintf(stderr," -I initalize fetchfile (pgp and spool)\n"); fprintf(stderr," -f user fetch only files from this user\n"); fprintf(stderr," -s [user@]server specify alternate SAFT-server and user name\n"); fprintf(stderr," -Cw=conffile send config file to server\n"); fprintf(stderr," -Cr=conffile read config file from server\n"); fprintf(stderr," (conffile is \"config\" or \"restrictions\", see: man sendfile)\n"); fprintf(stderr,"examples: %s -l\n",prg); fprintf(stderr," %s -a\n",prg); fprintf(stderr," %s hoppel.gif\n\n",prg); return(2); }