BSD 4_3_Net_1 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Tue, 31 Mar 1987 22:24:21 +0000 (14:24 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Tue, 31 Mar 1987 22:24:21 +0000 (14:24 -0800)
Work on file xns/examples/remotetool/xnsremote.c

Synthesized-from: CSRG/cd2/net.1

xns/examples/remotetool/xnsremote.c [new file with mode: 0644]

diff --git a/xns/examples/remotetool/xnsremote.c b/xns/examples/remotetool/xnsremote.c
new file mode 100644 (file)
index 0000000..95b4d60
--- /dev/null
@@ -0,0 +1,779 @@
+#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;
+       }
+}
+