/*%cc -o pull % -ldk
 */
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>

extern int errno;

char SERVER[]="/usr/lib/Rpush";
int server;

#define MAXCHARS 8192
char args[MAXCHARS];

char *bldargs(argv)
	register char *argv[];
{
	register char *s, *t;
	extern char *strcpy();
	s=strcpy(args, SERVER);
	s+=strlen(s);
	*s++=' ';
	while(t= *argv++){	/* assignment = */
		while(*s = *t++)
			if(s++ >= &args[MAXCHARS-1]){
				error("arg list too long", "");
				exit(1);
			}
		*s++=' ';
	}
	s[-1]='\0';
	return(args);
}

char *
basename(s)
	register char *s;
{
	extern char *strrchr();
	register char *t;
	t=strrchr(s, '/');
	return(t? t+1 : s);
}

char *
str(s, n)
	register char *s;
{
	static char strbuf[129];
	(void)strncpy(strbuf, s, n);
	strbuf[n]=0;
	return(strbuf);
}

int errors=0;
int vflag;

main(argc, argv)
	char *argv[];
{
	register n;
	char *targetdir;
	char buf[512];

	if(argc>1 && strcmp(argv[1], "-v")==0){
		vflag=1;
		argv++;
		--argc;
	}
	if(basename(argv[0])[0]=='R'){
		if(argc!=2){
			error("arg count", "");	/* It's ok; other guy will decrypt it */
			exit(1);
		}
		targetdir=argv[1];
	}else{
		if(argc<4){
			error("Usage: pull machine <remotefiles|dirs> localdir", "");
			exit(1);
		}
		targetdir=argv[argc-1];
		server=0;	/* Standard input */
		server=tdkexec(argv[1], bldargs(&argv[1]));
		if(server<0){
			extern char *dkerror;
			fprintf(stderr, "pull: can't execute %s (%s)\n", SERVER,
				dkerror);
			exit(1);
		}
	}
	if(mkdir(targetdir, 0777)==0){
		error("can't make directory", argv[1]);
		exit(1);
	}
	while((n=read(server, buf, sizeof buf))>0){
		switch(buf[0]){
		case 'D':
			if(mkdir(str(buf+4, n-4), o3(buf+1))==0)
				error("can't make directory", str(buf+1, n-1));
			break;
		case 'E':
			error("(remote)", str(buf+1, n-1));
			break;
		case 'F':
			createfile(str(buf+4, n-4), o3(buf+1));
			continue;	/* createfile() will read null message */
		default:
			buf[1]='\0';
			error("unknown message", buf);
			break;
		}
		if(read(server, buf, sizeof buf)!=0){
			error("synchronization error", "");
			do; while(read(server, buf, sizeof buf)>0);
		}
	}
	return(errors);
}

createfile(s, m)
	register char *s;
{
	char buf[1024];
	register f;
	register cc;
	if(server>1 && vflag)
		printf("pull: receive %s\n", s);
	if((f=creat(s, m))<0)
		error("can't create", s);
	else{
		if(read(server, buf, sizeof buf)>0){
			error("synchronization", "error");
			close(f);
			return;
		}
		while((cc=read(server, buf, sizeof buf))>0)
			if(write(f, buf, cc)!=cc){
				error("write error", s);
				if(errno==ENOSPC){
					error("file system is full; aborting", "");
					exit(1);
				}
				close(f);
				return;
			}
		close(f);
	}
}

error(s, t)
	char *s, *t;
{
	char ebuf[128];
	errors=1;
	sprintf(ebuf, "%s%s %s\n", server>0? "pull: " : "" ,s, t);
	write(2, ebuf, strlen(ebuf));
}

mkdir(s, m)
	register char *s;
{
	struct stat statbuf;
	register pid;
	int status;
	if(stat(s, &statbuf)<0){
		if((pid=fork())==0){
			execl("/bin/mkdir", "mkdir", s, 0);
			exit(1);
		}
		(void)wait(&status);
		chmod(s, m);
		return(!status);
	}
	return((statbuf.st_mode&S_IFMT)==S_IFDIR);
}

o3(s)
	register char *s;
{
	return(((s[0]-'0')*0100)+((s[1]-'0')*010)+(s[2]-'0'));
}
