4.4BSD/usr/src/contrib/xns/examples/remotetool/xnsremote.c

Compare this file to the similar file:
Show the results in this format:

#ifndef lint
static char *rcsid = "$Header: xnsremote.c,v 1.3 87/04/01 08:23:53 ed Exp $";
#endif lint

/*
 * Copyright (c) 1986, 1987 Xerox Corporation.
 */

/* $Log:	xnsremote.c,v $
 * Revision 1.3  87/04/01  08:23:53  ed
 * Changed for new MakeSecondaryCreds call.
 * 
 * Revision 1.2  87/03/25  10:55:53  ed
 * Don't reset usefiling in login.
 * 
 * Revision 1.1  87/03/17  16:29:19  ed
 * Initial revision
 * 
 * 
 */

#include <stdio.h>
#include <sys/time.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <netns/ns.h>
#include <netns/sp.h>
#include <xnscourier/FilingSubset1.h>
#include <xnscourier/Filing4.h>
#include <xnscourier/except.h>
#undef __Clearinghouse2			/* Filing4.h defs this */
#include <xnscourier/CH.h>
#include <xnscourier/filetypes.h>

#ifdef PRINTOPTION
#ifndef XNSPRINT
#define XNSPRINT	"/usr/new/xnsprint"
#endif XNSPRINT

#ifndef MAHA
#define MAHA		"/usr/new/maha"
#endif MAHA
#endif PRINTOPTION

#define ROOT_DIRECTORY "/"

CourierConnection *connected;
Clearinghouse3_ObjectName hostobjname;
Authentication3_Verifier verifier;

/* the following 3 items make up the current session */
FilingSubset1_Session session;	/* the current session */
Clearinghouse3_ObjectName username;
FilingSubset1_Handle rootHandle;
char cur_dir[512]= 0;
char cur_pathname[512]= 0;
char cur_name[512]= 0;

static FilingSubset1_ControlSequence nullControls = {0,0};
static FilingSubset1_ScopeSequence nullScope = {0,0};

/* global data used to communicate with BDT procedures
 */
extern GetAttributeSequences(), 
	listproc(), retrieveproc();

char *AttrToString();
Boolean AttrToBoolean();
LongCardinal AttrToLongCardinal();
Cardinal AttrToCardinal();

static (*ProcEachSeq)();
static FILE *fout= stdout;

Boolean files_found= FALSE;
Boolean filing_subset= TRUE;
Boolean usefiling= TRUE;
Boolean verbose= FALSE;

LongCardinal typevalue= 0;
char *service, *pager;
extern int errno;
char thru_options[512];

struct name_entry {
	char *pathname;
	LongCardinal type;
} ;

static struct name_entry *name_list= 0;
static int name_count= 0;
static int name_size= 0;
#define MAX_NAMES	10

main(argc, argv)
int argc;
char *argv[];
{
	char *file, *rightbrkt;
	char oldservice[100];
	char *index(), *getenv();
	int i;
	CourierConnection *hookup();
	int opt;
	extern int optind;
	extern char *optarg;

#ifdef PRINTOPTION
	static char *options= "fvP:";
	static char *usage= "Usage: %s [-f] [-v] [-P printer] file1 ... filen\n";
#else PRINTOPTION
	static char *options= "fvs";
	static char *usage= "Usage: %s [-f] [-v] [-s] file1 ... filen\n";
#endif PRINTOPTION

	if ( argc < 1 ) {
		fprintf(stderr, usage, argv[0]);
		exit(1);
	}

#ifndef PRINTOPTION
	pager= getenv("PAGER");
#endif PRINTOPTION

	strcpy(thru_options, "");

	while ((opt= getopt(argc, argv, options)) != EOF) 
		switch (opt) {
			case 'v':
				verbose++;
				break;

			case 'f':
				usefiling= 0;
				break;

#ifdef PRINTOPTION
			case 'P' :
				strcat(thru_options, " -P ");
				strcat(thru_options, optarg);
				break;
#else PRINTOPTION
			case 's' :
				pager= '\0';	/* override pager */
				break;
#endif PRINTOPTION
			default:
				fprintf(stderr, "Invalid command option -%c\n", opt);
				exit(1);
		}

	for ( ; optind < argc ; optind++ ) {
		if ( getserviceandfile(argv[optind], &service, &file) == 0 ) {
			fprintf(stderr, "Invalid name %s\n", argv[optind]);
			exit(1);
		}
		DURING {
			if ( strcmp(oldservice, service) != 0 ) {
				if ( (connected= hookup(service)) == (CourierConnection *)0 ) {
					fprintf(stderr, "\nCan't connect to %s\n", service);
					continue;
				}
				login(0,0);
				strcpy(oldservice, service);
			}

			getfile(file);

		} HANDLER {
			FilingErrMsg(Exception.Code, Exception.Message);
#ifndef PRINTOPTION
			if ( fout != stdout )
				pclose(fout);
#endif PRINTOPTION
		} END_HANDLER;

	}

	return(0);
}

getserviceandfile(name, srvcptr, fileptr)
char *name;
char **srvcptr, **fileptr;
{
	char *sptr, *fptr;
	char *index(), *rindex();

	/*
	 * look for Xerox forms first:
	 *	[host]filename
	 */

	if ( (sptr= index(name, '[')) != 0 ) {
		if ( (fptr= index(sptr, ']')) != 0 ) {
			*fptr= '\0';
			*srvcptr= sptr + 1;
			*fileptr= fptr + 1;
			return(1);
		} else
			return(0);
	}

	/*
	 *	(host)filename
	 */

	if ( (sptr= index(name, '(')) != 0 ) {
		if ( (fptr= index(sptr, ')')) != 0 ) {
			*fptr= '\0';
			*srvcptr= sptr + 1;
			*fileptr= fptr + 1;
			return(1);
		} else
			return(0);
	}

	/*
	 * look for XNS style with trailing : delimiter
	 * (assumes no : in file name, use alternate spec instead)
	 *	object:domain:organization:filename
	 *		domain & organization are optional
	 */

	if ( (fptr= rindex(name, ':')) != 0 ) {
		*fptr= '\0';
		*srvcptr= name;
		*fileptr= fptr + 1;
		return(1);
	} else
		return(0);
}

copyhandle(dest,src)
	FilingSubset1_Handle dest,src;
{
	if (dest == (Unspecified *) 0) {
		fprintf(stderr,"Oops.  dest is null in copyhandle\n");
		exit(1);
	}
	dest[0] = src[0];
	dest[1] = src[1];
}

getfilehandle(filename, handle)
	char *filename;
	FilingSubset1_Handle handle;
{
	FilingSubset1_Attribute pathattr[1];
	FilingSubset1_AttributeSequence attrseq;
	FilingSubset1_OpenResults openresult;
	Filing4_OpenResults openresult2;

	if (filename == (char *)0 || *filename == '\000' || (strcmp(filename, "/") == 0) ) {
		if ( filing_subset )
			copyhandle(handle,FilingSubset1_nullHandle);
		else
			copyhandle(handle,rootHandle);
		return;
	}

	attrseq.length = 1;
	attrseq.sequence = pathattr;
	pathattr[0].type = FilingSubset1_pathname;
	copyhandle(handle, FilingSubset1_nullHandle);
#ifdef XEROXFSCOMPATIBILITY
	if ( filename[0] == '/')
		StringToAttr(filename+1, &pathattr[0]);
	else
		StringToAttr(filename, &pathattr[0]);
#else XEROXFSCOMPATIBILITY
	StringToAttr(filename, &pathattr[0]);
#endif XEROXFSCOMPATIBILITY
	alarm(0);
	if ( filing_subset ) {
		openresult = FilingSubset1_Open(connected, NULL, attrseq,
					  handle, nullControls,
					  session);
		copyhandle(handle, openresult.file);
	} else {
		openresult2 = Filing4_Open(connected, NULL, attrseq,
					  handle, nullControls,
					  session);
		copyhandle(handle, openresult2.file);
	} 
}

getdirhandle(filename, handle)
	char *filename;
	FilingSubset1_Handle handle;
{
	FilingSubset1_Attribute pathattr[1];
	FilingSubset1_AttributeSequence attrseq;
	FilingSubset1_OpenResults openresult;
	Filing4_OpenResults openresult2;
	char *rindex();
	char *slash;

	if (filename == (char *)0 || *filename == '\000' || (strcmp(filename, "/") == 0) ) {
		strcpy(cur_pathname, "/");
		strcpy(cur_name, "/");
		if ( filing_subset )
			copyhandle(handle,FilingSubset1_nullHandle);
		else
			copyhandle(handle,rootHandle);
		return;
	} else if ( filename[0] == '/' ) {
		strcpy(cur_pathname, filename);
	} else {
		strcpy(cur_pathname, cur_dir);
		if ( strcmp(cur_pathname, "/") != 0 )
			strcat(cur_pathname, "/");
		strcat(cur_pathname, filename); 
	}

	if ( (slash= rindex(cur_pathname,'/')) == NULL )
		strcpy(cur_name, cur_pathname);
	else
		strcpy(cur_name, slash+1);

	if ( filing_subset ) {
		copyhandle(handle, FilingSubset1_nullHandle);
	} else {
		if ( slash == cur_pathname) {
			copyhandle(handle, rootHandle);
			return;
		}

		attrseq.length = 1;
		attrseq.sequence = pathattr;
		pathattr[0].type = FilingSubset1_pathname;
		copyhandle(handle, FilingSubset1_nullHandle);
		*slash= '\0';		/* separate pathname from name */
#ifdef XEROXFSCOMPATIBILITY
		if ( cur_pathname[0] == '/' )
			StringToAttr(cur_pathname+1, &pathattr[0]);
		else
			StringToAttr(cur_pathname, &pathattr[0]);
#else XEROXFSCOMPATIBILITY
		StringToAttr(cur_pathname, &pathattr[0]);
#endif XEROXFSCOMPATIBILITY
		*slash= '/';		/* and put back */
		alarm(0);
		if ( filing_subset ) {
			openresult = FilingSubset1_Open(connected, NULL, attrseq,
						  handle, nullControls,
						  session);
			copyhandle(handle, openresult.file);
		} else {
			openresult2 = Filing4_Open(connected, NULL, attrseq,
						  handle, nullControls,
						  session);
			copyhandle(handle, openresult2.file);
		}
	}
}

freefilehandle(handle)
	FilingSubset1_Handle handle;
{
	if (handle[0] == FilingSubset1_nullHandle[0] &&
	    handle[1] == FilingSubset1_nullHandle[1])
		return;		/* don't free nullHandle */
	if (handle[0] == rootHandle[0] &&
	    handle[1] == rootHandle[1])
		return;		/* don't free root directory */
	alarm(0);
	if ( filing_subset )
		FilingSubset1_Close(connected, NULL, handle, session);
	else
		Filing4_Close(connected, NULL, handle, session);
}

CourierConnection *
hookup(name)
	char *name;
{
	register struct ns_addr *hostaddr;
	extern struct ns_addr *getXNSaddr();
	Clearinghouse3_ObjectName defaultobjname;
	static char hnamebuf[128];
	CourierConnection *cconn;

	CH_NameDefault(&defaultobjname);
	hostobjname = CH_StringToName(name, &defaultobjname);
	if ((hostaddr = CH_LookupAddrDN( hostobjname, 0, hnamebuf, 128))) {
		/* should check here to be sure host is a file service */
		hostaddr->x_port = htons(5); /* ?? */
		cconn = CourierOpen(hostaddr);
		/* reset objname to flush wildcards */
		/* clear_Clearinghouse3_ThreePartName(&hostobjname); */
		hostobjname = CH_StringToName(hnamebuf, &defaultobjname);
	}
	return(cconn);
}


login(name,pwd)
	char *pwd;
	char *name;
{
	FilingSubset1_Credentials credentials;
	FilingSubset1_LogonResults logonresult;
	FilingSubset1_LogonResults *resultptr= &logonresult;
	Filing4_LogonResults logonresult2;
	FilingSubset1_AttributeSequence attrseq;
	FilingSubset1_OpenResults openresult;
	Filing4_OpenResults openresult2;


	if ( name != 0 )
		username = CH_StringToName(name,&hostobjname);

	if ( usefiling ) {
		filing_subset= FALSE;
		if ( name == 0 && pwd == 0 ) {
			GetSimpleCredsAndVerifier(&username, 0, 
							&credentials.primary, &verifier);
		} else {
			MakeSimpleCredsAndVerifier(&username,pwd,
						&credentials.primary, &verifier);
		}
		logonresult2= Filing4_Logon(connected, NULL, hostobjname,
						credentials.primary, verifier);
		resultptr= (FilingSubset1_LogonResults *) &logonresult2;
		
	} else {
		if ( name == 0 && pwd == 0 ) {
			GetSimpleCredsAndVerifier(&username, 0, &credentials.primary, &verifier);
			MakeSecondaryCreds(hostobjname.object, 0, 0, &credentials.secondary);
		} else {
			MakeSimpleCredsAndVerifier(0, pwd, &credentials.primary, &verifier);
			MakeSecondaryCreds(hostobjname.object, name, pwd, &credentials.secondary);
		}
		filing_subset= TRUE;
		DURING 
			logonresult = FilingSubset1_Logon(connected, NULL, hostobjname,
					    credentials, verifier);
		HANDLER {
			switch (Exception.Code) {
			case REJECT_ERROR:
				filing_subset= FALSE;
				logonresult2= Filing4_Logon(connected, NULL, hostobjname,
							credentials.primary, verifier);
				resultptr= (FilingSubset1_LogonResults *) &logonresult2;
				break;
			default:
				RERAISE;
			}
		} END_HANDLER;
	}

	if ( filing_subset )
		session = resultptr->session;
	else
		session = resultptr->session;

	attrseq.length= 0;
	attrseq.sequence= 0;
	if ( filing_subset ) {
		openresult= FilingSubset1_Open(connected, NULL, attrseq,
					 FilingSubset1_nullHandle, nullControls,
					 session);
		copyhandle(rootHandle, openresult.file);
	} else {
		openresult2= Filing4_Open(connected, NULL, attrseq,
					 FilingSubset1_nullHandle, nullControls,
					 session);
		copyhandle(rootHandle, openresult2.file);
	}
	strcpy(cur_dir, ROOT_DIRECTORY);
}

logout()
{
	if ( filing_subset )
		FilingSubset1_Logoff(connected, NULL, session);
	else
		Filing4_Logoff(connected, NULL, session);
	clear_FilingSubset1_Session(&session);
}


getfile(remote)
	char *remote;
{
	FILE *popen();
	FilingSubset1_Handle remotehandle; /* note: an array */
	FilingSubset1_Handle dirhandle; /* note: an array */
	FilingSubset1_AttributeTypeSequence typeseq;
	FilingSubset1_AttributeType tsvals[10];
	FilingSubset1_ScopeSequence scopeseq;
	FilingSubset1_Scope scope;
	char pcmd[500];
	int i;
	register struct name_entry *entry;

	name_count= 0;
	name_size= MAX_NAMES;
	if ( (name_list= (struct name_entry *) malloc(sizeof(struct name_entry) * name_size)) == 0 ) {
		perror("getfile: ");
		return;
	}

	typeseq.length = 0;  typeseq.sequence = tsvals;
	scopeseq.length= 1; scopeseq.sequence= &scope;
	scope.designator= FilingSubset1_filter;
	scope.FilingSubset1_filter_case.designator= FilingSubset1_matches;
	if ( filing_subset )
		scope.FilingSubset1_filter_case.FilingSubset1_matches_case.attribute.type= FilingSubset1_pathname;
	else
		scope.FilingSubset1_filter_case.FilingSubset1_matches_case.attribute.type= FilingSubset1_name;

	copyhandle(remotehandle, FilingSubset1_nullHandle);
	getdirhandle(remote, dirhandle);

	if ( filing_subset )
		StringToAttr(cur_pathname,&scope.FilingSubset1_filter_case.FilingSubset1_matches_case.attribute);
	else
		StringToAttr(cur_name,&scope.FilingSubset1_filter_case.FilingSubset1_matches_case.attribute);

	typeseq.length = 2;
	typeseq.sequence[0] = FilingSubset1_pathname;
	typeseq.sequence[1] = FilingSubset1_type;

	ProcEachSeq = listproc;
	if ( filing_subset )
		FilingSubset1_List(connected, GetAttributeSequences, dirhandle,
			     typeseq, scopeseq,
			     BulkData1_immediateSink, session);
	else
		Filing4_List(connected, GetAttributeSequences, dirhandle,
			     typeseq, scopeseq,
			     BulkData1_immediateSink, session);


	if ( !files_found ) {
		fprintf(stderr, "\n(%s)%s not found\n", service, remote);
	} else {
		for ( i= 0 ; i < name_count ; i++ ) {
			entry= &name_list[i];
#ifdef PRINTOPTION
			if ( (entry->type != FilingSubset1_tText) && (entry->type != TYPE_VPMailNote) &&
					(entry->type != TYPE_Interpress) ) {
				fprintf(stderr, "\n\n\n\nInvalid file type (%d)\n\n\n\n", entry->type);
				clear_String(&entry->pathname);
				continue;
			}

			if ( entry->type == TYPE_Interpress ) {
				sprintf(pcmd, "%s -q -b \"(%s)%s\"%s -", XNSPRINT, service, entry->pathname, thru_options);
			} else {
				sprintf(pcmd, "%s -b \"(%s)%s\"%s", MAHA, service, entry->pathname, thru_options);
			}

			if ( (fout= popen(pcmd, "w")) == NULL ) {
				perror("popen: ");
				exit(1);
			}

			if (verbose) {
			 	fprintf(stderr, "\n\printing (%s)%s...\n\n",service,entry->pathname);
			}
#else PRINTOPTION
			if ( entry->type != FilingSubset1_tText ) {
				fprintf(stderr, "\n\n\nCan only view text files.\n\n\n");
				clear_String(&entry->pathname);
				continue;
			}

			if ( pager == NULL || *pager == '\0' ) {
				fout= stdout;
			} else {
				sprintf(pcmd, "%s%s", pager, thru_options);
				if ( (fout= popen(pcmd, "w")) == NULL )
					fout= stdout;
			}

			if (verbose) {
			 	fprintf(stderr, "\n\n\n\nretrieving (%s)%s...\n\n\n\n",service,entry->pathname);
			}
#endif PRINTOPTION

			typevalue= entry->type;

			getfilehandle(entry->pathname, remotehandle);	/* get file handle */
			if ( filing_subset ) {
				FilingSubset1_Retrieve(connected, retrieveproc, remotehandle,
						 BulkData1_immediateSink, session);
			} else {
				Filing4_Retrieve(connected, retrieveproc, remotehandle,
						 BulkData1_immediateSink, session);
			}

			freefilehandle(remotehandle);
#ifdef PRINTOPTION
			pclose(fout);
#else PRINTOPTION
			if ( fout != stdout )
				pclose(fout);
#endif PRINTOPTION

			clear_String(&entry->pathname);
		}
	} 

	free(name_list);
	freefilehandle(dirhandle);

}

listproc(attr)
	FilingSubset1_AttributeSequence attr;
{
	int i;
	FilingSubset1_AttributeType t;
	struct name_entry *entry;

	files_found= TRUE;

/*
 *	Xerox file servers will return all versions of the requested file in
 *	ascending version order. We assume that the last version will be the
 *	highest and remember that name so that the retrieve will pull the
 *	highest version of the file. If we request just the file with no
 *	version, the server will return the oldest version (not what I would
 *	expect...)
 */

	if ( name_count > name_size ) {
		name_size += MAX_NAMES;
		name_list= (struct name_entry *) realloc(name_list,
				sizeof(struct name_entry) * name_size);
	}

	entry= &name_list[name_count];
	for (i = 0; i < attr.length; i++) {
		t = attr.sequence[i].type;
		if (t == FilingSubset1_name || t == FilingSubset1_pathname) {
			entry->pathname = AttrToString(&attr.sequence[i]);
		} else if (t == FilingSubset1_type) {
			entry->type = AttrToLongCardinal(&attr.sequence[i]);
		}
	}
	name_count++;
}


#define MAXPACKS 20
static
GetAttributeSequences(conn)
	CourierConnection *conn;
{
	int count, i;
	Unspecified buffer[MAXWORDS*MAXPACKS], *bp, *bufend;
	FilingSubset1_StreamOfAttributeSequence attrs;
	
	files_found= FALSE;

	bufend = buffer;
	bp = buffer+((MAXWORDS-1)*MAXPACKS);    /* end of available space */
	while ((count = BDTread(conn, (char*)bufend, 
				MAXWORDS*sizeof(Unspecified))) > 0) {
		bufend += count/sizeof(Unspecified);
		if (bufend > bp) {
			fprintf(stderr,"BDT read too big to fit\n");
			BDTabort(conn);
			/* should clear out stuff here if we knew how much */
		}
	}
	bp = buffer;
	while (bp < bufend) {
		bp += internalize_FilingSubset1_StreamOfAttributeSequence(&attrs,bp);
		if (0 == (int) attrs.designator) {
		   for (i=0; i < attrs.nextSegment_case.segment.length; i++) {
			(*ProcEachSeq)(
				attrs.nextSegment_case.segment.sequence[i]);
		   }
		   free(attrs.nextSegment_case.segment.sequence);
		} else {
		   for (i = 0; i < attrs.lastSegment_case.length; i++) {
			(*ProcEachSeq)(
				attrs.lastSegment_case.sequence[i]);
		   }
		   free(attrs.lastSegment_case.sequence);
		   return;
		}
	}
}

int
getBDTch(conn,bpp)
	CourierConnection *conn;
	u_char **bpp;
{
	static u_char buffer[SPPMAXDATA];
	static int count;

	if (*bpp == NULL) {*bpp = buffer; count = 0;}
	if (*bpp >= buffer+count) {
		count=BDTread(conn,buffer,sizeof(buffer));
		*bpp = buffer;
	}
	if (count <= 0) return(EOF);
	else return(*((*bpp)++));
		
}

retrieveproc(conn)
	CourierConnection *conn;
{
	int count, ocount, ch;
	char buffer[SPPMAXDATA];
	int charset, charset16;
	char *bp;

	errno = ocount = 0;
	fflush(fout);

	switch (typevalue) {
	default :
		fprintf(stderr, "Unsupported file type\n");
		BDTabort(conn);
		break;

	case TYPE_Interpress :
		while ((count = BDTread(conn, buffer, sizeof(buffer))) > 0) {
			if ((ocount = write (fileno(fout), buffer, count)) < 0) {
				perror("write");
				BDTabort(conn);
				break;
			}
		}
		if (count < 0) perror("netin");
		break;

	case TYPE_VPMailNote :
	case TYPE_A :
		charset = 0; charset16 = 0; bp = NULL;
		while ((ch = getBDTch(conn,&bp)) != EOF) {
			if (ch == '\377') {
				ch = getBDTch(conn,&bp);
				if (ch == '\377') charset16 = 1;
				else charset = ch;
				continue;
			}
			if (charset16) {
				charset = ch;
				ch = getBDTch(conn,&bp);
			}
			switch (charset) {
			case 0:	/* normal character set -- minimal xlation */
				if (ch == '\r') {
				    	int nextch;

				    	putc('\n',fout);
				    	if ( (nextch = getBDTch(conn,&bp)) != '\n'){
					    if (nextch == '\r')
						putc('\n',fout);
					    else if ( nextch != EOF )
				    		putc(nextch,fout);
					    else
						continue;
					}
					break;
				}
				else if (ch == ','+0200) ch = '_';
				/* more mapping here */
				putc(ch,fout);
				break;
			default:
				break; /* ignore */
			}
		}
		/* if (count < 0) perror("netin"); */
		break;
	}
}