home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / UNIX / ARCHIE / CLIENTS / C_ARCHI0.COM < prev    next >
Encoding:
Text File  |  1991-11-20  |  217.3 KB  |  8,194 lines

  1. $ write sys$output "Unpacking..."
  2. $ if f$search("archie.dir") .eqs. "" then create/dir [.ARCHIE]
  3. $ if f$search("[.ARCHIE]vms.dir") .eqs. "" then create/dir [.ARCHIE.VMS]
  4. $ set noverify
  5. $! This is a DCL shar-type archive created by Unix dclshar.
  6. $!
  7. $CREATE [.archie]INSTALL
  8. $DECK
  9. [Last changed: 11/20/91 v1.2]
  10.  
  11.  This is the minimal set of things you need to build an Archie client
  12. that takes advantage of the Prospero system.  It is derived from the
  13. 4.2beta version of Prospero, currently available as the file prospero.tar.Z
  14. on the host cs.washington.edu.
  15.  
  16.  * To make the client under Unix:
  17.  
  18.     - edit the Makefile, changing CC, OPTIONS, LDFLAGS, and RM if
  19.       necessary (odds are you won't have to do this..see below)
  20.     - edit the DEFINEs as necessary
  21.     - if you're in Finland, Australia, the UK, or Canada, please edit
  22.       archie.h and change ARCHIE_HOST appropriately (the US is set).
  23.     - type `make'
  24.  
  25.  I've tried to make this as portable as possible.  I'd encourage you
  26. to try doing a "make" without any changes to the Makefile, and see how
  27. it goes.  If it pukes, and you have to define something, please drop
  28. me a line---my goal is for anybody to just type "make" and not have to
  29. worry about things like what functions their system supports.
  30.  
  31.  * To make the client under VMS, you should edit MAKE.COM and select
  32. the appropriate define for your version of TCP/IP (currently either
  33. Multinet or Wallongong).  It will sense if you're using Gnu C or not.
  34. It's currently only been ported to VMS 5.4-2 -- I can't guarantee
  35. it'll work with older versions.
  36.  
  37.  * To make the client under MSDOS or OS/2, presently the only PC
  38. TCP/IP package archie has been modified for is FTP Software's PC/TCP
  39. for MSDOS (version 2.1 or higher) and OS/2 (version 1.1 and higher).
  40.  
  41.  It's been successfully built on:
  42.  
  43.   Machine            OS
  44.  
  45. * Apollo            Domain/OS 10.3
  46. * Apple Mac IIsomething        A/UX v2.01
  47. * CDC Mips systems, all sorts    EP/IX 1.2.3 and 1.3.1
  48. * Convex c210 & others        ConvexOS 9.0
  49. * DecStations -- all sorts    Ultrix 4.1 and 4.2
  50. * Encore Multimax 520 (XPC)    Encore UMAX 4.3
  51. * Encore Multimax 520        Encore Mach 1.1alpha
  52. * Harris HCX-9 (tahoe)        CX/UX 5.1
  53. * HP 9000/s300            MORE/bsd-4.3
  54. * HP 9000/s834            HP/UX 7.0
  55. * IBM PC            MSDOS and OS/2
  56. * IBM RS/6000            AIX
  57. * IBM RT            4.3BSD, and AIX
  58. * NeXT                NeXT OS 2.1
  59. * Sequent Symmetry        Dynix 3.1.1
  60. * SGI 4D/220GTX            SGI Irix 3.3.2
  61. * Solbourne Series 5/600    OS/MP 4.0Da
  62. * Stardent 3030            SysV Rel 3.0.1
  63. * Suns -- all sorts        SunOS 4.0.3, 4.1, and 4.1.1
  64. * Vax 8600            MORE/bsd-4.3
  65. * Vax 6000/310            VMS 5.4/Wallongong 5.1
  66. * MicroVax 3400            VMS 5.4-2/Multinet 2.2 and Multinet 3.0
  67.  
  68. -- Brendan Kehoe (brendan@cs.widener.edu)
  69. $EOD
  70. $!
  71. $CREATE [.archie]Makefile
  72. $DECK
  73. #
  74. # Last changed: 11/20/91, v1.2
  75. #
  76. # Makefile for the minimal build for an archie Prospero client.
  77.  
  78. # Your C compiler:
  79. CC=cc
  80.  
  81. # For most systems, these OPTIONS will suffice.  Exceptions:
  82. #
  83. #    * If you're on a Stardent, add -43
  84. #    * If you're running EP/IX, you may need to add -systype bsd43 ..try
  85. #      it without it first, though.
  86.  
  87. OPTIONS= -O -I. # -43    -systype bsd43
  88.  
  89. # For this, DEFINES is usually ok as-is.  Try it without any of these
  90. # first; if some stuff fails or shows up undefined, then come back and
  91. # add 'em.
  92. #
  93. #     * if you're on an Apple running A/UX, add              -DAUX
  94. #     * if you're using a BULL system (Bull DPX/2), add       -DBULL
  95. #     * if you want to include the debugging code (so you
  96. #       can help with problem-solving if any crop up), add    -DDEBUG
  97. #     * if you're running System V, add                  -DSYSV
  98. #     * if you're running a USG (System V.2) system, add      -DUSG
  99. #     * if you're running UTS, add                  -DUTS
  100. #     * if your system doesn't have the functions index(),
  101. #       rindex(), bcopy(), or bzero(), add                    -DFUNCS
  102. #     * if your system doesn't have the re_comp/regcmp or re_exec/regex
  103. #       routines (no regex(3)/regcmp(3X) library), then add   -DNOREGEX
  104. #     * if your system is lacking strspn(), add               -DSTRSPN
  105. DEFINES= -DDEBUG
  106.  
  107. #    Usually LDFLAGS is empty; if, after you build this, archie
  108. #     complains that it can't resolve ARCHIE.SURA.NET, you need
  109. #     to add `-lresolv'.
  110. #    * If you need the PW library (e.g. A/UX), add -lPW
  111. LDFLAGS= # -lresolv        -lPW
  112.  
  113. # Change this if necessary.
  114. RM=/bin/rm
  115.  
  116. # =========================
  117. # Yer' done....make archie.
  118. # =========================
  119. #
  120. CFLAGS=$(OPTIONS) $(DEFINES)
  121. #
  122. OBJS=    aquery.o archie.o atalloc.o dirsend.o get_pauth.o get_vdir.o \
  123.     perrmesg.o procquery.o ptalloc.o regex.o stcopy.o support.o \
  124.     vlalloc.o vl_comp.o
  125. #
  126. all: archie
  127.  
  128. archie: $(OBJS)
  129.     $(CC) $(CFLAGS) -o $@ $(OBJS) $(LDFLAGS)
  130.  
  131. $(OBJS): archie.h pmachine.h pcompat.h Makefile
  132.  
  133. procquery.o: copyright.h
  134.  
  135. clean:
  136.     $(RM) -f *.o archie
  137.  
  138. gclean: clean
  139.     $(RM) -f *~ archie.0* archie.com archie.tar* gmon.out archie.doc
  140.  
  141. unx-deadly:
  142.     unifdef -UXARCHIE xprocquery.c > procquery.c
  143.  
  144. udp: udp.o
  145.     $(CC) -o $@ udp.o
  146.  
  147. udptest: udp
  148.     @echo "This should print the date, if UDP's enabled, or hang if not:"
  149.     @./udp
  150.  
  151. FILES=    INSTALL Makefile Prospero README archie.c archie.h archie.lnk \
  152.     archie.doc archie.man aquery.c atalloc.c dirsend.c get_pauth.c \
  153.     get_vdir.c make.com makefile.dos makefile.os2 perrmesg.c \
  154.     patchlevel.h pauthent.h pcompat.h perrno.h pfs.h pmachine.h pprot.h \
  155.     procquery.c ptalloc.c rdgram.h regex.c regex.h stcopy.c support.c \
  156.     copyright.h udp.c vl_comp.c vlalloc.c vms.h vms_support.c vms/fd.h \
  157.     vms/in.h vms/pseudos.h vms/signal.h vms/socket.h vms/time.h \
  158.     vms/types.h vms/network.h vms/multi.opt vms/wall.opt
  159.  
  160. BFILES= $(FILES) xprocquery.c
  161.  
  162. dist: tar shar dcl
  163.  
  164. shar: archie.doc
  165.     makekit -narchie. $(FILES) vms > Manifest
  166.  
  167. archie.doc: archie.man
  168.     nroff -man archie.man | tr '\010' _ | sed -e s/__//g > archie.doc
  169.  
  170. dcl: archie.doc
  171.     echo '$$ write sys$$output "Unpacking..."' > archie.com
  172.     echo '$$ if f$$search("archie.dir") .eqs. "" then create/dir [.ARCHIE]' >> archie.com
  173.     echo '$$ if f$$search("[.ARCHIE]vms.dir") .eqs. "" then create/dir [.ARCHIE.VMS]' >> archie.com
  174.     echo '$$ set noverify' >> archie.com
  175.     (cd .. ; dclshar `echo $(FILES) | tr ' ' '\012' |\
  176.      sed -e "s/^/archie\//g"` >> archie/archie.com )
  177.     echo '$$ write sys$$output "Ok, now enter the ARCHIE directory and type @MAKE ."' >> archie.com
  178.  
  179. tar: archie.doc
  180.     ( cd .. ; tar cvf archie/archie.tar `echo $(FILES) |\
  181.      tr ' ' '\012' | sed -e "s/^/archie\//g"` )
  182.     compress -f archie.tar
  183.  
  184. atest: archie.doc
  185.     ( cd .. ; tar cvf archie/atest.tar `echo $(BFILES) |\
  186.      tr ' ' '\012' | sed -e "s/^/archie\//g"` )
  187.     compress -f atest.tar
  188. $EOD
  189. $!
  190. $CREATE [.archie]Prospero
  191. $DECK
  192. Prospero also allows users to access Archie as if it were part of a
  193. file system.  Here is an example of how Prospero can be used to access
  194. Archie in this manner.
  195.  
  196.   Script started on Mon Jul  1 22:36:42 1991
  197.   % source /home/ftp/archie/pfs/bin/vfsetup.source
  198.   % vfsetup guest
  199.   % venable
  200.   % cd /archive-sites/archie/regex
  201.   % cd prospero (This command specifies the query)
  202.   % ls -l
  203.   total 0
  204.   -r--r--r--   0 -               0 -            info-prospero.arc
  205.   dr-xr-xr-x   0 -               0 -            prospero
  206.   dr-xr-xr-x   0 -               0 -            prospero-papers
  207.   -r--r--r--   0 -               0 -            prospero.arc
  208.   -r--r--r--   0 -               0 -            prospero.tar.Z
  209.   (Note that the "vls" command could have been used)
  210.   (to show where the files were actually stored    )
  211.   % ls prospero (list a result if it is a directory)
  212.   prog.tar.Z      prospero.tar.Z
  213.   % cat info-prospero.arc  (The file is automatically retrieved and displayed)
  214.   >From bcn@n1dmm  Tue Dec  4 02:33:36 1990
  215.   Received: from n1dmm.cs.washington.edu by june.cs.washington.edu (5.64/7.0jh)
  216.           id AA24763; Tue, 4 Dec 90 02:33:36 -0800
  217.   Received: by n1dmm.cs.washington.edu (5.64/7.0h)
  218.           id AA08497; Tue, 4 Dec 90 02:33:31 -0800
  219.   Date: Tue, 4 Dec 90 02:33:31 -0800
  220.   From: bcn@cs.washington.edu (Clifford Neuman)
  221.   ...
  222.   % vdisable
  223.   % exit
  224.   script done on Mon Jul  1 22:39:33 1991
  225. $EOD
  226. $!
  227. $CREATE [.archie]README
  228. $DECK
  229. [Last changed 11/20/91 v1.2]
  230.  
  231.  Enclosed you'll find a Prospero client for the archie service.  It'll
  232. let you query the archie databases without actually using an
  233. interactive process on the remote server's machine (e.g. archie.sura.net),
  234. resulting in a MUCH better response time.  It also helps lessen the
  235. load on the archie server itself.
  236.  
  237.  This is a third child of Clifford Neuman's Prospero project.  It's really
  238. the Archie client that's included in the prospero stuff, but I've taken out
  239. everything that's unnecessary for this client to work.  (Aka, you don't
  240. have to build all of Prospero to get the Archie client.)  Khun Yee Fung
  241. wrote an archie client in Perl, and George Ferguson has written a client
  242. for use with XWindows, based in part upon this code.  A curses version is
  243. currently being developed to mimic the X client's look and feel.
  244.  
  245.  Using the Archie Prospero interface in its true form will probably be of
  246. interest---check out the file `Prospero' for an example of its interface.
  247. If you find it intriguing, you should probably get the full prospero kit
  248. from the University of Washington on cs.washington.edu in pub/prospero.tar.Z.
  249.  
  250.  Suffice to say, there are now a number of ways to query Archie without
  251. bogging a server down with your logins.
  252.  
  253.  Check out the man page (or archie.doc, if you're using VMS or DOS)
  254. for instructions on how to use this archie client.
  255.  
  256.  Please check to make sure you don't have "archie" aliased or modified
  257. in some way to do a telnet or rlogin (which you may've done before
  258. this command-line ability came into being).
  259.  
  260.  If Archie consistently hangs (at different times of day with
  261. different queries), it's possible that your site has UDP traffic on
  262. ports > 1000 blocked, for security reasons.  Type `make udptest' to
  263. check---if it prints out the date, the Archie server is probably down;
  264. if it doesn't print out the date, either Widener's computer is down
  265. (God forbid ;-) ) or you do indeed have UDP blocked.  See your system
  266. administrator in this case.  If the problem persists and haven't the
  267. vaguest, then write me describing the situation and what machine/OS
  268. you're using.
  269.  
  270.  Write to archie-l@cs.mcgill.ca with questions about Archie itself.
  271.  Write to info-prospero@isi.edu about the Prospero protocol.
  272.  Write to brendan@cs.widener.edu with questions about this specific package.
  273. $EOD
  274. $!
  275. $CREATE [.archie]archie.c
  276. $DECK
  277. /*
  278.  * Copyright (c) 1991 by the University of Washington
  279.  *
  280.  * For copying and distribution information, please see the file
  281.  * <copyright.h>.
  282.  *
  283.  * v1.2.0 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  284.  * v1.1.2 - 08/27/91 (bpk) - added <pmachine.h> for index()
  285.  * v1.1.1 - 08/22/91 (bpk) - added 0-9 as arguments
  286.  */
  287.  
  288. #include <copyright.h>
  289.  
  290. /*
  291.  * Archie client using the Prospero protocol.
  292.  *
  293.  * Suggestions and improvements to Brendan Kehoe (brendan@cs.widener.edu).
  294.  */
  295.  
  296. #include <stdio.h>
  297. #if defined(OS2)
  298. # include <pctcp.h>
  299. #endif
  300. #if defined(MSDOS)
  301. # include <string.h>
  302. # include <stdlib.h>
  303. #endif
  304.  
  305. #include <pfs.h>
  306. #include <rdgram.h>
  307. #include <archie.h>
  308. #include <pmachine.h>
  309.  
  310. int        listflag = 0;
  311. int        sortflag = 0;   /* 1 = by date                    */
  312. char        *progname;
  313. #ifdef DEBUG
  314. int        pfs_debug = 0;
  315. #endif
  316. extern int    rdgram_priority;
  317.  
  318. main(argc,argv)
  319.     int        argc;
  320.     char    *argv[];
  321.     {
  322.     char        *cur_arg;
  323.     char        qtype = '=';    /* Default to exact string match  */
  324.     char        etype = '=';    /* Type if only -e is specified   */
  325.     int        eflag = 0;    /* Exact flag specified          */
  326.     int        max_hits = MAX_HITS;
  327.     int        offset = 0;
  328.     int        exitflag = 0;    /* Display release identifier     */
  329.     int        tmp;
  330.     char        *host = ARCHIE_HOST;
  331.     static char *archies[] = { ARCHIES };
  332.  
  333.     progname = *argv;
  334.     argc--; argv++;
  335.  
  336.     while (argc > 0 && **argv == '-') {
  337.         cur_arg = argv[0]+1;
  338.  
  339.         /* If a - by itself, or --, then no more arguments */
  340.         if(!*cur_arg || ((*cur_arg == '-') && (!*(cur_arg+1)))) {
  341.             argc--, argv++;
  342.         goto scandone;
  343.         }
  344.  
  345.         while (*cur_arg) {
  346.         switch (*cur_arg++) {
  347. #ifdef DEBUG        
  348.         case 'D':  /* Debug level */
  349.             pfs_debug = 1; /* Default debug level */
  350.             if(*cur_arg && index("0123456789",*cur_arg)) {
  351.             sscanf(cur_arg,"%d",&pfs_debug);
  352.             cur_arg += strspn(cur_arg,"0123456789");
  353.             }
  354.             else if(argc > 2) {
  355.                 tmp = sscanf(argv[1],"%d",&pfs_debug);
  356.             if (tmp == 1) {argc--;argv++;}
  357.             }
  358.             break;
  359. #endif
  360. #ifndef XARCHIE
  361.         case 'L':
  362.             printf("Known archie servers:\n");
  363.             for (tmp = 0; tmp < NARCHIES; tmp++)
  364.             printf("\t%s\n", archies[tmp]);
  365.             printf("For the most up-to-date list, log into an Archie server & type `servers'.\n");
  366.             exitflag = 1;
  367.             break;
  368. #endif
  369.  
  370.         case 'N':  /* Priority (nice) */
  371.             rdgram_priority = RDGRAM_MAX_PRI; /* Use this if no # */
  372.             if(*cur_arg && index("-0123456789",*cur_arg)) {
  373.             sscanf(cur_arg,"%d",&rdgram_priority);
  374.             cur_arg += strspn(cur_arg,"-0123456789");
  375.             }
  376.             else if(argc > 2) {
  377.                 tmp = sscanf(argv[1],"%d",&rdgram_priority);
  378.             if (tmp == 1) {argc--;argv++;}
  379.             }
  380.             if(rdgram_priority > RDGRAM_MAX_SPRI) 
  381.             rdgram_priority = RDGRAM_MAX_PRI;
  382.             if(rdgram_priority < RDGRAM_MIN_PRI) 
  383.             rdgram_priority = RDGRAM_MIN_PRI;
  384.               break;
  385.  
  386.         case 'c':  /* substring (case sensitive) */
  387.             qtype = 'C';
  388.             etype = 'c';
  389.             break;
  390.  
  391.         case 'e':  /* Exact match */
  392.             /* If -e specified by itself, then we use the  */
  393.             /* default value of etype which must be '='    */
  394.             eflag++;
  395.             break;
  396.  
  397.         case 'h':  /* Host */
  398.             host = argv[1];
  399.             argc--; argv++;
  400.             break;
  401.  
  402.         case 'l':  /* List one match per line */
  403.             listflag++;
  404.             break;
  405.  
  406.         case '0': case '1': case '2': case '3': case '4':
  407.         case '5': case '6': case '7': case '8': case '9':
  408.             cur_arg--;
  409.         case 'm':  /* Max hits */
  410.             max_hits = -1;  
  411.             if(*cur_arg && index("0123456789",*cur_arg)) {
  412.             sscanf(cur_arg,"%d",&max_hits);
  413.             cur_arg += strspn(cur_arg,"0123456789");
  414.             }
  415.             else if(argc > 1) {
  416.                 tmp = sscanf(argv[1],"%d",&max_hits);
  417.             if (tmp == 1) {argc--;argv++;}
  418.             }
  419.             if (max_hits < 1) {
  420.             fprintf(stderr, "%s: -m option requires a value for max hits (>= 1)\n",
  421.                 progname);
  422. #ifdef VMS
  423.             exit(SS$_NORMAL); /* we already did the error above */
  424. #else
  425.             exit(1);
  426. #endif
  427.             }
  428.             break;
  429.  
  430.         case 'o':  /* Offset */
  431.             if(argc > 1) {
  432.               tmp = sscanf(argv[1],"%d",&offset);
  433.               if (tmp != 1)
  434.             argc = -1;
  435.               else {
  436.             argc--; argv++;
  437.               }
  438.             }
  439.             break;
  440.  
  441.         case 'r':  /* Regular expression search */
  442.             qtype = 'R';
  443.             etype = 'r';
  444.             break;
  445.  
  446.         case 's':  /* substring (case insensitive) */
  447.             qtype = 'S';
  448.             etype = 's';
  449.             break;
  450.  
  451.         case 't':  /* Sort inverted by date */
  452.             sortflag = 1;
  453.             break;
  454.  
  455.         case 'v':  /* Display version */
  456.             fprintf(stderr,
  457.             "Client version %s based upon Prospero version %s\n",
  458.                 CLIENT_VERSION, PFS_RELEASE);
  459.             exitflag++;
  460.             break;
  461.  
  462.         default:
  463.             fprintf(stderr,"Usage: %s [-[cers][l][t][m #][h host][L][N#]] string\n", progname);
  464. #ifdef VMS
  465.             exit(SS$_NORMAL); /* we already did the error above */
  466. #else
  467.             exit(1);
  468. #endif
  469.         }
  470.         }
  471.         argc--; argv++;
  472.     }
  473.  
  474.       scandone:
  475.  
  476.     if (eflag) qtype = etype;
  477.  
  478.     if ((argc != 1) && exitflag) exit(0);
  479.  
  480.     if (argc != 1) {
  481.         fprintf(stderr, "Usage: %s [-[cers][l][t][m #][h host][L][N#]] string\n", progname);
  482.         fprintf(stderr,"       -c : case sensitive substring search\n");
  483.         fprintf(stderr,"       -e : exact string match (default)\n");
  484.         fprintf(stderr,"       -r : regular expression search\n");
  485.         fprintf(stderr,"       -s : case insensitive substring search\n");
  486.         fprintf(stderr,"       -l : list one match per line\n");
  487.         fprintf(stderr,"       -t : sort inverted by date\n");
  488.         fprintf(stderr,"     -m # : specifies maximum number of hits to return (default %d)\n", max_hits);
  489.         fprintf(stderr,"  -h host : specifies server host\n");
  490.         fprintf(stderr,"       -L : list known servers\n");
  491.         fprintf(stderr,"      -N# : specifies query niceness level (0-35765)\n");
  492. #ifdef VMS
  493.         exit(SS$_NORMAL); /* we already did the error above */
  494. #else
  495.         exit(1);
  496. #endif
  497.     }
  498.  
  499.     procquery(host, argv[0], max_hits, offset, qtype, sortflag, listflag);
  500.  
  501.     exit(0);
  502.     }
  503. $EOD
  504. $!
  505. $CREATE [.archie]archie.h
  506. $DECK
  507. /*
  508.  * archie.h : Definitions for the programmatic Prospero interface to Archie
  509.  *
  510.  *     Written by Brendan Kehoe (brendan@cs.widener.edu), 
  511.  *                George Ferguson (ferguson@cs.rochester.edu), and
  512.  *                Clifford Neuman (bcn@isi.edu).
  513.  */
  514.  
  515. /*
  516.  * Archie server (one of):   archie.sura.net
  517.  *                 archie.mcgill.ca
  518.  *                           archie.funet.fi
  519.  *                           archie.au
  520.  *                 archie.doc.ic.ac.uk
  521.  */
  522. #define ARCHIE_HOST "ARCHIE.SURA.NET"
  523.  
  524. /* You don't wanna touch this.  */
  525. #ifndef XARCHIE
  526. # define ARCHIES    "archie.sura.net (USA, Mexico, etc)","archie.mcgill.ca (Canada)","archie.funet.fi (Finland/Mainland Europe)","archie.au (Australia/New Zealand)","archie.doc.ic.ac.uk (Great Britain/Ireland)"
  527. # define NARCHIES    5
  528. #endif
  529.  
  530. /*
  531.  * Default value for max hits.  Note that this is normally different
  532.  * for different client implementations.  Doing so makes it easier to
  533.  * collect statistics on the use of the various clients.
  534.  */
  535. #ifdef VMS
  536. # define    MAX_HITS    98    /* VMS Client */
  537. #else
  538. # ifdef XARCHIE
  539. #  define    MAX_HITS    99    /* X Client */
  540. # else
  541. #  define    MAX_HITS    95    /* Normal client */
  542. # endif
  543. #endif
  544.  
  545. /*
  546.  * CLIENT_VERSION may be used to identify the version of the client if 
  547.  * distributed separately from the Prospero distribution.  The version
  548.  * command should then identify both the client version and the Prospero
  549.  * version identifiers.   
  550.  */
  551. #ifdef XARCHIE
  552. # define CLIENT_VERSION    "1.3-X"
  553. #else
  554. # define CLIENT_VERSION "1.2"
  555. #endif
  556.  
  557. /* Procedures from user/aquery.c */
  558.  
  559. /* archie_query(host,string,max_hits,offset,query_type,cmp_proc,flags) */
  560. extern VLINK archie_query(); 
  561.  
  562. /* defcmplink(p,q) and invdatecmplink(p,q)                             */
  563. extern int defcmplink();    /* Compare by host then by filename    */
  564. extern int invdatecmplink();    /* Compare links inverted by date      */
  565.  
  566. /* Definitions for the comparison procedures                           */
  567. #define AQ_DEFCMP    defcmplink
  568. #define AQ_INVDATECMP    invdatecmplink
  569.  
  570. /* Flags                                                               */
  571. #define AQ_NOSORT    0x01    /* Don't sort                          */
  572. #define AQ_NOTRANS    0x02    /* Don't translate Archie responses    */
  573. $EOD
  574. $!
  575. $CREATE [.archie]archie.lnk
  576. $DECK
  577. aquery.lo archie.lo atalloc.lo dirsend.lo+
  578. Get_pauth.lo get_vdir.lo perrmesg.lo procquery.lo+
  579. ptalloc.lo regex.lo stcopy.lo support.lo+
  580. vlalloc.lo vl_comp.lo
  581. archie.unp
  582. archie/map/noi/co/li/stack:45000
  583. lsocket lnetlib lconfig lpc llibce
  584. $EOD
  585. $!
  586. $CREATE [.archie]archie.doc
  587. $DECK
  588.  
  589.  
  590.  
  591. ARCHIE(1)                USER COMMANDS                  ARCHIE(1)
  592.  
  593.  
  594.  
  595. NAME
  596.      archie - query the  Archie  anonymous  FTP  databases  using
  597.      Prospero
  598.  
  599. SYNOPSIS
  600.      archie [ -cers ] [ -l ] [ -t ] [ -m# ] [ -N# ] [ -h host ] [ -L ] string
  601.  
  602. DESCRIPTION
  603.      archie queries an archie anonymous FTP database looking  for
  604.      the  specified  string  using  the  Prospero protocol.  This
  605.      client is based on Prospero version Beta.4.2 and is provided
  606.      to  encourage non-interactive use of the Archie servers (and
  607.      subsequently better performance on both sides).
  608.  
  609.      The general method of use is of the form
  610.  
  611.           % archie string
  612.  
  613.      This will go to the archie server and ask it to look for all
  614.      known  systems  that have a file named `string' in their FTP
  615.      area.  archie will wait, and print out any matches.
  616.  
  617.      For example,
  618.  
  619.           % archie emacs
  620.  
  621.      will find all anonymous FTP sites  in  the  archie  database
  622.      that  have  files  named  emacs somewhere in their FTP area.
  623.      (This particular query would probably return a lot of direc-
  624.      tories.)  If you want a list of every filename that contains
  625.      emacs anywhere in it, you'd use
  626.  
  627.           % archie -c emacs
  628.  
  629.      Regular expressions, such as
  630.  
  631.           % archie -r '[xX][lL]isp'
  632.  
  633.      may also be used for searches.  (See the manual of a reason-
  634.      ably good editor, like GNU Emacs or vi, for more information
  635.      on using regular expressions.)
  636.  
  637.  
  638. OPTIONS
  639.      The options currently available to this archie client are:
  640.  
  641.      -c          Search substrings paying attention  to  upper  &
  642.                  lower case.
  643.      -e          Exact string match.  (This is the default.)
  644.      -r          Search using a regular expression.
  645.      -s          Search  substrings  ignoring  the  case  of  the
  646.                  letters.
  647.  
  648.  
  649.  
  650. Archie (Prospero) Last change: 20 November 1991                 1
  651.  
  652.  
  653.  
  654.  
  655.  
  656.  
  657. ARCHIE(1)                USER COMMANDS                  ARCHIE(1)
  658.  
  659.  
  660.  
  661.      -l          Output results in a form suitable for parsing by
  662.                  programs.
  663.      -t          Sort the results inverted by date.
  664.      -m#         Specifies the maximum number of  hits  (matches)
  665.                  to return (default of 95).
  666.      -N#         Sets the niceness of a query; by  default,  it's
  667.                  set  to  0.  Without an argument, -N defaults to
  668.                  35765.  If you use -N with an argument between 0
  669.                  and  35765,  it'll  adjust  itself  accordingly.
  670.                  (Note: VMS users will have to put quotes  around
  671.                  this  argument,  and -L, like ``-N45''; VMS will
  672.                  otherwise convert it to lowercase.)
  673.      -h host     Tells the client  to  query  the  Archie  server
  674.                  named host.
  675.      -L          Lists the Archie servers known  to  the  program
  676.                  when it was compiled.
  677.  
  678.   Quick Hits
  679.      You'll often find yourself making fast and  furious  queries
  680.      for  multiple  things  that all look similar (e.g. `telnet',
  681.      `net', etc).  If you get into the  habit  of  using  the  -c
  682.      option  when  performing  these  kinds  of searches, they'll
  683.      often prove more  fruitful  than  if  you  relied  upon  the
  684.      default of -e.
  685.  
  686.   Notes
  687.      The three search-modifying arguments (-c, -r,  and  -s)  are
  688.      all  mutually  exclusive;  only the last one counts.  If you
  689.      specify -e with any of -c, -r, or -s, the server will  first
  690.      check  for  an  exact  match,  then  fall  back to the case-
  691.      sensitive, case-insensitive, or regular  expression  search.
  692.      This  is so if there are matches that are particularly obvi-
  693.      ous, it will take a minimal amount of time to  satisfy  your
  694.      request.
  695.  
  696.      If you list a single `-' by itself,  any  further  arguments
  697.      will  be  taken  as  part  of  the  search  string.  This is
  698.      intended to enable searching for strings that begin  with  a
  699.      `-'; for example:
  700.  
  701.           % archie -s - -old
  702.  
  703.      will search for all filenames that contain the string `-old'
  704.      in them.
  705.  
  706. RESPONSE
  707.      Archie servers are set up to respond to a number of requests
  708.      in  a  queued fashion.  That is, smaller requests get served
  709.      much more quickly than do large requests.  As a result,  the
  710.      more  often  you query the Archie server, or the larger your
  711.      requests, the longer the queue will become, resulting  in  a
  712.      longer  waiting  period  for everyone's requests.  Please be
  713.  
  714.  
  715.  
  716. Archie (Prospero) Last change: 20 November 1991                 2
  717.  
  718.  
  719.  
  720.  
  721.  
  722.  
  723. ARCHIE(1)                USER COMMANDS                  ARCHIE(1)
  724.  
  725.  
  726.  
  727.      frugal when possible, for your benefit as well  as  for  the
  728.      other users.
  729.  
  730. QUERY PRIORITY
  731.      Please use the -N option whenever you don't  demand  immedi-
  732.      acy,  or  when  you're requesting things that could generate
  733.      large responses.  Even  when  using  the  nice  option,  you
  734.      should  still  try  to  avoid  big jobs during busy periods.
  735.      Here is a list of what we consider to be  nice  values  that
  736.      accurately reflect the priority of a job to the server.
  737.  
  738.           Normal              0
  739.           Nice                500
  740.           Nicer               1000
  741.           Very Nice           5000
  742.           Extremely Nice      10000
  743.           Nicest              32765
  744.  
  745.      The last priority, Nicest, would be used when a  job  should
  746.      wait  until  the  queue is essentially empty before running.
  747.      You should pick one of these values to use, possibly modify-
  748.      ing  it  slightly depending on where you think your priority
  749.      should land.  For example, 32760 would mean wait  until  the
  750.      queue  is  empty,  but  jump  ahead  of other jobs that have
  751.      selected Nicest.
  752.  
  753.      There are certain types of  things  that  we  suggest  using
  754.      Nicest  for,  irregardless.  In particular, any searches for
  755.      which you would have a hard time justifying the use of  any-
  756.      thing but extra resources.  (We all know what those searches
  757.      would be for.)
  758.  
  759. SEE ALSO
  760.      For more information on regular expressions, see the  manual
  761.      pages on:
  762.  
  763.      regex(3), ed(1)
  764.  
  765.      Also read the file archie/whatis on archie.mcgill.ca  for  a
  766.      detailed paper on Archie as a whole.
  767.  
  768. AUTHORS
  769.      The archie service was conceived  and  implemented  by  Alan
  770.      Emtage       (bajan@cs.mcgill.ca),       Peter       Deutsch
  771.      (peterd@cs.mcgill.ca),        and        Bill         Heelan
  772.      (wheelan@cs.mcgill.ca).   The  entire  Internet  is in their
  773.      debt.
  774.  
  775.      The  Prospero  system  was  created   by   Clifford   Neuman
  776.      (bcn@isi.edu);   write  to  info-prospero@isi.edu  for  more
  777.      information on the protocol and its use.
  778.  
  779.  
  780.  
  781.  
  782. Archie (Prospero) Last change: 20 November 1991                 3
  783.  
  784.  
  785.  
  786.  
  787.  
  788.  
  789. ARCHIE(1)                USER COMMANDS                  ARCHIE(1)
  790.  
  791.  
  792.  
  793.      This stripped client  was  put  together  by  Brendan  Kehoe
  794.      (brendan@cs.widener.edu),  with  modifications  by  Clifford
  795.      Neuman and George Ferguson (ferguson@cs.rochester.edu).
  796.  
  797. BUGS
  798.      There are none; only a few unexpected features.
  799.  
  800.  
  801.  
  802.  
  803.  
  804.  
  805.  
  806.  
  807.  
  808.  
  809.  
  810.  
  811.  
  812.  
  813.  
  814.  
  815.  
  816.  
  817.  
  818.  
  819.  
  820.  
  821.  
  822.  
  823.  
  824.  
  825.  
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843.  
  844.  
  845.  
  846.  
  847.  
  848. Archie (Prospero) Last change: 20 November 1991                 4
  849.  
  850.  
  851.  
  852. $EOD
  853. $!
  854. $CREATE [.archie]archie.man
  855. $DECK
  856. .\" Originally by Jeff Kellem
  857. .\"
  858. .TH ARCHIE 1 "20 November 1991" "Archie (Prospero)"
  859. .SH NAME
  860. archie \- query the Archie anonymous FTP databases using Prospero
  861. .SH SYNOPSIS
  862. .in +\w'\fBarchie \fR'u
  863. .ti -\w'\fBarchie \fR'u
  864. .B archie\
  865. \ [\ \fB\-cers\fR\ ]\
  866. \ [\ \fB\-l\fR\ ]\ [\ \fB\-t\fR\ ]\
  867. \ [\ \fB\-m#\fR\ ]\ [\ \fB\-N#\fR\ ]\
  868. \ [\ \fB\-h\fR\ \fIhost\fR\ ]\ [\ \fB\-L\fR\ ]\ \fIstring\fR
  869. .SH DESCRIPTION
  870. .B archie
  871. queries an archie anonymous FTP database looking for the specified
  872. .I string
  873. using the
  874. .B Prospero
  875. protocol.  This client is based on
  876. .B Prospero
  877. version Beta.4.2 and is provided to encourage non-interactive use of
  878. the Archie servers (and subsequently better performance on both
  879. sides).
  880.  
  881. The general method of use is of the form
  882.  
  883. .RS
  884. %
  885. .B archie string
  886. .RE
  887. .PP
  888.  
  889. This will go to the archie server and ask it to look for all known
  890. systems that have a file named `string' in their FTP area.  \fBarchie\fP
  891. will wait, and print out any matches.
  892.  
  893. For example,
  894.  
  895. .RS
  896. %
  897. .B archie emacs
  898. .RE
  899. .PP
  900.  
  901. will find all anonymous FTP sites in the archie database that have files
  902. named
  903. .B emacs
  904. somewhere in their FTP area.  (This particular query would probably
  905. return a lot of directories.)  If you want a list of every filename
  906. that contains \fBemacs\fR \fIanywhere\fR in it, you'd use
  907.  
  908. .RS
  909. %
  910. .B archie -c emacs
  911. .RE
  912. .PP
  913.  
  914. Regular expressions, such as
  915.  
  916. .RS
  917. %
  918. .B archie -r '[xX][lL]isp'
  919. .RE
  920. .PP
  921.  
  922. may also be used for searches.  (See the manual of a reasonably good
  923. editor, like GNU Emacs or vi, for more information on using regular
  924. expressions.)
  925.  
  926. .SH OPTIONS
  927. The options currently available to this
  928. .B archie
  929. client are:
  930.  
  931. .PD 0
  932. .TP 12
  933. .BR \-c
  934. Search substrings paying attention to upper & lower case.
  935. .TP
  936. .BR \-e
  937. Exact string match.  (This is the default.)
  938. .TP
  939. .BR \-r
  940. Search using a regular expression.
  941. .TP
  942. .BR \-s
  943. Search substrings ignoring the case of the letters.
  944. .TP
  945. .BR \-l
  946. Output results in a form suitable for parsing by programs.
  947. .TP
  948. .BR \-t
  949. Sort the results inverted by date.
  950. .TP
  951. .BI \-m#
  952. Specifies the maximum number of hits (matches) to return (default of 
  953. \fB95\fR).
  954. .TP
  955. .BI \-N#
  956. Sets the \fIniceness\fR of a query; by default, it's set to 0.
  957. Without an argument, \fB\-N\fR defaults to \fB35765\fR.  If you use
  958. \fB\-N\fR with an argument between 0 and 35765, it'll adjust itself
  959. accordingly.  (\fBNote\fR: VMS users will have to put quotes around
  960. this argument, and \fB\-L\fR, like ``\fB\-N45\fR''; VMS will otherwise convert
  961. it to lowercase.)
  962. .TP
  963. .BI \-h\ \fIhost\fR
  964. Tells the client to query the Archie server named \fIhost\fR.
  965. .TP
  966. .BI \-L
  967. Lists the Archie servers known to the program when it was compiled.
  968.  
  969. .PP
  970.  
  971. .SS Quick Hits
  972. You'll often find yourself making fast and furious queries for
  973. multiple things that all look similar (e.g. `telnet', `net', etc).  If
  974. you get into the habit of using the
  975. .BR \-c
  976. option when performing these kinds of searches, they'll often prove
  977. more fruitful than if you relied upon the default of
  978. .BR \-e .
  979.  
  980. .SS Notes
  981. The three search-modifying arguments (\fB\-c\fR, \fB\-r\fB, and \fB\-s\fR)
  982. are all mutually exclusive; only the last one counts.  If you specify
  983. \fB\-e\fR with any of \fB\-c\fR, \fB\-r\fB, or \fB\-s\fR,
  984. the server will first check for an exact match, then fall back to the
  985. case-sensitive, case-insensitive, or regular expression search.  This is
  986. so if there are matches that are particularly obvious, it will take a
  987. minimal amount of time to satisfy your request.
  988.  
  989. If you list a single `\-' by itself, any further arguments will be
  990. taken as part of the search string.  This is intended to enable
  991. searching for strings that begin with a `\-'; for example:
  992.  
  993. .RS
  994. %
  995. .B archie \-s \- \-old
  996. .RE
  997.  
  998. will search for all filenames that contain the string `\-old' in them.
  999.  
  1000. .SH RESPONSE
  1001. Archie servers are set up to respond to a number of requests in a
  1002. queued fashion.  That is, smaller requests get served much more
  1003. quickly than do large requests.  As a result, the more often you query
  1004. the Archie server, or the larger your requests, the longer the queue
  1005. will become, resulting in a longer waiting period for everyone's
  1006. requests.  Please be frugal when possible, for your benefit as well as
  1007. for the other users.
  1008.  
  1009. .SH QUERY PRIORITY
  1010. Please use the \fB\-N\fR option whenever you don't demand immediacy, or
  1011. when you're requesting things that could generate large responses.
  1012. Even when using the nice option, you should still try to avoid big
  1013. jobs during busy periods.  Here is a list of what we consider to be
  1014. nice values that accurately reflect the priority of a job to the server.
  1015.  
  1016. .RS
  1017. .TP 20
  1018. .B Normal
  1019. 0
  1020. .TP
  1021. .B Nice
  1022. 500
  1023. .TP
  1024. .B Nicer
  1025. 1000
  1026. .TP
  1027. .B Very Nice
  1028. 5000
  1029. .TP
  1030. .B Extremely Nice
  1031. 10000
  1032. .TP
  1033. .B Nicest
  1034. 32765
  1035. .RE
  1036.  
  1037. The last priority, \fBNicest\fR, would be used when a job should wait until
  1038. the queue is essentially empty before running.  You should pick one of
  1039. these values to use, possibly modifying it slightly depending on where
  1040. you think your priority should land.  For example, 32760 would mean
  1041. wait until the queue is empty, but jump ahead of other jobs that have
  1042. selected \fBNicest\fR.
  1043.  
  1044. There are certain types of things that we suggest using \fBNicest\fR
  1045. for, irregardless.  In particular, any searches for which you would
  1046. have a hard time justifying the use of anything but extra resources.
  1047. (We all know what those searches would be for.)
  1048.  
  1049. .SH SEE ALSO
  1050. For more information on regular expressions, see the manual pages on:
  1051.  
  1052. .BR regex (3) ,
  1053. .BR ed (1)
  1054.  
  1055. Also read the file \fBarchie/whatis\fR on \fBarchie.mcgill.ca\fR for a
  1056. detailed paper on Archie as a whole.
  1057.  
  1058. .SH AUTHORS
  1059. The 
  1060. .B archie
  1061. service was conceived and implemented by Alan Emtage (\fBbajan@cs.mcgill.ca\fR),
  1062. Peter Deutsch (\fBpeterd@cs.mcgill.ca\fR), and Bill Heelan
  1063. (\fBwheelan@cs.mcgill.ca\fR).  The entire Internet is in their debt.
  1064.  
  1065. The \fBProspero\fR system was created by Clifford Neuman
  1066. (\fBbcn@isi.edu\fR); write to \fBinfo\-prospero@isi.edu\fR for more
  1067. information on the protocol and its use.
  1068.  
  1069. This stripped client was put together by Brendan Kehoe
  1070. (\fBbrendan@cs.widener.edu\fR), with modifications by
  1071. Clifford Neuman and George Ferguson (\fBferguson@cs.rochester.edu\fR).
  1072.  
  1073. .SH BUGS
  1074. There are none; only a few unexpected features.
  1075.  
  1076. $EOD
  1077. $!
  1078. $CREATE [.archie]aquery.c
  1079. $DECK
  1080. /*
  1081.  * aquery.c : Programmatic Prospero interface to Archie
  1082.  *
  1083.  * Copyright (c) 1991 by the University of Washington
  1084.  *
  1085.  * For copying and distribution information, please see the file
  1086.  * <copyright.h>.
  1087.  *
  1088.  * Originally part of the Prospero Archie client by Clifford 
  1089.  * Neuman (bcn@isi.edu).  Modifications, addition of programmatic interface,
  1090.  * and new sorting code by George Ferguson (ferguson@cs.rochester.edu) 
  1091.  * and Brendan Kehoe (brendan@cs.widener.edu).  MSDOS and OS2 modifications
  1092.  * to use with PC/TCP by Mark Towfiq (towfiq@FTP.COM).
  1093.  *
  1094.  * v1.2.1 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  1095.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  1096.  * v1.1.3 - 08/30/91 (bpk) - cast index()
  1097.  * v1.1.2 - 08/20/91 (bcn) - make it do it properly (new invdatecmplink)
  1098.  * v1.1.1 - 08/20/91 (bpk) - made sorting go inverted as we purport it does
  1099.  */
  1100. #include <copyright.h>
  1101.  
  1102. #include <stdio.h>
  1103.  
  1104. #include <pfs.h>
  1105. #include <perrno.h>
  1106. #include <archie.h>
  1107.  
  1108. #include <pmachine.h>
  1109. #ifdef NEED_STRING_H
  1110. # include <string.h>            /* for char *index() */
  1111. #else
  1112. # include <strings.h>            /* for char *index() */
  1113. #endif
  1114.  
  1115. static void translateArchieResponse();
  1116.  
  1117. extern int pwarn;
  1118. extern char p_warn_string[];
  1119.  
  1120. /*
  1121.  * archie_query : Sends a request to _host_, telling it to search for
  1122.  *                _string_ using _query_type_ as the search method.
  1123.  *                No more than _max_hits_ matches are to be returned
  1124.  *                skipping over _offset_ matches.
  1125.  *
  1126.  *          archie_query returns a linked list of virtual links. 
  1127.  *                If _flags_ does not include AQ_NOTRANS, then the Archie
  1128.  *                responses will be translated. If _flags_ does not include 
  1129.  *                AQ_NOSORT, then the list will be sorted using _cmp_proc_ to
  1130.  *                compare pairs of links.  If _cmp_proc_ is NULL or AQ_DEFCMP,
  1131.  *                then the default comparison procedure, defcmplink(), is used
  1132.  *                sorting by host, then filename. If cmp_proc is AQ_INVDATECMP
  1133.  *                then invdatecmplink() is used, sorting inverted by date.
  1134.  *                otherwise a user-defined comparison procedure is called.
  1135.  *
  1136.  *                archie_query returns NULL and sets perrno if the query
  1137.  *                failed. Note that it can return NULL with perrno == PSUCCESS
  1138.  *                if the query didn't fail but there were simply no matches.
  1139.  *
  1140.  *   query_type:  S  Substring search ignoring case   
  1141.  *                C  Substring search with case significant
  1142.  *                R  Regular expression search
  1143.  *                =  Exact String Match
  1144.  *            s,c,e  Tries exact match first and falls back to S, C, or R 
  1145.  *                   if not found.
  1146.  *
  1147.  *     cmp_proc:  AQ_DEFCMP      Sort by host, then filename
  1148.  *                AQ_INVDATECMP  Sort inverted by date
  1149.  *
  1150.  *        flags:  AQ_NOSORT      Don't sort results
  1151.  *                AQ_NOTRANS     Don't translate results
  1152.  */
  1153. VLINK 
  1154. archie_query(host,string,max_hits,offset,query_type,cmp_proc,flags)
  1155.     char    *host,*string;
  1156.     int        max_hits,offset;
  1157.     char    query_type;
  1158.     int        (*cmp_proc)();
  1159.     int        flags;
  1160.     {
  1161.     char qstring[MAX_VPATH];    /* For construting the query  */
  1162.     VLINK    links;        /* Matches returned by server */
  1163.     VDIR_ST    dir_st;         /* Filled in by get_vdir      */
  1164.     VDIR    dir= &dir_st;
  1165.     
  1166.     VLINK    p,q,r,lowest,nextp,pnext,pprev;
  1167.     int    tmp;
  1168.  
  1169.     /* Set the cmp_proc if not given */
  1170.     if (cmp_proc == NULL) cmp_proc = defcmplink;
  1171.  
  1172.     /* Make the query string */
  1173.     sprintf(qstring,"ARCHIE/MATCH(%d,%d,%c)/%s",
  1174.         max_hits,offset,query_type,string);
  1175.  
  1176.     /* Initialize Prospero structures */
  1177.     perrno = PSUCCESS; *p_err_string = '\0';
  1178.     pwarn = PNOWARN; *p_warn_string = '\0';
  1179.     vdir_init(dir);
  1180.     
  1181.     /* Retrieve the list of matches, return error if there was one */
  1182. #if defined(MSDOS)
  1183.     if(tmp = get_vdir(host, qstring, "", dir, (long)GVD_ATTRIB|GVD_NOSORT,
  1184.         NULL, NULL)) {
  1185. #else
  1186.     if(tmp = get_vdir(host,qstring,"",dir,GVD_ATTRIB|GVD_NOSORT,NULL,NULL)) {
  1187. # endif
  1188.         perrno = tmp;
  1189.         return(NULL);
  1190.     }
  1191.  
  1192.     /* Save the links, and clear in dir in case it's used again   */
  1193.     links = dir->links; dir->links = NULL;
  1194.  
  1195.     /* As returned, list is sorted by suffix, and conflicting     */
  1196.     /* suffixes appear on a list of "replicas".  We want to       */
  1197.     /* create a one-dimensional list sorted by host then filename */
  1198.     /* and maybe by some other parameter                          */
  1199.  
  1200.     /* First flatten the doubly-linked list */
  1201.     for (p = links; p != NULL; p = nextp) {
  1202.         nextp = p->next;
  1203.         if (p->replicas != NULL) {
  1204.         p->next = p->replicas;
  1205.         p->next->previous = p;
  1206.         for (r = p->replicas; r->next != NULL; r = r->next)
  1207.             /*EMPTY*/ ;
  1208.         r->next = nextp;
  1209.         nextp->previous = r;
  1210.         p->replicas = NULL;
  1211.         }
  1212.     }
  1213.  
  1214.     /* Translate the filenames unless NOTRANS was given */
  1215.     if (!(flags & AQ_NOTRANS))
  1216.         for (p = links; p != NULL; p = p->next)
  1217.         translateArchieResponse(p);
  1218.  
  1219.     /* If NOSORT given, then just hand it back */
  1220.     if (flags & AQ_NOSORT) {
  1221.         perrno = PSUCCESS;
  1222.         return(links);
  1223.     }
  1224.  
  1225.     /* Otherwise sort it using a selection sort and the given cmp_proc */
  1226.     for (p = links; p != NULL; p = nextp) {
  1227.         nextp = p->next;
  1228.         lowest = p;
  1229.         for (q = p->next; q != NULL; q = q->next)
  1230.         if ((*cmp_proc)(q,lowest) < 0)
  1231.             lowest = q;
  1232.         if (p != lowest) {
  1233.         /* swap the two links */
  1234.         pnext = p->next;
  1235.         pprev = p->previous;
  1236.         if (lowest->next != NULL)
  1237.             lowest->next->previous = p;
  1238.         p->next = lowest->next;
  1239.         if (nextp == lowest) {
  1240.             p->previous = lowest;
  1241.         } else {
  1242.             lowest->previous->next = p;
  1243.             p->previous = lowest->previous;
  1244.         }
  1245.         if (nextp == lowest) {
  1246.             lowest->next = p;
  1247.         } else {
  1248.             pnext->previous = lowest;
  1249.             lowest->next = pnext;
  1250.         }
  1251.         if (pprev != NULL)
  1252.             pprev->next = lowest;
  1253.         lowest->previous = pprev;
  1254.         /* keep the head of the list in the right place */
  1255.         if (links == p)
  1256.             links = lowest;
  1257.         }
  1258.     }
  1259.  
  1260.     /* Return the links */
  1261.     perrno = PSUCCESS;
  1262.     return(links);
  1263.     }
  1264.  
  1265. /*
  1266.  * translateArchieResponse: 
  1267.  *
  1268.  *   If the given link is for an archie-pseudo directory, fix it. 
  1269.  *   This is called unless AQ_NOTRANS was given to archie_query().
  1270.  */
  1271. static void
  1272. translateArchieResponse(l)
  1273.     VLINK l;
  1274.     {
  1275.     char *slash;
  1276.  
  1277.     if (strcmp(l->type,"DIRECTORY") == 0) {
  1278.         if (strncmp(l->filename,"ARCHIE/HOST",11) == 0) {
  1279.         l->type = stcopyr("EXTERNAL(AFTP,DIRECTORY)",l->type);
  1280.         l->host = stcopyr(l->filename+12,l->host);
  1281.         slash = (char *)index(l->host,'/');
  1282.         if (slash) {
  1283.             l->filename = stcopyr(slash,l->filename);
  1284.             *slash++ = '\0';
  1285.         } else
  1286.             l->filename = stcopyr("",l->filename);
  1287.         }
  1288.     }
  1289.     }
  1290.  
  1291. /*
  1292.  * defcmplink: The default link comparison function for sorting. Compares
  1293.  *           links p and q first by host then by filename. Returns < 0 if p
  1294.  *             belongs before q, > 0 if p belongs after q, and == 0 if their
  1295.  *             host and filename fields are identical.
  1296.  */
  1297. int
  1298. defcmplink(p,q)
  1299.     VLINK p,q;
  1300.     {
  1301.     int result;
  1302.  
  1303.     if ((result=strcmp(p->host,q->host)) != 0)
  1304.         return(result);
  1305.     else
  1306.         return(strcmp(p->filename,q->filename));
  1307.     }
  1308.  
  1309. /*
  1310.  * invdatecmplink: An alternative comparison function for sorting that
  1311.  *               compares links p and q first by LAST-MODIFIED date,
  1312.  *                 if they both have that attribute. If both links
  1313.  *                 don't have that attribute or the dates are the
  1314.  *                 same, it then calls defcmplink() and returns its 
  1315.  *           value.
  1316.  */
  1317. int
  1318. invdatecmplink(p,q)
  1319.     VLINK p,q;
  1320.     {
  1321.     PATTRIB pat,qat;
  1322.     char *pdate,*qdate;
  1323.     int result;
  1324.     
  1325.     pdate = qdate = NULL;
  1326.     for (pat = p->lattrib; pat; pat = pat->next)
  1327.         if(strcmp(pat->aname,"LAST-MODIFIED") == 0)
  1328.         pdate = pat->value.ascii;
  1329.     for (qat = q->lattrib; qat; qat = qat->next)
  1330.         if(strcmp(qat->aname,"LAST-MODIFIED") == 0)
  1331.         qdate = qat->value.ascii;
  1332.     if(!pdate && !qdate) return(defcmplink(p,q));
  1333.     if(!pdate) return(1); 
  1334.     if(!qdate) return(-1);
  1335.     if((result=strcmp(qdate,pdate)) == 0) return(defcmplink(p,q));
  1336.     else return(result);
  1337.     }
  1338. $EOD
  1339. $!
  1340. $CREATE [.archie]atalloc.c
  1341. $DECK
  1342. /*
  1343.  * Copyright (c) 1989, 1990 by the University of Washington
  1344.  *
  1345.  * For copying and distribution information, please see the file
  1346.  * <copyright.h>.
  1347.  */
  1348.  
  1349. #include <copyright.h>
  1350. #include <stdio.h>
  1351.  
  1352. #include <pfs.h>
  1353. #include <pmachine.h> /* for correct definition of ZERO */
  1354.  
  1355. static PATTRIB    lfree = NULL;
  1356. int        pattrib_count = 0;
  1357. int        pattrib_max = 0;
  1358.  
  1359. /*
  1360.  * atalloc - allocate and initialize vlink structure
  1361.  *
  1362.  *    ATALLOC returns a pointer to an initialized structure of type
  1363.  *    PATTRIB.  If it is unable to allocate such a structure, it
  1364.  *    returns NULL.
  1365.  */
  1366. PATTRIB
  1367. atalloc()
  1368.     {
  1369.     PATTRIB    at;
  1370.     if(lfree) {
  1371.         at = lfree;
  1372.         lfree = lfree->next;
  1373.     }
  1374.     else {
  1375.         at = (PATTRIB) malloc(sizeof(PATTRIB_ST));
  1376.         if (!at) return(NULL);
  1377.         pattrib_max++;
  1378.     }
  1379.  
  1380.     pattrib_count++;
  1381.  
  1382.     ZERO(at);
  1383.     /* Initialize and fill in default values; all items are
  1384.        0 [or NULL] save precedence */
  1385.     at->precedence = ATR_PREC_OBJECT;
  1386.  
  1387.     return(at);
  1388.     }
  1389.  
  1390. /*
  1391.  * atfree - free a PATTRIB structure
  1392.  *
  1393.  *    ATFREE takes a pointer to a PATTRRIB structure and adds it to
  1394.  *    the free list for later reuse.
  1395.  */
  1396. void
  1397. atfree(at)
  1398.     PATTRIB    at;
  1399.     {
  1400.     if(at->aname) stfree(at->aname);
  1401.  
  1402.     if((strcmp(at->avtype,"ASCII") == 0) && at->value.ascii) 
  1403.         stfree(at->value.ascii);
  1404.     if((strcmp(at->avtype,"LINK") == 0) && at->value.link) 
  1405.         vlfree(at->value.link);
  1406.     
  1407.     if(at->avtype) stfree(at->avtype);
  1408.  
  1409.     at->next = lfree;
  1410.     at->previous = NULL;
  1411.     lfree = at;
  1412.     pattrib_count--;
  1413.     }
  1414.  
  1415. /*
  1416.  * atlfree - free a PATTRIB structure
  1417.  *
  1418.  *    ATLFREE takes a pointer to a PATTRIB structure frees it and any linked
  1419.  *    PATTRIB structures.  It is used to free an entrie list of PATTRIB
  1420.  *    structures.
  1421.  */
  1422. void
  1423. atlfree(at)
  1424.     PATTRIB    at;
  1425.     {
  1426.     PATTRIB    nxt;
  1427.  
  1428.     while(at != NULL) {
  1429.         nxt = at->next;
  1430.         atfree(at);
  1431.         at = nxt;
  1432.     }
  1433.     }
  1434.  
  1435. $EOD
  1436. $!
  1437. $CREATE [.archie]dirsend.c
  1438. $DECK
  1439. /*
  1440.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  1441.  *
  1442.  * For copying and distribution information, please see the file
  1443.  * <copyright.h>.
  1444.  *
  1445.  * v1.2.4 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  1446.  * v1.2.3 - 11/04/91 (bcn) - removed host comparison and replaced with check
  1447.  *                 for connection id (undoes effect of v1.2.2.).
  1448.  * v1.2.2 - 11/02/91 (gf)  - removed extra inet_ntoa() calls and stuff for
  1449.  *                 multi-interface nets (lmjm@doc.imperial.ac.uk)
  1450.  * v1.2.1 - 10/20/91 (gf)  - asynch implementation
  1451.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  1452.  * v1.1.2 - 08/30/91 (bpk) - added VMS support
  1453.  * v1.1.1 - 08/29/91 (bcn) - changed backoff handling
  1454.  * v1.1.0 - 08/13/91 (gf)  - added XArchie status calls
  1455.  *
  1456.  * gf: 20 Oct 1991:
  1457.  *  Broken into pieces so that under X dirsend() doesn't block in select()
  1458.  *  but rather uses Xt calls to allow continued event processing. If
  1459.  *  XARCHIE is not defined, can still be used since processEvent() will
  1460.  *  use select() in this case.
  1461.  */
  1462.  
  1463. #include <copyright.h>
  1464. #include <stdio.h>
  1465. #include <errno.h>
  1466.  
  1467. #ifdef VMS
  1468. # ifdef WALLONGONG
  1469. #  include "twg$tcp:[netdist.include]netdb.h"
  1470. # else /* Multinet */
  1471. #  include "multinet_root:[multinet.include]netdb.h"
  1472. # endif
  1473. # include <vms.h>
  1474. #else /* not VMS */
  1475. # include <sys/types.h> /* this may/will define FD_SET etc */
  1476. # include <pmachine.h>
  1477. # ifdef NEED_TIME_H
  1478. #  include <time.h>
  1479. # else
  1480. #  include <sys/time.h>
  1481. # endif
  1482. # ifdef NEED_STRING_H
  1483. #  include <string.h>
  1484. # else
  1485. #  include <strings.h>
  1486. # endif
  1487. # include <netdb.h>
  1488. # include <sys/socket.h>
  1489. # ifdef NEED_SELECT_H
  1490. #  include <sys/select.h>
  1491. # endif /* NEED_SELECT_H */
  1492. # ifndef IN_H
  1493. #  include <netinet/in.h>
  1494. #  define IN_H
  1495. # endif
  1496. # ifndef hpux
  1497. #  include <arpa/inet.h>
  1498. # endif
  1499. #endif /* !VMS */
  1500.  
  1501. #include <pfs.h>
  1502. #include <pprot.h>
  1503. #include <pcompat.h>
  1504. #include <perrno.h>
  1505.  
  1506. /* Gnu C currently fails to pass structures on Sparcs properly.  This directly
  1507.    effects the calling of inet_ntoa().  To get around it, we use this hack;
  1508.    take the address of what's being called to inet_ntoa, so it gets it
  1509.    properly.  This won't be necessary with gcc 2.0.  */
  1510. #if defined(sun) && defined(__GNUC__) && !defined(__GNU_LIBRARY__)
  1511. # define SUN_GNU_FIX &
  1512. #else
  1513. # define SUN_GNU_FIX
  1514. #endif
  1515.  
  1516. static int notprived = 0;
  1517. #ifndef MSDOS
  1518. extern int errno;
  1519. #endif
  1520. extern int perrno;
  1521. extern int rdgram_priority;
  1522. #ifdef DEBUG
  1523. extern int pfs_debug;
  1524. #endif
  1525. extern int pfs_disable_flag;
  1526.  
  1527. char    *nlsindex();
  1528.  
  1529. #define max(X, Y)  ((X) > (Y) ? (X) : (Y))
  1530.  
  1531. static int        dir_udp_port = 0;    /* Remote UDP port number */
  1532.  
  1533. static unsigned short    next_conn_id = 0;
  1534.  
  1535. #ifdef XARCHIE
  1536. int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  1537. int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  1538. #else /* !XARCHIE */
  1539. static int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  1540. static int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  1541. #endif /* XARCHIE */
  1542.  
  1543. /* These were parameters to dirsend() */
  1544. static PTEXT pkt;
  1545. static char *hostname;
  1546. static struct sockaddr_in *hostaddr;
  1547.  
  1548. /* These were locals in dirsend(). Note that the initializations here
  1549.  * are really meaningless since we have to redo them for each call to
  1550.  * dirsend() since they were formerly automatically initialized.
  1551.  */
  1552. static PTEXT        first = NULL;    /* First returned packet     */
  1553. static PTEXT        next;        /* The one we are waiting for      */
  1554. static PTEXT        vtmp;           /* For reorganizing linked list  */
  1555. static PTEXT        comp_thru;    /* We have all packets though    */
  1556. static int        lp = -1;    /* Opened UDP port             */
  1557. static int        hdr_len;    /* Header Length                 */
  1558. static int        nd_pkts;    /* Number of packets we want     */
  1559. static int        no_pkts;    /* Number of packets we have     */
  1560. static int        pkt_cid;        /* Packet connection identifier  */
  1561. static unsigned short    this_conn_id;    /* Connection ID we are using    */
  1562. static unsigned short    recvd_thru;    /* Received through              */
  1563. static short        priority;    /* Priority for request          */
  1564. static short        one = 0;    /* Pointer to value 1            */
  1565. static short        zero = 0;    /* Pointer to value 0         */
  1566. static char        *seqtxt;    /* Pointer to text w/ sequence # */
  1567. static struct sockaddr_in  us;        /* Our address                   */
  1568. static struct sockaddr_in  to;        /* Address to send query     */
  1569. static struct sockaddr_in  from;    /* Reply received from         */
  1570. static int        from_sz;    /* Size of from structure     */
  1571. static struct hostent    *host;        /* Host info from gethostbyname  */
  1572. static long        newhostaddr;    /* New host address from *host   */
  1573. static int        req_udp_port=0; /* Requested port (optional)     */
  1574. static char        *openparen;    /* Delimits port in name         */
  1575. static char        hostnoport[500];/* Host name without port        */
  1576. static int        ns;        /* Number of bytes actually sent */
  1577. static int        nr;        /* Number of bytes received      */
  1578. static fd_set        readfds;    /* Used for select         */
  1579. static int        tmp;
  1580. static char        *ctlptr;    /* Pointer to control field      */
  1581. static short        stmp;        /* Temp short for conversions    */
  1582. static int        backoff;    /* Server requested backoff      */
  1583. static unsigned char    rdflag11;    /* First byte of flags (bit vect)*/
  1584. static unsigned char    rdflag12;    /* Second byte of flags (int)    */
  1585. static int        scpflag = 0;    /* Set if any sequencd cont pkts */
  1586. static int        ackpend = 0;    /* Acknowledgement pending      */
  1587. static int        gaps = 0;    /* Gaps present in recvd pkts   */
  1588. static struct timeval    timeout;    /* Time to wait for response    */
  1589. static struct timeval    ackwait;    /* Time to wait before acking   */
  1590. static struct timeval    gapwait;    /* Time to wait b4 filling gaps */
  1591. static struct timeval    *selwait;    /* Time to wait for select      */
  1592. static int        retries;    /* was = client_dirsrv_retry    */
  1593. char   to_hostname[512];        /* lmjm: saves inet_ntoa() str  */
  1594.  
  1595. /* These are added so dirsend() "blocks" properly */
  1596. static PTEXT dirsendReturn;
  1597. static int dirsendDone;
  1598.  
  1599. /* And here are the values for dirsendDone */
  1600. #define DSRET_DONE        1
  1601. #define DSRET_SEND_ERROR    -1
  1602. #define DSRET_RECV_ERROR    -2
  1603. #define DSRET_SELECT_ERROR    -3
  1604. #define DSRET_TIMEOUT        -4
  1605. #define DSRET_ABORTED        -5
  1606.  
  1607. /* New procedures to break up dirsend() */
  1608. static int initDirsend();
  1609. static void retryDirsend(), keepWaitingDirsend();
  1610. static void timeoutProc();
  1611. static void readProc();
  1612.  
  1613. /* Wrappers around X calls to allow non-X usage */
  1614. static void addInputSource(), removeInputSource();
  1615. static void addTimeOut(), removeTimeOut();
  1616. static void processEvent();
  1617.  
  1618. /* Extra stuff for the asynchronous X version of dirsend() */
  1619. #ifdef XARCHIE
  1620. #include <X11/Intrinsic.h>
  1621. extern XtAppContext appContext;
  1622. #else
  1623. typedef char *XtPointer;
  1624. typedef char *XtInputId;
  1625. typedef char *XtIntervalId;
  1626. #endif
  1627. static XtInputId inputId;
  1628. static XtIntervalId timerId = (XtIntervalId)0;
  1629.  
  1630. /*
  1631.  * dirsend - send packet and receive response
  1632.  *
  1633.  *   DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
  1634.  *   and a pointer to a host address.  It then sends the supplied
  1635.  *   packet off to the directory server on the specified host.  If
  1636.  *   hostaddr points to a valid address, that address is used.  Otherwise,
  1637.  *   the hostname is looked up to obtain the address.  If hostaddr is a
  1638.  *   non-null pointer to a 0 address, then the address will be replaced
  1639.  *   with that found in the hostname lookup.
  1640.  *
  1641.  *   DIRSEND will wait for a response and retry an appropriate
  1642.  *   number of times as defined by timeout and retries (both static
  1643.  *   variables).  It will collect however many packets form the reply, and
  1644.  *   return them in a structure (or structures) of type PTEXT.
  1645.  *
  1646.  *   DIRSEND will free the packet that it is presented as an argument.
  1647.  *   The packet is freed even if dirsend fails.
  1648.  */
  1649. PTEXT
  1650. dirsend(pkt_p,hostname_p,hostaddr_p)
  1651.     PTEXT pkt_p;
  1652.     char *hostname_p;
  1653.     struct sockaddr_in    *hostaddr_p;
  1654. {
  1655.     /* copy parameters to globals since other routines use them */
  1656.     pkt = pkt_p;
  1657.     hostname = hostname_p;
  1658.     hostaddr = hostaddr_p;
  1659.     /* Do the initializations of formerly auto variables */
  1660.     first = NULL;
  1661.     lp = -1;
  1662.     one = 0;
  1663.     zero = 0;
  1664.     req_udp_port=0;
  1665.     scpflag = 0;
  1666.     ackpend = 0;
  1667.     gaps = 0;
  1668.     retries = client_dirsrv_retry;
  1669.  
  1670.     if (initDirsend() < 0)
  1671.     return(NULL);
  1672.     addInputSource();
  1673.     /* set the first timeout */
  1674.     retryDirsend();
  1675.  
  1676.     dirsendReturn = NULL;
  1677.     dirsendDone = 0;
  1678.     /* Until one of the callbacks says to return, keep processing events */
  1679.     while (!dirsendDone)
  1680.     processEvent();
  1681.     /* Clean up event generators */
  1682.     removeTimeOut();
  1683.     removeInputSource();
  1684. #ifdef XARCHIE
  1685.     /* Set status if needed (has to be outside of loop or X will crash) */
  1686.     switch (dirsendDone) {
  1687.     case DSRET_SEND_ERROR: status0("Send error"); break;
  1688.     case DSRET_RECV_ERROR: status0("Recv error"); break;
  1689.         case DSRET_TIMEOUT:
  1690.         status1("Connection to %s timed out",to_hostname);
  1691.         break;
  1692.         case DSRET_ABORTED: status0("Aborted"); break;
  1693.     }
  1694. #endif
  1695.     /* Return whatever we're supposed to */
  1696.     return(dirsendReturn);
  1697. }
  1698.  
  1699.  
  1700. /*    -    -    -    -    -    -    -    -    */
  1701. /* This function does all the initialization that used to be done at the
  1702.  * start of dirsend(), including opening the socket descriptor "lp". It
  1703.  * returns the descriptor if successful, otherwise -1 to indicate that
  1704.  * dirsend() should return NULL immediately.
  1705.  */
  1706. static int
  1707. initDirsend()
  1708. {
  1709. #ifdef XARCHIE
  1710.     status0("Initializing");
  1711. #endif
  1712.  
  1713.     if(one == 0) one = htons((short) 1);
  1714.  
  1715.     priority = htons(rdgram_priority);
  1716.  
  1717.     timeout.tv_sec = client_dirsrv_timeout;
  1718.     timeout.tv_usec = 0;
  1719.  
  1720.     ackwait.tv_sec = 0;
  1721.     ackwait.tv_usec = 500000;
  1722.  
  1723.     gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
  1724.     gapwait.tv_usec = 0;
  1725.  
  1726.     comp_thru = NULL;
  1727.     perrno = 0;
  1728.     nd_pkts = 0;
  1729.     no_pkts = 0;
  1730.     pkt_cid = 0;
  1731.  
  1732.     /* Find first connection ID */
  1733.     if(next_conn_id == 0) {
  1734.     srand(getpid()+time(0));
  1735.     next_conn_id = rand();
  1736.     }
  1737.  
  1738.  
  1739.     /* If necessary, find out what udp port to send to */
  1740.     if (dir_udp_port == 0) {
  1741.         register struct servent *sp;
  1742.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  1743. #ifdef USE_ASSIGNED_PORT
  1744.         if ((sp = getservbyname("prospero","udp")) == 0) {
  1745. #ifdef DEBUG
  1746.         if (pfs_debug)
  1747.         fprintf(stderr, "dirsrv: udp/prospero unknown service - using %d\n", 
  1748.             PROSPERO_PORT);
  1749. #endif
  1750.         dir_udp_port = htons((u_short) PROSPERO_PORT);
  1751.         }
  1752. #else
  1753.         if ((sp = getservbyname("dirsrv","udp")) == 0) {
  1754. #ifdef DEBUG
  1755.         if (pfs_debug)
  1756.         fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %d\n", 
  1757.             DIRSRV_PORT);
  1758. #endif
  1759.         dir_udp_port = htons((u_short) DIRSRV_PORT);
  1760.         }
  1761. #endif
  1762.     else dir_udp_port = sp->s_port;
  1763.     pfs_enable = tmp;
  1764. #ifdef DEBUG
  1765.         if (pfs_debug > 3)
  1766.             fprintf(stderr,"dir_udp_port is %d\n", ntohs(dir_udp_port));
  1767. #endif
  1768.     }
  1769.  
  1770.     /* If we were given the host address, then use it.  Otherwise  */
  1771.     /* lookup the hostname.  If we were passed a host address of   */
  1772.     /* 0, we must lookup the host name, then replace the old value */
  1773.     if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
  1774.     /* I we have a null host name, return an error */
  1775.     if((hostname == NULL) || (*hostname == '\0')) {
  1776. #ifdef DEBUG
  1777.             if (pfs_debug)
  1778.                 fprintf(stderr, "dirsrv: Null hostname specified\n");
  1779. #endif
  1780.         perrno = DIRSEND_BAD_HOSTNAME;
  1781.         ptlfree(pkt);
  1782.             /* return(NULL); */
  1783.         return(-1);
  1784.     }
  1785.     /* If a port is included, save it away */
  1786.     if(openparen = index(hostname,'(')) {
  1787.         sscanf(openparen+1,"%d",&req_udp_port);
  1788.         strncpy(hostnoport,hostname,400);
  1789.         if((openparen - hostname) < 400) {
  1790.         *(hostnoport + (openparen - hostname)) = '\0';
  1791.         hostname = hostnoport;
  1792.         }
  1793.     }
  1794.     tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  1795.         if((host = gethostbyname(hostname)) == NULL) {
  1796.         pfs_enable = tmp;
  1797.         /* Check if a numeric address */
  1798.         newhostaddr = inet_addr(hostname);
  1799.         if(newhostaddr == -1) {
  1800. #ifdef DEBUG
  1801.         if (pfs_debug)
  1802.           fprintf(stderr, "dirsrv: Can't resolve host %s\n",hostname);
  1803. #endif
  1804.         perrno = DIRSEND_BAD_HOSTNAME;
  1805.         ptlfree(pkt);
  1806.         /* return(NULL); */
  1807.         return(-1);
  1808.         }
  1809.         bzero((char *)&to, S_AD_SZ);
  1810.         to.sin_family = AF_INET;
  1811.         bcopy(&newhostaddr, (char *)&to.sin_addr, 4);
  1812.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  1813.     }
  1814.     else {
  1815.         pfs_enable = tmp;
  1816.         bzero((char *)&to, S_AD_SZ);
  1817.         to.sin_family = host->h_addrtype;
  1818.         bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length);
  1819.         if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  1820.     }
  1821.     }
  1822.     else bcopy(hostaddr,&to, S_AD_SZ);
  1823.     /* lmjm: Save away the hostname */
  1824.     strncpy(to_hostname,
  1825.         inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&to.sin_addr),
  1826.         sizeof(to_hostname)-1);
  1827.  
  1828.     if(req_udp_port) to.sin_port = htons(req_udp_port);
  1829.     else to.sin_port = dir_udp_port;
  1830.  
  1831.     /* If a port was specified in hostaddr, use it, otherwise fill it in */
  1832.     if(hostaddr) {
  1833.     if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
  1834.     else hostaddr->sin_port = to.sin_port;
  1835.     }
  1836.  
  1837.     /* Must open a new port each time. we do not want to see old */
  1838.     /* responses to messages we are done with                    */
  1839.     if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  1840. #ifdef DEBUG
  1841.         if (pfs_debug)
  1842.             fprintf(stderr,"dirsrv: Can't open socket\n");
  1843. #endif
  1844.     perrno = DIRSEND_UDP_CANT;
  1845.     ptlfree(pkt);
  1846.         /* return(NULL); */
  1847.     return(-1);
  1848.     }
  1849.  
  1850.     /* Try to bind it to a privileged port - loop through candidate */
  1851.     /* ports trying to bind.  If failed, that's OK, we will let the */
  1852.     /* system assign a non-privileged port later                    */
  1853.     if(!notprived) {
  1854.     for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP; 
  1855.         tmp++) {
  1856.         bzero((char *)&us, sizeof(us));
  1857.         us.sin_family = AF_INET;
  1858.         us.sin_port = htons((u_short) tmp);
  1859.         if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
  1860.         if(errno != EADDRINUSE) {
  1861.             notprived++;
  1862.             break;
  1863.         }
  1864.         }
  1865.         else break;
  1866.     }
  1867.     }
  1868.  
  1869. #ifndef USE_V3_PROT
  1870.     /* Add header */
  1871.     if(rdgram_priority) {
  1872.     pkt->start -= 15;
  1873.     pkt->length += 15;
  1874.     *(pkt->start) = (char) 15;
  1875.     bzero(pkt->start+9,4);
  1876.     *(pkt->start+11) = 0x02;
  1877.     bcopy(&priority,pkt->start+13,2);
  1878.     }
  1879.     else {
  1880.     pkt->start -= 9;
  1881.     pkt->length += 9;
  1882.     *(pkt->start) = (char) 9;
  1883.     }
  1884.     this_conn_id = htons(next_conn_id++);
  1885.     if(next_conn_id == 0) next_conn_id++;
  1886.     bcopy(&this_conn_id,pkt->start+1,2);
  1887.     bcopy(&one,pkt->start+3,2);
  1888.     bcopy(&one,pkt->start+5,2);
  1889.     bzero(pkt->start+7,2);
  1890. #endif
  1891.  
  1892. #ifdef DEBUG
  1893.     if (pfs_debug > 2) {
  1894. #ifndef USE_V3_PROT
  1895.         if (to.sin_family == AF_INET) {
  1896.         if(req_udp_port) 
  1897.         fprintf(stderr,"Sending message to %s+%d(%d)...",
  1898.             to_hostname, req_udp_port, ntohs(this_conn_id));
  1899.         else fprintf(stderr,"Sending message to %s(%d)...",
  1900.              to_hostname, ntohs(this_conn_id));
  1901.     }
  1902. #else
  1903.         if (to.sin_family == AF_INET) 
  1904.         fprintf(stderr,"Sending message to %s...", to_hostname);
  1905. #endif
  1906.         else
  1907.             fprintf(stderr,"Sending message...");
  1908.         (void) fflush(stderr);
  1909.     }
  1910. #endif
  1911.  
  1912.     first = ptalloc();
  1913.     next = first;
  1914.  
  1915. #ifdef XARCHIE
  1916.     status1("Connecting to %s",to_hostname);
  1917. #endif
  1918.     return(lp);
  1919. }
  1920.  
  1921. /*    -    -    -    -    -    -    -    -    */
  1922. /*
  1923.  * This used to be a label to goto to retry the last packet. Now we resend
  1924.  * the packet and call keepWaitingDirsend() to wait for a reply. (We
  1925.  * call keepWaitingDirsend() because formerly the code dropped through
  1926.  * the keep_waiting label.)
  1927.  */
  1928. static void
  1929. retryDirsend()
  1930. {
  1931.     gaps = ackpend = 0;
  1932.  
  1933.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  1934.     if(ns != pkt->length) {
  1935. #ifdef DEBUG
  1936.     if (pfs_debug) {
  1937.     fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  1938.         perror("");
  1939.     }
  1940. #endif
  1941.     close(lp);
  1942.     perrno = DIRSEND_NOT_ALL_SENT;
  1943.     ptlfree(first);
  1944.     ptlfree(pkt);
  1945.     /* return(NULL); */
  1946.     dirsendReturn = NULL;
  1947.     dirsendDone = DSRET_SEND_ERROR;
  1948.     }
  1949. #ifdef DEBUG
  1950.     if (pfs_debug > 2) fprintf(stderr,"Sent.\n");
  1951. #endif
  1952.     keepWaitingDirsend();
  1953. }
  1954.  
  1955. /*    -    -    -    -    -    -    -    -    */
  1956. /*
  1957.  * This used to be a label to goto to set the appropriate timeout value
  1958.  * and blocked in select(). Now we set selwait and the fd_sets to the
  1959.  * appropriate values, and in X register a new timeout, then return to
  1960.  * allow event processing.
  1961.  */
  1962. static void
  1963. keepWaitingDirsend()
  1964. {
  1965.     /* We come back to this point (by a goto) if the packet */
  1966.     /* received is only part of the response, or if the     */
  1967.     /* response came from the wrong host            */
  1968.  
  1969. #ifdef DEBUG
  1970.     if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
  1971. #endif
  1972.     FD_ZERO(&readfds);
  1973.     FD_SET(lp, &readfds);
  1974.  
  1975.     if(ackpend) selwait = &ackwait;
  1976.     else if(gaps) selwait = &gapwait;
  1977.     else selwait = &timeout;
  1978.  
  1979.     addTimeOut();
  1980. }
  1981.  
  1982. /*    -    -    -    -    -    -    -    -    */
  1983. /*
  1984.  * This routine is called when a timeout occurs. It includes the code that
  1985.  * was formerly used when select() returned 0 (indicating a timeout).
  1986.  */
  1987. /*ARGSUSED*/
  1988. static void
  1989. timeoutProc(client_data,id)
  1990. XtPointer client_data;
  1991. XtIntervalId *id;
  1992. {
  1993.     if (gaps || ackpend) { /* Send acknowledgment */
  1994.     /* Acks are piggybacked on retries - If we have received */
  1995.     /* an ack from the server, then the packet sent is only  */
  1996.     /* an ack and the rest of the message will be empty      */
  1997. #ifdef DEBUG
  1998.     if (pfs_debug > 2) {
  1999.             fprintf(stderr,"Acknowledging (%s).\n",
  2000.             (ackpend ? "requested" : "gaps"));
  2001.     }    
  2002. #endif
  2003.     retryDirsend();
  2004.     return;
  2005.     }
  2006.  
  2007.     if (retries-- > 0) {
  2008.     timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
  2009. #ifdef DEBUG
  2010.     if (pfs_debug > 2) {
  2011.             fprintf(stderr,"Timed out.  Setting timeout to %d seconds.\n",
  2012.             timeout.tv_sec);
  2013.     }
  2014. #endif
  2015. #ifdef XARCHIE
  2016.         status1("Timed out -- retrying (%d seconds)",timeout.tv_sec);
  2017. #endif
  2018.     retryDirsend();
  2019.     return;
  2020.     }
  2021.  
  2022. #ifdef DEBUG
  2023.     if (pfs_debug) {
  2024.     fprintf(stderr, "select failed(timeoutProc): readfds=%x ",
  2025.         readfds);
  2026.     perror("");
  2027.     }
  2028. #endif
  2029.     close(lp);
  2030.     perrno = DIRSEND_SELECT_FAILED;
  2031.     ptlfree(first);
  2032.     ptlfree(pkt);
  2033.     /* return(NULL); */
  2034.     dirsendReturn = NULL;
  2035.     dirsendDone = DSRET_TIMEOUT;
  2036. }
  2037.  
  2038. /*    -    -    -    -    -    -    -    -    */
  2039. /*
  2040.  * This function is called whenever there's something to read on the
  2041.  * connection. It includes the code that was run when select() returned
  2042.  * greater than 0 (indicating read ready).
  2043.  */
  2044. /*ARGSUSED*/
  2045. static void
  2046. readProc(client_data,source,id)
  2047. XtPointer client_data;
  2048. int *source;
  2049. XtInputId *id;
  2050. {
  2051.     /* We got something to read, so clear the timer */
  2052.     removeTimeOut();
  2053.  
  2054.     from_sz = sizeof(from);
  2055.     next->start = next->dat;
  2056.     if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
  2057. #ifdef DEBUG
  2058.         if (pfs_debug) perror("recvfrom");
  2059. #endif
  2060.     close(lp);
  2061.     perrno = DIRSEND_BAD_RECV;
  2062.     ptlfree(first);
  2063.     ptlfree(pkt);
  2064.     /* return(NULL) */
  2065.     dirsendReturn = NULL;
  2066.     dirsendDone = DSRET_RECV_ERROR;
  2067.         return;
  2068.     }
  2069.  
  2070.     next->length = nr;
  2071.     
  2072.     *(next->start + next->length) = NULL;
  2073.  
  2074. #ifdef DEBUG
  2075.     if (pfs_debug > 2)
  2076.         fprintf(stderr,"Received packet from %s\n",
  2077.         inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&from.sin_addr));
  2078. #endif
  2079.  
  2080. #ifdef XARCHIE
  2081.     {
  2082.         static int num = 2;
  2083.     if (num == 2)
  2084.         status1("Connected to %s",to_hostname);
  2085.     else
  2086.         status1("Receiving...%c",(num?'+':'*'));
  2087.     num = !num;
  2088.     }
  2089. #endif
  2090.  
  2091.     /* For the current format, if the first byte is less than             */
  2092.     /* 20, then the first two bits are a version number and the next six  */
  2093.     /* are the header length (including the first byte).                  */
  2094.     if((hdr_len = (unsigned char) *(next->start)) < 20) {
  2095.     ctlptr = next->start + 1;
  2096.     next->seq = 0;
  2097.     if(hdr_len >= 3) {     /* Connection ID */
  2098.         bcopy(ctlptr,&stmp,2);
  2099.         if(stmp) pkt_cid = ntohs(stmp);
  2100.         ctlptr += 2;
  2101.     }
  2102.     if(pkt_cid && this_conn_id && (pkt_cid != this_conn_id)) {
  2103.         /* The packet is not for us */
  2104.         /* goto keep_waiting; */
  2105.         keepWaitingDirsend();
  2106.         return;
  2107.     }
  2108.     if(hdr_len >= 5) {    /* Packet number */
  2109.         bcopy(ctlptr,&stmp,2);
  2110.         next->seq = ntohs(stmp);
  2111.         ctlptr += 2;
  2112.     }
  2113.     else { /* No packet number specified, so this is the only one */
  2114.         next->seq = 1;
  2115.         nd_pkts = 1;
  2116.     }
  2117.     if(hdr_len >= 7) {        /* Total number of packets */
  2118.         bcopy(ctlptr,&stmp,2);  /* 0 means don't know      */
  2119.         if(stmp) nd_pkts = ntohs(stmp);
  2120.         ctlptr += 2;
  2121.     }
  2122.     if(hdr_len >= 9) {    /* Receievd through */
  2123.         bcopy(ctlptr,&stmp,2);  /* 1 means received request */
  2124. #ifndef USE_V3_PROT
  2125.         if((stmp) && (ntohs(stmp) == 1)) {
  2126.         /* Future retries will be acks only */
  2127.         pkt->length = 9;
  2128.         bcopy(&zero,pkt->start+3,2);
  2129. #ifdef DEBUG
  2130.         if(pfs_debug > 2) 
  2131.             fprintf(stderr,"Server acked request - retries will be acks only\n");
  2132. #endif
  2133.         }
  2134. #endif
  2135.         ctlptr += 2;
  2136.     }
  2137.     if(hdr_len >= 11) {    /* Backoff */
  2138.         bcopy(ctlptr,&stmp,2);
  2139.         if(stmp) {
  2140.         backoff = ntohs(stmp);
  2141. #ifdef DEBUG
  2142.         if(pfs_debug > 2) 
  2143.             fprintf(stderr,"Backing off to %d seconds\n", backoff);
  2144. #endif
  2145.         timeout.tv_sec = backoff;
  2146.         if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
  2147.             /* Probably a long queue on the server - don't give up */
  2148.             retries = client_dirsrv_retry;
  2149.         }
  2150.         }
  2151.         ctlptr += 2;
  2152.     }
  2153.     if(hdr_len >= 12) {    /* Flags (1st byte) */
  2154.         bcopy(ctlptr,&rdflag11,1);
  2155.         if(rdflag11 & 0x80) {
  2156. #ifdef DEBUG
  2157.         if(pfs_debug > 2) 
  2158.             fprintf(stderr,"Ack requested\n");
  2159. #endif
  2160.         ackpend++;
  2161.         }
  2162.         if(rdflag11 & 0x40) {
  2163. #ifdef DEBUG
  2164.         if(pfs_debug > 2) 
  2165.             fprintf(stderr,"Sequenced control packet\n");
  2166. #endif
  2167.         next->length = -1;
  2168.         scpflag++;
  2169.         }
  2170.         ctlptr += 1;
  2171.     }
  2172.     if(hdr_len >= 13) {    /* Flags (2nd byte) */
  2173.         /* Reserved for future use */
  2174.         bcopy(ctlptr,&rdflag12,1);
  2175.         ctlptr += 1;
  2176.     }
  2177.     if(next->seq == 0) {
  2178.         /* goto keep_waiting; */
  2179.         keepWaitingDirsend();
  2180.         return;
  2181.     }
  2182.     if(next->length >= 0) next->length -= hdr_len;
  2183.     next->start += hdr_len;
  2184.     goto done_old;
  2185.     }
  2186.  
  2187.     pkt_cid = 0;
  2188.  
  2189.     /* if intermediate format (between old and new), then process */
  2190.     /* and go to done_old                                         */
  2191.     ctlptr = next->start + max(0,next->length-20);
  2192.     while(*ctlptr) ctlptr++;
  2193.     /* Control fields start after the terminating null */
  2194.     ctlptr++;
  2195.     /* Until old version are gone, must be 4 extra bytes minimum */
  2196.     /* When no version 3 servers, can remove the -4              */
  2197.     if(ctlptr < (next->start + next->length - 4)) {
  2198.     /* Connection ID */
  2199.     bcopy(ctlptr,&stmp,2);
  2200.     if(stmp) pkt_cid = ntohs(stmp);
  2201.     ctlptr += 2;
  2202.     if(pkt_cid && this_conn_id && (pkt_cid != this_conn_id)) {
  2203.         /* The packet is not for us */
  2204.         /* goto keep_waiting; */
  2205.         keepWaitingDirsend();
  2206.         return;
  2207.     }
  2208.     /* Packet number */
  2209.     if(ctlptr < (next->start + next->length)) {
  2210.         bcopy(ctlptr,&stmp,2);
  2211.         next->seq = ntohs(stmp);
  2212.         ctlptr += 2;
  2213.     }
  2214.     /* Total number of packets */
  2215.     if(ctlptr < (next->start + next->length)) {
  2216.         bcopy(ctlptr,&stmp,2);
  2217.         if(stmp) nd_pkts = ntohs(stmp);
  2218.         ctlptr += 2;
  2219.     }
  2220.     /* Receievd through */
  2221.     if(ctlptr < (next->start + next->length)) {
  2222.         /* Not supported by clients */
  2223.         ctlptr += 2;
  2224.     }
  2225.     /* Backoff */
  2226.     if(ctlptr < (next->start + next->length)) {
  2227.         bcopy(ctlptr,&stmp,2);
  2228.         backoff = ntohs(stmp);
  2229. #ifdef DEBUG
  2230.         if(pfs_debug > 2) 
  2231.         fprintf(stderr,"Backing off to %d seconds\n", backoff);
  2232. #endif
  2233.         if(backoff) timeout.tv_sec = backoff;
  2234.         ctlptr += 2;
  2235.     }
  2236.     if(next->seq == 0) {
  2237.         /* goto keep_waiting; */
  2238.         keepWaitingDirsend();
  2239.         return;
  2240.     }
  2241.     goto done_old;
  2242.  
  2243.     }
  2244.  
  2245.     /* Notes that we have to start searching 11 bytes before the    */
  2246.     /* expected start of the MULTI-PACKET line because the message  */
  2247.     /* might include up to 10 bytes of data after the trailing null */
  2248.     /* The order of those bytes is two bytes each for Connection ID */
  2249.     /* Packet-no, of, Received-through, Backoff                     */
  2250.     seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET"); 
  2251.     if(seqtxt) seqtxt+= 13;
  2252.  
  2253.     if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
  2254.  
  2255.     tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
  2256. #ifdef DEBUG    
  2257.     if (pfs_debug && (tmp == 0)) 
  2258.     fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);    
  2259. #endif
  2260.  done_old:
  2261. #ifdef DEBUG
  2262.     if(pfs_debug > 2) fprintf(stderr,"Packet %d of %d\n",next->seq,nd_pkts);
  2263. #endif
  2264.     if ((first == next) && (no_pkts == 0)) {
  2265.     if(first->seq == 1) {
  2266.         comp_thru = first;
  2267.         /* If only one packet, then return it */
  2268.         if(nd_pkts == 1) goto all_done;
  2269.     }
  2270.     else gaps++;
  2271.     no_pkts = 1;
  2272.     next = ptalloc();
  2273.     /* goto keep_waiting; */
  2274.     keepWaitingDirsend();
  2275.     return;
  2276.     }
  2277.     
  2278.     if(comp_thru && (next->seq <= comp_thru->seq))
  2279.     ptfree(next);
  2280.     else if (next->seq < first->seq) {
  2281.     vtmp = first;
  2282.     first = next;
  2283.     first->next = vtmp;
  2284.     first->previous = NULL;
  2285.     vtmp->previous = first;
  2286.     if(first->seq == 1) comp_thru = first;
  2287.     no_pkts++;
  2288.     }
  2289.     else {
  2290.     vtmp = (comp_thru ? comp_thru : first);
  2291.     while (vtmp->seq < next->seq) {
  2292.         if(vtmp->next == NULL) {
  2293.         vtmp->next = next;
  2294.         next->previous = vtmp;
  2295.         next->next = NULL;
  2296.         no_pkts++;
  2297.         goto ins_done;
  2298.         }
  2299.         vtmp = vtmp->next;
  2300.     }
  2301.     if(vtmp->seq == next->seq)
  2302.         ptfree(next);
  2303.     else {
  2304.         vtmp->previous->next = next;
  2305.         next->previous = vtmp->previous;
  2306.         next->next = vtmp;
  2307.         vtmp->previous = next;
  2308.         no_pkts++;
  2309.     }
  2310.     }   
  2311.  
  2312. ins_done:
  2313.     
  2314.     while(comp_thru && comp_thru->next && 
  2315.       (comp_thru->next->seq == (comp_thru->seq + 1))) {
  2316.     comp_thru = comp_thru->next;
  2317. #ifndef USE_V3_PROT
  2318.     recvd_thru = htons(comp_thru->seq);
  2319.     bcopy(&recvd_thru,pkt->start+7,2); /* Let server know we got it */
  2320. #endif
  2321.     /* We've made progress, so reset retry count */
  2322.     retries = client_dirsrv_retry;
  2323.     /* Also, next retry will be only an acknowledgement */
  2324.     /* but for now, we can't fill in the ack field      */
  2325. #ifdef DEBUG
  2326.     if(pfs_debug > 2) 
  2327.         fprintf(stderr,"Packets now received through %d\n",comp_thru->seq);
  2328. #endif
  2329.     }
  2330.  
  2331.     /* See if there are any gaps */
  2332.     if(!comp_thru || comp_thru->next) gaps++;
  2333.     else gaps = 0;
  2334.  
  2335.     if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
  2336.     next = ptalloc();
  2337.     /* goto keep_waiting; */
  2338.     keepWaitingDirsend();
  2339.     return;
  2340.     }
  2341.  
  2342.  all_done:
  2343.     if(ackpend) { /* Send acknowledgement if requested */
  2344. #ifdef DEBUG
  2345.     if (pfs_debug > 2) {
  2346.         if (to.sin_family == AF_INET)
  2347.         fprintf(stderr,"Acknowledging final packet to %s(%d)\n",
  2348.             to_hostname, ntohs(this_conn_id));
  2349.             else
  2350.                 fprintf(stderr,"Acknowledging final packet\n");
  2351.         (void) fflush(stderr);
  2352.     }
  2353. #endif
  2354.     ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  2355.     if(ns != pkt->length) {
  2356. #ifdef DEBUG
  2357.         if (pfs_debug) {
  2358.         fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  2359.         perror("");
  2360.         }
  2361. #endif
  2362.     }
  2363.  
  2364.     }
  2365.     close(lp);
  2366.     ptlfree(pkt);
  2367.  
  2368.     /* Get rid of any sequenced control packets */
  2369.     if(scpflag) {
  2370.     while(first && (first->length < 0)) {
  2371.         vtmp = first;
  2372.         first = first->next;
  2373.         if(first) first->previous = NULL;
  2374.         ptfree(vtmp);
  2375.     }
  2376.     vtmp = first;
  2377.     while(vtmp && vtmp->next) {
  2378.         if(vtmp->next->length < 0) {
  2379.         if(vtmp->next->next) {
  2380.             vtmp->next = vtmp->next->next;
  2381.             ptfree(vtmp->next->previous);
  2382.             vtmp->next->previous = vtmp;
  2383.         }
  2384.         else {
  2385.             ptfree(vtmp->next);
  2386.             vtmp->next = NULL;
  2387.         }
  2388.         }
  2389.         vtmp = vtmp->next;
  2390.     }
  2391.     }
  2392.  
  2393.     /* return(first); */
  2394.     dirsendReturn = first;
  2395.     dirsendDone = DSRET_DONE;
  2396.  
  2397. }
  2398. /*    -    -    -    -    -    -    -    -    */
  2399. /* These routines allow dirsend() to run with or without X by providing
  2400.  * wrappers around the calls that handle the asynchronous communication.
  2401.  * All parameters are passed using globals.
  2402.  * Under X: The input sources and timeouts are set using Xt calls, and
  2403.  *        processEvent() just calls XtAppProcessEvent().
  2404.  * Non-X: None of the input sources and timeouts are used, and
  2405.  *      processEvent() calls select() to handle both timeouts and the
  2406.  *      socket file descriptor. The return value of select() is used
  2407.  *      to determine which callback routine to call.
  2408.  */
  2409.  
  2410. static void
  2411. addInputSource()
  2412. {
  2413. #ifdef XARCHIE
  2414.     inputId = XtAppAddInput(appContext,lp,XtInputReadMask,readProc,NULL);
  2415. #endif
  2416. }
  2417.  
  2418. static void
  2419. removeInputSource()
  2420. {
  2421. #ifdef XARCHIE
  2422.     XtRemoveInput(inputId);
  2423. #endif
  2424. }
  2425.  
  2426. static void
  2427. addTimeOut()
  2428. {
  2429. #ifdef XARCHIE
  2430.     unsigned long timeoutLen = selwait->tv_sec*1000 + selwait->tv_usec/1000;
  2431.  
  2432.     /* old timeout can still be there if we are being called after the
  2433.      * file descriptor was read, so we remove it just to be sure. */
  2434.     removeTimeOut();
  2435.     timerId = XtAppAddTimeOut(appContext,timeoutLen,timeoutProc,NULL);
  2436. #endif
  2437. }
  2438.  
  2439. static void
  2440. removeTimeOut()
  2441. {
  2442. #ifdef XARCHIE
  2443.     if (timerId != (XtIntervalId)0) {
  2444.     XtRemoveTimeOut(timerId);
  2445.     timerId = (XtIntervalId)0;
  2446.     }
  2447. #endif
  2448. }
  2449.  
  2450. static void
  2451. processEvent()
  2452. {
  2453. #ifdef XARCHIE
  2454.     XtAppProcessEvent(appContext,XtIMAll);
  2455. #else
  2456.     /* select - either recv is ready, or timeout */
  2457.     /* see if timeout or error or wrong descriptor */
  2458.     tmp = select(lp + 1, &readfds, (fd_set *)0, (fd_set *)0, selwait);
  2459.     if (tmp == 0) {
  2460.     timeoutProc(NULL,&timerId);
  2461.     } else if ((tmp < 0) || !FD_ISSET(lp,&readfds)) {
  2462. #ifdef DEBUG
  2463.     if (pfs_debug) {
  2464.         fprintf(stderr, "select failed(processEvent): readfds=%x ",
  2465.             readfds);
  2466.         perror("");
  2467.     }
  2468. #endif
  2469.     close(lp);
  2470.     perrno = DIRSEND_SELECT_FAILED;
  2471.     ptlfree(first);
  2472.     ptlfree(pkt);
  2473.     /* return(NULL); */
  2474.     dirsendReturn = NULL;
  2475.     dirsendDone = DSRET_SELECT_ERROR;
  2476.     } else {
  2477.     readProc(NULL,&lp,&inputId);
  2478.     }
  2479. #endif /* XARCHIE */
  2480. }
  2481.  
  2482. void
  2483. abortDirsend()
  2484. {
  2485.     if (!dirsendDone) {
  2486.     close(lp);
  2487.     ptlfree(first);
  2488.     ptlfree(pkt);
  2489.     dirsendReturn = NULL;
  2490.     dirsendDone = DSRET_ABORTED;
  2491.     }
  2492.     return;
  2493. }
  2494. $EOD
  2495. $!
  2496. $CREATE [.archie]get_pauth.c
  2497. $DECK
  2498. /*
  2499.  * Copyright (c) 1989, 1990 by the University of Washington
  2500.  *
  2501.  * For copying and distribution information, please see the file
  2502.  * <copyright.h>.
  2503.  *
  2504.  * v1.2.2 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  2505.  * v1.2.1 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  2506.  * v1.2.0 - 09/17/91 (bpk) - fixed it up (thanks to synful)
  2507.  * v1.1.1 - 08/30/91 (bpk) - added VMS support
  2508.  */
  2509.  
  2510. #include <copyright.h>
  2511. #include <stdio.h>
  2512. #ifndef VMS
  2513. # include <sys/types.h> /* this may/will define FD_SET etc */
  2514. # include <pmachine.h>
  2515. #endif
  2516.  
  2517. #ifdef NEED_STRING_H
  2518. # include <string.h>
  2519. #else
  2520. # include <strings.h>
  2521. #endif
  2522.  
  2523. #ifndef VMS
  2524. # if defined(MSDOS) && !defined(OS2)
  2525. #  include <rwconf.h>
  2526. # else
  2527. #  include <pwd.h>
  2528. # endif
  2529. #else
  2530. # include <jpidef.h>
  2531. # include <vms.h>
  2532. #endif
  2533.  
  2534. #include <pcompat.h>
  2535. #include <pauthent.h>
  2536.  
  2537. PAUTH
  2538. get_pauth(type)
  2539.     int        type;
  2540.     {
  2541.     static PAUTH_ST   no_auth_st;
  2542.     static PAUTH          no_auth = NULL;
  2543. #if !defined(VMS) && !defined(MSDOS) || defined(OS2)
  2544.     struct passwd *whoiampw;
  2545. #else
  2546.     char username[13];
  2547.     unsigned short usernamelen;
  2548.     struct {
  2549.         unsigned short buflen;
  2550.         unsigned short itmcod;
  2551.         char *bufadr;
  2552.         unsigned short *retlenadr;
  2553.         unsigned long null;
  2554.     } jpi_itemlist;
  2555. #endif
  2556.  
  2557.     if(no_auth == NULL) {
  2558.         no_auth = &no_auth_st;
  2559.         strcpy(no_auth->auth_type,"UNAUTHENTICATED");
  2560.  
  2561.         /* find out who we are */
  2562. #ifndef VMS
  2563. #if defined(MSDOS) && !defined(OS2)
  2564.         if (!getconf("general", "user", no_auth->authenticator, 250)
  2565.         || (strlen (no_auth->authenticator) == 0))
  2566.           strcpy(no_auth->authenticator,"nobody");
  2567. #else /* not MSDOS */
  2568.         DISABLE_PFS(whoiampw = getpwuid(getuid()));
  2569.         if (whoiampw == 0) strcpy(no_auth->authenticator,"nobody");
  2570.         else strcpy(no_auth->authenticator, whoiampw->pw_name);
  2571. #endif /* not MSDOS */
  2572. #else
  2573.         jpi_itemlist.buflen = sizeof(username);
  2574.         jpi_itemlist.itmcod = JPI$_USERNAME;
  2575.         jpi_itemlist.bufadr = &username;
  2576.         jpi_itemlist.retlenadr = &usernamelen;
  2577.         jpi_itemlist.null = 0;
  2578.         if (SYS$GETJPI(0, 0, 0, &jpi_itemlist, 0, 0, 0) & 0x1)
  2579.         {
  2580.         username[usernamelen] = 0;
  2581.         strcpy(no_auth->authenticator, username);
  2582.         } else
  2583.         strcpy(no_auth->authenticator, "nobody");
  2584. #endif
  2585.     }
  2586.     return(no_auth);
  2587.     }
  2588. $EOD
  2589. $!
  2590. $CREATE [.archie]get_vdir.c
  2591. $DECK
  2592. /*
  2593.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  2594.  *
  2595.  * For copying and distribution information, please see the file
  2596.  * <copyright.h>.
  2597.  *
  2598.  * v1.2.2 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  2599.  * v1.2.1 - 10/23/91 (bpk) - added missing code
  2600.  * v1.2.0 - 09/17/91 (bpk) - added new get_vdir code
  2601.  * v1.1.1 - 08/30/91 (bpk) - cast rindex()
  2602.  */
  2603.  
  2604. #include <copyright.h>
  2605. #include <stdio.h>
  2606.  
  2607. #include <pfs.h>
  2608. #include <pprot.h>
  2609. #include <perrno.h>
  2610. #include <pcompat.h>
  2611. #include <pauthent.h>
  2612. #include <pmachine.h>
  2613.  
  2614. #ifdef NEED_STRING_H
  2615. # include <string.h>
  2616. #else
  2617. # include <strings.h>
  2618. #endif
  2619.  
  2620. #ifdef DEBUG
  2621. extern int    pfs_debug;
  2622. #endif
  2623.  
  2624. extern int    pwarn;
  2625. extern char    p_warn_string[];
  2626. extern int    perrno;
  2627. extern char    p_err_string[];
  2628.  
  2629. /*
  2630.  * get_vdir - Get contents of a directory given its location
  2631.  *
  2632.  *          GET_VDIR takes a directory location, a list of desired
  2633.  *          components, a pointer to a directory structure to be 
  2634.  *          filled in, and flags.  It then queries the appropriate 
  2635.  *          directory server and retrieves the desired information.
  2636.  *
  2637.  *      ARGS:   dhost       - Host on which directory resides
  2638.  *              dfile       - Directory on that host
  2639.  *              components  - The names from the directory we want
  2640.  *        dir        - Structure to be filled in
  2641.  *            flags       - Options.  See FLAGS
  2642.  *        filters     - filters to be applied to result 
  2643.  *              acomp       - Pointer to remaining components
  2644.  *
  2645.  *     FLAGS:    GVD_UNION   - Do not expand union links
  2646.  *        GVD_EXPAND  - Expand union links locally
  2647.  *        GVD_REMEXP  - Request remote expansion (& local if refused)
  2648.  *        GVD_LREMEXP - Request remote expansion of local union links
  2649.  *        GVD_VERIFY  - Only verify that args are for a directory
  2650.  *              GVD_ATTRIB  - Request attributes from directory server
  2651.  *              GVD_NOSORT  - Do not sort links when adding to directory
  2652.  *
  2653.  *   RETURNS:   PSUCCESS (0) or error code
  2654.  *        On some codes addition information in p_err_string
  2655.  *
  2656.  *     NOTES:   If acomp is non-null the string it points to might be modified
  2657.  *
  2658.  *              If the directory passed as an argument already has
  2659.  *        links or union links, then those lists will be freed
  2660.  *              before the new contents are filled in.
  2661.  *
  2662.  *              If a filter is passed to the procedure, and application of
  2663.  *              the filter results in additional union link, then those links
  2664.  *              will (or will not) be expanded as specified in the FLAGS field.
  2665.  *
  2666.  *              If the list of components in NULL, or the null string, then
  2667.  *              get_vdir will return all links in the requested directory.
  2668.  *
  2669.  *      BUGS:   Doesn't process union links yet
  2670.  *              Doesn't process errors returned from server
  2671.  *        Doesn't expand union links if requested to
  2672.  */
  2673. int
  2674. get_vdir(dhost,dfile,components,dir,flags,filters,acomp)
  2675.     char    *dhost;        /* Host on which directory resides           */
  2676.     char    *dfile;        /* Name of file on that host                 */
  2677.     char    *components;    /* Component name (wildcards allowed)        */
  2678.     VDIR    dir;        /* Structure to be filled in             */
  2679.     long    flags;        /* Flags                         */
  2680.     VLINK    filters;    /* Filters to be applied to result           */
  2681.     char    *acomp;        /* Components left to be resolved            */
  2682.     {
  2683.         PTEXT    request;    /* Text of request to dir server             */
  2684.     PTEXT    resp;            /* Response from dir server                 */
  2685.  
  2686.     char    ulcomp[MAX_VPATH];/* Work space for new current component    */
  2687.     char    *comp = components;
  2688.  
  2689.     VLINK    cur_link = NULL;/* Current link being filled in              */
  2690.     VLINK     exp = NULL;     /* The current ulink being expanded         */
  2691.     VLINK    pul = NULL;     /* Prev union link (insert new one after it) */
  2692.     VLINK    l;        /* Temp link pointer                  */
  2693.     int    mcomp;        /* Flag - check multiple components          */
  2694.     int    unresp;        /* Flag - received unresolved response       */
  2695.     int    getattrib = 0;  /* Get attributes from server                */
  2696.     int    vl_insert_flag; /* Flags to vl_insert                        */
  2697.  
  2698.     int    fwdcnt = MAX_FWD_DEPTH;
  2699.  
  2700.     int    no_links = 0;   /* Count of number of links found         */
  2701.  
  2702.     char    options[40];    /* LIST option                               */
  2703.     char    *opt;           /* After leading +                           */
  2704.  
  2705.     PAUTH    authinfo;
  2706.  
  2707.     /* Treat null string like NULL (return entire directory) */
  2708.     if(!components || !*components) comp = NULL;
  2709.  
  2710.     if(acomp && !filters) mcomp = 1;
  2711.     else mcomp = 0;
  2712.  
  2713.     if(flags&GVD_ATTRIB) {
  2714.         getattrib++;
  2715.         flags &= (~GVD_ATTRIB);
  2716.     }
  2717.  
  2718.     if(flags&GVD_NOSORT) vl_insert_flag = VLI_NOSORT;
  2719.     else vl_insert_flag = VLI_ALLOW_CONF;
  2720.     flags &= (~GVD_NOSORT);
  2721.  
  2722.     if(filters) comp = NULL;
  2723.  
  2724.     perrno = 0;
  2725.  
  2726.     authinfo = get_pauth(PFSA_UNAUTHENTICATED);
  2727.  
  2728.     *options = '\0';
  2729.  
  2730.     if(getattrib) {
  2731.         strcat(options,"+ATTRIBUTES");
  2732.         flags &= (~GVD_ATTRIB);
  2733.     }
  2734.  
  2735.     if(!filters) { /* Can't do remote expansion if filters to be applied */
  2736.         if(flags == GVD_REMEXP) strcat(options,"+EXPAND");
  2737.         if(flags == GVD_LREMEXP) strcat(options,"+LEXPAND");
  2738.     }
  2739.  
  2740.     /* If all we are doing is verifying that dfile is a directory */
  2741.     /* then we do not want a big response from the directory      */
  2742.     /* server.  A NOT-FOUND is sufficient.                  */
  2743.     if(flags == GVD_VERIFY)
  2744. #ifdef NEWVERIFYOPT
  2745.         strcat(options,"+VERIFY");
  2746. #else
  2747.     comp = "%#$PRobably_nOn_existaNT$#%";
  2748. #endif
  2749.  
  2750.     if(*options) opt = options+1;
  2751.     else opt = "''";
  2752.  
  2753.     startover:
  2754.     request = ptalloc();
  2755.  
  2756.     sprintf(request->start,
  2757.         "VERSION %d\nAUTHENTICATOR %s %s\nDIRECTORY ASCII %s\nLIST %s COMPONENTS %s%s%s\n",
  2758.         VFPROT_VNO, authinfo->auth_type, authinfo->authenticator,
  2759.         dfile,opt, (comp ? comp : ""), (mcomp ? "/" : ""),
  2760.         (mcomp ? acomp : ""));
  2761.  
  2762.     request->length = strlen(request->start);
  2763.  
  2764. #ifdef DEBUG
  2765.     if(pfs_debug > 2)
  2766.         fprintf(stderr,"Sending message to dirsrv:\n%s",request->start);
  2767. #endif
  2768.  
  2769. #if defined(MSDOS)
  2770.     resp = dirsend(request,dhost,0L);
  2771. #else
  2772.     resp = dirsend(request,dhost,0);
  2773. #endif
  2774.  
  2775. #ifdef DEBUG
  2776.     if(pfs_debug && (resp == NULL)) {
  2777.         fprintf(stderr,"Dirsend failed: %d\n",perrno);
  2778.     }
  2779. #endif
  2780.  
  2781.     /* If we don't get a response, then if the requested       */
  2782.     /* directory, return error, if a ulink, mark it unexpanded */
  2783.     if(resp == NULL) {
  2784.         if(exp) exp->expanded = FAILED;
  2785.         else return(perrno);
  2786.     }
  2787.  
  2788.     unresp = 0;
  2789.  
  2790.     /* Here we must parse reponse and put in directory */
  2791.     /* While looking at each packet            */
  2792.     while(resp) {
  2793.         PTEXT        vtmp;
  2794.         char        *line;
  2795.  
  2796.         vtmp = resp;
  2797. #ifdef DEBUG
  2798.         if(pfs_debug > 3) fprintf(stderr,"%s\n",resp->start);
  2799. #endif
  2800.         /* Look at each line in packet */
  2801.         for(line = resp->start;line != NULL;line = nxtline(line)) {
  2802.         switch (*line) {
  2803.             
  2804.             /* Temporary variables to hold link info */
  2805.             char    l_linktype;
  2806.             char     l_name[MAX_DIR_LINESIZE];
  2807.             char    l_type[MAX_DIR_LINESIZE];
  2808.             char     l_htype[MAX_DIR_LINESIZE];
  2809.             char     l_host[MAX_DIR_LINESIZE];
  2810.             char     l_ntype[MAX_DIR_LINESIZE];
  2811.             char     l_fname[MAX_DIR_LINESIZE];
  2812.             int        l_version;
  2813.             char     t_unresolved[MAX_DIR_LINESIZE];
  2814.             int        l_magic;
  2815.             int        tmp;
  2816.  
  2817.         case 'L': /* LINK or LINK-INFO */
  2818.             if(strncmp(line,"LINK-INFO",9) == 0) {
  2819.             PATTRIB        at;
  2820.             PATTRIB        last_at;
  2821.             at = parse_attribute(line);
  2822.             if(!at) break;
  2823.  
  2824.             /* Cant have link info without a link */
  2825.             if(!cur_link) {
  2826.                 perrno = DIRSRV_BAD_FORMAT;
  2827.                 atfree(at);
  2828.                 break;
  2829.             }
  2830.             
  2831.             if(cur_link->lattrib) {
  2832.                 last_at = cur_link->lattrib;
  2833.                 while(last_at->next) last_at = last_at->next;
  2834.                 at->previous = last_at;
  2835.                 last_at->next = at;
  2836.             }
  2837.             else {
  2838.                 cur_link->lattrib = at;
  2839.                 at->previous = NULL;
  2840.             }
  2841.             break;
  2842.             }
  2843.  
  2844.             /* Not LINK-INFO, must be LINK - if not check for error */
  2845.             if(strncmp(line,"LINK",4) != 0) goto scanerr;
  2846.  
  2847.             /* If only verifying, don't want to change dir */
  2848.             if(flags == GVD_VERIFY) {
  2849.             break;
  2850.             }
  2851.             /* If first link and some links in dir, free them */
  2852.             if(!no_links++) {
  2853.             if(dir->links) vllfree(dir->links); dir->links=NULL;
  2854.             if(dir->ulinks) vllfree(dir->ulinks); dir->ulinks=NULL;
  2855.             }
  2856.             
  2857.             cur_link = vlalloc();
  2858.  
  2859.             /* parse and insert file info */
  2860.             tmp = sscanf(line,"LINK %c %s %s %s %s %s %s %d %d", &l_linktype,
  2861.                  l_type, l_name, l_htype, l_host, 
  2862.                  l_ntype, l_fname, &(cur_link->version),
  2863.                  &(cur_link->f_magic_no));
  2864.  
  2865.             if(tmp != 9) {
  2866.             perrno = DIRSRV_BAD_FORMAT;
  2867.             vlfree(cur_link);
  2868.             break;
  2869.             }
  2870.  
  2871.             cur_link->linktype = l_linktype;
  2872.             cur_link->type = stcopyr(l_type,cur_link->type);
  2873.             cur_link->name = stcopyr(unquote(l_name),cur_link->name);
  2874.             cur_link->hosttype = stcopyr(l_htype,cur_link->hosttype);
  2875.             cur_link->host = stcopyr(l_host,cur_link->host);
  2876.             cur_link->nametype = stcopyr(l_ntype,cur_link->nametype);
  2877.             cur_link->filename = stcopyr(l_fname,cur_link->filename);
  2878.  
  2879.             /* Double check to make sure we don't get */
  2880.             /* back unwanted components              */
  2881.             /* OK to keep if special (URP) links      */
  2882.             /* or if mcomp specified                  */
  2883.             if(!mcomp && (cur_link->linktype == 'L') && 
  2884.                (!wcmatch(cur_link->name,comp))) {
  2885.             vlfree(cur_link);
  2886.             break;
  2887.             }
  2888.  
  2889.             /* If other optional info was sent back, it must */
  2890.             /* also be parsed before inserting link     ***  */
  2891.             
  2892.             
  2893.             if(cur_link->linktype == 'L') 
  2894.             vl_insert(cur_link,dir,vl_insert_flag);
  2895.             else {
  2896.             tmp = ul_insert(cur_link,dir,pul);
  2897.  
  2898.             /* If inserted after pul, next one after cur_link */
  2899.             if(pul && (!tmp || (tmp == UL_INSERT_SUPERSEDING)))
  2900.                 pul = cur_link;
  2901.             }
  2902.             
  2903.             break;
  2904.  
  2905.         case 'F': /* FILTER, FAILURE or FORWARDED*/
  2906.             /* FORWARDED */
  2907.             if(strncmp(line,"FORWARDED",9) == 0) {
  2908.             if(fwdcnt-- <= 0) {
  2909.                 ptlfree(resp);
  2910.                 perrno = PFS_MAX_FWD_DEPTH;
  2911.                 return(perrno);
  2912.             }
  2913.             /* parse and start over */
  2914.  
  2915.             tmp = sscanf(line,"FORWARDED %s %s %s %s %d %d", 
  2916.                      l_htype,l_host,l_ntype,l_fname,
  2917.                      &l_version, &l_magic);
  2918.  
  2919.             dhost = stcopy(l_host);
  2920.             dfile = stcopy(l_fname);
  2921.  
  2922.             if(tmp < 4) {
  2923.                 perrno = DIRSRV_BAD_FORMAT;
  2924.                 break;
  2925.             }
  2926.  
  2927.             ptlfree(resp);
  2928.             goto startover;
  2929.             }
  2930.             if(strncmp(line,"FILTER",6) != 0) goto scanerr;
  2931.             break;
  2932.  
  2933.  
  2934.         case 'M': /* MULTI-PACKET (processed by dirsend) */
  2935.         case 'P': /* PACKET (processed by dirsend) */
  2936.             break;
  2937.  
  2938.         case 'N': /* NOT-A-DIRECTORY or NONE-FOUND */
  2939.             /* NONE-FOUND, we just have no links to insert */
  2940.             /* It is not an error, but we must clear any   */
  2941.             /* old links in the directory arg              */
  2942.             if(strncmp(line,"NONE-FOUND",10) == 0) {
  2943.             /* If only verifying, don't want to change dir */
  2944.             if(flags == GVD_VERIFY) {
  2945.                 break;
  2946.             }
  2947.  
  2948.             /* If first link and some links in dir, free them */
  2949.             if(!no_links++) {
  2950.                 if(dir->links) vllfree(dir->links);
  2951.                 if(dir->ulinks) vllfree(dir->ulinks);
  2952.                 dir->links = NULL;
  2953.                 dir->ulinks = NULL;
  2954.             }
  2955.             break;
  2956.             }
  2957.             /* If NOT-A-DIRECTORY or anything else, scan error */
  2958.             goto scanerr;
  2959.  
  2960.         case 'U': /* UNRESOLVED */
  2961.             if(strncmp(line,"UNRESOLVED",10) != 0) {
  2962.             goto scanerr;
  2963.             }
  2964.             tmp = sscanf(line,"UNRESOLVED %s", t_unresolved);
  2965.             if(tmp < 1) {
  2966.             perrno = DIRSRV_BAD_FORMAT;
  2967.             break;
  2968.             }
  2969.             /* If multiple components were resolved */
  2970.             if(strlen(t_unresolved) < strlen(acomp)) {
  2971.             strcpy(ulcomp,acomp);
  2972.             /* ulcomp is the components that were resolved */
  2973.             *(ulcomp+strlen(acomp)-strlen(t_unresolved)-1) = '\0';
  2974.             /* Comp gets the last component resolved */
  2975.             comp = (char *) rindex(ulcomp,'/');
  2976.             if(comp) comp++;
  2977.             else comp = ulcomp;
  2978.             /* Let rd_vdir know what remains */
  2979.             strcpy(acomp,t_unresolved);
  2980.             }
  2981.             unresp = 1;
  2982.             break;
  2983.  
  2984.         case 'V': /* VERSION-NOT-SUPPORTED */
  2985.             if(strncmp(line,"VERSION-NOT-SUPPORTED",21) == 0) {
  2986.             perrno = DIRSRV_BAD_VERS;
  2987.             return(perrno);
  2988.             }
  2989.             goto scanerr;
  2990.  
  2991.         scanerr:
  2992.         default:
  2993.             if(*line && (tmp = scan_error(line))) {
  2994.             ptlfree(resp);
  2995.             return(tmp);
  2996.             }
  2997.             break;
  2998.         }
  2999.         }
  3000.  
  3001.         resp = resp->next;
  3002.  
  3003.         ptfree(vtmp);
  3004.     }
  3005.  
  3006.     /* We sent multiple components and weren't told any */
  3007.     /* were unresolved                                  */
  3008.     if(mcomp && !unresp) {
  3009.         /* ulcomp is the components that were resolved */
  3010.         strcpy(ulcomp,acomp);
  3011.         /* Comp gets the last component resolved */
  3012.         comp = (char *) rindex(ulcomp,'/');
  3013.         if(comp) comp++;
  3014.         else comp = ulcomp;
  3015.         /* If we have union links to resolve, only one component remains */
  3016.         mcomp = 0;
  3017.         /* Let rd_vdir know what remains */
  3018.         *acomp = '\0';
  3019.     }
  3020.  
  3021.     /* If only verifying, we already know it is a directory */
  3022.     if(flags == GVD_VERIFY) return(PSUCCESS);
  3023.  
  3024.     /* Don't return if matching was delayed by the need to filter    */
  3025.     /* if FIND specified, and dir->links is non null, then we have   */
  3026.     /* found a match, and should return.                             */
  3027.     if((flags & GVD_FIND) && dir->links && (!filters))
  3028.         return(PSUCCESS);
  3029.  
  3030.     /* If expand specified, and ulinks must be expanded, making sure */
  3031.         /* that the order of the links is maintained properly            */
  3032.  
  3033. expand_ulinks:
  3034.  
  3035.     if((flags != GVD_UNION) && (flags != GVD_VERIFY)) {
  3036.  
  3037.         l = dir->ulinks;
  3038.  
  3039.         /* Find first unexpanded ulink */
  3040.         while(l && l->expanded && (l->linktype == 'U')) l = l->next;
  3041.         
  3042.         /* Only expand if a FILE or DIRECTORY -  Mark as  */
  3043.             /* failed otherwise                               */
  3044.         /* We must still add support for symbolic ulinks */
  3045.         if(l) {
  3046.         if ((strcmp(l->type,"DIRECTORY") == 0) || 
  3047.             (strcmp(l->type,"FILE") == 0)) {
  3048.             l->expanded = TRUE;
  3049.             exp = l;
  3050.             pul = l;
  3051.             dhost = l->host;
  3052.             dfile = l->filename;
  3053.             goto startover; /* was get_contents; */
  3054.         }
  3055.         else l->expanded = FAILED;
  3056.         }
  3057.     }
  3058.  
  3059.     /* Double check to make sure we don't get */
  3060.     /* back unwanted components          */
  3061.     /* OK to keep if special (URP) links      */
  3062.     if(components && *components) {
  3063.         l = dir->links;
  3064.         while(l) {
  3065.         VLINK    ol;
  3066.         if((l->linktype == 'L') && (!wcmatch(l->name,components))) {
  3067.             if(l == dir->links)
  3068.             dir->links = l->next;
  3069.             else l->previous->next = l->next;
  3070.             if(l->next) l->next->previous = l->previous;
  3071.             ol = l;
  3072.             l = l->next;
  3073.             vlfree(ol);
  3074.         }
  3075.         else l = l->next;
  3076.         }
  3077.     }
  3078.  
  3079.     return(PSUCCESS);
  3080.     }
  3081. $EOD
  3082. $!
  3083. $CREATE [.archie]make.com
  3084. $DECK
  3085. $!
  3086. $! MAKE.COM - build the Archie client for VMS (5.4-2, others?)
  3087. $!            for MultiNet TCP/IP, v2.2 & 3.0, and Wallongong 5.xx+
  3088. $!
  3089. $! v1.2.1 - 11/12/91 (bpk) - use option files
  3090. $! v1.2   - 09/25/91 (bpk) - ported to Wallongong
  3091. $!        - 09/20/91 (bpk) - fixed up strings.h stuff, etc
  3092. $! v1.1   - 09/17/91 (bpk) - works with 3.0 now
  3093. $! v1.0   - 08/30/91 (bpk) - Original
  3094. $!
  3095. $! * If you're running Multinet 3.0, leave this alone.  If you're
  3096. $! running any version of Multinet less than 3.0 (e.g. 2.2), comment
  3097. $! it out.
  3098. $ mdef := ,multinet_30=1
  3099. $! * If you're running Wallongong TCP, uncomment this.
  3100. $!wall := ,wallongong=1
  3101. $! * Type @MAKE now.
  3102. $!
  3103. $!-----
  3104. $ ve := f$verify(0)
  3105. $ set noverify
  3106. $ on error then goto hell
  3107. $ echo := write sys$output
  3108. $!
  3109. $ cc := cc/opt=noinline
  3110. $ deb := /define=(debug=1,funcs=1,noregex=1'mdef 'wall)
  3111. $!cdeb := /debug
  3112. $ if f$trnlnm("GNU_CC") .nes. "" then cc := gcc/optimize
  3113. $!
  3114. $ if f$search("strings.h") .nes. "" then delete/nolog/noconfirm []strings.h;*
  3115. $ if "''cc'" .nes. "GCC" then copy/noconfirm sys$library:string.h []strings.h
  3116. $!
  3117. $ echo "Compiling aquery.c..."
  3118. $ 'cc/include=([])'deb 'cdeb    aquery.c
  3119. $ echo "Compiling archie.c..."
  3120. $ 'cc/include=([])'deb 'cdeb    archie.c
  3121. $ echo "Compiling atalloc.c..."
  3122. $ 'cc/include=([])'deb 'cdeb    atalloc.c
  3123. $! Expect one warning with dirsend.c.
  3124. $ echo "Compiling dirsend.c (expect a warning) ..."
  3125. $ 'cc/include=([])'deb 'cdeb    dirsend.c
  3126. $ echo "Compiling get_pauth.c..."
  3127. $ 'cc/include=([])'deb 'cdeb    get_pauth.c
  3128. $ echo "Compiling get_vdir.c..."
  3129. $ 'cc/include=([])'deb 'cdeb    get_vdir.c
  3130. $ echo "Compiling perrmesg.c..."
  3131. $ 'cc/include=([])'deb 'cdeb    perrmesg.c
  3132. $ echo "Compiling procquery.c..."
  3133. $ 'cc/include=([])'deb 'cdeb    procquery.c
  3134. $ echo "Compiling ptalloc.c..."
  3135. $ 'cc/include=([])'deb 'cdeb    ptalloc.c
  3136. $ echo "Compiling regex.c..."
  3137. $ 'cc/include=([])'deb 'cdeb    regex.c
  3138. $ echo "Compiling stcopy.c..."
  3139. $ 'cc/include=([])'deb 'cdeb    stcopy.c
  3140. $ echo "Compiling support.c..."
  3141. $ 'cc/include=([])'deb 'cdeb    support.c
  3142. $ echo "Compiling vlalloc.c..."
  3143. $ 'cc/include=([])'deb 'cdeb    vlalloc.c
  3144. $ echo "Compiling vl_comp.c..."
  3145. $ 'cc/include=([])'deb 'cdeb    vl_comp.c
  3146. $ do_vs := ,
  3147. $ if "''mdef'" .nes. "" then libs := [.vms]multi
  3148. $ if "''wall'" .nes. "" then libs := [.vms]wall
  3149. $ if "''mdef'" .eqs. "" .and. "''wall'" .eqs. "" then gosub dosup
  3150. $!
  3151. $ echo "Linking..."
  3152. $ link'cdeb/exe=archie aquery+archie+atalloc+-
  3153. dirsend+get_pauth+get_vdir+-
  3154. perrmesg+procquery+ptalloc+regex+stcopy+support+vlalloc+vl_comp'do_vs-
  3155. 'libs/option
  3156. $ out:
  3157. $ echo "Done! Define the symbol ARCHIE & fire away."
  3158. $!
  3159. $ hell:
  3160. $ if 've .eq. 1 then set verify
  3161. $ exit
  3162. $!
  3163. $ dosup:
  3164. $ echo "Compiling vms_support.c ..."
  3165. $ 'cc/include=([])'deb 'cdeb    vms_support.c
  3166. $ do_vs := +vms_support,
  3167. $! Multinet 2.2 still needs to get the resolving stuff.
  3168. $ libs := [.vms]multi
  3169. $ return
  3170. $EOD
  3171. $!
  3172. $CREATE [.archie]makefile.dos
  3173. $DECK
  3174. #
  3175. # Last changed: 11/20/91, v1.2
  3176. #
  3177. # Makefile for the minimal build for an archie Prospero client.
  3178. #.INCLUDE ../../../builtins
  3179.  
  3180. OBJS    = aquery.lo    archie.lo    atalloc.lo    dirsend.lo    \
  3181.       get_pauth.lo    get_vdir.lo    perrmesg.lo    procquery.lo    \
  3182.       ptalloc.lo    regex.lo    stcopy.lo    support.lo    \
  3183.       vlalloc.lo    vl_comp.lo
  3184. HDRS    = archie.h    pmachine.h    pcompat.h
  3185.  
  3186. DEFINES    = -DDEBUG -DNOREGEX -DUSG
  3187.  
  3188. CFLAGS    = -Oeclgsz -Gs -Zi -W4 -I. $(DEFINES)
  3189.  
  3190. EXE    = archie.exe
  3191.  
  3192. all: $(EXE)
  3193.  
  3194. $(OBJS): $(HDRS)
  3195.  
  3196. $(EXE): $(OBJS) Makefile archie.lnk
  3197.     link @archie.lnk
  3198.     exepack archie.unp archie.exe
  3199.  
  3200. clean:
  3201.     +-del *.lo
  3202.     +-del *.exe
  3203.  
  3204. $EOD
  3205. $!
  3206. $CREATE [.archie]makefile.os2
  3207. $DECK
  3208. #
  3209. # Last changed: 11/20/91, v1.2
  3210. #
  3211. # Makefile for the minimal build for an archie Prospero client.
  3212. .INCLUDE ../../../builtins
  3213.  
  3214. OBJS    = aquery.obj    archie.obj    atalloc.obj    dirsend.obj    \
  3215.       get_pauth.obj    get_vdir.obj    perrmesg.obj    procquery.obj    \
  3216.       ptalloc.obj    regex.obj    stcopy.obj    support.obj    \
  3217.       vlalloc.obj    vl_comp.obj
  3218. HDRS    = archie.h    pmachine.h    pcompat.h
  3219.  
  3220. DEFINES    = -DDEBUG -DNOREGEX
  3221.  
  3222. IFLAGS    = -I. -I../../../include $(DEFINES)
  3223.  
  3224. LFLAGS     = /stack:30000/nod/noe/noi/map/CO
  3225. LIBS    = pctcp bsd ftpcrt socket os2
  3226. EXE    = archie.exe
  3227.  
  3228. all: $(EXE)
  3229.  
  3230. install: $(EXE)
  3231.     cp $[m,*.exe,$**] ..\..\..\bin
  3232.     @touch install
  3233.  
  3234. $(OBJS): $(HDRS)
  3235.  
  3236. $(EXE): $(OBJS) Makefile
  3237.     $(LD) $(LFLAGS) $(L_DEBUG) <@<
  3238. $[s,"+ \n",$[m,*.obj,$**]]
  3239. $*
  3240. $*
  3241. $(LIBS)
  3242.  
  3243. <
  3244.     +markexe lfns $@
  3245.     +markexe windowcompat $@
  3246.  
  3247. clean:
  3248.     +-del *.obj
  3249.     +-del *.exe
  3250.  
  3251. $EOD
  3252. $!
  3253. $CREATE [.archie]perrmesg.c
  3254. $DECK
  3255. /*
  3256.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3257.  *
  3258.  * For copying and distribution information, please see the file
  3259.  * <copyright.h>.
  3260.  */
  3261.  
  3262. #include <copyright.h>
  3263. #include <perrno.h>
  3264. #include <stdio.h>
  3265.  
  3266. /* This file and perrno.h should always be updated simultaneously */
  3267.  
  3268. int    perrno = 0;
  3269. int    pwarn = 0;
  3270. char    p_err_string[P_ERR_STRING_SZ];
  3271. char    p_warn_string[P_ERR_STRING_SZ];
  3272.  
  3273. char    *p_err_text[256] = {
  3274.     /*   0 */ "Success (prospero)",
  3275.     /*   1 */ "Port unknown (dirsend)",
  3276.     /*   2 */ "Can't open local UDP port (dirsend)",
  3277.     /*   3 */ "Can't resolve hostname (dirsend)",
  3278.     /*   4 */ "Unable to send entire message (dirsend)",
  3279.     /*   5 */ "Timed out (dirsend)",
  3280.     /*   6 */ "Recvfrom failed (dirsend)",
  3281.     /*   7 */ "",    /*   8 */ "",    /*   9 */ "",    /*  10 */ "",
  3282.     /*  11 */ "Sendto failed (reply)",
  3283.     /*  12 */ "",    /*  13 */ "",    /*  14 */ "",    /*  15 */ "",
  3284.     /*  16 */ "",    /*  17 */ "",    /*  18 */ "",    /*  19 */ "",
  3285.     /*  20 */ "",
  3286.     /*  21 */ "Link already exists (vl_insert)",
  3287.     /*  22 */ "Link with same name already exists (vl_insert)",
  3288.     /*  23 */ "",    /*  24 */ "",
  3289.     /*  25 */ "Link already exists (ul_insert)",
  3290.     /*  26 */ "Replacing existing link (ul_insert)",
  3291.     /*  27 */ "Previous entry not found in dir->ulinks (ul_insert)",
  3292.     /*  28 */ "",    /*  29 */ "",    /*  30 */ "",    /*  31 */ "",
  3293.     /*  32 */ "",    /*  33 */ "",    /*  34 */ "",    /*  35 */ "",
  3294.     /*  36 */ "",    /*  37 */ "",    /*  38 */ "",    /*  39 */ "",
  3295.     /*  40 */ "",
  3296.     /*  41 */ "Temporary not found (rd_vdir)",
  3297.     /*  42 */ "Namespace not closed with object (rd_vdir)",
  3298.     /*  43 */ "Alias for namespace not defined (rd_vdir)",
  3299.     /*  44 */ "Specified namespace not found (rd_vdir)",
  3300.     /*  45 */ "",    /*  46 */ "",    /*  47 */ "",    /*  48 */ "",
  3301.     /*  49 */ "",    /*  50 */ "",
  3302.     /*  51 */ "File access method not supported (pfs_access)",
  3303.     /*  52 */ "",    /*  53 */ "",    /*  54 */ "",
  3304.     /*  55 */ "Pointer to cached copy - delete on close (pmap_cache)",
  3305.     /*  56 */ "Unable to retrieve file (pmap_cache)",
  3306.     /*  57 */ "",    /*  58 */ "",    /*  59 */ "",    /*  60 */ "",
  3307.     /*  61 */ "Directory already exists (mk_vdir)",
  3308.     /*  62 */ "Link with same name already exists (mk_vdir)",
  3309.     /*  63 */ "",    /*  64 */ "",
  3310.     /*  65 */ "Not a virtual system (vfsetenv)",
  3311.     /*  66 */ "Can't find directory (vfsetenv)",
  3312.     /*  67 */ "",    /*  68 */ "",    /*  69 */ "",    /*  70 */ "",
  3313.     /*  71 */ "Link already exists (add_vlink)",
  3314.     /*  72 */ "Link with same name already exists (add_vlink)",
  3315.     /*  73 */ "",    /*  74 */ "",    /*  75 */ "",    /*  76 */ "",
  3316.     /*  77 */ "",    /*  78 */ "",    /*  79 */ "",    /*  80 */ "",
  3317.     /*  81 */ "",    /*  82 */ "",    /*  83 */ "",    /*  84 */ "",
  3318.     /*  85 */ "",    /*  86 */ "",    /*  87 */ "",    /*  88 */ "",
  3319.     /*  89 */ "",    /*  90 */ "",    /*  91 */ "",    /*  92 */ "",
  3320.     /*  93 */ "",    /*  94 */ "",    /*  95 */ "",    /*  96 */ "",
  3321.     /*  97 */ "",    /*  98 */ "",    /*  99 */ "",    /* 100 */ "",
  3322.     /* 101 */ "",    /* 102 */ "",    /* 103 */ "",    /* 104 */ "",
  3323.     /* 105 */ "",    /* 106 */ "",    /* 107 */ "",    /* 108 */ "",
  3324.     /* 109 */ "",    /* 110 */ "",    /* 111 */ "",    /* 112 */ "",
  3325.     /* 113 */ "",    /* 114 */ "",    /* 115 */ "",    /* 116 */ "",
  3326.     /* 117 */ "",    /* 118 */ "",    /* 119 */ "",    /* 120 */ "",
  3327.     /* 121 */ "",    /* 122 */ "",    /* 123 */ "",    /* 124 */ "",
  3328.     /* 125 */ "",    /* 126 */ "",    /* 127 */ "",    /* 128 */ "",
  3329.     /* 129 */ "",    /* 130 */ "",    /* 131 */ "",    /* 132 */ "",
  3330.     /* 133 */ "",    /* 134 */ "",    /* 135 */ "",    /* 136 */ "",
  3331.     /* 137 */ "",    /* 138 */ "",    /* 139 */ "",    /* 140 */ "",
  3332.     /* 141 */ "",    /* 142 */ "",    /* 143 */ "",    /* 144 */ "",
  3333.     /* 145 */ "",    /* 146 */ "",    /* 147 */ "",    /* 148 */ "",
  3334.     /* 149 */ "",    /* 150 */ "",    /* 151 */ "",    /* 152 */ "",
  3335.     /* 153 */ "",    /* 154 */ "",    /* 155 */ "",    /* 156 */ "",
  3336.     /* 157 */ "",    /* 158 */ "",    /* 159 */ "",    /* 160 */ "",
  3337.     /* 161 */ "",    /* 162 */ "",    /* 163 */ "",    /* 164 */ "",
  3338.     /* 165 */ "",    /* 166 */ "",    /* 167 */ "",    /* 168 */ "",
  3339.     /* 169 */ "",    /* 170 */ "",    /* 171 */ "",    /* 172 */ "",
  3340.     /* 173 */ "",    /* 174 */ "",    /* 175 */ "",    /* 176 */ "",
  3341.     /* 177 */ "",    /* 178 */ "",    /* 179 */ "",    /* 180 */ "",
  3342.     /* 181 */ "",    /* 182 */ "",    /* 183 */ "",    /* 184 */ "",
  3343.     /* 185 */ "",    /* 186 */ "",    /* 187 */ "",    /* 188 */ "",
  3344.     /* 189 */ "",    /* 190 */ "",    /* 191 */ "",    /* 192 */ "",
  3345.     /* 193 */ "",    /* 194 */ "",    /* 195 */ "",    /* 196 */ "",
  3346.     /* 197 */ "",    /* 198 */ "",    /* 199 */ "",    /* 200 */ "",
  3347.     /* 201 */ "",    /* 202 */ "",    /* 203 */ "",    /* 204 */ "",
  3348.     /* 205 */ "",    /* 206 */ "",    /* 207 */ "",    /* 208 */ "",
  3349.     /* 209 */ "",    /* 210 */ "",    /* 211 */ "",    /* 212 */ "",
  3350.     /* 213 */ "",    /* 214 */ "",    /* 215 */ "",    /* 216 */ "",
  3351.     /* 217 */ "",    /* 218 */ "",    /* 219 */ "",    /* 220 */ "",
  3352.     /* 221 */ "",    /* 222 */ "",    /* 223 */ "",    /* 224 */ "",
  3353.     /* 225 */ "",    /* 226 */ "",    /* 227 */ "",    /* 228 */ "",
  3354.     /* 229 */ "",
  3355.     /* 230 */ "File not found (prospero)",
  3356.     /* 231 */ "Directory not found (prospero)",
  3357.     /* 232 */ "Symbolic links nested too deep (prospero)",
  3358.     /* 233 */ "Environment not initialized - source vfsetup.source then run vfsetup",
  3359.     /* 234 */ "Can't traverse an external file (prospero)",
  3360.     /* 235 */ "Forwarding chain is too long (prospero)",
  3361.     /* 236 */ "",    /* 237 */ "",    /* 238 */ "",    /* 239 */ "",
  3362.     /* 240 */ "",    /* 241 */ "",
  3363.     /* 242 */ "Authentication required (prospero server)",
  3364.     /* 243 */ "Not authorized (prospero server)",
  3365.     /* 244 */ "Not found (prospero server)",
  3366.     /* 245 */ "Bad version number (prospero server)",
  3367.     /* 246 */ "Not a directory (prospero server)",
  3368.     /* 247 */ "Already exists (prospero server)",
  3369.     /* 248 */ "Link with same name already exists (prospero server)",
  3370.     /* 249 */ "",    /* 250 */ "",
  3371.     /* 251 */ "Command not implemented on server (dirsrv)",
  3372.     /* 252 */ "Bad format for response (dirsrv)",
  3373.     /* 253 */ "Protocol error (prospero server)",
  3374.     /* 254 */ "Unspecified server failure (prospero server)",
  3375.     /* 255 */ "Generic Failure (prospero)"};
  3376.  
  3377. char    *p_warn_text[256] = {
  3378.     /*   0 */ "No warning",
  3379.     /*   1 */ "You are using an old version of this program",
  3380.     /*   2 */ "From server",
  3381.     /*   3 */ "Unrecognized line in response from server",
  3382.   /* 4-254 */ "", "", "", "", "", "", "", "", "", "", "", "", "",
  3383.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3384.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3385.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3386.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3387.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3388.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3389.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3390.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3391.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3392.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3393.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3394.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3395.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3396.   "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
  3397.     /* 255 */ ""};
  3398.  
  3399. #ifndef ARCHIE
  3400. perrmesg(prefix,no,text)
  3401.     char    *prefix;
  3402.     int        no;
  3403.     char    *text;
  3404.     {
  3405.     fprintf(stderr,"%s%s%s%s\n", (prefix ? prefix : ""),
  3406.         (no ? p_err_text[no] : p_err_text[perrno]),
  3407.         ((text ? (*text ? " - " : "") : 
  3408.           (!no && *p_err_string ? " - " : ""))),
  3409.         (text ? text : (no ? "" : p_err_string)));
  3410.     }
  3411.  
  3412. sperrmesg(buf,prefix,no,text)
  3413.     char    *buf;
  3414.     char    *prefix;
  3415.     int        no;
  3416.     char    *text;
  3417.     {
  3418.     sprintf(buf,"%s%s%s%s\n", (prefix ? prefix : ""),
  3419.         (no ? p_err_text[no] : p_err_text[perrno]),
  3420.         ((text ? (*text ? " - " : "") : 
  3421.           (!no && *p_err_string ? " - " : ""))),
  3422.         (text ? text : (no ? "" : p_err_string)));
  3423.     }
  3424.  
  3425. pwarnmesg(prefix,no,text)
  3426.     char    *prefix;
  3427.     int        no;
  3428.     char    *text;
  3429.     {
  3430.     fprintf(stderr,"%s%s%s%s\n", (prefix ? prefix : ""),
  3431.         (no ? p_warn_text[no] : p_warn_text[pwarn]),
  3432.         ((text ? (*text ? " - " : "") : 
  3433.           (!no && *p_warn_string ? " - " : ""))),
  3434.         (text ? text : (no ? "" : p_warn_string)));
  3435.     }
  3436.  
  3437. spwarnmesg(buf,prefix,no,text)
  3438.     char    *buf;
  3439.     char    *prefix;
  3440.     int        no;
  3441.     char    *text;
  3442.     {
  3443.     sprintf(buf,"%s%s%s%s\n", (prefix ? prefix : ""),
  3444.         (no ? p_warn_text[no] : p_warn_text[pwarn]),
  3445.         ((text ? (*text ? " - " : "") : 
  3446.           (!no && *p_warn_string ? " - " : ""))),
  3447.         (text ? text : (no ? "" : p_warn_string)));
  3448.     }
  3449. #endif
  3450. $EOD
  3451. $!
  3452. $CREATE [.archie]patchlevel.h
  3453. $DECK
  3454. /*
  3455.  * Archie v1.2
  3456.  *
  3457.  * History:
  3458.  *
  3459.  * 11/20/91 v1.2 - Release.
  3460.  * 11/18/91      - ported to DOS & OS/2
  3461.  * 11/12/91      - finally got to test under Multinet 3.0
  3462.  * 10/03/91      - replaced regex.c for oz
  3463.  * 09/25/91     - added Wallongong support
  3464.  * 08/30/91      - ported to VMS
  3465.  * 08/20/91 v1.1 - Major revisions
  3466.  * 07/31/91 v1.0 - Original
  3467.  */
  3468. $EOD
  3469. $!
  3470. $CREATE [.archie]pauthent.h
  3471. $DECK
  3472. /*
  3473.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3474.  *
  3475.  * For copying and distribution information, please see the file
  3476.  * <copyright.h>.
  3477.  */
  3478.  
  3479. #include <copyright.h>
  3480.  
  3481. #define PFSA_UNAUTHENTICATED        1
  3482.  
  3483. struct pfs_auth_info {
  3484.     char            auth_type[100];
  3485.     char            authenticator[250];
  3486. };
  3487.  
  3488. typedef struct pfs_auth_info *PAUTH;
  3489. typedef struct pfs_auth_info PAUTH_ST;
  3490.  
  3491. PAUTH get_pauth();
  3492.  
  3493. #ifndef VMS
  3494. # ifndef IN_H
  3495. #  include <netinet/in.h>
  3496. #  define IN_H
  3497. # endif
  3498. #else
  3499. # ifndef _ARCHIE_VMS
  3500. #  include <vms.h>
  3501. # endif
  3502. #endif
  3503.  
  3504. struct client_info {
  3505.     int                ainfo_type;
  3506.     char            *auth_type;
  3507.     char            *authenticator;
  3508.     char            *userid;
  3509.     short            port;
  3510.     struct in_addr        haddr;
  3511.     struct pfs_auth_info    *previous;
  3512.     struct pfs_auth_info    *next;
  3513. };
  3514.  
  3515. typedef struct client_info *CINFO;
  3516. typedef struct client_info CINFO_ST;
  3517. $EOD
  3518. $!
  3519. $CREATE [.archie]pcompat.h
  3520. $DECK
  3521. /*
  3522.  * Copyright (c) 1989, 1990 by the University of Washington
  3523.  *
  3524.  * For copying and distribution information, please see the file
  3525.  * <copyright.h>.
  3526.  */
  3527.  
  3528. #include <copyright.h>
  3529.  
  3530. /* 
  3531.  * pcompat.h - Definitions for compatability library
  3532.  *
  3533.  * This file contains the defintions used by the compatability
  3534.  * library.  Among the definitions are the possible values for
  3535.  * pfs_disable_flag.  This file also contains the external 
  3536.  * declaration of that variable.  Note, however that the 
  3537.  * the module pfs_disable_flag.o is included in libpfs.a
  3538.  * because some of the routines in that library set it.
  3539.  * The only place it is checked, however, is in pfs_access, 
  3540.  * found in libpcompat.a
  3541.  *
  3542.  */
  3543.  
  3544. extern    int        pfs_default;
  3545. extern    int        pfs_enable;
  3546.  
  3547. /* Definitions for values of pfs_enable */
  3548. #define PMAP_DISABLE      0
  3549. #define PMAP_ENABLE       1
  3550. #define PMAP_COLON      2
  3551. #define PMAP_ATSIGN_NF      3
  3552. #define PMAP_ATSIGN      4
  3553.  
  3554. #define DISABLE_PFS(stmt) {int DpfStmp; DpfStmp = pfs_enable;\
  3555.                pfs_enable = PMAP_DISABLE; \
  3556.                stmt; \
  3557.                pfs_enable = DpfStmp;}
  3558.  
  3559. /* Definitions for PFS_ACCESS */
  3560. #define PFA_MAP           0  /* Map the file name only                       */
  3561. #define PFA_CREATE        1  /* Create file if not found                     */
  3562. #define PFA_CRMAP         2  /* Map file name.  Map to new name if not found */
  3563. #define PFA_RO            4  /* Access to file is read only                  */
  3564.  
  3565. #define check_pfs_default() if(pfs_default == -1) get_pfs_default()
  3566. $EOD
  3567. $!
  3568. $CREATE [.archie]perrno.h
  3569. $DECK
  3570. /*
  3571.  * Copyright (c) 1989, 1990 by the University of Washington
  3572.  *
  3573.  * For copying and distribution information, please see the file
  3574.  * <copyright.h>.
  3575.  */
  3576.  
  3577. #include <copyright.h>
  3578.  
  3579. /* this file and p_err_text.c should be updated simultaneously */
  3580.  
  3581. /*
  3582.  * perrno.h - definitions for perrno
  3583.  *
  3584.  * This file contains the declarations and defintions of of the external
  3585.  * error values in which errors are returned by the pfs and psrv
  3586.  * libraries.
  3587.  */
  3588.  
  3589. #define        P_ERR_STRING_SZ 100     /* Size of error string        */
  3590.  
  3591. extern int    perrno;
  3592. extern char    p_err_string[];
  3593. extern char    *p_err_text[];
  3594.  
  3595. extern int    pwarn;
  3596. extern char    p_warn_string[];
  3597. extern char    *p_warn_text[];
  3598.  
  3599. /* Error codes returned or found in verrno */
  3600.  
  3601. #ifndef PSUCCESS
  3602. #define    PSUCCESS        0
  3603. #endif
  3604.  
  3605. /* dirsend (perrno) */
  3606. #define DIRSEND_PORT_UNKN    1    /* DIRSRV UDP port unknown      */
  3607. #define DIRSEND_UDP_CANT    2    /* Can't open local UDP port    */
  3608. #define DIRSEND_BAD_HOSTNAME    3    /* Can't resolve hostname       */
  3609. #define DIRSEND_NOT_ALL_SENT    4    /* Didn't send entire message   */
  3610. #define DIRSEND_SELECT_FAILED    5    /* Select failed            */
  3611. #define DIRSEND_BAD_RECV    6    /* Recvfrom failed             */
  3612.  
  3613. /* reply */
  3614. #define REPLY_NOTSENT        11    /* Reply: sendto failed            */
  3615.  
  3616. /* vl_insert */
  3617. #define VL_INSERT_ALREADY_THERE    21    /* Link already exists            */
  3618. #define VL_INSERT_CONFLICT    22    /* Link exists with same name   */
  3619.  
  3620. /* ul_insert */
  3621. #define UL_INSERT_ALREADY_THERE 25    /* Link already exists        */
  3622. #define UL_INSERT_SUPERSEDING   26    /* Replacing existing link    */
  3623. #define UL_INSERT_POS_NOTFOUND  27    /* Prv entry not in dir->ulinks */
  3624.  
  3625. /* rd_vdir */
  3626. #define RVD_DIR_NOT_THERE    41    /* Temporary NOT_FOUND            */
  3627. #define RVD_NO_CLOSED_NS    42    /* Namespace not closed w/ object:: */
  3628. #define RVD_NO_NS_ALIAS        43    /* No alias for namespace NS#:      */
  3629. #define RVD_NS_NOT_FOUND    44    /* Specified namespace not found    */
  3630.  
  3631. /* pfs_access */
  3632. #define PFSA_AM_NOT_SUPPORTED   51      /* Access method not supported  */
  3633.  
  3634. /* pmap_cache */
  3635. #define PMC_DELETE_ON_CLOSE     55    /* Delete cached copy on close   */
  3636. #define PMC_RETRIEVE_FAILED     56      /* Unable to retrieve file       */
  3637.  
  3638. /* mk_vdir */
  3639. /* #define MKVD_ALREADY_EXISTS     61    /* Directory already exists      */
  3640. /* #define MKVD_NAME_CONFLICT    62    /* Link with name already exists */
  3641.  
  3642. /* vfsetenv */
  3643. #define VFSN_NOT_A_VS        65    /* Not a virtual system          */
  3644. #define VFSN_CANT_FIND_DIR    66    /* Not a virtual system          */
  3645.  
  3646. /* add_vlink */
  3647. /* #define ADDVL_ALREADY_EXISTS    71    /* Directory already exists      */
  3648. /* #define ADDVL_NAME_CONFLICT    72    /* Link with name already exists */
  3649.  
  3650. /* Local error codes on server */
  3651.  
  3652. /* dsrdir */
  3653. #define DSRDIR_NOT_A_DIRECTORY 111    /* Not a directory name        */
  3654. /* dsrfinfo */
  3655. #define DSRFINFO_NOT_A_FILE    121      /* Object not found             */
  3656. #define DSRFINFO_FORWARDED     122      /* Object has moved             */
  3657.  
  3658. /* Error codes that may be returned by various procedures               */
  3659. #define PFS_FILE_NOT_FOUND     230      /* File not found               */
  3660. #define PFS_DIR_NOT_FOUND      231      /* Directory in path not found  */
  3661. #define PFS_SYMLINK_DEPTH      232    /* Max sym-link depth exceeded  */
  3662. #define PFS_ENV_NOT_INITIALIZED    233    /* Can't read environment    */
  3663. #define PFS_EXT_USED_AS_DIR    234    /* Can't use externals as dirs  */
  3664. #define PFS_MAX_FWD_DEPTH      235    /* Exceeded max forward depth   */
  3665.  
  3666. /* Error codes returned by directory server                    */
  3667. /* some of these duplicate errors from individual routines     */
  3668. /* some of those error codes should be eliminated              */
  3669. #define DIRSRV_AUTHENT_REQ     242      /* Authentication required       */
  3670. #define DIRSRV_NOT_AUTHORIZED  243      /* Not authorized                */
  3671. #define DIRSRV_NOT_FOUND       244      /* Not found                     */
  3672. #define DIRSRV_BAD_VERS        245
  3673. #define DIRSRV_NOT_DIRECTORY   246
  3674. #define DIRSRV_ALREADY_EXISTS  247    /* Identical link already exists */
  3675. #define DIRSRV_NAME_CONFLICT   248    /* Link with name already exists */
  3676.  
  3677. #define DIRSRV_UNIMPLEMENTED   251      /* Unimplemented command         */
  3678. #define DIRSRV_BAD_FORMAT      252
  3679. #define DIRSRV_ERROR           253
  3680. #define DIRSRV_SERVER_FAILED   254      /* Unspecified server failure    */
  3681.  
  3682. #ifndef PFAILURE
  3683. #define    PFAILURE            255
  3684. #endif
  3685.  
  3686. /* Warning codes */
  3687.  
  3688. #define PNOWARN             0    /* No warning indicated         */
  3689. #define PWARN_OUT_OF_DATE     1    /* Software is out of date       */
  3690. #define PWARN_MSG_FROM_SERVER     2      /* Warning in p_warn_string      */
  3691. #define PWARN_UNRECOGNIZED_RESP  3    /* Unrecognized line in response */
  3692. #define PWARNING           255    /* Warning in p_warn_string      */
  3693. $EOD
  3694. $!
  3695. $CREATE [.archie]pfs.h
  3696. $DECK
  3697. /*
  3698.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  3699.  *
  3700.  * For copying and distribution information, please see the file
  3701.  * <copyright.h>.
  3702.  *
  3703.  * v1.2.0 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  3704.  * v1.1.2 - 08/30/91 (bpk) - added VMS support
  3705.  * v1.1.1 - 08/20/91 (bpk) - 4.2 -> 4.2B
  3706.  */
  3707.  
  3708. #include <copyright.h>
  3709.  
  3710. #ifdef VMS
  3711. # include <vms.h>
  3712. #else /* not VMS */
  3713. # ifndef _TYPES_
  3714. #  include <sys/types.h>
  3715. # endif /* _TYPES_ */
  3716. # ifndef IN_H
  3717. #  include <netinet/in.h> 
  3718. #  define IN_H
  3719. # endif
  3720. #endif /* VMS */
  3721.  
  3722. #ifndef NULL
  3723. # if defined(MSDOS)
  3724. #  include <stdio.h>
  3725. # else
  3726. #  define NULL 0
  3727. # endif /* MSDOS */
  3728. #endif /* NULL */
  3729.  
  3730. #define        PFS_RELEASE    "Beta.4.2D"
  3731. /* moved up for vdir_init */
  3732. #define ZERO(p)        bzero((char *)(p), sizeof(*(p)))
  3733.  
  3734. /* General Definitions */
  3735.  
  3736. #define        MAX_PTXT_LEN    1250     /* Max length of PTEXT structure   */
  3737. #define        MAX_PTXT_HDR    32       /* Max offset for start            */
  3738. #define        P_ERR_STRING_SZ 100     /* Size of error string        */
  3739. #define        MAX_VPATH    1024     /* Max length of virtual pathname  */
  3740.  
  3741. /* Definition of text structure used to pass text around */
  3742.  
  3743. struct ptext {
  3744.     int            length;          /* Length of text (from start)    */
  3745.     char        *start;          /* Start of text            */
  3746.     char        dat[MAX_PTXT_LEN+2*MAX_PTXT_HDR];/* The data itself */
  3747.     unsigned long     mbz;          /* ZERO to catch runaway strings  */
  3748.     struct ptext    *previous;        /* Previous element in list       */
  3749.     struct ptext    *next;          /* Next element in linked list    */
  3750.     int            seq;          /* Sequence Number            */
  3751. };
  3752.  
  3753. typedef struct ptext *PTEXT;
  3754. typedef struct ptext PTEXT_ST;
  3755.  
  3756. /* Request structure: maintains information about server requests */
  3757. struct preq {
  3758.     int            cid;          /* Connection ID                  */
  3759.     short        priority;      /* Connection priority            */
  3760.     int            pf_priority;      /* Priority assigned by pri_func  */
  3761.     int            recv_tot;      /* Total # of packets received    */
  3762.     int            trns_tot;      /* Total # of packets to transmit */
  3763.     struct ptext    *cpkt;          /* Current packet being filled in */
  3764.     struct ptext    *recv;          /* Received packets               */
  3765.     struct ptext    *trns;          /* Transmitted packets            */
  3766.     int            rcvd_thru;      /* Received all packets through # */
  3767.     struct preq        *previous;        /* Previous element in list       */
  3768.     struct preq        *next;          /* Next element in linked list    */
  3769.     struct sockaddr_in    fromto;       /* Sender/Destination            */
  3770. };
  3771.  
  3772. typedef struct preq *PREQ;
  3773. typedef struct preq PREQ_ST;
  3774.  
  3775.  
  3776. /* Definition of structure containing information on virtual link */
  3777.  
  3778. struct vlink {
  3779.     int            dontfree;      /* Flag: don't free this link     */
  3780.     char        *name;          /* Component of path name        */
  3781.     char        linktype;      /* L = Link, U = Union, N= Native */
  3782.     int            expanded;      /* Has a union link been expanded */
  3783.     char        *type;            /* Type of object pointed to      */
  3784.     struct vlink    *filters;      /* Filters associated with link   */
  3785.     struct vlink    *replicas;      /* Replicas (* see comment below) */
  3786.     char        *hosttype;      /* Type of hostname            */
  3787.     char        *host;          /* Files physical location        */
  3788.     char        *nametype;      /* Type of filename            */
  3789.     char        *filename;      /* System level filename        */
  3790.     long        version;      /* Version number of destination  */
  3791.     long        f_magic_no;      /* File's magic number        */
  3792.     struct acl        *acl;          /* ACL for link            */
  3793.     long        dest_exp;      /* Expiration for dest of link    */
  3794.     long        link_exp;      /* Expiration of link itself      */
  3795.     char        *args;          /* Arguments if this is a filter  */
  3796.     struct pattrib    *lattrib;      /* Attributes associated w/ link  */
  3797.     struct pfile    *f_info;      /* Info to be assoicated w/ file  */
  3798.     struct vlink    *previous;        /* Previous elt in linked list    */
  3799.     struct vlink    *next;          /* Next element in linked list    */
  3800. };
  3801.  
  3802. typedef struct vlink *VLINK;
  3803. typedef struct vlink VLINK_ST;
  3804.  
  3805. /* * Note that vlink->replicas is not really a list of replicas of the  */
  3806. /*   object.  Instead, it is a list of the objects returned during name */
  3807. /*   resolution that share the same name as the current object.  Such   */
  3808. /*   an object should only be considered a replica if it also shares    */
  3809. /*   the same non-zero magic number.                                    */
  3810.  
  3811. /* Definition of structure continiaing virtual directory information    */
  3812.  
  3813. struct vdir {
  3814.     int            version;      /* Version of local directory fmt  */
  3815.     int            inc_native;      /* Include the native directory    */
  3816.     long        magic_no;      /* Magic number of current file    */
  3817.     struct acl        *dacl;            /* Default acl for links in dir    */
  3818.     struct pfile    *f_info;      /* Directory file info             */
  3819.     struct vlink    *links;          /* The directory entries         */
  3820.     struct vlink    *lastlink;      /* Last directory entry            */
  3821.     struct vlink    *ulinks;      /* The entries for union links     */
  3822.     struct vdir        *previous;        /* Previous element in linked list */
  3823.     struct vdir        *next;          /* Next element in linked list     */
  3824. };
  3825.  
  3826. typedef struct vdir *VDIR;
  3827. typedef struct vdir VDIR_ST;
  3828.  
  3829. /* Initialize directory */
  3830. #define vdir_init(dir)  ZERO(dir)
  3831. /* XXX: was
  3832.  
  3833.   dir->version = 0;     dir->inc_native = 0; \
  3834.   dir->magic_no = 0;    dir->f_info = NULL; \
  3835.   dir->links = NULL;    dir->lastlink = NULL; \
  3836.   dir->ulinks = NULL;   dir->dacl = NULL; \
  3837.   dir->previous = NULL; dir->next = NULL;
  3838. */
  3839.  
  3840. #define vdir_copy(d1,d2) d2->version = d1->version; \
  3841.                          d2->inc_native = d1->inc_native; \
  3842.                          d2->magic_no = d1->magic_no; \
  3843.                  d2->f_info = d1->f_info; \
  3844.                          d2->links = d1->links; \
  3845.                          d2->lastlink = d1->lastlink; \
  3846.                          d2->ulinks = d1->ulinks; \
  3847.                          d2->dacl = d1->dacl; \
  3848.                          d2->previous = d1->previous; \
  3849.                          d2->next = d1->next; 
  3850.                          
  3851. /* Values of ->inc_native in vdir structure */
  3852. #define VDIN_REALONLY    -1   /* Include native files, but not . and ..       */
  3853. #define VDIN_NONATIVE     0   /* Do not include files from native directory   */
  3854. #define VDIN_INCLNATIVE     1   /* Include files from native directory          */
  3855. #define VDIN_NATIVEONLY  2   /* All entries in directory are from native dir */
  3856. #define VDIN_PSEUDO      3   /* Directory is not real                        */
  3857.  
  3858.  
  3859. /* Definition of structure containing information on a specific file */
  3860.  
  3861. union avalue {
  3862.     char        *ascii;        /* Character string                */
  3863.     struct vlink    *link;        /* A link               */
  3864. };
  3865.  
  3866.  
  3867. struct pattrib {
  3868.     char        precedence;    /* Precedence for link attribute   */
  3869.     char        *aname;        /* Name of the attribute           */
  3870.     char        *avtype;    /* Type of the attribute value     */
  3871.     union avalue    value;        /* Attribute Value                 */
  3872.     struct pattrib    *previous;      /* Previous element in linked list */
  3873.     struct pattrib    *next;        /* Next element in linked list     */
  3874. };
  3875.  
  3876. typedef struct pattrib *PATTRIB;
  3877. typedef struct pattrib PATTRIB_ST;
  3878.  
  3879. #define     ATR_PREC_OBJECT  'O'   /* Authoritative answer for object */
  3880. #define     ATR_PREC_LINK    'L'   /* Authoritative answer for link   */
  3881. #define     ATR_PREC_CACHED  'C'   /* Object info cached w/ link      */
  3882. #define     ATR_PREC_REPLACE 'R'   /* From link (replaces O)          */
  3883. #define     ATR_PREC_ADD     'A'   /* From link (additional value)    */
  3884.  
  3885. /* **** Incomplete **** */
  3886. struct pfile {
  3887.     int            version;      /* Version of local finfo format   */
  3888.     long        f_magic_no;      /* Magic number of current file    */
  3889.     long        exp;          /* Expiration date of timeout      */
  3890.     long        ttl;          /* Time to live after reference    */
  3891.     long        last_ref;      /* Time of last reference          */
  3892.     struct vlink    *forward;      /* List of forwarding pointers     */
  3893.     struct vlink    *backlinks;      /* Partial list of back links      */
  3894.     struct pattrib    *attributes;      /* List of file attributes         */
  3895.     struct pfile    *previous;        /* Previous element in linked list */
  3896.     struct pfile    *next;          /* Next element in linked list     */
  3897. };
  3898.  
  3899. typedef struct pfile *PFILE;
  3900. typedef struct pfile PFILE_ST;
  3901.  
  3902. /* Definition of structure contining an access control list entry */
  3903.  
  3904. struct acl {
  3905.     int            acetype;      /* Access Contol Entry type       */
  3906.     char        *atype;           /* Authentication type            */
  3907.     char        *rights;          /* Rights                         */
  3908.     char        *principals;      /* Authorized principals          */
  3909.     struct restrict     *restrictions;    /* Restrictions on use            */
  3910.     struct acl        *previous;        /* Previous elt in linked list    */
  3911.     struct acl        *next;          /* Next element in linked list    */
  3912. };
  3913. typedef struct acl *ACL;
  3914. typedef struct acl ACL_ST;
  3915.  
  3916. #define ACL_NONE        0         /* Nobody authorized by ths entry */
  3917. #define ACL_DEFAULT        1         /* System default                 */
  3918. #define ACL_SYSTEM        2         /* System administrator           */
  3919. #define ACL_OWNER               3         /* Directory owner                */
  3920. #define ACL_DIRECTORY           4         /* Same as directory              */
  3921. #define ACL_ANY                 5         /* Any user                       */
  3922. #define ACL_AUTHENT             6         /* Authenticated principal        */
  3923. #define ACL_LGROUP              7         /* Local group                    */
  3924. #define ACL_GROUP               8         /* External group                 */
  3925. #define ACL_ASRTHOST            10        /* Check host and asserted userid */
  3926. #define ACL_TRSTHOST            11        /* ASRTHOST from privileged port  */
  3927.  
  3928.  
  3929. /* Definition of structure contining access restrictions */
  3930. /* for future extensions                                 */
  3931. struct restrict {
  3932.     struct acl        *previous;        /* Previous elt in linked list    */
  3933.     struct acl        *next;          /* Next element in linked list    */
  3934. };
  3935.  
  3936. /* Definitions for send_to_dirsrv */
  3937. #define    CLIENT_DIRSRV_TIMEOUT        4    /* time between retries      */
  3938. #define CLIENT_DIRSRV_BACKOFF(x)  (2 * x)    /* Backoff algorithm         */
  3939. #define CLIENT_DIRSRV_RETRY        3    /* retry this many times     */
  3940.  
  3941. /* Definitions for rd_vlink and rd_vdir */
  3942. #define        SYMLINK_NESTING 10       /* Max nesting depth for sym links */
  3943.  
  3944. /* Definition fo check_acl */
  3945. #define        ACL_NESTING     10       /* Max depth for ACL group nesting */
  3946.  
  3947. /* Flags for mk_vdir */
  3948. #define         MKVD_LPRIV     1   /* Minimize privs for creator in new ACL    */
  3949.  
  3950. /* Flags for get_vdir */
  3951. #define         GVD_UNION      0    /* Do not expand union links              */
  3952. #define      GVD_EXPAND     1   /* Expand union links locally             */
  3953. #define         GVD_LREMEXP    3   /* Request remote expansion of local links   */
  3954. #define         GVD_REMEXP     7   /* Request remote expansion of all links     */
  3955. #define         GVD_VERIFY     8    /* Only verify args are for a directory      */
  3956. #define      GVD_FIND       16   /* Stop expanding when match is found        */
  3957. #define         GVD_ATTRIB    32   /* Request attributes from remote server     */
  3958. #define         GVD_NOSORT       64   /* Do not sort links when adding to dir      */
  3959.  
  3960. /* Flags for rd_vdir */
  3961. #define         RVD_UNION      GVD_UNION
  3962. #define         RVD_EXPAND     GVD_EXPAND 
  3963. #define         RVD_LREMEXP    GVD_LREMEXP
  3964. #define         RVD_REMEXP     GVD_REMEXP
  3965. #define         RVD_DFILE_ONLY GVD_VERIFY /* Only return ptr to dir file        */
  3966. #define      RVD_FIND       GVD_FIND   
  3967. #define      RVD_ATTRIB     GVD_ATTRIB
  3968. #define         RVD_NOSORT        GVD_NOSORT
  3969. #define         RVD_NOCACHE    128
  3970.  
  3971. /* Flags for add_vlink */
  3972. #define         AVL_UNION      1   /* Link is a union link                      */
  3973.  
  3974. /* Flags for vl_insert */
  3975. #define         VLI_NOCONFLICT 0   /* Do not insert links w/ conflicting names  */
  3976. #define      VLI_ALLOW_CONF 1   /* Allow links with conflicting names        */
  3977. #define         VLI_NOSORT     2   /* Allow conflicts and don't sort            */
  3978.  
  3979. /* Flags for mapname */
  3980. #define      MAP_READWRITE  0   /* Named file to be read and written         */
  3981. #define         MAP_READONLY   1   /* Named file to be read only                */
  3982.  
  3983. /* Flags for modify_acl */
  3984. #define         MACL_NOSYSTEM   0x01
  3985. #define      MACL_NOSELF     0x02
  3986. #define      MACL_DEFAULT    0x08
  3987. #define      MACL_SET        0x0C
  3988. #define      MACL_INSERT     0x14
  3989. #define      MACL_DELETE     0x10
  3990. #define      MACL_ADD        0x1C
  3991. #define      MACL_SUBTRACT   0x18
  3992. #define      MACL_LINK       0x00
  3993. #define      MACL_DIRECTORY  0x20
  3994. #define      MACL_OBJECT     0x60
  3995. #define      MACL_INCLUDE    0x40
  3996.  
  3997. #define      MACL_OP    (MACL_DEFAULT|MACL_SET|MACL_INSERT|\
  3998.              MACL_DELETE|MACL_ADD|MACL_SUBTRACT)
  3999.  
  4000. #define      MACL_OTYPE (MACL_LINK|MACL_DIRECTORY|MACL_OBJECT|MACL_INCLUDE)
  4001.  
  4002. /* Access methods returned by Pget_am */
  4003. #define P_AM_ERROR            0
  4004. #define P_AM_FTP            1
  4005. #define P_AM_AFTP            2  /* Anonymous FTP  */
  4006. #define P_AM_NFS            4
  4007. #define P_AM_KNFS            8  /* Kerberized NFS */
  4008. #define P_AM_AFS               16
  4009.  
  4010. /* Return codes */
  4011.  
  4012. #define        PSUCCESS    0
  4013. #define        PFAILURE    255
  4014.  
  4015. /* Hush up warnings.  */
  4016. void vllfree();
  4017.  
  4018. /* Procedures in libpfs.a */
  4019.  
  4020. char *pget_wdhost(), *pget_wdfile(), *pget_wd(), *pget_hdhost();
  4021. char *pget_hdfile(), *pget_hd(), *pget_rdhost(), *pget_rdfile();
  4022. char *pget_dhost(), *pget_dfile(), *pget_vsname(), *nlsindex();
  4023. char *sindex(), *strtok(), *nxtline(), *unquote(), *stcopy();
  4024. char *stcopyr(), *readheader(), *month_sname();
  4025.  
  4026. long        asntotime();
  4027.  
  4028. PTEXT        ptalloc();
  4029. PTEXT        dirsend();
  4030.  
  4031. PREQ        pralloc();
  4032. PREQ        get_next_request();
  4033.  
  4034. VLINK        rd_slink();
  4035. VLINK        rd_vlink();
  4036. VLINK        vl_delete();
  4037. VLINK        vlalloc();
  4038. VLINK        vlcopy();
  4039.  
  4040. PFILE        pfalloc();
  4041.  
  4042. PATTRIB         parse_attribute();
  4043. PATTRIB         atalloc();
  4044. PATTRIB     pget_at();
  4045.  
  4046. ACL             acalloc();
  4047. ACL             get_acl();
  4048.  
  4049. /* Miscellaneous useful definitions */
  4050. #ifndef TRUE
  4051. #define TRUE        1
  4052. #define FALSE        0
  4053. #endif
  4054.  
  4055. #define AUTHORIZED      1
  4056. #define NOT_AUTHORIZED  0
  4057. #define NEG_AUTHORIZED  -1
  4058.  
  4059. #ifndef NULL
  4060. #define NULL        0
  4061. #endif
  4062.  
  4063. #define FAILED        -1
  4064. $EOD
  4065. $!
  4066. $CREATE [.archie]pmachine.h
  4067. $DECK
  4068. /*
  4069.  * Miscellaneous system dependencies.
  4070.  *
  4071.  * I kept the name pmachine.h because it was already in all of the files...this
  4072.  * barely resembles the pmachine.h that comes with the real Prospero, tho.
  4073.  *
  4074.  * v1.2.0 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  4075.  */
  4076.  
  4077. #ifdef hpux
  4078. # define FUNCS
  4079. # define NOREGEX
  4080. #endif
  4081.  
  4082. #if defined(USG) || defined(SYSV)
  4083. # define FUNCS
  4084. #endif
  4085.  
  4086. #ifdef OS2
  4087. # include <pctcp.h>
  4088. #endif
  4089. #ifdef MSDOS
  4090. # include <string.h>
  4091. # include <stdlib.h>
  4092. #endif
  4093.  
  4094. #ifdef _AIX
  4095. #define _NONSTD_TYPES
  4096. #define _BSD_INCLUDES
  4097. #endif
  4098.  
  4099. /* ==== */
  4100. #ifdef FUNCS
  4101. # define index        strchr
  4102. # define rindex        strrchr
  4103. # ifndef AUX
  4104. #  define bcopy(a,b,n)    memcpy(b,a,n)
  4105. #  define bzero(a,n)    memset(a,0,n)
  4106. # endif
  4107. #endif
  4108.  
  4109. #if defined(BULL) || defined(_AIX)
  4110. # define NEED_SELECT_H
  4111. #endif
  4112. #if defined(USG) || defined(UTS) || defined(_AIX)
  4113. # define NEED_STRING_H
  4114. #endif
  4115. #if defined(USG) || defined(UTS) || defined(_AIX) || defined(AUX)
  4116. # define NEED_TIME_H
  4117. #endif
  4118.  
  4119. #ifdef VMS
  4120. /* Get the system status stuff.  */
  4121. # include <ssdef.h>
  4122. #endif /* VMS */
  4123.  
  4124. /*
  4125.  * FD_SET: lib/pfs/dirsend.c, user/vget/ftp.c
  4126.  */
  4127. #if !defined(FD_SET) && !defined(VMS)
  4128. #define    NFDBITS        32
  4129. #define    FD_SETSIZE    32
  4130. #define    FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  4131. #define    FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  4132. #define    FD_ISSET(n, p)    ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  4133. #define FD_ZERO(p)    bzero((char *)(p), sizeof(*(p)))
  4134. #endif
  4135. $EOD
  4136. $!
  4137. $CREATE [.archie]pprot.h
  4138. $DECK
  4139. /*
  4140.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  4141.  *
  4142.  * For copying and distribution information, please see the file
  4143.  * <copyright.h>.
  4144.  *
  4145.  * v1.2.0 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  4146.  */
  4147.  
  4148. #include <copyright.h>
  4149.  
  4150. #ifndef MAXPATHLEN
  4151. # ifdef VMS
  4152. #  define MAXPATHLEN 32
  4153. # else /* not VMS */
  4154. #  if defined(MSDOS) && !defined(OS2)
  4155. #   define MAXPATHLEN 255
  4156. #  else /* not MSDOS */
  4157. #   include <sys/param.h>
  4158. #  endif /* MSDOS && !OS2 */
  4159. # endif /* VMS */
  4160. #endif
  4161.  
  4162. /* Protocol Definitions */
  4163.  
  4164. #define           VFPROT_VNO    1      /* Protocol Version Number           */
  4165.  
  4166. #define           DIRSRV_PORT      1525   /* Server port used if not in srvtab */
  4167. #define        PROSPERO_PORT    191    /* Officially assigned prived port   */
  4168. #define           PROS_FIRST_PRIVP 901    /* First privileged port to try      */
  4169. #define        PROS_NUM_PRIVP   20     /* Number of privileged ports to try */
  4170.  
  4171. #define           MAXPKT            1024   /* Max size of response from server  */
  4172. #define           SEQ_SIZE        32     /* Max size of sequence text in resp */ 
  4173. #define           MAX_DIR_LINESIZE 160+MAXPATHLEN /* Max linesize in directory */
  4174.  
  4175. #define           MAX_FWD_DEPTH    20     /* Max fwd pointers to follow        */
  4176.  
  4177. #define S_AD_SZ        sizeof(struct sockaddr_in)
  4178.  
  4179. /* Replacement for strtok that doesn't keep state.  Both the variable  */
  4180. /* S and the variable S_next must be defined.  To initialize, assign   */
  4181. /* the string to be stepped through to S_next, then call get_token on  */
  4182. /* S.  The first token will be in S, and S_next will point to the next */
  4183. /* token.  Like strtok, this macro does modify the string passed to it */
  4184. #define get_token(S,C) \
  4185.     S = S/**/_next; \
  4186.     if(S) { \
  4187.      while(*S == C) S++; \
  4188.      S/**/_next = index(S,C); \
  4189.      if(S/**/_next) *(S/**/_next++) = '\0'; \
  4190.      if(!*S) S = NULL; \
  4191.     }
  4192.  
  4193.  
  4194. $EOD
  4195. $!
  4196. $CREATE [.archie]procquery.c
  4197. $DECK
  4198. /*
  4199.  * procquery.c : Routines for processing results from Archie
  4200.  *
  4201.  * Originally part of the Prospero Archie client by Cliff Neuman (bcn@isi.edu).
  4202.  * Modified by Brendan Kehoe (brendan@cs.widener.edu).
  4203.  * Re-modified by George Ferguson (ferguson@cs.rochester.edu).
  4204.  *
  4205.  * Copyright (c) 1991 by the University of Washington
  4206.  *
  4207.  * For copying and distribution information, please see the file
  4208.  * <copyright.h>.
  4209.  *
  4210.  * v1.2.2 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  4211.  * v1.2.1 - 10/18/91 (bpk) - warning stuff
  4212.  * v1.2.0 - 09/20/91 (bpk) - VMS under Multinet 3.0 too
  4213.  * v1.1.1 - 08/20/91 (bpk) - took out archie_query from error msg
  4214.  */
  4215. #include <copyright.h>
  4216. #include <stdio.h>
  4217. #include <pfs.h>
  4218. #include <perrno.h>
  4219. #include <pmachine.h>
  4220. #include <archie.h>
  4221.  
  4222. #ifdef NEED_TIME_H
  4223. # include <time.h>
  4224. #else
  4225. # ifndef VMS
  4226. #  include <sys/time.h>
  4227. # endif
  4228. #endif
  4229.  
  4230. extern int client_dirsrv_timeout,client_dirsrv_retry;    /* dirsend.c */
  4231. extern char *progname;
  4232.  
  4233.  
  4234. /*
  4235.  * Functions defined here
  4236.  */
  4237. void display_link(), procquery();
  4238.  
  4239. /*
  4240.  * Data defined here
  4241.  */
  4242. extern int pwarn, perrno;
  4243. int pfs_debug;
  4244. static struct tm *presenttime;
  4245. static char lastpath[MAX_VPATH] = "\001";
  4246. static char lasthost[MAX_VPATH] = "\001";
  4247.  
  4248. /*    -    -    -    -    -    -    -    -    */
  4249. /*
  4250.  * display_link : Prints the contents of the given virtual link. If
  4251.  *    listflag is 0, then this uses last{host,path} to save state
  4252.  *    between calls for a less verbose output. If listflag is non-zero
  4253.  *    then all information is printed every time.
  4254.  */
  4255. void
  4256. display_link(l,listflag)
  4257. VLINK l;
  4258. int listflag;
  4259. {
  4260.     PATTRIB     ap;
  4261.     char    linkpath[MAX_VPATH];
  4262.     int        dirflag = 0;
  4263. #ifdef MSDOS
  4264.     unsigned long size = 0L;
  4265. #else
  4266.     int        size = 0;
  4267. #endif
  4268.     char    *modes = "";
  4269.     char    archie_date[20];
  4270.     char    *gt_date = "";
  4271.     int        gt_year = 0;
  4272.     int        gt_mon = 0;
  4273.     int        gt_day = 0;
  4274.     int        gt_hour = 0;
  4275.     int        gt_min = 0;
  4276.     
  4277.     /* Initialize local buffers */
  4278.     *archie_date = '\0';
  4279.  
  4280.     /* Remember if we're looking at a directory */
  4281.     if (sindex(l->type,"DIRECTORY"))
  4282.     dirflag = 1;
  4283.     else
  4284.     dirflag = 0;
  4285.     
  4286.     /* Extract the linkpath from the filename */
  4287.     strcpy(linkpath,l->filename);
  4288.     *(linkpath + (strlen(linkpath) - strlen(l->name) - 1)) = '\0';
  4289.     
  4290.     /* Is this a new host? */
  4291.     if (strcmp(l->host,lasthost) != 0) {
  4292.     if (!listflag)
  4293.         printf("\nHost %s\n\n",l->host);
  4294.     strcpy(lasthost,l->host);
  4295.     *lastpath = '\001';
  4296.     }
  4297.     
  4298.     /* Is this a new linkpath (location)? */
  4299.     if(strcmp(linkpath,lastpath) != 0) {
  4300.     if (!listflag)
  4301.         printf("    Location: %s\n",(*linkpath ? linkpath : "/"));
  4302.     strcpy(lastpath,linkpath);
  4303.     }
  4304.     
  4305.     /* Parse the attibutes of this link */
  4306.     for (ap = l->lattrib; ap; ap = ap->next) {
  4307.     if (strcmp(ap->aname,"SIZE") == 0) {
  4308. #ifdef MSDOS
  4309.         sscanf(ap->value.ascii,"%lu",&size);
  4310. #else
  4311.         sscanf(ap->value.ascii,"%d",&size);
  4312. #endif
  4313.     } else if(strcmp(ap->aname,"UNIX-MODES") == 0) {
  4314.         modes = ap->value.ascii;
  4315.     } else if(strcmp(ap->aname,"LAST-MODIFIED") == 0) {
  4316.         gt_date = ap->value.ascii;
  4317.         sscanf(gt_date,"%4d%2d%2d%2d%2d",>_year,
  4318.            >_mon, >_day, >_hour, >_min);
  4319.         if ((12 * (presenttime->tm_year + 1900 - gt_year) + 
  4320.                     presenttime->tm_mon - gt_mon) > 6) 
  4321.         sprintf(archie_date,"%s %2d %4d",month_sname(gt_mon),
  4322.             gt_day, gt_year);
  4323.         else
  4324.         sprintf(archie_date,"%s %2d %02d:%02d",month_sname(gt_mon),
  4325.              gt_day, gt_hour, gt_min);
  4326.     }
  4327.     }
  4328.     
  4329.     /* Print this link's information */
  4330.     if (listflag)
  4331. #if defined(MSDOS)
  4332.     printf("%s %6lu %s %s%s\n",gt_date,size,l->host,l->filename,
  4333.            (dirflag ? "/" : ""));
  4334. #else
  4335.     printf("%s %6d %s %s%s\n",gt_date,size,l->host,l->filename,
  4336.            (dirflag ? "/" : ""));
  4337. #endif
  4338.     else
  4339. #ifdef MSDOS
  4340.     printf("      %9s %s %10lu  %s  %s\n",(dirflag ? "DIRECTORY" : "FILE"),
  4341.                     modes,size,archie_date,l->name);
  4342. #else
  4343.     printf("      %9s %s %10d  %s  %s\n",(dirflag ? "DIRECTORY" : "FILE"),
  4344.                     modes,size,archie_date,l->name);
  4345. #endif /* MSDOS */
  4346.  
  4347.  
  4348.     /* Free the attibutes */
  4349.     atlfree(l->lattrib);
  4350.     l->lattrib = NULL;
  4351. }
  4352.  
  4353. /*    -    -    -    -    -    -    -    -    */
  4354. /*
  4355.  * procquery : Process the given query and display the results. If
  4356.  *    sortflag is non-zero, then the results are sorted by increasing
  4357.  *    date, else by host/filename. If listflag is non-zero then each
  4358.  *    entry is printed on a separate, complete line. Note that listflag
  4359.  *    is ignored by xarchie.
  4360.  */
  4361. void
  4362. procquery(host,str,max_hits,offset,query_type,sortflag,listflag)
  4363. char *host,*str;
  4364. int max_hits,offset;
  4365. char query_type;
  4366. int sortflag,listflag;
  4367. {
  4368.     VLINK l;
  4369.     long now;
  4370.     extern int rdgram_priority;
  4371.  
  4372.     /* initialize data structures for this query */
  4373.     (void)time(&now);
  4374.     presenttime = localtime(&now);
  4375.  
  4376.     /* Do the query */
  4377.     if (sortflag == 1)
  4378.     l = archie_query(host,str,max_hits,offset,query_type,AQ_INVDATECMP,0);
  4379.     else
  4380.     l = archie_query(host,str,max_hits,offset,query_type,NULL,0);
  4381.  
  4382.     /* Error? */
  4383.     if (perrno != PSUCCESS) {
  4384.     if (p_err_text[perrno]) {
  4385.         if (*p_err_string)
  4386.         fprintf(stderr, "%s: failed: %s - %s\n", progname,
  4387.                 p_err_text[perrno], p_err_string);
  4388.         else
  4389.             fprintf(stderr, "%s failed: %s\n", progname, p_err_text[perrno]);
  4390.     } else
  4391.         fprintf(stderr, "%s failed: Undefined error %d (prospero)", perrno);
  4392.     }
  4393.  
  4394.     /* Warning? */
  4395.     if (pwarn != PNOWARN) {
  4396.     if (*p_warn_string)
  4397.         fprintf(stderr, "%s: Warning! %s - %s\n", progname,
  4398.         p_warn_text[pwarn], p_warn_string);
  4399.     else
  4400.         fprintf(stderr, "%s: Warning! %s\n", progname, p_warn_text[pwarn]);
  4401.     }
  4402.  
  4403.  
  4404.     /* Display the results */
  4405.  
  4406.     if (l == (VLINK)NULL && pwarn == PNOWARN && perrno == PSUCCESS) {
  4407.     if (! listflag) puts ("No matches.");
  4408.     exit (1);
  4409.     }
  4410.  
  4411.     *lasthost = '\001';
  4412.     *lastpath = '\001';
  4413.     while (l != NULL) {
  4414.     display_link(l,listflag);
  4415.     l = l->next;
  4416.     }
  4417. }
  4418. $EOD
  4419. $!
  4420. $CREATE [.archie]ptalloc.c
  4421. $DECK
  4422. /*
  4423.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  4424.  *
  4425.  * For copying and distribution information, please see the file
  4426.  * <copyright.h>.
  4427.  *
  4428.  * v1.2.0 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  4429.  */
  4430.  
  4431. #include <copyright.h>
  4432. #include <stdio.h>
  4433.  
  4434. #include <pfs.h>
  4435. #include <pmachine.h> /* for correct definition of ZERO */
  4436. #ifdef MSDOS
  4437. # define free _pfree   /* otherwise we get conflicts with free() */
  4438. #endif
  4439.  
  4440. static PTEXT    free = NULL;
  4441. int         ptext_count = 0;
  4442. int        ptext_max = 0;
  4443.  
  4444. /*
  4445.  * ptalloc - allocate and initialize ptext structure
  4446.  *
  4447.  *    PTALLOC returns a pointer to an initialized structure of type
  4448.  *    PTEXT.  If it is unable to allocate such a structure, it
  4449.  *    returns NULL.
  4450.  */
  4451. PTEXT
  4452. ptalloc()
  4453.     {
  4454.     PTEXT    vt;
  4455.     if(free) {
  4456.         vt = free;
  4457.         free = free->next;
  4458.     }
  4459.     else {
  4460.         vt = (PTEXT) malloc(sizeof(PTEXT_ST));
  4461.         if (!vt) return(NULL);
  4462.         ptext_max++;
  4463.     }
  4464.     ptext_count++;
  4465.  
  4466.     /* nearly all parts are 0 [or NULL] */
  4467.     ZERO(vt);
  4468.     /* The offset is to leave room for additional headers */
  4469.     vt->start = vt->dat + MAX_PTXT_HDR;
  4470.  
  4471.     return(vt);
  4472.     }
  4473.  
  4474. /*
  4475.  * ptfree - free a VTEXT structure
  4476.  *
  4477.  *    VTFREE takes a pointer to a VTEXT structure and adds it to
  4478.  *    the free list for later reuse.
  4479.  */
  4480. void
  4481. ptfree(vt)
  4482.     PTEXT    vt;
  4483.     {
  4484.     vt->next = free;
  4485.     vt->previous = NULL;
  4486.     free = vt;
  4487.     ptext_count--;
  4488.     }
  4489.  
  4490. /*
  4491.  * ptlfree - free a VTEXT structure
  4492.  *
  4493.  *    VTLFREE takes a pointer to a VTEXT structure frees it and any linked
  4494.  *    VTEXT structures.  It is used to free an entrie list of VTEXT
  4495.  *    structures.
  4496.  */
  4497. void
  4498. ptlfree(vt)
  4499.     PTEXT    vt;
  4500.     {
  4501.     PTEXT    nxt;
  4502.  
  4503.     while(vt != NULL) {
  4504.         nxt = vt->next;
  4505.         ptfree(vt);
  4506.         vt = nxt;
  4507.     }
  4508.     }
  4509.  
  4510. $EOD
  4511. $!
  4512. $CREATE [.archie]rdgram.h
  4513. $DECK
  4514. /*
  4515.  * Copyright (c) 1991 by the University of Washington
  4516.  *
  4517.  * For copying and distribution information, please see the file
  4518.  * <copyright.h>.
  4519.  */
  4520.  
  4521. #include <copyright.h>
  4522.  
  4523. /* Queuing priorities for datagrams */
  4524. #define           RDGRAM_MAX_PRI   32765  /* Maximum user proiority          */
  4525. #define           RDGRAM_MAX_SPRI  32767  /* Maximum priority for system use */
  4526. #define           RDGRAM_MIN_PRI  -32765  /* Maximum user proiority          */
  4527. #define           RDGRAM_MIN_SPRI -32768  /* Maximum priority for system use */
  4528.  
  4529. int    rdgram_priority = 0;
  4530. $EOD
  4531. $!
  4532. $CREATE [.archie]regex.c
  4533. $DECK
  4534. #include <pmachine.h>
  4535.  
  4536. #ifdef NOREGEX
  4537. /*
  4538.  * These routines are BSD regex(3)/ed(1) compatible regular-expression
  4539.  * routines written by Ozan S. Yigit, Computer Science, York University.
  4540.  * Parts of the code that are not needed by Prospero have been removed,
  4541.  * but most of the accompanying information has been left intact. 
  4542.  * This file is to be included on those operating systems that do not
  4543.  * support re_comp and re_exec.
  4544.  */
  4545.  
  4546. /*
  4547.  * regex - Regular expression pattern matching
  4548.  *         and replacement
  4549.  *
  4550.  * by:  Ozan S. Yigit (oz@nexus.yorku.ca)
  4551.  *    Dept. of Computing Services
  4552.  *      York University
  4553.  *
  4554.  * These routines are the PUBLIC DOMAIN equivalents 
  4555.  * of regex routines as found in 4.nBSD UN*X, with minor
  4556.  * extensions.
  4557.  *
  4558.  * Modification history:
  4559.  *
  4560.  * $Log:    regex.c,v $
  4561.  * Revision 1.3  89/04/01  14:18:09  oz
  4562.  * Change all references to a dfa: this is actually an nfa.
  4563.  * 
  4564.  * Revision 1.2  88/08/28  15:36:04  oz
  4565.  * Use a complement bitmap to represent NCL.
  4566.  * This removes the need to have seperate 
  4567.  * code in the pmatch case block - it is 
  4568.  * just CCL code now.
  4569.  * 
  4570.  * Use the actual CCL code in the CLO
  4571.  * section of pmatch. No need for a recursive
  4572.  * pmatch call.
  4573.  * 
  4574.  * Use a bitmap table to set char bits in an
  4575.  * 8-bit chunk.
  4576.  * 
  4577.  * Routines:
  4578.  *      re_comp:        compile a regular expression into
  4579.  *                      a NFA.
  4580.  *
  4581.  *            char *re_comp(s)
  4582.  *            char *s;
  4583.  *
  4584.  *      re_exec:        execute the NFA to match a pattern.
  4585.  *
  4586.  *            int re_exec(s)
  4587.  *            char *s;
  4588.  *
  4589.  * Regular Expressions:
  4590.  *
  4591.  *      [1]     char    matches itself, unless it is a special
  4592.  *                      character (metachar): . \ [ ] * + ^ $
  4593.  *
  4594.  *      [2]     .       matches any character.
  4595.  *
  4596.  *      [3]     \       matches the character following it, except
  4597.  *            when followed by a left or right round bracket,
  4598.  *            a digit 1 to 9 or a left or right angle bracket. 
  4599.  *            (see [7], [8] and [9])
  4600.  *            It is used as an escape character for all 
  4601.  *            other meta-characters, and itself. When used
  4602.  *            in a set ([4]), it is treated as an ordinary
  4603.  *            character.
  4604.  *
  4605.  *      [4]     [set]   matches one of the characters in the set.
  4606.  *                      If the first character in the set is "^",
  4607.  *                      it matches a character NOT in the set, i.e. 
  4608.  *            complements the set. A shorthand S-E is 
  4609.  *            used to specify a set of characters S upto 
  4610.  *            E, inclusive. The special characters "]" and 
  4611.  *            "-" have no special meaning if they appear 
  4612.  *            as the first chars in the set.
  4613.  *                      examples:        match:
  4614.  *
  4615.  *                              [a-z]    any lowercase alpha
  4616.  *
  4617.  *                              [^]-]    any char except ] and -
  4618.  *
  4619.  *                              [^A-Z]   any char except uppercase
  4620.  *                                       alpha
  4621.  *
  4622.  *                              [a-zA-Z] any alpha
  4623.  *
  4624.  *      [5]     *       any regular expression form [1] to [4], followed by
  4625.  *                      closure char (*) matches zero or more matches of
  4626.  *                      that form.
  4627.  *
  4628.  *      [6]     +       same as [5], except it matches one or more.
  4629.  *
  4630.  *      [7]             a regular expression in the form [1] to [10], enclosed
  4631.  *                      as \(form\) matches what form matches. The enclosure
  4632.  *                      creates a set of tags, used for [8] and for
  4633.  *                      pattern substution. The tagged forms are numbered
  4634.  *            starting from 1.
  4635.  *
  4636.  *      [8]             a \ followed by a digit 1 to 9 matches whatever a
  4637.  *                      previously tagged regular expression ([7]) matched.
  4638.  *
  4639.  *    [9]    \<    a regular expression starting with a \< construct
  4640.  *        \>    and/or ending with a \> construct, restricts the
  4641.  *            pattern matching to the beginning of a word, and/or
  4642.  *            the end of a word. A word is defined to be a character
  4643.  *            string beginning and/or ending with the characters
  4644.  *            A-Z a-z 0-9 and _. It must also be preceded and/or
  4645.  *            followed by any character outside those mentioned.
  4646.  *
  4647.  *      [10]            a composite regular expression xy where x and y
  4648.  *                      are in the form [1] to [10] matches the longest
  4649.  *                      match of x followed by a match for y.
  4650.  *
  4651.  *      [11]    ^    a regular expression starting with a ^ character
  4652.  *        $    and/or ending with a $ character, restricts the
  4653.  *                      pattern matching to the beginning of the line,
  4654.  *                      or the end of line. [anchors] Elsewhere in the
  4655.  *            pattern, ^ and $ are treated as ordinary characters.
  4656.  *
  4657.  *
  4658.  * Acknowledgements:
  4659.  *
  4660.  *    HCR's Hugh Redelmeier has been most helpful in various
  4661.  *    stages of development. He convinced me to include BOW
  4662.  *    and EOW constructs, originally invented by Rob Pike at
  4663.  *    the University of Toronto.
  4664.  *
  4665.  * References:
  4666.  *              Software tools            Kernighan & Plauger
  4667.  *              Software tools in Pascal        Kernighan & Plauger
  4668.  *              Grep [rsx-11 C dist]            David Conroy
  4669.  *        ed - text editor        Un*x Programmer's Manual
  4670.  *        Advanced editing on Un*x    B. W. Kernighan
  4671.  *        regexp routines            Henry Spencer
  4672.  *
  4673.  * Notes:
  4674.  *
  4675.  *    This implementation uses a bit-set representation for character
  4676.  *    classes for speed and compactness. Each character is represented 
  4677.  *    by one bit in a 128-bit block. Thus, CCL always takes a 
  4678.  *    constant 16 bytes in the internal nfa, and re_exec does a single
  4679.  *    bit comparison to locate the character in the set.
  4680.  *
  4681.  * Examples:
  4682.  *
  4683.  *    pattern:    foo*.*
  4684.  *    compile:    CHR f CHR o CLO CHR o END CLO ANY END END
  4685.  *    matches:    fo foo fooo foobar fobar foxx ...
  4686.  *
  4687.  *    pattern:    fo[ob]a[rz]    
  4688.  *    compile:    CHR f CHR o CCL bitset CHR a CCL bitset END
  4689.  *    matches:    fobar fooar fobaz fooaz
  4690.  *
  4691.  *    pattern:    foo\\+
  4692.  *    compile:    CHR f CHR o CHR o CHR \ CLO CHR \ END END
  4693.  *    matches:    foo\ foo\\ foo\\\  ...
  4694.  *
  4695.  *    pattern:    \(foo\)[1-3]\1    (same as foo[1-3]foo)
  4696.  *    compile:    BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
  4697.  *    matches:    foo1foo foo2foo foo3foo
  4698.  *
  4699.  *    pattern:    \(fo.*\)-\1
  4700.  *    compile:    BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
  4701.  *    matches:    foo-foo fo-fo fob-fob foobar-foobar ...
  4702.  * 
  4703.  */
  4704.  
  4705. #define MAXNFA  1024
  4706. #define MAXTAG  10
  4707.  
  4708. #define OKP     1
  4709. #define NOP     0
  4710.  
  4711. #define CHR     1
  4712. #define ANY     2
  4713. #define CCL     3
  4714. #define BOL     4
  4715. #define EOL     5
  4716. #define BOT     6
  4717. #define EOT     7
  4718. #define BOW    8
  4719. #define EOW    9
  4720. #define REF     10
  4721. #define CLO     11
  4722.  
  4723. #define END     0
  4724.  
  4725. /*
  4726.  * The following defines are not meant
  4727.  * to be changeable. They are for readability
  4728.  * only.
  4729.  *
  4730.  */
  4731. #define MAXCHR    128
  4732. #define CHRBIT    8
  4733. #define BITBLK    MAXCHR/CHRBIT
  4734. #define BLKIND    0170
  4735. #define BITIND    07
  4736.  
  4737. #define ASCIIB    0177
  4738.  
  4739. typedef /*unsigned*/ char CHAR;
  4740.  
  4741. static int  tagstk[MAXTAG];             /* subpat tag stack..*/
  4742. static CHAR nfa[MAXNFA];        /* automaton..       */
  4743. static int  sta = NOP;                   /* status of lastpat */
  4744.  
  4745. static CHAR bittab[BITBLK];        /* bit table for CCL */
  4746.                     /* pre-set bits...   */
  4747. static CHAR bitarr[] = {1,2,4,8,16,32,64,128};
  4748.  
  4749. static int internal_error;
  4750.  
  4751. static void
  4752. chset(c)
  4753. register CHAR c;
  4754. {
  4755.     bittab[((c) & BLKIND) >> 3] |= bitarr[(c) & BITIND];
  4756. }
  4757.  
  4758. #define badpat(x)    return (*nfa = END, x)
  4759. #define store(x)    *mp++ = x
  4760.  
  4761. char *     
  4762. re_comp(pat)
  4763. char *pat;
  4764. {
  4765.     register char *p;               /* pattern pointer   */
  4766.     register CHAR *mp = nfa;        /* nfa pointer       */
  4767.     register CHAR *lp;              /* saved pointer..   */
  4768.     register CHAR *sp = nfa;        /* another one..     */
  4769.  
  4770.     register int tagi = 0;          /* tag stack index   */
  4771.     register int tagc = 1;          /* actual tag count  */
  4772.  
  4773.     register int n;
  4774.     register CHAR mask;        /* xor mask -CCL/NCL */
  4775.     int c1, c2;
  4776.         
  4777.     if (!pat || !*pat)
  4778.         if (sta)
  4779.             return 0;
  4780.         else
  4781.             badpat("No previous regular expression");
  4782.     sta = NOP;
  4783.  
  4784.     for (p = pat; *p; p++) {
  4785.         lp = mp;
  4786.         switch(*p) {
  4787.  
  4788.         case '.':               /* match any char..  */
  4789.             store(ANY);
  4790.             break;
  4791.  
  4792.         case '^':               /* match beginning.. */
  4793.             if (p == pat)
  4794.                 store(BOL);
  4795.             else {
  4796.                 store(CHR);
  4797.                 store(*p);
  4798.             }
  4799.             break;
  4800.  
  4801.         case '$':               /* match endofline.. */
  4802.             if (!*(p+1))
  4803.                 store(EOL);
  4804.             else {
  4805.                 store(CHR);
  4806.                 store(*p);
  4807.             }
  4808.             break;
  4809.  
  4810.         case '[':               /* match char class..*/
  4811.             store(CCL);
  4812.  
  4813.             if (*++p == '^') {
  4814.                 mask = 0377;    
  4815.                 p++;
  4816.             }
  4817.             else
  4818.                 mask = 0;
  4819.  
  4820.             if (*p == '-')        /* real dash */
  4821.                 chset(*p++);
  4822.             if (*p == ']')        /* real brac */
  4823.                 chset(*p++);
  4824.             while (*p && *p != ']') {
  4825.                 if (*p == '-' && *(p+1) && *(p+1) != ']') {
  4826.                     p++;
  4827.                     c1 = *(p-2) + 1;
  4828.                     c2 = *p++;
  4829.                     while (c1 <= c2)
  4830.                         chset(c1++);
  4831.                 }
  4832. #ifdef EXTEND
  4833.                 else if (*p == '\\' && *(p+1)) {
  4834.                     p++;
  4835.                     chset(*p++);
  4836.                 }
  4837. #endif
  4838.                 else
  4839.                     chset(*p++);
  4840.             }
  4841.             if (!*p)
  4842.                 badpat("Missing ]");
  4843.  
  4844.             for (n = 0; n < BITBLK; bittab[n++] = (char) 0)
  4845.                 store(mask ^ bittab[n]);
  4846.     
  4847.             break;
  4848.  
  4849.         case '*':               /* match 0 or more.. */
  4850.         case '+':               /* match 1 or more.. */
  4851.             if (p == pat)
  4852.                 badpat("Empty closure");
  4853.             lp = sp;        /* previous opcode */
  4854.             if (*lp == CLO)        /* equivalence..   */
  4855.                 break;
  4856.             switch(*lp) {
  4857.  
  4858.             case BOL:
  4859.             case BOT:
  4860.             case EOT:
  4861.             case BOW:
  4862.             case EOW:
  4863.             case REF:
  4864.                 badpat("Illegal closure");
  4865.             default:
  4866.                 break;
  4867.             }
  4868.  
  4869.             if (*p == '+')
  4870.                 for (sp = mp; lp < sp; lp++)
  4871.                     store(*lp);
  4872.  
  4873.             store(END);
  4874.             store(END);
  4875.             sp = mp;
  4876.             while (--mp > lp)
  4877.                 *mp = mp[-1];
  4878.             store(CLO);
  4879.             mp = sp;
  4880.             break;
  4881.  
  4882.         case '\\':              /* tags, backrefs .. */
  4883.             switch(*++p) {
  4884.  
  4885.             case '(':
  4886.                 if (tagc < MAXTAG) {
  4887.                     tagstk[++tagi] = tagc;
  4888.                     store(BOT);
  4889.                     store(tagc++);
  4890.                 }
  4891.                 else
  4892.                     badpat("Too many \\(\\) pairs");
  4893.                 break;
  4894.             case ')':
  4895.                 if (*sp == BOT)
  4896.                     badpat("Null pattern inside \\(\\)");
  4897.                 if (tagi > 0) {
  4898.                     store(EOT);
  4899.                     store(tagstk[tagi--]);
  4900.                 }
  4901.                 else
  4902.                     badpat("Unmatched \\)");
  4903.                 break;
  4904.             case '<':
  4905.                 store(BOW);
  4906.                 break;
  4907.             case '>':
  4908.                 if (*sp == BOW)
  4909.                     badpat("Null pattern inside \\<\\>");
  4910.                 store(EOW);
  4911.                 break;
  4912.             case '1':
  4913.             case '2':
  4914.             case '3':
  4915.             case '4':
  4916.             case '5':
  4917.             case '6':
  4918.             case '7':
  4919.             case '8':
  4920.             case '9':
  4921.                 n = *p-'0';
  4922.                 if (tagi > 0 && tagstk[tagi] == n)
  4923.                     badpat("Cyclical reference");
  4924.                 if (tagc > n) {
  4925.                     store(REF);
  4926.                     store(n);
  4927.                 }
  4928.                 else
  4929.                     badpat("Undetermined reference");
  4930.                 break;
  4931. #ifdef EXTEND
  4932.             case 'b':
  4933.                 store(CHR);
  4934.                 store('\b');
  4935.                 break;
  4936.             case 'n':
  4937.                 store(CHR);
  4938.                 store('\n');
  4939.                 break;
  4940.             case 'f':
  4941.                 store(CHR);
  4942.                 store('\f');
  4943.                 break;
  4944.             case 'r':
  4945.                 store(CHR);
  4946.                 store('\r');
  4947.                 break;
  4948.             case 't':
  4949.                 store(CHR);
  4950.                 store('\t');
  4951.                 break;
  4952. #endif
  4953.             default:
  4954.                 store(CHR);
  4955.                 store(*p);
  4956.             }
  4957.             break;
  4958.  
  4959.         default :               /* an ordinary char  */
  4960.             store(CHR);
  4961.             store(*p);
  4962.             break;
  4963.         }
  4964.         sp = lp;
  4965.     }
  4966.     if (tagi > 0)
  4967.         badpat("Unmatched \\(");
  4968.     store(END);
  4969.     sta = OKP;
  4970.     return 0;
  4971. }
  4972.  
  4973.  
  4974. static char *bol;
  4975. static char *bopat[MAXTAG];
  4976. static char *eopat[MAXTAG];
  4977. char *pmatch();
  4978.  
  4979. /*
  4980.  * re_exec:
  4981.  *     execute nfa to find a match.
  4982.  *
  4983.  *    special cases: (nfa[0])    
  4984.  *        BOL
  4985.  *            Match only once, starting from the
  4986.  *            beginning.
  4987.  *        CHR
  4988.  *            First locate the character without
  4989.  *            calling pmatch, and if found, call
  4990.  *            pmatch for the remaining string.
  4991.  *        END
  4992.  *            re_comp failed, poor luser did not
  4993.  *            check for it. Fail fast.
  4994.  *
  4995.  *    If a match is found, bopat[0] and eopat[0] are set
  4996.  *    to the beginning and the end of the matched fragment,
  4997.  *    respectively.
  4998.  *
  4999.  */
  5000.  
  5001. int
  5002. re_exec(lp)
  5003. register char *lp;
  5004. {
  5005.     register char c;
  5006.     register char *ep = 0;
  5007.     register CHAR *ap = nfa;
  5008.  
  5009.     bol = lp;
  5010.  
  5011.     bopat[0] = 0;
  5012.     bopat[1] = 0;
  5013.     bopat[2] = 0;
  5014.     bopat[3] = 0;
  5015.     bopat[4] = 0;
  5016.     bopat[5] = 0;
  5017.     bopat[6] = 0;
  5018.     bopat[7] = 0;
  5019.     bopat[8] = 0;
  5020.     bopat[9] = 0;
  5021.  
  5022.     switch(*ap) {
  5023.  
  5024.     case BOL:            /* anchored: match from BOL only */
  5025.         ep = pmatch(lp,ap);
  5026.         break;
  5027.     case CHR:            /* ordinary char: locate it fast */
  5028.         c = *(ap+1);
  5029.         while (*lp && *lp != c)
  5030.             lp++;
  5031.         if (!*lp)        /* if EOS, fail, else fall thru. */
  5032.             return 0;
  5033.     default:            /* regular matching all the way. */
  5034.         while (*lp) {
  5035.             if ((ep = pmatch(lp,ap)))
  5036.                 break;
  5037.             lp++;
  5038.         }
  5039.         break;
  5040.     case END:            /* munged automaton. fail always */
  5041.         return 0;
  5042.     }
  5043.     if (!ep)
  5044.         return 0;
  5045.  
  5046.     if (internal_error)
  5047.         return -1;
  5048.  
  5049.     bopat[0] = lp;
  5050.     eopat[0] = ep;
  5051.     return 1;
  5052. }
  5053.  
  5054. /* 
  5055.  * pmatch: 
  5056.  *    internal routine for the hard part
  5057.  *
  5058.  *     This code is mostly snarfed from an early
  5059.  *     grep written by David Conroy. The backref and
  5060.  *     tag stuff, and various other mods are by oZ.
  5061.  *
  5062.  *    special cases: (nfa[n], nfa[n+1])
  5063.  *        CLO ANY
  5064.  *            We KNOW ".*" will match ANYTHING
  5065.  *            upto the end of line. Thus, go to
  5066.  *            the end of line straight, without
  5067.  *            calling pmatch recursively. As in
  5068.  *            the other closure cases, the remaining
  5069.  *            pattern must be matched by moving
  5070.  *            backwards on the string recursively,
  5071.  *            to find a match for xy (x is ".*" and 
  5072.  *            y is the remaining pattern) where
  5073.  *            the match satisfies the LONGEST match
  5074.  *            for x followed by a match for y.
  5075.  *        CLO CHR
  5076.  *            We can again scan the string forward
  5077.  *            for the single char without recursion, 
  5078.  *            and at the point of failure, we execute 
  5079.  *            the remaining nfa recursively, as
  5080.  *            described above.
  5081.  *
  5082.  *    At the end of a successful match, bopat[n] and eopat[n]
  5083.  *    are set to the beginning and end of subpatterns matched
  5084.  *    by tagged expressions (n = 1 to 9).    
  5085.  *
  5086.  */
  5087.  
  5088. /*
  5089.  * character classification table for word boundary
  5090.  * operators BOW and EOW. the reason for not using 
  5091.  * ctype macros is that we can let the user add into 
  5092.  * our own table. see re_modw. This table is not in
  5093.  * the bitset form, since we may wish to extend it
  5094.  * in the future for other character classifications. 
  5095.  *
  5096.  *    TRUE for 0-9 A-Z a-z _
  5097.  */
  5098. static char chrtyp[MAXCHR] = {
  5099.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  5100.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  5101.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  5102.     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  5103.     0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 
  5104.     1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 
  5105.     0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 
  5106.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  5107.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  5108.     1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 
  5109.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  5110.     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 
  5111.     1, 1, 1, 0, 0, 0, 0, 0
  5112.     };
  5113.  
  5114. #define inascii(x)    (0177&(x))
  5115. #define iswordc(x)     chrtyp[inascii(x)]
  5116. #define isinset(x,y)     ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND])
  5117.  
  5118. /*
  5119.  * skip values for CLO XXX to skip past the closure
  5120.  *
  5121.  */
  5122.  
  5123. #define ANYSKIP    2     /* [CLO] ANY END ...         */
  5124. #define CHRSKIP    3    /* [CLO] CHR chr END ...     */
  5125. #define CCLSKIP 18    /* [CLO] CCL 16bytes END ... */
  5126.  
  5127. static char *
  5128. pmatch(lp, ap)
  5129. register char *lp;
  5130. register CHAR *ap;
  5131. {
  5132.     register int op, c, n;
  5133.     register char *e;        /* extra pointer for CLO */
  5134.     register char *bp;        /* beginning of subpat.. */
  5135.     register char *ep;        /* ending of subpat..     */
  5136.     char *are;            /* to save the line ptr. */
  5137.  
  5138.     while ((op = *ap++) != END)
  5139.         switch(op) {
  5140.  
  5141.         case CHR:
  5142.             if (*lp++ != *ap++)
  5143.                 return 0;
  5144.             break;
  5145.         case ANY:
  5146.             if (!*lp++)
  5147.                 return 0;
  5148.             break;
  5149.         case CCL:
  5150.             c = *lp++;
  5151.             if (!isinset(ap,c))
  5152.                 return 0;
  5153.             ap += BITBLK;
  5154.             break;
  5155.         case BOL:
  5156.             if (lp != bol)
  5157.                 return 0;
  5158.             break;
  5159.         case EOL:
  5160.             if (*lp)
  5161.                 return 0;
  5162.             break;
  5163.         case BOT:
  5164.             bopat[*ap++] = lp;
  5165.             break;
  5166.         case EOT:
  5167.             eopat[*ap++] = lp;
  5168.             break;
  5169.          case BOW:
  5170.             if (lp!=bol && iswordc(lp[-1]) || !iswordc(*lp))
  5171.                 return 0;
  5172.             break;
  5173.         case EOW:
  5174.             if (lp==bol || !iswordc(lp[-1]) || iswordc(*lp))
  5175.                 return 0;
  5176.             break;
  5177.         case REF:
  5178.             n = *ap++;
  5179.             bp = bopat[n];
  5180.             ep = eopat[n];
  5181.             while (bp < ep)
  5182.                 if (*bp++ != *lp++)
  5183.                     return 0;
  5184.             break;
  5185.         case CLO:
  5186.             are = lp;
  5187.             switch(*ap) {
  5188.  
  5189.             case ANY:
  5190.                 while (*lp)
  5191.                     lp++;
  5192.                 n = ANYSKIP;
  5193.                 break;
  5194.             case CHR:
  5195.                 c = *(ap+1);
  5196.                 while (*lp && c == *lp)
  5197.                     lp++;
  5198.                 n = CHRSKIP;
  5199.                 break;
  5200.             case CCL:
  5201.                 while ((c = *lp) && isinset(ap+1,c))
  5202.                     lp++;
  5203.                 n = CCLSKIP;
  5204.                 break;
  5205.             default:
  5206.                 internal_error++;
  5207.                 return 0;
  5208.             }
  5209.  
  5210.             ap += n;
  5211.  
  5212.             while (lp >= are) {
  5213.                 if (e = pmatch(lp, ap))
  5214.                     return e;
  5215.                 --lp;
  5216.             }
  5217.             return 0;
  5218.         default:
  5219.             internal_error++;
  5220.             return 0;
  5221.         }
  5222.     return lp;
  5223. }
  5224. #endif /* Need regex libraries? Compile to nothing if not.  */
  5225. $EOD
  5226. $!
  5227. $CREATE [.archie]regex.h
  5228. $DECK
  5229. /*
  5230.  * regex.h : External defs for Ozan Yigit's regex functions, for systems
  5231.  *    that don't have them builtin. See regex.c for copyright and other
  5232.  *    details.
  5233.  *
  5234.  * Note that this file can be included even if we're linking against the
  5235.  * system routines, since the interface is (deliberately) identical.
  5236.  *
  5237.  * George Ferguson, ferguson@cs.rochester.edu, 11 Sep 1991.
  5238.  */
  5239.  
  5240. #if defined(AUX) || defined(USG)
  5241. /* Let them use ours if they wish.  */
  5242. # ifndef NOREGEX
  5243. extern char *regcmp();
  5244. extern char *regex();
  5245. #define re_comp regcmp
  5246. #define re_exec regex
  5247. # endif
  5248. #else
  5249. extern char *re_comp();
  5250. extern int re_exec();
  5251. #endif
  5252. $EOD
  5253. $!
  5254. $CREATE [.archie]stcopy.c
  5255. $DECK
  5256. /*
  5257.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  5258.  *
  5259.  * For copying and distribution information, please see the file
  5260.  * <copyright.h>.
  5261.  *
  5262.  * v1.2.1 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  5263.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  5264.  */
  5265.  
  5266. #include <copyright.h>
  5267. #include <stdio.h>
  5268. #include <pmachine.h>
  5269.  
  5270. #ifdef NEED_STRING_H
  5271. # include <string.h>
  5272. #else
  5273. # include <strings.h>
  5274. #endif
  5275.  
  5276. #if defined(MSDOS)
  5277. # include <stdlib.h>
  5278. #endif
  5279.  
  5280. char    *stcopyr();
  5281.  
  5282. int    string_count = 0;
  5283. int    string_max = 0;
  5284.  
  5285. /*
  5286.  * stcopy - allocate space for and copy a string
  5287.  *
  5288.  *     STCOPY takes a string as an argument, allocates space for
  5289.  *     a copy of the string, copies the string to the allocated space,
  5290.  *     and returns a pointer to the copy.
  5291.  */
  5292.  
  5293. char *
  5294. stcopy(st)
  5295.     char    *st;
  5296.     {
  5297.       if (!st) return(NULL);
  5298.       if (string_max < ++string_count) string_max = string_count;
  5299.  
  5300.       return strcpy((char *)malloc(strlen(st) + 1), st);
  5301.     }
  5302.  
  5303. /*
  5304.  * stcopyr - copy a string allocating space if necessary
  5305.  *
  5306.  *     STCOPYR takes a string, S, as an argument, and a pointer to a second
  5307.  *     string, R, which is to be replaced by S.  If R is long enough to
  5308.  *     hold S, S is copied.  Otherwise, new space is allocated, and R is
  5309.  *     freed.  S is then copied to the newly allocated space.  If S is
  5310.  *     NULL, then R is freed and NULL is returned.
  5311.  *
  5312.  *     In any event, STCOPYR returns a pointer to the new copy of S,
  5313.  *     or a NULL pointer.
  5314.  */
  5315. char *
  5316. stcopyr(s,r)
  5317.     char    *s;
  5318.     char    *r;
  5319.     {
  5320.     int    sl;
  5321.  
  5322.     if(!s && r) {
  5323.         free(r);
  5324.         string_count--;
  5325.         return(NULL);
  5326.     }
  5327.     else if (!s) return(NULL);
  5328.  
  5329.     sl = strlen(s) + 1;
  5330.  
  5331.     if(r) {
  5332.         if ((strlen(r) + 1) < sl) {
  5333.         free(r);
  5334.         r = (char *) malloc(sl);
  5335.         }
  5336.     }
  5337.     else {
  5338.         r = (char *) malloc(sl);
  5339.         string_count++;
  5340.         if(string_max < string_count) string_max = string_count;
  5341.     }
  5342.         
  5343.     return strcpy(r,s);
  5344.     }
  5345.  
  5346. /*
  5347.  * stfree - free space allocated by stcopy or stalloc
  5348.  *
  5349.  *     STFREE takes a string that was returned by stcopy or stalloc 
  5350.  *     and frees the space that was allocated for the string.
  5351.  */
  5352. void
  5353. stfree(st)
  5354.     char *st;
  5355.     {
  5356.     if(st) {
  5357.         free(st);
  5358.         string_count--;
  5359.     }
  5360.     }
  5361.  
  5362.  
  5363. $EOD
  5364. $!
  5365. $CREATE [.archie]support.c
  5366. $DECK
  5367. /*
  5368.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  5369.  *
  5370.  * For copying and distribution information, please see the file
  5371.  * <copyright.h>.
  5372.  *
  5373.  * v1.2.2 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  5374.  * v1.2.1 - 09/23/91 (gf)  - made it use regex.h---much nicer
  5375.  * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  5376.  * v1.1.1 - 08/30/91 (bpk) - added VMS support; cast index()
  5377.  */
  5378.  
  5379. /*
  5380.  * Miscellaneous routines pulled from ~beta/lib/pfs and ~beta/lib/filters
  5381.  */
  5382.  
  5383. #include <copyright.h>
  5384. #include <stdio.h>
  5385.  
  5386. #include <errno.h>
  5387.  
  5388. #ifdef VMS
  5389. # ifdef WALLONGONG
  5390. #  include "twg$tcp:[netdist.include]netdb.h"
  5391. # else /* Multinet */
  5392. #  include "multinet_root:[multinet.include]netdb.h"
  5393. # endif
  5394. # include <vms.h>
  5395. #else /* not VMS */
  5396. # include <sys/types.h>
  5397. # include <pmachine.h>
  5398. # ifdef NEED_STRING_H
  5399. #  include <string.h>
  5400. # else
  5401. #  include <strings.h>
  5402. # endif
  5403. # include <netdb.h>
  5404. # if !defined(MSDOS) || defined(OS2)
  5405. #  include <sys/file.h>
  5406. #  include <sys/param.h>
  5407. # endif
  5408. #endif /* VMS */
  5409.  
  5410. #include <pfs.h>
  5411. #include <pprot.h>
  5412. #include <perrno.h>
  5413. #include <pcompat.h>
  5414. #include <pauthent.h>
  5415.  
  5416. #include "regex.h"
  5417.  
  5418. int    pfs_enable = PMAP_ATSIGN;
  5419.  
  5420. #ifndef FALSE
  5421. # define TRUE     1
  5422. # define FALSE   0
  5423. #endif
  5424.  
  5425. /* 
  5426.  * wcmatch - Match string s against template containing widlcards
  5427.  *
  5428.  *         WCMATCH takes a string and a template, and returns
  5429.  *         true if the string matches the template, and 
  5430.  *         FALSE otherwise.
  5431.  *
  5432.  *    ARGS:  s        - string to be tested
  5433.  *           template - Template containing optional wildcards
  5434.  *
  5435.  * RETURNS:  TRUE (non-zero) on match.  FALSE (0) otherwise.
  5436.  *
  5437.  *    NOTE:  If template is NULL, will return TRUE.
  5438.  *
  5439.  */
  5440. int
  5441. wcmatch(s,template)
  5442.     char    *s;
  5443.     char    *template;
  5444.     {
  5445.     char    temp[200];
  5446.     char    *p = temp;
  5447.  
  5448.     if(!template) return(TRUE);
  5449.     *p++ = '^';
  5450.  
  5451.     while(*template) {
  5452.         if(*template == '*') {*(p++)='.'; *(p++) = *(template++);}
  5453.         else if(*template == '?') {*(p++)='.';template++;}
  5454.         else if(*template == '.') {*(p++)='\\';*(p++)='.';template++;}
  5455.         else if(*template == '[') {*(p++)='\\';*(p++)='[';template++;}
  5456.         else if(*template == '$') {*(p++)='\\';*(p++)='$';template++;}
  5457.         else if(*template == '^') {*(p++)='\\';*(p++)='^';template++;}
  5458.         else if(*template == '\\') {*(p++)='\\';*(p++)='\\';template++;}
  5459.         else *(p++) = *(template++);
  5460.     }
  5461.         
  5462.     *p++ = '$';
  5463.     *p++ = '\0';
  5464.  
  5465.     if(re_comp(temp)) return(FALSE);
  5466.  
  5467. #ifdef AUX
  5468.     if (re_exec(s) == (char *)NULL)
  5469.       return 0;
  5470.     return 1;
  5471. #else
  5472.     return(re_exec(s));
  5473. #endif
  5474.     }
  5475.  
  5476. /*
  5477.  * ul_insert - Insert a union link at the right location
  5478.  *
  5479.  *             UL_INSERT takes a directory and a union link to be added
  5480.  *             to a the list of union links in the directory.  It then
  5481.  *             inserts the union link in the right spot in the linked
  5482.  *             list of union links associated with that directory.
  5483.  *
  5484.  *           If an identical link already exists, then the link which
  5485.  *             would be evaluated earlier (closer to the front of the list)
  5486.  *             wins and the other one is freed.  If this happens, an error
  5487.  *             will also be returned.
  5488.  *        
  5489.  *    ARGS:    ul    - link to be inserted
  5490.  *           vd    - directory to get link
  5491.  *             p     - vl that this link will apper after
  5492.  *                     NULL - This vl will go at end of list
  5493.  *                     vd   - This vl will go at head of list
  5494.  *
  5495.  * RETURNS:    Success, or UL_INSERT_ALREADY_THERE or UL_INSERT_SUPERSEDING
  5496.  */
  5497. int
  5498. ul_insert(ul,vd,p)
  5499.     VLINK    ul;        /* Link to be inserted                   */
  5500.     VDIR    vd;        /* Directory to receive link             */
  5501.     VLINK    p;        /* Union link to appear prior to new one */
  5502.     {
  5503.     VLINK    current;
  5504.  
  5505.     /* This is the first ul in the directory */
  5506.     if(vd->ulinks == NULL) {
  5507.         vd->ulinks = ul;
  5508.         ul->previous = NULL;
  5509.         ul->next = NULL;
  5510.         return(PSUCCESS);
  5511.     }
  5512.  
  5513.     /* This ul will go at the head of the list */
  5514.     if(p == (VLINK) vd) {
  5515.         ul->next = vd->ulinks;
  5516.         ul->next->previous = ul;
  5517.         vd->ulinks = ul;
  5518.         ul->previous = NULL;
  5519.     }
  5520.     /* Otherwise, decide if it must be inserted at all  */
  5521.     /* If an identical link appears before the position */
  5522.     /* at which the new one is to be inserted, we can   */
  5523.     /* return without inserting it                 */
  5524.     else {
  5525.         current = vd->ulinks;
  5526.  
  5527.         while(current) {
  5528.         /* p == NULL means we insert after last link */
  5529.         if(!p && (current->next == NULL))
  5530.             p = current;
  5531.  
  5532.         if(vl_comp(current,ul) == 0) {
  5533.             vlfree(ul);
  5534.             return(UL_INSERT_ALREADY_THERE);
  5535.         }
  5536.  
  5537.         if(current == p) break;
  5538.         current = current->next;
  5539.         }
  5540.  
  5541.         /* If current is null, p was not found */
  5542.         if(current == NULL)
  5543.         return(UL_INSERT_POS_NOTFOUND);
  5544.  
  5545.         /* Insert ul */
  5546.         ul->next = p->next;
  5547.         p->next = ul;
  5548.         ul->previous = p;
  5549.         if(ul->next) ul->next->previous = ul;
  5550.     }
  5551.  
  5552.     /* Check for identical links after ul */
  5553.     current = ul->next;
  5554.  
  5555.     while(current) {
  5556.         if(vl_comp(current,ul) == 0) {
  5557.         current->previous->next = current->next;
  5558.         if(current->next)
  5559.             current->next->previous = current->previous;
  5560.         vlfree(current);
  5561.         return(UL_INSERT_SUPERSEDING);
  5562.         }
  5563.         current = current->next;
  5564.     }
  5565.     
  5566.     return(PSUCCESS);
  5567.     }
  5568.  
  5569. /*
  5570.  * vl_insert - Insert a directory link at the right location
  5571.  *
  5572.  *             VL_INSERT takes a directory and a link to be added to a 
  5573.  *             directory and inserts it in the linked list of links for
  5574.  *             that directory.  
  5575.  *
  5576.  *             If a link already exists with the same name, and if the
  5577.  *             information associated with the new link matches that in
  5578.  *             the existing link, an error is returned.  If the information
  5579.  *             associated with the new link is different, but the magic numbers
  5580.  *             match, then the new link will be added as a replica of the
  5581.  *             existing link.  If the magic numbers do not match, the new
  5582.  *             link will only be added to the list of "replicas" if the
  5583.  *             allow_conflict flag has been set.
  5584.  * 
  5585.  *             If the link is not added, an error is returned and the link
  5586.  *             is freed.  Ordering for the list of links is by the link name.  
  5587.  *        
  5588.  *             If vl is a union link, then VL_INSERT calls ul_insert with an
  5589.  *           added argument indicating the link is to be included at the
  5590.  *             end of the union link list.
  5591.  * 
  5592.  *    ARGS:    vl - Link to be inserted, vd - directory to get link
  5593.  *             allow_conflict - insert links with conflicting names
  5594.  *
  5595.  * RETURNS:    Success, or VL_INSERT_ALREADY_THERE
  5596.  */
  5597. int
  5598. vl_insert(vl,vd,allow_conflict)
  5599.     VLINK    vl;        /* Link to be inserted               */
  5600.     VDIR    vd;        /* Directory to receive link         */
  5601.     int        allow_conflict;    /* Allow duplicate names             */
  5602.     {
  5603.     VLINK    current;    /* To step through list             */
  5604.     VLINK    crep;        /* To step through list of replicas  */
  5605.     int    retval;        /* Temp for checking returned values */
  5606.  
  5607.     /* This can also be used to insert union links at end of list */
  5608.     if(vl->linktype == 'U') return(ul_insert(vl,vd,NULL));
  5609.  
  5610.     /* If this is the first link in the directory */
  5611.     if(vd->links == NULL) {
  5612.         vd->links = vl;
  5613.         vl->previous = NULL;
  5614.         vl->next = NULL;
  5615.         vd->lastlink = vl;
  5616.         return(PSUCCESS);
  5617.     }
  5618.  
  5619.     /* If no sorting is to be done, just insert at end of list */
  5620.     if(allow_conflict == VLI_NOSORT) {
  5621.         vd->lastlink->next = vl;
  5622.         vl->previous = vd->lastlink;
  5623.         vl->next = NULL;
  5624.         vd->lastlink = vl;
  5625.         return(PSUCCESS);
  5626.     }
  5627.  
  5628.     /* If it is to be inserted at start of list */
  5629.     if(vl_comp(vl,vd->links) < 0) {
  5630.         vl->next = vd->links;
  5631.         vl->previous = NULL;
  5632.         vl->next->previous = vl;
  5633.         vd->links = vl;
  5634.         return(PSUCCESS);
  5635.     }
  5636.  
  5637.     current = vd->links;
  5638.  
  5639.     /* Otherwise, we must find the right spot to insert it */
  5640.     while((retval = vl_comp(vl,current)) > 0) {
  5641.         if(!current->next) {
  5642.         /* insert at end */
  5643.         vl->previous = current;
  5644.         vl->next = NULL;
  5645.         current->next = vl;
  5646.         vd->lastlink = vl;
  5647.         return(PSUCCESS);
  5648.         }
  5649.         current = current->next;
  5650.     }
  5651.  
  5652.     /* If we found an equivilant entry already in list */
  5653.     if(!retval) {
  5654.         if(vl_equal(vl,current)) {
  5655.         vlfree(vl);
  5656.         return(VL_INSERT_ALREADY_THERE);
  5657.         }
  5658.         if((allow_conflict == VLI_NOCONFLICT) &&
  5659.            ((vl->f_magic_no != current->f_magic_no) ||
  5660.         (vl->f_magic_no==0)))
  5661.         return(VL_INSERT_CONFLICT);
  5662.         /* Insert the link into the list of "replicas" */
  5663.         /* If magic is 0, then create a pseudo magic number */
  5664.         if(vl->f_magic_no == 0) vl->f_magic_no = -1;
  5665.         crep = current->replicas;
  5666.         if(!crep) {
  5667.         current->replicas = vl;
  5668.         vl->next = NULL;
  5669.         vl->previous = NULL;
  5670.         }
  5671.         else {
  5672.         while(crep->next) {
  5673.             /* If magic was 0, then we need a unique magic number */
  5674.             if((crep->f_magic_no < 0) && (vl->f_magic_no < 1))
  5675.             (vl->f_magic_no)--;
  5676.             crep = crep->next;
  5677.         }
  5678.         /* If magic was 0, then we need a unique magic number */
  5679.         if((crep->f_magic_no < 0) && (vl->f_magic_no < 1))
  5680.             (vl->f_magic_no)--;
  5681.         crep->next = vl;
  5682.         vl->previous = crep;
  5683.         vl->next = NULL;
  5684.         }
  5685.         return(PSUCCESS);
  5686.     }
  5687.  
  5688.     /* We found the spot where vl is to be inserted */
  5689.     vl->next = current;
  5690.     vl->previous = current->previous;
  5691.     current->previous = vl;
  5692.     vl->previous->next = vl;
  5693.     return(PSUCCESS);
  5694.     }
  5695.  
  5696. /*
  5697.  * nlsindex - Find first instance of string 2 in string 1 following newline
  5698.  *
  5699.  *          NLSINDEX scans string 1 for the first instance of string
  5700.  *          2 that immediately follows a newline.  If found, NLSINDEX
  5701.  *          returns a pointer to the first character of that instance.
  5702.  *          If no instance is found, NLSINDEX returns NULL (0).
  5703.  *
  5704.  *    NOTE:   This function is only useful for searching strings that
  5705.  *            consist of multiple lines.  s1 is assumed to be preceeded
  5706.  *           by a newline.  Thus, if s2 is at the start of s1, it will
  5707.  *          be found.
  5708.  *    ARGS:   s1 - string to be searched
  5709.  *            s2 - string to be found
  5710.  * RETURNS:   First instance of s2 in s1, or NULL (0) if not found
  5711.  */
  5712. char *
  5713. nlsindex(s1,s2)
  5714.     char    *s1;        /* String to be searched */
  5715.     char    *s2;        /* String to be found    */
  5716.     {
  5717.     register int s2len = strlen(s2);
  5718.     char    *curline = s1;    /* Pointer to start of current line */
  5719.  
  5720.     /* In case s2 appears at start of s1 */
  5721.     if(strncmp(curline,s2,s2len) == 0)
  5722.         return(curline);
  5723.  
  5724.     /* Check remaining lines of s1 */
  5725.     while((curline = (char *) index(curline,'\n')) != NULL) {
  5726.         curline++;
  5727.         if(strncmp(curline,s2,s2len) == 0)
  5728.         return(curline);
  5729.     }
  5730.  
  5731.     /* We didn't find it */
  5732.     return(NULL);
  5733.     }
  5734.  
  5735. /*
  5736.  * month_sname - Return a month name from it's number
  5737.  *
  5738.  *               MONTH_SNAME takes a number in the range 0
  5739.  *               to 12 and returns a pointer to a string
  5740.  *               representing the three letter abbreviation
  5741.  *             for that month.  If the argument is out of 
  5742.  *         range, MONTH_SNAME returns a pointer to "Unk".
  5743.  *
  5744.  *       ARGS:   n - Number of the month
  5745.  *    RETURNS:   Abbreviation for selected month
  5746.  */
  5747. char *month_sname(n)
  5748.     int n;        /* Month number */
  5749. {
  5750.     static char *name[] = { "Unk",
  5751.         "Jan","Feb","Mar","Apr","May","Jun",
  5752.         "Jul","Aug","Sep","Oct","Nov","Dec"
  5753.     };
  5754.     return((n < 1 || n > 12) ? name[0] : name[n]);
  5755. }
  5756.  
  5757. /*
  5758.  * sindex - Find first instance of string 2 in string 1 
  5759.  *
  5760.  *          SINDEX scans string 1 for the first instance of string
  5761.  *          2.  If found, SINDEX returns a pointer to the first
  5762.  *          character of that instance.  If no instance is found, 
  5763.  *          SINDEX returns NULL (0).
  5764.  *
  5765.  *    ARGS:   s1 - string to be searched
  5766.  *            s2 - string to be found
  5767.  * RETURNS:   First instance of s2 in s1, or NULL (0) if not found
  5768.  */
  5769. char *
  5770. sindex(s1,s2)
  5771.     char    *s1;        /* String to be searched   */
  5772.     char    *s2;        /* String to be found      */
  5773.     {
  5774.     register int s2len = strlen(s2);
  5775.     char    *s = s1;    /* Temp pointer to string  */
  5776.  
  5777.     /* Check for first character of s2 */
  5778.     while((s = (char *) index(s,*s2)) != NULL) {
  5779.         if(strncmp(s,s2,s2len) == 0)
  5780.         return(s);
  5781.         s++;
  5782.     }
  5783.  
  5784.     /* We didn't find it */
  5785.     return(NULL);
  5786.     }
  5787.  
  5788. int
  5789. scan_error(erst)
  5790.     char    *erst;
  5791.     {
  5792.     *p_err_string = '\0';
  5793.  
  5794.     if(strncmp(erst,"NOT-A-DIRECTORY",15) == 0) 
  5795.         return(DIRSRV_NOT_DIRECTORY);
  5796.  
  5797.     if(strncmp(erst,"UNIMPLEMENTED",13) == 0) {
  5798.         perrno = DIRSRV_UNIMPLEMENTED;
  5799.         sscanf(erst+13,"%*[^\n \t\r]%*[ \t]%[^\n]",p_err_string);
  5800.         return(perrno);
  5801.     }
  5802.  
  5803.     if(strncmp(erst,"WARNING ",8) == 0) {
  5804.         erst += 8;
  5805.         *p_warn_string = '\0';
  5806.         sscanf(erst,"%*[^\n \t\r]%*[ \t]%[^\n]",p_warn_string);
  5807.         /* Return values for warnings are negative */
  5808.         if(strncmp(erst,"OUT-OF-DATE",11) == 0) {
  5809.         pwarn = PWARN_OUT_OF_DATE;
  5810.         return(PSUCCESS);
  5811.         }
  5812.         if(strncmp(erst,"MESSAGE",7) == 0) {
  5813.         pwarn = PWARN_MSG_FROM_SERVER;
  5814.         return(PSUCCESS);
  5815.         }
  5816.         pwarn = PWARNING;
  5817.         sscanf(erst,"%[^\n]",p_warn_string);
  5818.         return(PSUCCESS);
  5819.     }
  5820.     else if(strncmp(erst,"ERROR",5) == 0) {
  5821.         if(*(erst+5)) sscanf(erst+6,"%[^\n]",p_err_string);
  5822.         perrno = DIRSRV_ERROR;
  5823.         return(perrno);
  5824.     }
  5825.     /* The rest start with "FAILURE" */
  5826.     else if(strncmp(erst,"FAILURE",7) != 0) {
  5827.         /* Unrecognized - Give warning, but return PSUCCESS */
  5828.         if(pwarn == 0) {
  5829.         *p_warn_string = '\0';
  5830.         pwarn = PWARN_UNRECOGNIZED_RESP;
  5831.         sscanf(erst,"%[^\n]",p_warn_string);
  5832.         }
  5833.         return(PSUCCESS);
  5834.     }
  5835.  
  5836.     if(strncmp(erst,"FAILURE ",8) != 0) {
  5837.         perrno = PFAILURE;
  5838.         return(perrno);
  5839.     }    
  5840.     erst += 8;
  5841.     
  5842.     sscanf(erst,"%*[^\n \t\r]%*[ \t]%[^\n]",p_err_string);
  5843.  
  5844.     /* Still to add               */
  5845.     /* DIRSRV_AUTHENT_REQ     242 */
  5846.     /* DIRSRV_BAD_VERS        245 */
  5847.  
  5848.     if(strncmp(erst,"NOT-FOUND",9) == 0) 
  5849.         perrno = DIRSRV_NOT_FOUND;
  5850.     else if(strncmp(erst,"NOT-AUTHORIZED",13) == 0) 
  5851.         perrno = DIRSRV_NOT_AUTHORIZED;
  5852.     else if(strncmp(erst,"ALREADY-EXISTS",14) == 0) 
  5853.         perrno = DIRSRV_ALREADY_EXISTS;
  5854.     else if(strncmp(erst,"NAME-CONFLICT",13) == 0) 
  5855.         perrno = DIRSRV_NAME_CONFLICT;
  5856.     else if(strncmp(erst,"SERVER-FAILED",13) == 0) 
  5857.         perrno = DIRSRV_SERVER_FAILED;
  5858.      /* Use it whether it starts with FAILURE or not */
  5859.     else if(strncmp(erst,"NOT-A-DIRECTORY",15) == 0) 
  5860.         perrno = DIRSRV_NOT_DIRECTORY;
  5861.     else perrno = PFAILURE;
  5862.  
  5863.     return(perrno);
  5864.     }
  5865.  
  5866. PATTRIB 
  5867. parse_attribute(line)
  5868.     char    *line;
  5869.     {
  5870.     char    l_precedence[MAX_DIR_LINESIZE];
  5871.     char    l_name[MAX_DIR_LINESIZE];
  5872.     char    l_type[MAX_DIR_LINESIZE];
  5873.     char    l_value[MAX_DIR_LINESIZE];
  5874.     PATTRIB    at;
  5875.     int    tmp;
  5876.  
  5877.     tmp = sscanf(line,"OBJECT-INFO %s %s %[^\n]", l_name, l_type, l_value);
  5878.     
  5879.     if(tmp < 3) {
  5880.         tmp = sscanf(line,"LINK-INFO %s %s %s %[^\n]", l_precedence,
  5881.              l_name, l_type, l_value);
  5882.         if(tmp < 4) {
  5883.         perrno = DIRSRV_BAD_FORMAT;
  5884.         return(NULL);
  5885.         }
  5886.     }
  5887.  
  5888.     at = atalloc();
  5889.  
  5890.     if(tmp == 4) {
  5891.         if(strcmp(l_precedence,"CACHED") == 0) 
  5892.         at->precedence = ATR_PREC_CACHED;
  5893.         else if(strcmp(l_precedence,"LINK") == 0) 
  5894.         at->precedence = ATR_PREC_LINK;
  5895.         else if(strcmp(l_precedence,"REPLACEMENT") == 0) 
  5896.         at->precedence = ATR_PREC_REPLACE;
  5897.         else if(strcmp(l_precedence,"ADDITIONAL") == 0) 
  5898.         at->precedence = ATR_PREC_ADD;
  5899.     }
  5900.  
  5901.     at->aname = stcopy(l_name);
  5902.     at->avtype = stcopy(l_type);
  5903.     if(strcmp(l_type,"ASCII") == 0) 
  5904.         at->value.ascii = stcopy(l_value);
  5905.     else if(strcmp(l_type,"LINK") == 0) {
  5906.         char        ftype[MAX_DIR_LINESIZE];
  5907.         char        lname[MAX_DIR_LINESIZE];
  5908.         char        htype[MAX_DIR_LINESIZE];
  5909.         char        host[MAX_DIR_LINESIZE];
  5910.         char        ntype[MAX_DIR_LINESIZE];
  5911.         char        fname[MAX_DIR_LINESIZE];
  5912.         VLINK        al;
  5913.  
  5914.         al = vlalloc();
  5915.         at->value.link = al;
  5916.  
  5917.         tmp = sscanf(l_value,"%c %s %s %s %s %s %s %d %d",
  5918.              &(al->linktype),
  5919.              ftype,lname,htype,host,ntype,fname,
  5920.              &(al->version),
  5921.              &(al->f_magic_no));
  5922.         if(tmp == 9) {
  5923.         al->type = stcopyr(ftype,al->type);
  5924.         al->name = stcopyr(unquote(lname),al->name);
  5925.         al->hosttype = stcopyr(htype,al->hosttype);
  5926.         al->host = stcopyr(host,al->host);
  5927.         al->nametype = stcopyr(ntype,al->nametype);
  5928.         al->filename = stcopyr(fname,al->filename);
  5929.         }
  5930.         else {
  5931.         perrno = DIRSRV_BAD_FORMAT;
  5932.         return(NULL);
  5933.         }
  5934.         
  5935.     }
  5936.  
  5937.     return(at);
  5938.     }
  5939.  
  5940. /*
  5941.  * nxtline - Find the next line in the string
  5942.  *
  5943.  *          NXTLINE takes a string and returns a pointer to
  5944.  *          the character immediately following the next newline.
  5945.  *
  5946.  *    ARGS:   s - string to be searched
  5947.  *
  5948.  * RETURNS:   Next line or NULL (0) on failure
  5949.  */
  5950. char *
  5951. nxtline(s)
  5952.     char    *s;        /* String to be searched */
  5953.  {
  5954.     s = (char *) index(s,'\n');
  5955.     if(s) return(++s);
  5956.     else return(NULL);
  5957.     }
  5958.  
  5959.  
  5960. /*
  5961.  * unquote - unquote string if necessary
  5962.  *
  5963.  *          UNQUOTE takes a string and unquotes it if it has been quoted.
  5964.  *
  5965.  *    ARGS:   s - string to be unquoted
  5966.  *            
  5967.  * RETURNS:   The original string.  If the string has been quoted, then the
  5968.  *            result appears in static storage, and must be copied if 
  5969.  *            it is to last beyond the next call to quote.
  5970.  *
  5971.  */
  5972. char *
  5973. unquote(s)
  5974.     char    *s;        /* String to be quoted */
  5975.     {
  5976.     static char    unquoted[200];
  5977.     char        *c = unquoted;
  5978.  
  5979.     if(*s != '\'') return(s);
  5980.  
  5981.     s++;
  5982.  
  5983.     /* This should really treat a quote followed by other */
  5984.     /* than a quote or a null as an error                 */
  5985.     while(*s) {
  5986.         if(*s == '\'') s++;
  5987.         if(*s) *c++ = *s++;
  5988.     }
  5989.  
  5990.     *c++ = '\0';
  5991.  
  5992.     return(unquoted);
  5993.     }
  5994.  
  5995. #if defined(DEBUG) && defined(STRSPN)
  5996. /* needed for -D option parsing */
  5997. /*
  5998.  * strspn - Count initial characters from chrs in s
  5999.  *
  6000.  *          STRSPN counts the occurances of chacters from chrs
  6001.  *            in the string s preceeding the first occurance of
  6002.  *            a character not in s.
  6003.  *
  6004.  *    ARGS:   s    - string to be checked
  6005.  *            chrs - string of characters we are looking for
  6006.  *
  6007.  * RETURNS:   Count of initial characters from chrs in s
  6008.  */
  6009. strspn(s,chrs)
  6010.     char    *s;    /* String to search                         */
  6011.     char    *chrs; /* String of characters we are looking for  */
  6012.     {
  6013.     char    *cp;   /* Pointer to the current character in chrs */
  6014.     int    count; /* Count of characters seen so far          */
  6015.     
  6016.     count = 0;
  6017.  
  6018.     while(*s) {
  6019.         for(cp = chrs;*cp;cp++)
  6020.         if(*cp == *s) {
  6021.             s++;
  6022.             count++;
  6023.             goto done;
  6024.         }
  6025.         return(count);
  6026.     done:
  6027.         ;
  6028.     }
  6029.     return(count);
  6030.     }
  6031. #endif
  6032. $EOD
  6033. $!
  6034. $CREATE [.archie]copyright.h
  6035. $DECK
  6036. /* 
  6037.   Copyright (c) 1989, 1990, 1991 by the University of Washington
  6038.  
  6039.   Permission to use, copy, modify, and distribute this software and its
  6040.   documentation for non-commercial purposes and without fee is hereby
  6041.   granted, provided that the above copyright notice appear in all copies
  6042.   and that both the copyright notice and this permission notice appear in
  6043.   supporting documentation, and that the name of the University of
  6044.   Washington not be used in advertising or publicity pertaining to
  6045.   distribution of the software without specific, written prior
  6046.   permission.  The University of Washington makes no representations
  6047.   about the suitability of this software for any purpose.  It is
  6048.   provided "as is" without express or implied warranty.
  6049.  
  6050.   Prospero was written by Clifford Neuman (bcn@isi.edu).
  6051.  
  6052.   Questions concerning this software should be directed to 
  6053.   info-prospero@isi.edu.
  6054.  
  6055.   */
  6056. $EOD
  6057. $!
  6058. $CREATE [.archie]udp.c
  6059. $DECK
  6060. /*
  6061.  * udp - Check if UDP traffic is allowed on this host; we open port 1527 on
  6062.  *       a system (default of cs.widener.edu), which is expecting it; the
  6063.  *       date is output (e.g. very similar to the daytime service).  This
  6064.  *       will conclusively tell us if UDP traffic on ports > 1000 is allowed.
  6065.  *
  6066.  *    It should print out the date if UDP traffic's not blocked on your
  6067.  *    system.  If it just hangs, try these tests too:
  6068.  *      a. run it with -d  (e.g. "udp -d"); that goes to the normal UDP port
  6069.  *         to print the date.  If it works, then you can be sure that any
  6070.  *         UDP traffic > port 1000 is blocked on your system.
  6071.  *      b. if it hangs too, try "telnet 147.31.254.130 13" and see if
  6072.  *         _that_ prints the date; if it doesn't, it's another problem (your
  6073.  *         network can't get to me, e.g.).
  6074.  *
  6075.  * Compile by: cc -o udp udp.c
  6076.  *
  6077.  * Brendan Kehoe, brendan@cs.widener.edu, Oct 1991.
  6078.  */
  6079.  
  6080. #include <stdio.h>
  6081. #include <sys/types.h>
  6082. #include <sys/socket.h>
  6083. #include <netinet/in.h>
  6084. #ifndef hpux
  6085. # include <arpa/inet.h>
  6086. #endif
  6087.  
  6088. #define    SIZE    2048
  6089. #define    HOST    "147.31.254.130"    /* cs.widener.edu */
  6090. #define PORT    1527
  6091.  
  6092. main (argc, argv)
  6093.      int argc;
  6094.      char **argv;
  6095. {
  6096.   int s, len;
  6097.   struct sockaddr_in server, sa;
  6098.   char buf[SIZE];
  6099.  
  6100.   if ((s = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
  6101.     {
  6102.       perror ("socket()");
  6103.       exit (1);
  6104.     }
  6105.  
  6106.   bzero ((char *) &sa, sizeof (sa));
  6107.   sa.sin_family = AF_INET;
  6108.   sa.sin_addr.s_addr = htonl (INADDR_ANY);
  6109.   sa.sin_port = htons (0);
  6110.  
  6111.   if (bind (s, (struct sockaddr *) &sa, sizeof (sa)) < 0)
  6112.     {
  6113.       perror ("bind()");
  6114.       exit (1);
  6115.     }
  6116.  
  6117.   bzero ((char *) &server, sizeof (server));
  6118.   server.sin_family = AF_INET;
  6119.   server.sin_addr.s_addr = inet_addr (HOST);
  6120.   if (argc > 1 && strcmp(*(argv + 1), "-d") == 0)
  6121.     server.sin_port = htons ((unsigned short) 13);
  6122.   else
  6123.     server.sin_port = htons ((unsigned short) PORT);
  6124.  
  6125.   /* yoo hoo, we're here .. */
  6126.   if (sendto (s, "\n", 1, 0, &server, sizeof (server)) < 0)
  6127.     {
  6128.       perror ("sendto()");
  6129.       exit (1);
  6130.     }
  6131.  
  6132.   /* slurp */
  6133.   len = sizeof (server);
  6134.   if (recvfrom (s, buf, sizeof (buf), 0, &server, &len) < 0)
  6135.     {
  6136.       perror ("recvfrom");
  6137.       exit (1);
  6138.     }
  6139.  
  6140.   printf ("%s", buf);
  6141.   close (s);
  6142. }
  6143. $EOD
  6144. $!
  6145. $CREATE [.archie]vl_comp.c
  6146. $DECK
  6147. /*
  6148.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  6149.  *
  6150.  * For copying and distribution information, please see the file
  6151.  * <copyright.h>.
  6152.  */
  6153.  
  6154. #include <copyright.h>
  6155. #include <pfs.h>
  6156.  
  6157. /*
  6158.  * vl_comp - compare the names of two virtual links
  6159.  *
  6160.  *           VL_COMP compares the names of two links.  It returns
  6161.  *           0 if they are equal, negative if vl1 < vl2, and positive if
  6162.  *           vl1 > vl2.
  6163.  *
  6164.  *    ARGS:  vl1,vl2 - Virtual links to be compared
  6165.  * 
  6166.  * RETURNS:  0 if equal, + is vl1 > vl2, - if vl1 < vl2
  6167.  *
  6168.  *   NOTES:  Order of significance is as follows.  Existence,
  6169.  *           name.  If names do not exist, then hosttype, host,
  6170.  *           native filenametype, native filename.  The only time
  6171.  *           the name will not exist if if the link is a union link.
  6172.  */
  6173. int
  6174. vl_comp(vl1,vl2)
  6175.     VLINK    vl1;
  6176.     VLINK    vl2;
  6177.     {
  6178.     int    retval;
  6179.  
  6180.     if(vl1->name && !vl2->name) return(1);
  6181.     if(!vl1->name && vl2->name) return(-1);
  6182.     if(vl1->name && vl2->name && (*(vl1->name) || *(vl2->name)))
  6183.         return(strcmp(vl1->name,vl2->name));
  6184.  
  6185.     retval = strcmp(vl1->hosttype,vl2->hosttype);
  6186.     if(!retval) retval = strcmp(vl1->host,vl2->host);
  6187.     if(!retval) retval = strcmp(vl1->nametype,vl2->nametype);
  6188.     if(!retval) retval = strcmp(vl1->filename,vl2->filename);
  6189.     return(retval);
  6190.     }
  6191.  
  6192. /*
  6193.  * vl_equal - compare the values of two virtual links
  6194.  *
  6195.  *           VL_EQUAL compares the values of two links.  It returns
  6196.  *           1 if all important fields are the same, and 0 otherwise.
  6197.  *
  6198.  *    ARGS:  vl1,vl2 - Virtual links to be compared
  6199.  * 
  6200.  * RETURNS:  1 if equal, 0 if not equal
  6201.  *
  6202.  */
  6203. int
  6204. vl_equal(vl1,vl2)
  6205.     VLINK    vl1;
  6206.     VLINK    vl2;
  6207.     {
  6208.       return strcmp(vl1->name, vl2->name) == 0         &&
  6209.          vl1->linktype == vl2->linktype            &&
  6210.          strcmp(vl1->type, vl2->type) == 0         &&
  6211.          strcmp(vl1->hosttype, vl2->hosttype) == 0 &&
  6212.          strcmp(vl1->host, vl2->host) == 0         &&
  6213.          strcmp(vl1->nametype, vl2->nametype) == 0 &&
  6214.          strcmp(vl1->filename, vl2->filename) == 0 &&
  6215.          vl1->version == vl2->version              &&
  6216.          vl1->f_magic_no == vl2->f_magic_no        ;
  6217.  
  6218.     }
  6219.  
  6220. $EOD
  6221. $!
  6222. $CREATE [.archie]vlalloc.c
  6223. $DECK
  6224. /*
  6225.  * Copyright (c) 1989, 1990, 1991 by the University of Washington
  6226.  *
  6227.  * For copying and distribution information, please see the file
  6228.  * <copyright.h>.
  6229.  */
  6230.  
  6231. #include <copyright.h>
  6232. #include <stdio.h>
  6233.  
  6234. #include <pfs.h>
  6235. #include <pmachine.h>
  6236.  
  6237. static VLINK    lfree = NULL;
  6238. int        vlink_count = 0;
  6239. int        vlink_max = 0;
  6240.  
  6241. /*
  6242.  * vlalloc - allocate and initialize vlink structure
  6243.  *
  6244.  *    VLALLOC returns a pointer to an initialized structure of type
  6245.  *    VLINK.  If it is unable to allocate such a structure, it
  6246.  *    returns NULL.
  6247.  */
  6248. VLINK
  6249. vlalloc()
  6250.     {
  6251.     VLINK    vl;
  6252.     if(lfree) {
  6253.         vl = lfree;
  6254.         lfree = lfree->next;
  6255.     }
  6256.     else {
  6257.         vl = (VLINK) malloc(sizeof(VLINK_ST));
  6258.         if (!vl) return(NULL);
  6259.         vlink_max++;
  6260.     }
  6261.  
  6262.     vlink_count++;
  6263.  
  6264.     /* Initialize and fill in default values */
  6265.     /* Since all but four are set to a zero-value,
  6266.        why not just wipe it clean?  */
  6267.     ZERO(vl);
  6268.  
  6269.     vl->linktype = 'L';
  6270.     vl->type = stcopy("FILE");
  6271.     vl->hosttype = stcopy("INTERNET-D");
  6272.     vl->nametype = stcopy("ASCII");
  6273.  
  6274.     return(vl);
  6275.     }
  6276.  
  6277. /*
  6278.  * vlfree - free a VLINK structure
  6279.  *
  6280.  *    VLFREE takes a pointer to a VLINK structure and adds it to
  6281.  *    the free list for later reuse.
  6282.  */
  6283. void
  6284. vlfree(vl)
  6285.     VLINK    vl;
  6286.     {
  6287.         extern int string_count;
  6288.  
  6289.     if(vl->dontfree) return;
  6290.     /* many of these don't need to call stfree(); since a check
  6291.        for pointer validity's already done before even calling
  6292.        it, we can just call free() here then do one big decrement
  6293.        of string_count at the end.  */
  6294.     if(vl->name) free(vl->name);
  6295.     stfree(vl->type);
  6296.     if(vl->replicas) vllfree(vl->replicas);
  6297.     stfree(vl->hosttype);
  6298.     if(vl->host) free(vl->host);
  6299.     stfree(vl->nametype);
  6300.     if(vl->filename) free(vl->filename);
  6301.     if(vl->args) free(vl->args);
  6302.     if(vl->lattrib) atlfree(vl->lattrib);
  6303.     /* No allocation routines for f_info yet */
  6304.     vl->f_info = NULL;
  6305.     vl->next = lfree;
  6306.     vl->previous = NULL;
  6307.     lfree = vl;
  6308.     vlink_count--;
  6309.     string_count -= 4; /* freed name, host, filename, and args */
  6310.     }
  6311.  
  6312. /*
  6313.  * vllfree - free a VLINK structure
  6314.  *
  6315.  *    VLLFREE takes a pointer to a VLINK structure frees it and any linked
  6316.  *    VLINK structures.  It is used to free an entrie list of VLINK
  6317.  *    structures.
  6318.  */
  6319. void
  6320. vllfree(vl)
  6321.     VLINK    vl;
  6322.     {
  6323.     VLINK    nxt;
  6324.  
  6325.     while((vl != NULL) && !vl->dontfree) {
  6326.         nxt = vl->next;
  6327.         vlfree(vl);
  6328.         vl = nxt;
  6329.     }
  6330.     }
  6331.  
  6332. $EOD
  6333. $!
  6334. $CREATE [.archie]vms.h
  6335. $DECK
  6336. #ifndef _ARCHIE_VMS
  6337. #define _ARCHIE_VMS
  6338. #include <pmachine.h>
  6339.  
  6340. #if !defined(MULTINET_30) && !defined(WALLONGONG)
  6341. #include "[.vms]pseudos.h"
  6342. #include "[.vms]types.h"
  6343. #include "[.vms]in.h"
  6344. #include "[.vms]signal.h"
  6345. #include "[.vms]socket.h"
  6346. #include "[.vms]time.h"
  6347.  
  6348. #else
  6349.  
  6350. /* time_t gets multiply defined <ekup> */
  6351. #ifndef __TYPES
  6352. #define __TYPES
  6353. #endif
  6354. #ifdef MULTINET_30
  6355. # include "multinet_root:[multinet.include.sys]types.h"
  6356. # include "multinet_root:[multinet.include.netinet]in.h"
  6357. # include "multinet_root:[multinet.include.sys]socket.h"
  6358. # include "multinet_root:[multinet.include.sys]time.h"
  6359. #endif /* MULTINET_30 */
  6360.  
  6361. #ifdef WALLONGONG
  6362. /* We don't want size_t defined.  */
  6363. # ifndef __STDDEF
  6364. #  define __STDDEF
  6365. # endif
  6366. # include "twg$tcp:[netdist.include.sys]types.h"
  6367. # include "twg$tcp:[netdist.include.netinet]in.h"
  6368. # include "twg$tcp:[netdist.include.sys]socket.h"
  6369. # include "twg$tcp:[netdist.include.sys]time.h"
  6370. #endif /* WALLONGONG */
  6371.  
  6372. #endif /* !MULTINET and !WALLONGONG */
  6373.  
  6374. #endif /* _ARCHIE_VMS */
  6375. $EOD
  6376. $!
  6377. $CREATE [.archie]vms_support.c
  6378. $DECK
  6379. /* Emulation of 4.2 UNIX socket interface routines includes drivers for
  6380.    Wollongong, CMU-TEK, UCX tcp/ip interface and also emulates the SUN
  6381.    version of X.25 sockets.  The TWG will also work for MultiNet.  */
  6382.  
  6383. /* This is from unixlib, by P.Kay@massey.ac.nz; wonderful implementation.
  6384.    You can get the real thing on 130.123.1.4 as unixlib_tar.z.  */
  6385.  
  6386. #include <stdio.h>
  6387. #include <errno.h>
  6388. #include <ssdef.h>
  6389. #include <dvidef.h>
  6390. #include <signal.h>
  6391. #include <sys$library:msgdef.h>
  6392. #include <iodef.h>
  6393. #include <ctype.h>
  6394. #include <vms.h>
  6395. #include "[.vms]network.h"
  6396.  
  6397. #define QIO_FAILED (st != SS$_NORMAL || p[s].iosb[0] != SS$_NORMAL)
  6398. #define QIO_ST_FAILED (st != SS$_NORMAL)
  6399.  
  6400. /* Socket routine.  */
  6401. int
  6402. VMSsocket (domain, type, protocol)
  6403.      int domain, type, protocol;
  6404. {
  6405.   struct descriptor inetdesc, x25desc, mbxdesc;
  6406.   int i, st, s, p_initialise ();
  6407.   long ucx_sock_def;
  6408.   char *getenv ();
  6409.  
  6410.   if (!tcp_make)
  6411.     set_tcp_make ();
  6412.  
  6413.   if (p_initialised == 0)
  6414.     {
  6415.       for (i = 0; i < 32; i++)
  6416.     p_initialise (i);
  6417.  
  6418.       p_initialised = 1;
  6419.     }
  6420.  
  6421.   /* First of all, get a file descriptor and file ptr we can associate with
  6422.      the socket, allocate a buffer, and remember the socket details.  */
  6423.   s = dup (0);
  6424.   if (s > 31)
  6425.     {
  6426.       errno = EMFILE;
  6427.       close (s);
  6428.       return -1;
  6429.     }
  6430.  
  6431.   p[s].fptr = fdopen (s, "r");
  6432.   p[s].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  6433.   p[s].domain = domain;
  6434.   p[s].type = type;
  6435.   p[s].protocol = protocol;
  6436.  
  6437.   /* Handle the case of INET and X.25 separately.  */
  6438.   if (domain == AF_INET)
  6439.     {
  6440.       if (tcp_make == NONE)
  6441.     {
  6442.       printf ("Trying to obtain a TCP socket when we don't have TCP!\n");
  6443.       exit (1);
  6444.     }
  6445.       if (tcp_make == CMU)
  6446.     {
  6447.       /* For CMU we need only assign a channel.  */
  6448.       inetdesc.size = 3;
  6449.       inetdesc.ptr = "IP:";
  6450.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  6451.         return -1;
  6452.     }
  6453.       else if (tcp_make == UCX)
  6454.     {
  6455.       /* For UCX assign channel and associate a socket with it.  */
  6456.       inetdesc.size = 3;
  6457.       inetdesc.ptr = "BG:";
  6458.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  6459.         return -1;
  6460.  
  6461.       ucx_sock_def = (domain << 24) + (type << 16) + protocol;
  6462.       st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
  6463.              &ucx_sock_def, 0, 0, 0, 0, 0);
  6464.       if (QIO_FAILED)
  6465.         return -1;
  6466.     }
  6467.       else
  6468.     {
  6469.       /* For TWG we assign the channel and associate a socket with it.  */
  6470.       inetdesc.size = 7;
  6471.       inetdesc.ptr = "_INET0:";
  6472.  
  6473.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  6474.         return -1;
  6475.  
  6476.       st = sys$qiow (0, p[s].channel, IO$_SOCKET, p[s].iosb, 0, 0,
  6477.              domain, type, 0, 0, 0, 0);
  6478.       if (QIO_FAILED)
  6479.         return -1;
  6480.     }
  6481.     }
  6482.   else
  6483.     /* We don't handle any other domains yet.  */
  6484.     return -1;
  6485.  
  6486.   /* For each case if we are successful we return the descriptor.  */
  6487.   return s;
  6488. }
  6489.  
  6490. /* Bind routine.  */
  6491. VMSbind (s, name, namelen)
  6492.      int s;
  6493.      union socket_addr *name;
  6494.      int namelen;
  6495. {
  6496.   char infobuff[1024], lhost[32];
  6497.   int st;
  6498.  
  6499.   if (!tcp_make)
  6500.     set_tcp_make ();
  6501.  
  6502.   if (p[s].domain == AF_INET)
  6503.     {
  6504.       /* One main problem with bind is that if we're given a port number
  6505.      of 0, then we're expected to return a unique port number.  Since
  6506.      we don't KNOW, we return 1050+s and look to Lady Luck.  */
  6507.       if (tcp_make == CMU)
  6508.     {
  6509.       if (name->in.sin_port == 0 && p[s].type != SOCK_DGRAM)
  6510.         name->in.sin_port = 1050 + s;
  6511.       p[s].namelen = namelen;
  6512.       bcopy (name, &(p[s].name), namelen);
  6513.  
  6514.       if (p[s].type == SOCK_DGRAM)
  6515.         {
  6516.           /* Another problem is that CMU still needs an OPEN request
  6517.          even if it's a datagram socket.  */
  6518.           st = sys$qiow (0, p[s].channel, TCP$OPEN, p[s].iosb,
  6519.                  0, 0, 0, 0, ntohs (p[s].name.in.sin_port),
  6520.                  0, 1, 0);
  6521.           if (QIO_ST_FAILED)
  6522.         return -1;
  6523.  
  6524.           p[s].cmu_open = 1;
  6525.           sys$qiow (0, p[s].channel, TCP$INFO, p[s].iosb,
  6526.             0, 0, &infobuff, 1024, 0, 0, 0, 0);
  6527.           bcopy (infobuff + 264, &(p[s].name.in.sin_port), 2);
  6528.           p[s].name.in.sin_port = htons (p[s].name.in.sin_port);
  6529.  
  6530.           /* So get it another way.  */
  6531.           bcopy (infobuff + 136, lhost, infobuff[1]);
  6532.           lhost[infobuff[1]] = '\0';
  6533.           sys$qiow (0, p[s].channel, GTHST, p[s].iosb,
  6534.             0, 0, &infobuff, 1024, 1, lhost, 0, 0);
  6535.           bcopy (infobuff + 4, &(p[s].name.in.sin_addr), 4);
  6536.  
  6537.           /* Be prepared to receive a message.  */
  6538.           hang_a_read (s);
  6539.         }
  6540.     }
  6541.       else if (tcp_make == UCX)
  6542.     {
  6543.       /* UCX will select a prot for you.  If the port's number is 0,
  6544.          translate "name" into an item_2 list.  */
  6545.       struct itemlist lhost;
  6546.       lhost.length = namelen;
  6547.       lhost.code = 0;
  6548.       lhost.dataptr = (char *) name;
  6549.  
  6550.       st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
  6551.              0, 0, &lhost, 0, 0, 0);
  6552.       if (QIO_FAILED)
  6553.         return -1;
  6554.  
  6555.       if (p[s].type == SOCK_DGRAM)
  6556.         hang_a_read (s);
  6557.  
  6558.     }
  6559.       else
  6560.     {
  6561.       /* WG is more straightforward */
  6562.       st = sys$qiow (0, p[s].channel, IO$_BIND, p[s].iosb,
  6563.              0, 0, name, namelen, 0, 0, 0, 0);
  6564.       if (QIO_FAILED)
  6565.         return -1;
  6566.  
  6567.       /* If it's a datagram, get ready for the message.  */
  6568.       if (p[s].type == SOCK_DGRAM)
  6569.         hang_a_read (s);
  6570.     }
  6571.     }
  6572.   else
  6573.     /* We don't handle any other domain yet.  */
  6574.     return -1;
  6575.  
  6576.   return 0;
  6577. }
  6578.  
  6579. /* Connect routine.  */
  6580. VMSconnect (s, name, namelen)
  6581.      int s;
  6582.      union socket_addr *name;
  6583.      int namelen;
  6584. {
  6585.   int pr, fl, st;
  6586.   char *inet_ntoa ();
  6587.   static struct
  6588.   {
  6589.     int len;
  6590.     char name[128];
  6591.   } gethostbuf;
  6592.   extern int connect_ast ();
  6593.  
  6594.   if (!tcp_make)
  6595.     set_tcp_make ();
  6596.  
  6597.   /* For datagrams we need to remember who the name was so we can send all
  6598.      messages to that address without having to specify it all the time.  */
  6599.   if (p[s].connected)
  6600.     {
  6601.       if (p[s].connected == 1)
  6602.     errno = EISCONN;
  6603.       else
  6604.     {
  6605.       errno = ECONNREFUSED;
  6606.       p[s].connected = 0;
  6607.     }
  6608.       return -1;
  6609.     }
  6610.  
  6611.   if (p[s].connect_pending)
  6612.     {
  6613.       errno = EALREADY;
  6614.       return -1;
  6615.     }
  6616.  
  6617.   p[s].passive = 0;
  6618.   p[s].tolen = namelen;
  6619.   bcopy (name, &(p[s].to), namelen);
  6620.  
  6621.   if (p[s].domain == AF_INET)
  6622.     {
  6623.       if (tcp_make == CMU)
  6624.     {
  6625.  
  6626.       /* Get the info about the remote host  and open up a connection.  */
  6627.       st = sys$qiow (0, p[s].channel, GTHST, p[s].iosb, 0, 0, &gethostbuf,
  6628.              132, 2, name->in.sin_addr.s_addr, 0, 0);
  6629.       if (QIO_FAILED)
  6630.         {
  6631.           strcpy (gethostbuf.name, inet_ntoa (name->in.sin_addr.s_addr));
  6632.           gethostbuf.len = strlen (gethostbuf.name);
  6633.         }
  6634.       gethostbuf.name[gethostbuf.len] = 0;
  6635.  
  6636.       /* TCP */
  6637.       pr = 0;
  6638.       /* Active */
  6639.       fl = 1;
  6640.  
  6641.       /* Nothing else for datagrams.  */
  6642.       if (p[s].type == SOCK_DGRAM)
  6643.         return (0);
  6644.       st = sys$qio (s, p[s].channel, TCP$OPEN, p[s].iosb, connect_ast,
  6645.             &p[s], &(gethostbuf.name), ntohs (name->in.sin_port),
  6646.             ntohs (p[s].name.in.sin_port), fl, pr, 0);
  6647.       if (QIO_ST_FAILED)
  6648.         return -1;
  6649.     }
  6650.       else if (tcp_make == UCX)
  6651.     {
  6652.       /* Both UDP and TCP can use a connect - IO$_ACCESS */
  6653.       p[s].rhost.length = namelen;
  6654.       p[s].rhost.code = 0;
  6655.       p[s].rhost.dataptr = (char *) name;
  6656.  
  6657.       st = sys$qio (s, p[s].channel, IO$_ACCESS, p[s].iosb, connect_ast,
  6658.             &p[s], 0, 0, &p[s].rhost, 0, 0, 0);
  6659.       if (QIO_ST_FAILED)
  6660.         return -1;
  6661.     }
  6662.       else
  6663.     {
  6664.       /* TWG */
  6665.       if (p[s].type == SOCK_DGRAM)
  6666.         return (0);
  6667.       st = sys$qio (s, p[s].channel, IO$_CONNECT, p[s].iosb, connect_ast,
  6668.             &p[s], name, namelen, 0, 0, 0, 0);
  6669.       if (QIO_ST_FAILED)
  6670.         return -1;
  6671.     }
  6672.     }
  6673.   else
  6674.     /* We don't handle any other domain yet.  */
  6675.     return -1;
  6676.  
  6677.   if (p[s].non_blocking)
  6678.     {
  6679.       if (p[s].connected)
  6680.     {
  6681.       if (p[s].connected == 1)
  6682.         return 0;
  6683.       else
  6684.         {
  6685.           p[s].connected = 0;
  6686.           errno = ECONNREFUSED;
  6687.           return -1;
  6688.         }
  6689.     }
  6690.       else
  6691.     {
  6692.       p[s].connect_pending = 1;
  6693.       errno = EINPROGRESS;
  6694.       return -1;
  6695.     }
  6696.     }
  6697.   else
  6698.     {
  6699.       /* wait for the connection to occur */
  6700.       if (p[s].connected)
  6701.     {
  6702.       if (p[s].connected == 1)
  6703.         return 0;
  6704.       else
  6705.         {
  6706.           p[s].connected = 0;
  6707.           errno = ECONNREFUSED;
  6708.           return -1;
  6709.         }
  6710.     }
  6711.  
  6712.       /* Timed out? */
  6713.       if (wait_efn (s) == -1)
  6714.     return -1;
  6715.  
  6716.       if (p[s].connected != SS$_NORMAL)
  6717.     {
  6718.       errno = ECONNREFUSED;
  6719.       return -1;
  6720.     }
  6721.  
  6722.       return 0;
  6723.     }
  6724. }
  6725.  
  6726. /* Listen routine.  */
  6727. VMSlisten (s, backlog)
  6728.      int s;
  6729.      int backlog;
  6730. {
  6731.   int st;
  6732.  
  6733.   if (!tcp_make)
  6734.     set_tcp_make ();
  6735.  
  6736.   p[s].passive = 1;
  6737.   p[s].backlog = backlog;
  6738.   if (p[s].domain == AF_INET)
  6739.     {
  6740.       if (tcp_make == CMU)
  6741.     {
  6742.       /* For the CMU sockets we can't do the open call in listen;
  6743.          we have to do it in hang_an_accept, because when we close
  6744.          off the connection we have to be ready to accept another
  6745.          one.  accept() also calls hang_an_accept on the old
  6746.          descriptor.  */
  6747.  
  6748.       /* Nothing */
  6749.     }
  6750.       else if (tcp_make == UCX)
  6751.     {
  6752.  
  6753.       /* Doc Verbage sez backlog is descriptor of byte.  Doc examples
  6754.          and common sense say backlog is value.  Value doesn't work,
  6755.          so let's try descriptor of byte after all.  */
  6756.       struct descriptor bl;
  6757.       unsigned char ucx_backlog;
  6758.  
  6759.       ucx_backlog = (unsigned char) backlog;
  6760.       bl.size = sizeof (ucx_backlog);
  6761.       bl.ptr = (char *) &ucx_backlog;
  6762.  
  6763.       st = sys$qiow (0, p[s].channel, IO$_SETMODE, p[s].iosb, 0, 0,
  6764.              0, 0, 0, &bl, 0, 0);
  6765.       if (QIO_FAILED)
  6766.         return -1;
  6767.     }
  6768.       else
  6769.     {
  6770.       /* TWG */
  6771.       st = sys$qiow (0, p[s].channel, IO$_LISTEN, p[s].iosb, 0, 0,
  6772.              backlog, 0, 0, 0, 0, 0);
  6773.       if (QIO_FAILED)
  6774.         return -1;
  6775.     }
  6776.     }
  6777.   else
  6778.     /* We don't handle any other domain yet.  */
  6779.     return -1;
  6780.  
  6781.   p[s].status = LISTENING;
  6782.   hang_an_accept (s);
  6783.   return 0;
  6784. }
  6785.  
  6786. /* Accept routine.  */
  6787. int
  6788. VMSaccept (s, addr, addrlen)
  6789.      int s;
  6790.      union socket_addr *addr;
  6791.      int *addrlen;
  6792. {
  6793.   int news, st;
  6794.   struct descriptor inetdesc;
  6795.  
  6796.   if (!tcp_make)
  6797.     set_tcp_make ();
  6798.  
  6799.   if (p[s].non_blocking && !p[s].accept_pending)
  6800.     {
  6801.       errno = EWOULDBLOCK;
  6802.       return -1;
  6803.     }
  6804.  
  6805.   /* hang_an_accept set up an incoming connection request so we have first
  6806.      to hang around until one appears or we time out.  */
  6807.   if (p[s].domain == AF_INET)
  6808.     {
  6809.       if (tcp_make == CMU)
  6810.     {
  6811.       char infobuff[1024];
  6812.  
  6813.       /* Timed out?  */
  6814.       if (wait_efn (s) == -1)
  6815.         return -1;
  6816.  
  6817.       /* Ok, get a new descriptor ...  */
  6818.       news = dup (0);
  6819.       if (news > 31)
  6820.         {
  6821.           errno = EMFILE;
  6822.           close (news);
  6823.           return -1;
  6824.         }
  6825.  
  6826.       /* ... and copy all of our data across.  */
  6827.       bcopy (&p[s], &p[news], sizeof (p[0]));
  6828.  
  6829.       /* But not this field, of course! */
  6830.       p[news].s = news;
  6831.  
  6832.       sys$qiow (0, p[news].channel, TCP$INFO, p[news].iosb,
  6833.             0, 0, &infobuff, 1024, 0, 0, 0, 0);
  6834.  
  6835.       /* Copy across the connection info if necessary.  */
  6836.       if (addr != 0)
  6837.         {
  6838.           *addrlen = sizeof (struct sockaddr_in);
  6839.           bcopy (infobuff + 132, &(addr->in.sin_port), 2);
  6840.           addr->in.sin_port = htons (addr->in.sin_port);
  6841.           addr->in.sin_family = AF_INET;
  6842.           bcopy (infobuff + 272, &(addr->in.sin_addr), 4);
  6843.           p[news].fromlen = *addrlen;
  6844.           bcopy (addr, &(p[news].from), *addrlen);
  6845.         }
  6846.       p[news].status = PASSIVE_CONNECTION;
  6847.  
  6848.       /* Get a new file ptr for the socket.  */
  6849.       p[news].fptr = fdopen (news, "r");
  6850.  
  6851.       /* Reset this field.  */
  6852.       p[news].accept_pending = 0;
  6853.  
  6854.       /* Allocate a buffer.  */
  6855.       p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  6856.       p[news].fd_leftover = 0;
  6857.  
  6858.       /* Be prepared to get msgs.  */
  6859.       hang_a_read (news);
  6860.  
  6861.       /* Now fix up our previous socket so it's again listening
  6862.          for connections.  */
  6863.       inetdesc.size = 3;
  6864.       inetdesc.ptr = "IP:";
  6865.       if (sys$assign (&inetdesc, &p[s].channel, 0, 0) != SS$_NORMAL)
  6866.         return -1;
  6867.       p[s].status = LISTENING;
  6868.       hang_an_accept (s);
  6869.  
  6870.       /* Return the new socket descriptor.  */
  6871.       return news;
  6872.     }
  6873.       else if (tcp_make == UCX)
  6874.     {
  6875.       /* UCX does the actual accept from hang_an_accept.  The accept info
  6876.         is put into the data structure for the "listening" socket.
  6877.         These just need to be copied into a newly allocated socket for
  6878.         the connect and the listening socket re-started.  */
  6879.  
  6880.       /* Wait for event flag from accept being received inside
  6881.          of hang_an_accept().  */
  6882.  
  6883.       if (wait_efn (s) == -1)
  6884.         /* Timed out.  */
  6885.         return -1;
  6886.  
  6887.       /* Ok, get a new descriptor ...  */
  6888.       news = dup (0);
  6889.       if (news > 31)
  6890.         {
  6891.           errno = EMFILE;
  6892.           close (news);
  6893.           return -1;
  6894.         }
  6895.       /* ... and copy all of our data across.  */
  6896.       bcopy (&p[s], &p[news], sizeof (p[0]));
  6897.       p[news].s = news;    /* but not this field */
  6898.       p[news].channel = p[s].ucx_accept_chan;
  6899.  
  6900.       /* Initialize the remote host address item_list_3 struct.  */
  6901.       p[news].rhost.length = sizeof (struct sockaddr_in);
  6902.       p[news].rhost.code = 0;
  6903.       p[news].rhost.dataptr = (char *) &p[news].from;
  6904.       p[news].rhost.retlenptr = &p[news].fromdummy;
  6905.  
  6906.       if (addr != 0)
  6907.         {
  6908.           /* Return the caller's info, if requested.  */
  6909.           *addrlen = p[news].fromdummy;
  6910.           bcopy (&p[news].from, addr, p[news].fromdummy);
  6911.         }
  6912.  
  6913.       /* Finish fleshing out the new structure.  */
  6914.       p[news].status = PASSIVE_CONNECTION;
  6915.  
  6916.       /* Get a new file pointer for the socket.  */
  6917.       p[news].fptr = fdopen (news, "r");
  6918.  
  6919.       /* Reset this field.  */
  6920.       p[news].accept_pending = 0;
  6921.  
  6922.       /* Allocate a buffer.  */
  6923.       p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  6924.       p[news].fd_leftover = 0;
  6925.  
  6926.       /* Get it started reading.  */
  6927.       hang_a_read (news);
  6928.  
  6929.       p[s].status = LISTENING;
  6930.       hang_an_accept (s);
  6931.  
  6932.       return news;
  6933.     }
  6934.       else
  6935.     {
  6936.       /* TWG */
  6937.       struct descriptor inetdesc;
  6938.       int size;
  6939.  
  6940.       /* Time out?  */
  6941.       if (wait_efn (s) == -1)
  6942.         return -1;
  6943.  
  6944.       /* Ok, get a new descriptor ...  */
  6945.       news = dup (0);
  6946.       if (news > 31)
  6947.         {
  6948.           errno = EMFILE;
  6949.           close (news);
  6950.           return -1;
  6951.         }
  6952.  
  6953.       /* Assign a new channel.  */
  6954.       inetdesc.size = 7;
  6955.       inetdesc.ptr = "_INET0:";
  6956.       st = sys$assign (&inetdesc, &p[news].channel, 0, 0);
  6957.       if (QIO_ST_FAILED)
  6958.         {
  6959.           p[s].accept_pending = 0;
  6960.           sys$clref (s);
  6961.           return -1;
  6962.         }
  6963.  
  6964.       /* From info needs an int length field! */
  6965.       size = sizeof (p[s].from) + 4;
  6966.       st = sys$qiow (0, p[news].channel, IO$_ACCEPT, p[news].iosb, 0, 0,
  6967.              &p[s].fromdummy, size, p[s].channel, 0, 0, 0);
  6968.  
  6969.       if (QIO_ST_FAILED || p[news].iosb[0] != SS$_NORMAL)
  6970.         {
  6971.           p[s].accept_pending = 0;
  6972.           sys$clref (s);
  6973.           return -1;
  6974.         }
  6975.  
  6976.       if (addr != 0)
  6977.         {
  6978.           /* Return the caller's info if requested.  */
  6979.           *addrlen = p[s].fromdummy;
  6980.           bcopy (&p[s].from, addr, *addrlen);
  6981.         }
  6982.  
  6983.       /* Fix up our new data structure.  */
  6984.       p[news].status = PASSIVE_CONNECTION;
  6985.       p[news].domain = AF_INET;
  6986.       p[news].passive = 1;
  6987.       p[news].fptr = fdopen (news, "r");
  6988.       /* Allocate a buffer.  */
  6989.       p[news].fd_buff = (unsigned char *) malloc (BUF_SIZE);
  6990.  
  6991.       /* Be prepared to accept msgs.  */
  6992.       hang_a_read (news);
  6993.  
  6994.       /* Get the old descriptor back onto accepting.  */
  6995.       hang_an_accept (s);
  6996.       return news;
  6997.     }
  6998.     }
  6999.   else
  7000.     /* We don't handle any other domain yet.  */
  7001.     return -1;
  7002. }
  7003.  
  7004. /* Recv routine.  */
  7005. int
  7006. VMSrecv (s, buf, len, flags)
  7007.      int s;
  7008.      char *buf;
  7009.      int len, flags;
  7010. {
  7011.   return recvfrom (s, buf, len, flags, 0, 0);
  7012. }
  7013.  
  7014. /* Revfrom routine.  */
  7015. int
  7016. VMSrecvfrom (s, buf, len, flags, from, fromlen)
  7017.      int s;
  7018.      char *buf;
  7019.      int len, flags;
  7020.      union socket_addr *from;
  7021.      int *fromlen;
  7022. {
  7023.   int number;
  7024.  
  7025.   if (!tcp_make)
  7026.     set_tcp_make ();
  7027.  
  7028.   if (p[s].domain != AF_INET && p[s].domain != AF_X25)
  7029.     return -1;
  7030.  
  7031.   /* If we're not onto datagrams, then it's possible that a previous
  7032.      call to recvfrom didn't read all the data, and left some behind.
  7033.      So first of all, look in our data buffer for any leftovers that
  7034.      will satisfy this read.  */
  7035.  
  7036.   /* We couldn't satisfy the request from previous calls so we must now
  7037.      wait for a message to come through.  */
  7038.   if (wait_efn (s) == -1)
  7039.     /* Timed out.  */
  7040.     return -1;
  7041.  
  7042.   if (p[s].closed_by_remote == 1)
  7043.     {
  7044.       /* This could have happened! */
  7045.       errno = ECONNRESET;
  7046.       return -1;
  7047.     }
  7048.  
  7049.   if (from != NULL)
  7050.     {
  7051.       if (tcp_make == CMU)
  7052.     {
  7053.       if (p[s].type == SOCK_DGRAM)
  7054.         {
  7055.           /* Not documented but we get the from data from the beginning of
  7056.          the data buffer.  */
  7057.           *fromlen = sizeof (p[s].from.in);
  7058.           from->in.sin_family = AF_INET;
  7059.           bcopy (&p[s].fd_buff[8], &(from->in.sin_port), 2);
  7060.           from->in.sin_port = htons (from->in.sin_port);
  7061.           bcopy (&p[s].fd_buff[0], &(from->in.sin_addr), 4);
  7062.  
  7063.           /* Remove the address data from front of data buffer.  */
  7064.           bcopy (p[s].fd_buff + 12, p[s].fd_buff, p[s].fd_buff_size);
  7065.         }
  7066.       else
  7067.         {
  7068.           *fromlen = p[s].fromlen;
  7069.           bcopy (&p[s].from, from, p[s].fromlen);
  7070.         }
  7071.     }
  7072.       else if (tcp_make == UCX)
  7073.     {
  7074.       *fromlen = p[s].fromdummy;
  7075.       bcopy (&p[s].from, from, p[s].fromdummy);
  7076.     }
  7077.       else
  7078.     {
  7079.       *fromlen = p[s].fromlen;
  7080.       bcopy (&p[s].from, from, p[s].fromlen);
  7081.     }
  7082.     }
  7083.  
  7084.   /* We may've received too much.  */
  7085.   number = p[s].fd_buff_size;
  7086.   if (number <= len)
  7087.     {
  7088.       /* If we haven't give back all the data available.  */
  7089.       bcopy (p[s].fd_buff, buf, number);
  7090.       p[s].fd_leftover = 0;
  7091.       hang_a_read (s);
  7092.       return (number);
  7093.     }
  7094.   else
  7095.     {
  7096.       /* If we have too much data then split it up.  */
  7097.       p[s].fd_leftover = p[s].fd_buff;
  7098.       bcopy (p[s].fd_leftover, buf, len);
  7099.       /* And change the pointers.  */
  7100.       p[s].fd_leftover += len;
  7101.       p[s].fd_buff_size -= len;
  7102.       return (len);
  7103.     }
  7104. }
  7105.  
  7106. /* Send routine.  */
  7107. int
  7108. VMSsend (s, msg, len, flags)
  7109.      int s;
  7110.      char *msg;
  7111.      int len, flags;
  7112. {
  7113.   return sendto (s, msg, len, flags, 0, 0);
  7114. }
  7115.  
  7116. /* Sendto routine.  */
  7117. int
  7118. VMSsendto (s, msg, len, flags, to, tolen)
  7119.      int s;
  7120.      unsigned char *msg;
  7121.      int len, flags;
  7122.      union socket_addr *to;
  7123.      int tolen;
  7124. {
  7125.   int i, j, st, size;
  7126.   unsigned char udpbuf[BUF_SIZE + 12];
  7127.   char infobuff[1024], lhost[32];
  7128.   unsigned short int temp;
  7129.  
  7130.   if (!tcp_make)
  7131.     set_tcp_make ();
  7132.  
  7133.   /* First remember who we sent it to and set the value of size.  */
  7134.   if (to != 0)
  7135.     {
  7136.       p[s].tolen = tolen;
  7137.       bcopy (to, &(p[s].to), tolen);
  7138.       size = tolen;
  7139.     }
  7140.   else
  7141.     size = 0;
  7142.  
  7143.   if (p[s].domain == AF_INET)
  7144.     {
  7145.       /* We might never have started a read for udp (socket/sendto) so
  7146.      put one here.  */
  7147.       if (p[s].type == SOCK_DGRAM)
  7148.     hang_a_read (s);
  7149.  
  7150.       if (tcp_make == CMU)
  7151.     {
  7152.       if (p[s].type == SOCK_DGRAM)
  7153.         {
  7154.           /* We might never have opened up a udp connection yet,
  7155.          so check.  */
  7156.           if (p[s].cmu_open != 1)
  7157.         {
  7158.           st = sys$qiow (0, p[s].channel, TCP$OPEN, p[s].iosb, 0, 0,
  7159.                  0, 0, 0, 0, 1, 0);
  7160.           if (QIO_ST_FAILED)
  7161.             return -1;
  7162.  
  7163.           p[s].cmu_open = 1;
  7164.           sys$qiow (0, p[s].channel, TCP$INFO, p[s].iosb,
  7165.                 0, 0, &infobuff, 1024, 0, 0, 0, 0);
  7166.           bcopy (infobuff + 264, &(p[s].name.in.sin_port), 2);
  7167.           p[s].name.in.sin_port = htons (p[s].name.in.sin_port);
  7168.           bcopy (infobuff + 136, lhost, infobuff[1]);
  7169.           lhost[infobuff[1]] = '\0';
  7170.           sys$qiow (0, p[s].channel, GTHST, p[s].iosb,
  7171.                 0, 0, &infobuff, 1024, 1, lhost, 0, 0);
  7172.           bcopy (infobuff + 4, &(p[s].name.in.sin_addr), 4);
  7173.         }
  7174.  
  7175.           /* This isn't well documented.  To send to a UDP socket, we
  7176.          need to put the address info at the beginning of the
  7177.          buffer.  */
  7178.           bcopy (msg, udpbuf + 12, len);
  7179.           bcopy (&p[s].to.in.sin_addr, udpbuf + 4, 4);
  7180.           temp = ntohs (p[s].to.in.sin_port);
  7181.           bcopy (&temp, udpbuf + 10, 2);
  7182.           bcopy (&p[s].name.in.sin_addr, udpbuf, 4);
  7183.           temp = ntohs (p[s].name.in.sin_port);
  7184.           bcopy (&temp, udpbuf + 8, 2);
  7185.           temp = len + 12;
  7186.           st = sys$qiow (0, p[s].channel, TCP$SEND, p[s].iosb, 0, 0,
  7187.                  udpbuf, temp, 0, 0, 0, 0);
  7188.           if (QIO_FAILED)
  7189.         return -1;
  7190.         }
  7191.       else
  7192.         {
  7193.           /* TCP (! UDP)  */
  7194.           st = sys$qiow (0, p[s].channel, TCP$SEND, p[s].iosb, 0, 0,
  7195.                  msg, len, 0, 0, 0, 0);
  7196.           if (QIO_FAILED)
  7197.         return -1;
  7198.         }
  7199.       return len;
  7200.     }
  7201.       else if (tcp_make == UCX)
  7202.     {
  7203.       struct itemlist rhost;
  7204.       rhost.length = sizeof (struct sockaddr_in);
  7205.       rhost.code = 0;
  7206.       rhost.dataptr = (char *) &p[s].to;
  7207.  
  7208.       st = sys$qiow (0, p[s].channel, IO$_WRITEVBLK, p[s].iosb, 0, 0,
  7209.              msg, len, &rhost, 0, 0, 0);
  7210.       if (QIO_FAILED)
  7211.         return -1;
  7212.  
  7213.       return len;
  7214.     }
  7215.       else
  7216.     {
  7217.       /* TWG */
  7218.       st = sys$qiow (0, p[s].channel, IO$_WRITEVBLK, p[s].iosb,
  7219.              0, 0, msg, len, 0, &p[s].to, size, 0);
  7220.       if (QIO_FAILED)
  7221.         return -1;
  7222.  
  7223.       return len;
  7224.     }
  7225.     }
  7226.   else
  7227.     /* We don't handle any other domain yet.  */
  7228.     return -1;
  7229. }
  7230.  
  7231. /* Getsockname routine.  */
  7232. int
  7233. VMSgetsockname (s, name, namelen)
  7234.      int s;
  7235.      union socket_addr *name;
  7236.      int *namelen;
  7237. {
  7238.   int st;
  7239.  
  7240.   if (!tcp_make)
  7241.     set_tcp_make ();
  7242.  
  7243.   if (p[s].domain == AF_INET)
  7244.     {
  7245.       if (tcp_make == CMU)
  7246.     {
  7247.       /* For CMU we just return values held in our data structure.  */
  7248.       *namelen = p[s].namelen;
  7249.       bcopy (&(p[s].name), name, *namelen);
  7250.       return (0);
  7251.     }
  7252.       else if (tcp_make == UCX)
  7253.     {
  7254.       /* An item_list_3 descriptor.  */
  7255.       struct itemlist lhost;
  7256.  
  7257.       lhost.length = *namelen;
  7258.       lhost.code = 0;
  7259.       lhost.dataptr = (char *) name;
  7260.  
  7261.       /* Fill in namelen with actual ret len value.  */
  7262.       lhost.retlenptr = (short int *) namelen;
  7263.  
  7264.       st = sys$qiow (0, p[s].channel, IO$_SENSEMODE, p[s].iosb, 0, 0,
  7265.              0, 0, &lhost, 0, 0, 0);
  7266.       if (QIO_FAILED)
  7267.         return -1;
  7268.  
  7269.       return 0;
  7270.     }
  7271.       else
  7272.     {
  7273.       /* TWG gives us the information. */
  7274.       st = sys$qiow (0, p[s].channel, IO$_GETSOCKNAME, p[s].iosb,
  7275.              0, 0, name, namelen, 0, 0, 0, 0);
  7276.       if (QIO_FAILED)
  7277.         return -1;
  7278.  
  7279.       return 0;
  7280.     }
  7281.     }
  7282.   else
  7283.     /* We don't handle any other domain yet.  */
  7284.     return -1;
  7285. }
  7286.  
  7287. /* Select routine.  */
  7288. int
  7289. VMSselect (nfds, readfds, writefds, exceptfds, timeout)
  7290.      int nfds;
  7291.      fd_set *readfds, *writefds, *exceptfds;
  7292.      struct timeval *timeout;
  7293. {
  7294.   int timer, fd, alarm_set, total, end;
  7295.   long mask, cluster;
  7296.   struct descriptor termdesc;
  7297.   static fd_set new_readfds, new_writefds, new_exceptfds;
  7298.  
  7299.   FD_ZERO (&new_readfds);
  7300.   FD_ZERO (&new_writefds);
  7301.   FD_ZERO (&new_exceptfds);
  7302.   total = 0;
  7303.  
  7304.   /* Assign a terminal channel if we haven't already.  */
  7305.   if (terminal.chan == -1)
  7306.     {
  7307.       termdesc.size = 10;
  7308.       termdesc.ptr = "SYS$INPUT:";
  7309.       sys$assign (&termdesc, &terminal.chan, 0, 0);
  7310.     }
  7311.   alarm_set = 0;
  7312.   if (timeout != NULL)
  7313.     {
  7314.       /* If a timeout is given then set the alarm.  */
  7315.       end = timeout->tv_sec;
  7316.       if (timer != 0)
  7317.     {
  7318.       /* We need to reset the alarm if it didn't fire, but we set it.  */
  7319.       alarm_set = 1;
  7320.       si_alarm (end);
  7321.     }
  7322.     }
  7323.   else
  7324.     end = 1;
  7325.  
  7326.   do
  7327.     {
  7328.       if (exceptfds)
  7329.     {
  7330.        /* Nothing */ ;
  7331.     }
  7332.  
  7333.       if (writefds)
  7334.     {
  7335.       for (fd = 0; fd < nfds; fd++)
  7336.         if (FD_ISSET (fd, writefds))
  7337.           {
  7338.         if (p[fd].connect_pending)
  7339.            /* Nothing */ ;
  7340.         else if ((p[fd].status == ACTIVE_CONNECTION)
  7341.              || (p[fd].status == PASSIVE_CONNECTION))
  7342.           {
  7343.             FD_SET (fd, &new_writefds);
  7344.             total++;
  7345.           }
  7346.           }
  7347.     }
  7348.  
  7349.       if (readfds)
  7350.     {
  7351.       /* True if data pending or an accept.  */
  7352.       for (fd = 3; fd < nfds; fd++)
  7353.         if (FD_ISSET (fd, readfds) &&
  7354.         ((p[fd].fd_buff_size != -1) || (p[fd].accept_pending == 1)))
  7355.           {
  7356.         FD_SET (fd, &new_readfds);
  7357.         total++;
  7358.           }
  7359.     }
  7360.  
  7361.       if (total || (end == 0))
  7362.     break;
  7363.  
  7364.       /* Otherwise, wait on an event flag.  It's possible that the wait can
  7365.      be stopped by a spurious event flag being set -- i.e. one that's
  7366.      got a status not normal.  So we've got to be prepared to loop
  7367.      around the wait until a valid reason happens.  */
  7368.  
  7369.       /* Set up the wait mask.  */
  7370.       cluster = 0;
  7371.       mask = 0;
  7372.       for (fd = 3; fd < nfds; fd++)
  7373.     {
  7374.       sys$clref (fd);
  7375.       if (readfds)
  7376.         if FD_ISSET
  7377.           (fd, readfds) mask |= (1 << fd);
  7378.       if (writefds)
  7379.         if FD_ISSET
  7380.           (fd, writefds) mask |= (1 << fd);
  7381.       if (exceptfds)
  7382.         if FD_ISSET
  7383.           (fd, exceptfds) mask |= (1 << fd);
  7384.     }
  7385.  
  7386.       mask |= (1 << TIMER_EFN);
  7387.  
  7388.       /* Clear it off just in case.  */
  7389.       sys$clref (TIMER_EFN);
  7390.  
  7391.       /* Wait around.  */
  7392.       sys$wflor (cluster, mask);
  7393.  
  7394.       mask = 0;
  7395.       if (read_efn (TIMER_EFN))
  7396.     {
  7397.       errno = EINTR;
  7398.       break;
  7399.     }
  7400.   } while (1);
  7401.   /*NOTREACHED*/
  7402.  
  7403.   /* Unset the alarm if we set it.  */
  7404.   if (alarm_set == 1)
  7405.     alarm (0);
  7406.  
  7407.   if (readfds)
  7408.     *readfds = new_readfds;
  7409.  
  7410.   if (writefds)
  7411.     *writefds = new_writefds;
  7412.  
  7413.   if (exceptfds)
  7414.     *exceptfds = new_exceptfds;
  7415.  
  7416.   return total;
  7417. }
  7418.  
  7419. /* Shutdown routine.  */
  7420. VMSshutdown (s, how)
  7421.      int s, how;
  7422. {
  7423.   int st;
  7424.   int ucx_how;
  7425.  
  7426.   if (!tcp_make)
  7427.     set_tcp_make ();
  7428.  
  7429.   if (p[s].domain == AF_INET)
  7430.     {
  7431.       if (tcp_make == CMU)
  7432.     {
  7433.       /* For CMU we just close off.  */
  7434.       si_close (s);
  7435.       return 0;
  7436.     }
  7437.       else if (tcp_make == UCX)
  7438.     {
  7439.       st = sys$qiow (0, p[s].channel, IO$_DEACCESS | IO$M_SHUTDOWN,
  7440.              p[s].iosb, 0, 0, 0, 0, 0, how, 0, 0);
  7441.       if (QIO_FAILED)
  7442.         return -1;
  7443.  
  7444.       return 0;
  7445.     }
  7446.       else
  7447.     {
  7448.       /* TWG lets us do it.  */
  7449.       st = sys$qiow (0, p[s].channel, IO$_SHUTDOWN, p[s].iosb, 0, 0, how,
  7450.              0, 0, 0, 0, 0);
  7451.       if (QIO_FAILED)
  7452.         return -1;
  7453.  
  7454.       return 0;
  7455.     }
  7456.     }
  7457.   else                /* it wasn't a socket */
  7458.     return -1;
  7459. }
  7460.  
  7461. /*   */
  7462.  
  7463. /* The following routines are used by the above socket calls.  */
  7464.  
  7465. /* hang_a_read sets up a read to be finished at some later time.  */
  7466. hang_a_read (s)
  7467.      int s;
  7468. {
  7469.   extern int read_ast ();
  7470.   int size, st;
  7471.  
  7472.   /* Don't bother if we already did it.  */
  7473.   if (p[s].read_outstanding == 1)
  7474.     return;
  7475.  
  7476.   /* Have a read outstanding.  */
  7477.   p[s].read_outstanding = 1;
  7478.   size = sizeof (p[s].from) + 4;
  7479.   sys$clref (s);
  7480.  
  7481.   /* Clear off the event flag just in case, and reset the buf size.  */
  7482.   p[s].fd_buff_size = -1;
  7483.   if (p[s].domain == AF_INET)
  7484.     {
  7485.       if (tcp_make == CMU)
  7486.     {
  7487.       st = sys$qio (s, p[s].channel, TCP$RECEIVE, p[s].iosb, read_ast,
  7488.             &p[s], p[s].fd_buff, BUF_SIZE, 0, 0, 0, 0);
  7489.       if (QIO_ST_FAILED)
  7490.         return -1;
  7491.     }
  7492.       else if (tcp_make == UCX)
  7493.     {
  7494.  
  7495.       p[s].rhost.length = sizeof (struct sockaddr_in);
  7496.       p[s].rhost.code = 0;
  7497.       p[s].rhost.dataptr = (char *) &p[s].from;
  7498.       p[s].rhost.retlenptr = &p[s].fromdummy;
  7499.  
  7500.       st = sys$qio (s, p[s].channel, IO$_READVBLK, p[s].iosb, read_ast,
  7501.             &p[s], p[s].fd_buff, BUF_SIZE, &p[s].rhost, 0, 0, 0);
  7502.       if (QIO_ST_FAILED)
  7503.         return -1;
  7504.     }
  7505.       else
  7506.     {
  7507.       /* TWG */
  7508.       st = sys$qio (s, p[s].channel, IO$_READVBLK, p[s].iosb, read_ast,
  7509.             &p[s], p[s].fd_buff, BUF_SIZE, 0, &p[s].fromlen,
  7510.             size, 0);
  7511.       if (QIO_ST_FAILED)
  7512.         return -1;
  7513.     }
  7514.     }
  7515.   else
  7516.     /* We don't handle any other domain yet.  */
  7517.     return -1;
  7518. }
  7519.  
  7520. /* hang_an_accept waits for a connection request to come in.  */
  7521. hang_an_accept (s)
  7522.      int s;
  7523. {
  7524.   extern int accept_ast ();
  7525.   int st;
  7526.  
  7527.   /* Clear the event flag just in case.  */
  7528.   sys$clref (s);
  7529.  
  7530.   /* Reset our flag & buf size.  */
  7531.   p[s].accept_pending = 0;
  7532.   p[s].fd_buff_size = -1;
  7533.   if (p[s].domain == AF_INET)
  7534.     {
  7535.       if (tcp_make == CMU)
  7536.     {
  7537.       st = sys$qio (s, p[s].channel, TCP$OPEN, p[s].iosb, accept_ast,
  7538.             &p[s], 0, 0, ntohs (p[s].name.in.sin_port), 0, 0, 0);
  7539.       if (QIO_ST_FAILED)
  7540.         return -1;
  7541.     }
  7542.       else if (tcp_make == UCX)
  7543.     {
  7544.       struct descriptor inetdesc;
  7545.  
  7546.       /* Assign channel for actual connection off listener.  */
  7547.       inetdesc.size = 3;
  7548.       inetdesc.ptr = "BG:";
  7549.       if (sys$assign (&inetdesc, &p[s].ucx_accept_chan, 0,
  7550.               0) != SS$_NORMAL)
  7551.         return -1;
  7552.  
  7553.       /* UCX's accept returns remote host info and the channel for a new
  7554.          socket to perform reads/writes on, so a sys$assign isn't
  7555.          really necessary.  */
  7556.       p[s].rhost.length = sizeof (struct sockaddr_in);
  7557.       p[s].rhost.dataptr = (char *) &p[s].from;
  7558.       p[s].fromdummy = 0;
  7559.       p[s].rhost.retlenptr = &p[s].fromdummy;
  7560.  
  7561.       st = sys$qio (s, p[s].channel, IO$_ACCESS | IO$M_ACCEPT, p[s].iosb,
  7562.             accept_ast, &p[s], 0, 0, &p[s].rhost,
  7563.             &p[s].ucx_accept_chan, 0, 0);
  7564.       if (QIO_ST_FAILED)
  7565.         return -1;
  7566.     }
  7567.       else
  7568.     {
  7569.       st = sys$qio (s, p[s].channel, IO$_ACCEPT_WAIT, p[s].iosb,
  7570.             accept_ast, &p[s], 0, 0, 0, 0, 0, 0);
  7571.       if (QIO_ST_FAILED)
  7572.         return -1;
  7573.     }
  7574.     }
  7575.   else
  7576.     /* We don't handle any other domain yet.  */
  7577.     return -1;
  7578. }
  7579.  
  7580. /* wait_efn just sets up a wait on either an event or the timer.  */
  7581. wait_efn (s)
  7582.      int s;
  7583. {
  7584.   long mask, cluster;
  7585.  
  7586.   cluster = 0;
  7587.   sys$clref (TIMER_EFN);
  7588.   mask = (1 << s) | (1 << TIMER_EFN);
  7589.   sys$wflor (cluster, mask);
  7590.  
  7591.   if (read_efn (TIMER_EFN))
  7592.     {
  7593.       errno = EINTR;
  7594.       return -1;
  7595.     }
  7596.  
  7597.   return 0;
  7598. }
  7599.  
  7600. /* read_ast is called by the system whenever a read is done.  */
  7601. read_ast (p)
  7602.      struct fd_entry *p;
  7603. {
  7604.   int i, j;
  7605.   unsigned char *v, *w;
  7606.  
  7607.   /* Reset the outstanding flag.  */
  7608.   p->read_outstanding = 0;
  7609.   if (p->iosb[0] == SS$_NORMAL)
  7610.     {
  7611.       /* Check no errors.  */
  7612.       p->fd_buff_size = p->iosb[1];
  7613.       if (tcp_make == CMU)
  7614.     {
  7615.       /* fiddle for DGRMs */
  7616.       if (p->type == SOCK_DGRAM)
  7617.         p->fd_buff_size -= 12;
  7618.     }
  7619.       if (p->sig_req == 1)
  7620.     gsignal (SIGIO);
  7621.     }
  7622.   else if (p->iosb[0] == SS$_CLEARED)
  7623.     p->closed_by_remote = 1;
  7624.   else if (tcp_make == UCX)
  7625.     {
  7626.       if (p->iosb[0] == SS$_LINKDISCON)
  7627.     p->closed_by_remote = 1;
  7628.     }
  7629. }
  7630.  
  7631. /* accept_ast is called whenever an incoming call is detected.  */
  7632. accept_ast (p)
  7633.      struct fd_entry *p;
  7634. {
  7635.   if (p->iosb[0] == SS$_NORMAL)
  7636.     p->accept_pending = 1;
  7637.   else
  7638.     /* If it failed set up another listen.  */
  7639.     listen (p->s, p[p->s].backlog);
  7640. }
  7641.  
  7642. /* connect_ast is called whenever an async connect is made.  */
  7643. connect_ast (p)
  7644.      struct fd_entry *p;
  7645. {
  7646.   p->connect_pending = 0;
  7647.   if ((p->connected = p->iosb[0]) == SS$_NORMAL)
  7648.     {
  7649.       /* We made the connection.  */
  7650.       p->status = ACTIVE_CONNECTION;
  7651.  
  7652.       /* Be prepared to accept a msg.  */
  7653.       hang_a_read (p->s);
  7654.     }
  7655. }
  7656.  
  7657. /*   */
  7658. /* These routines handle stream I/O.  */
  7659.  
  7660. /* si_close -- must close off any connection in progress.  */
  7661. si_close (s)
  7662.      int s;
  7663. {
  7664.   if (!tcp_make)
  7665.     set_tcp_make ();
  7666.  
  7667.   if ((s < 0) || (s > 31))
  7668.     return -1;
  7669.  
  7670.   if (p[s].channel != 0)
  7671.     {
  7672.       /* Was it one of our descriptors? */
  7673.       if (p[s].domain == AF_INET)
  7674.     {
  7675.       if (tcp_make == CMU)
  7676.         sys$qiow (0, p[s].channel, TCP$CLOSE, p[s].iosb,
  7677.               0, 0, 0, 0, 0, 0, 0, 0);
  7678.       if (p[s].status != HANDED_OFF)
  7679.         sys$dassgn (p[s].channel);
  7680.       close (s);
  7681.       free (p[s].fd_buff);
  7682.       p_initialise (s);
  7683.     }
  7684.       return 0;
  7685.     }
  7686.   else
  7687.     {
  7688.       /* Re-initialise data structure just in case.  */
  7689.       p[s].fd_buff_size = -1;
  7690.       p[s].accept_pending = 0;
  7691.       p[s].status = INITIALISED;
  7692.       return close (s);
  7693.     }
  7694. }
  7695.  
  7696. /* si_alarm -- insert a call to our own alarm function.  */
  7697. si_alarm (i)
  7698.      int i;
  7699. {
  7700.   extern int pre_alarm ();
  7701.  
  7702.   /* Make the call to pre_alarm instead of what the user wants;
  7703.      pre_alarm will call his routine when it finishes.  */
  7704.   /* VAX needs this call each time! */
  7705.   signal (SIGALRM, pre_alarm);
  7706.   alarm (i);
  7707. }
  7708.  
  7709. /* pre_alarm -- gets called first on an alarm signal.  */
  7710. pre_alarm ()
  7711. {
  7712.   /* Come here first so we can set our timer event flag.  */
  7713.   sys$setef (TIMER_EFN);
  7714.   (*alarm_function) ();
  7715. }
  7716.  
  7717. /* p_initialise - initialise our data array.  */
  7718. p_initialise (s)
  7719.      int s;
  7720. {
  7721.   int j;
  7722.   for (j = 0; j < 4; j++)
  7723.     p[s].iosb[j] = 0;
  7724.   p[s].channel = 0;
  7725.   p[s].fd_buff_size = -1;
  7726.   p[s].accept_pending = 0;
  7727.   p[s].connect_pending = 0;
  7728.   p[s].connected = 0;
  7729.   p[s].fd_buff = NULL;
  7730.   p[s].fd_leftover = NULL;
  7731.   p[s].fptr = NULL;
  7732.   p[s].s = s;
  7733.   p[s].name.in.sin_port = 0;
  7734.   p[s].masklen = 4;
  7735.   for (j = 0; j < 16; j++)
  7736.     p[s].mask[j] = 0xff;
  7737.   p[s].need_header = 0;
  7738.   p[s].status = INITIALISED;
  7739.   p[s].read_outstanding = 0;
  7740.   p[s].cmu_open = 0;
  7741.   p[s].x25_listener = 0;
  7742.   p[s].mother = s;
  7743.   p[s].child = 0;
  7744.   p[s].no_more_accepts = 0;
  7745.   p[s].closed_by_remote = 0;
  7746.   p[s].non_blocking = 0;
  7747.   p[s].sig_req = 0;
  7748.   sys$clref (s);
  7749. }
  7750.  
  7751. /* read_efn -- see whether an event flag is set.  */
  7752. read_efn (i)
  7753.      int i;
  7754. {
  7755.   int j;
  7756.   sys$readef (i, &j);
  7757.   j &= (1 << i);
  7758.  
  7759.   return j;
  7760. }
  7761.  
  7762. static
  7763. set_tcp_make ()
  7764. {
  7765.   struct descriptor inetdesc;
  7766.   int channel;
  7767.   /* first try CMU */
  7768.   inetdesc.size = 3;
  7769.   inetdesc.ptr = "IP:";
  7770.   if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
  7771.     {
  7772.       sys$dassgn (channel);
  7773.       tcp_make = CMU;
  7774.       return;
  7775.     }
  7776.  
  7777.   /* next try TWG */
  7778.   inetdesc.size = 7;
  7779.   inetdesc.ptr = "_INET0:";
  7780.   if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
  7781.     {
  7782.       sys$dassgn (channel);
  7783.       tcp_make = WG;
  7784.       return;
  7785.     }
  7786.  
  7787.   /* next try UCX */
  7788.   inetdesc.size = 4;
  7789.   inetdesc.ptr = "BG0:";
  7790.   if (sys$assign (&inetdesc, &channel, 0, 0) == SS$_NORMAL)
  7791.     {
  7792.       sys$dassgn (channel);
  7793.       tcp_make = UCX;
  7794.       return;
  7795.     }
  7796.  
  7797.   /* nothing there oh dear!*/
  7798.   tcp_make = NONE;
  7799.   return;
  7800. }
  7801.  
  7802. static char *
  7803. getdevicename (channel)
  7804.      unsigned short int channel;
  7805. {
  7806.   int st;
  7807.   struct
  7808.   {
  7809.     struct itemlist id;
  7810.     int eol;
  7811.   } itmlst;
  7812.   static char name[64];
  7813.   short int lgth;
  7814.  
  7815.   name[0] = '\0';
  7816.   itmlst.id.code = DVI$_DEVNAM;
  7817.   itmlst.id.length = 64;
  7818.   itmlst.id.dataptr = name;
  7819.   itmlst.id.retlenptr = &lgth;
  7820.   itmlst.eol = 0;
  7821.   st = sys$getdvi (0, channel, 0, &itmlst, 0, 0, 0, 0);
  7822.   if (QIO_ST_FAILED)
  7823.     fprintf (stderr, "error getting device name %d\n", st);
  7824.  
  7825.   return (name);
  7826. }
  7827. $EOD
  7828. $!
  7829. $CREATE [.archie.vms]fd.h
  7830. $DECK
  7831. #ifndef _VMS_FD
  7832. #define _VMS_FD
  7833.  
  7834. typedef struct fd_set
  7835. {
  7836.   int fds_bits[1];
  7837. } fd_set;
  7838.  
  7839. #define FD_SETSIZE          (sizeof (fd_set) * 8)
  7840. #define FD_SET(f,s)         ((s)->fds_bits[0] |= (1 << (f)))
  7841. #define FD_CLR(f,s)         ((s)->fds_bits[0] &= ~(1 << (f)))
  7842. #define FD_ISSET(f,s)       ((s)->fds_bits[0] & (1 << (f)))
  7843. #define FD_ZERO(s)          ((s)->fds_bits[0] = 0)
  7844.  
  7845. #endif /* _VMS_FD */
  7846. $EOD
  7847. $!
  7848. $CREATE [.archie.vms]in.h
  7849. $DECK
  7850. /* netinet/in.h */
  7851. struct in_addr
  7852. {
  7853.   union
  7854.   {
  7855.     struct
  7856.     {
  7857.       unsigned char s_b1, s_b2, s_b3, s_b4;
  7858.     } S_un_b;
  7859.     struct
  7860.     {
  7861.       unsigned short s_w1, s_w2;
  7862.     } S_un_w;
  7863.     unsigned long S_addr;
  7864.   } S_un;
  7865. #define   s_addr S_un.S_addr
  7866. #define   s_host S_un.S_un_b.s_b2
  7867. #define   s_net  S_un.S_un_b.s_b1
  7868. #define   s_imp  S_un.S_un_w.s_w2
  7869. #define   s_impno S_un.S_un_b.s_b4
  7870. #define   s_lh   S_un.S_un_b.s_b3
  7871. };
  7872.  
  7873. #define INADDR_ANY 0x00000000
  7874. #define INADDR_BROADCAST 0xffffffff
  7875. #define INADDR_LOOPBACK 0x7f000001
  7876.  
  7877. struct sockaddr_in
  7878. {
  7879.   short sin_family;
  7880.   unsigned short sin_port;
  7881.   struct in_addr sin_addr;
  7882.   char sin_zero[8];
  7883. };
  7884.  
  7885. #define ntohl(x) (( (((unsigned long) x) >> 24)& 0x000000ff ) |\
  7886.                   ( (((unsigned long) x) >> 8) & 0x0000ff00 ) |\
  7887.                   ( (((unsigned long) x) << 8) & 0x00ff0000 ) |\
  7888.                   ( (((unsigned long) x) << 24)& 0xff000000 ))
  7889. #define ntohs(x) (( (((unsigned short) x) >> 8) |\
  7890.                   ( (((unsigned short) x) << 8)) & 0xffff ))
  7891. #define htonl(x) (( (((unsigned long) x) >> 24)& 0x000000ff ) |\
  7892.                   ( (((unsigned long) x) >> 8) & 0x0000ff00 ) |\
  7893.                   ( (((unsigned long) x) << 8) & 0x00ff0000 ) |\
  7894.                   ( (((unsigned long) x) << 24)& 0xff000000 ))
  7895. #define htons(x) (( (((unsigned short) x) >> 8) |\
  7896.                   ( (((unsigned short) x) << 8)) & 0xffff ))
  7897.  
  7898. #define IPPORT_RESERVED 1024
  7899. $EOD
  7900. $!
  7901. $CREATE [.archie.vms]pseudos.h
  7902. $DECK
  7903. /* These are so we don't end up using the MultiNet versions.  */
  7904. #define socket    VMSsocket
  7905. #define bind    VMSbind
  7906. #define connect    VMSconnect
  7907. #define listen    VMSlisten
  7908. #define accept    VMSaccept
  7909. #define select    VMSselect
  7910. #define recv    VMSrecv
  7911. #define recvfrom    VMSrecvfrom
  7912. #define send    VMSsend
  7913. #define sendto    VMSsendto
  7914. #define getsockname    VMSgetsockname
  7915. #define shutdown    VMSshutdown
  7916. #define getsockopt    VMSgetsockopt
  7917. #define setsockopt    VMSsetsockopt
  7918. $EOD
  7919. $!
  7920. $CREATE [.archie.vms]signal.h
  7921. $DECK
  7922. /* signal.h */
  7923. #define SIGURG  16
  7924. #define SIGTSTP 18
  7925. #define SIGCHLD 20
  7926. #define SIGIO   23
  7927. #define sigmask(m) (1 << ((m)-1))
  7928.  
  7929. #ifndef __GNUC__
  7930. # include <sys$library:signal.h>
  7931. #else /* Gnu C */
  7932. # include <gnu_cc_include:[000000]signal.h>
  7933. #endif /* not Gnu C */
  7934. $EOD
  7935. $!
  7936. $CREATE [.archie.vms]socket.h
  7937. $DECK
  7938. /* sys/socket.h */
  7939. #define SOCK_STREAM     1
  7940. #define SOCK_DGRAM      2
  7941.  
  7942. #define SO_DEBUG        0x01
  7943. #define SO_ACCEPTCONN   0x02
  7944. #define SO_REUSEADDR    0x04
  7945. #define SO_KEEPALIVE    0x08
  7946. #define SO_LINGER       0x80
  7947. #define SO_DONTLINGER   (~SO_LINGER)
  7948.  
  7949. #define AF_UNSPEC       0
  7950. #define AF_ERROR        0
  7951. #define AF_INET         2
  7952. #define AF_CCITT        10
  7953. #define AF_X25          10
  7954.  
  7955. struct sockaddr
  7956. {
  7957.   unsigned short sa_family;
  7958.   char sa_data[14];
  7959. };
  7960.  
  7961. #define SOL_SOCKET      0xffff
  7962.  
  7963. #define MSG_OOB 1
  7964. #define MSG_PEEK 2
  7965. $EOD
  7966. $!
  7967. $CREATE [.archie.vms]time.h
  7968. $DECK
  7969. #ifndef __PKTIME
  7970. #define __PKTIME
  7971.  
  7972. struct timeval
  7973. {
  7974.   long tv_sec;
  7975.   long tv_usec;
  7976. };
  7977.  
  7978. struct timezone
  7979. {
  7980.   int tz_minuteswest;
  7981.   int tz_dsttime;
  7982. };
  7983.  
  7984. struct itimerval
  7985. {
  7986.   struct timeval it_interval;
  7987.   struct timeval it_value;
  7988. };
  7989.  
  7990. #define ITIMER_REAL 0
  7991. #define timerclear(x) (x)->tv_sec = (x)->tv_usec = 0
  7992.  
  7993. #ifndef __GNUC__
  7994. # include <sys$library:time.h>
  7995. #else /* not Gnu C */
  7996. # include <gnu_cc_include:[000000]time.h>
  7997. #endif /* Gnu C */
  7998.  
  7999. #endif /* __PKTIME */
  8000. $EOD
  8001. $!
  8002. $CREATE [.archie.vms]types.h
  8003. $DECK
  8004. /* sys/types.h */
  8005. #ifndef _types_
  8006. #define _types_
  8007.  
  8008. #ifndef __GNUC__
  8009. # include <sys$library:stddef.h>
  8010. #endif /* not Gnu C */
  8011.  
  8012. typedef unsigned char u_char;
  8013. typedef unsigned short u_short;
  8014. typedef unsigned int u_int;
  8015. typedef unsigned long u_long;
  8016.  
  8017. typedef long daddr_t;
  8018. typedef char *caddr_t;
  8019.  
  8020. #include <sys$library:types.h>
  8021.  
  8022. typedef unsigned short ino_t;
  8023. typedef char *dev_t;
  8024. typedef unsigned int off_t;
  8025. typedef long key_t;
  8026.  
  8027. #include "[.vms]fd.h"
  8028.  
  8029. #endif /* _types */
  8030. $EOD
  8031. $!
  8032. $CREATE [.archie.vms]network.h
  8033. $DECK
  8034. /* Miscellaneous things for the networking library.  */
  8035.  
  8036. /* Actually an itemlist_3, but can be used for itemlist_2's.  */
  8037. struct itemlist
  8038. {
  8039.   short length;
  8040.   short code;
  8041.   char *dataptr;
  8042.   short *retlenptr;
  8043. };
  8044.  
  8045. union socket_addr
  8046. {
  8047.   struct sockaddr_in in;
  8048. };
  8049.  
  8050. #define   TCP$SEND        (IO$_WRITEVBLK)
  8051. #define   TCP$RECEIVE     (IO$_READVBLK)
  8052. #define   TCP$OPEN        (IO$_CREATE)
  8053. #define   TCP$CLOSE       (IO$_DELETE)
  8054. #define   TCP$ABORT       (IO$_DEACCESS)
  8055. #define   TCP$STATUS      (IO$_ACPCONTROL)
  8056. #define   TCP$INFO        (IO$_MODIFY)
  8057. #define   GTHST           (IO$_SKIPFILE)
  8058.  
  8059. #define   IO$_SEND        (IO$_WRITEVBLK)
  8060. #define   IO$_RECEIVE     (IO$_READVBLK)
  8061. #ifndef IO$S_FCODE
  8062. #define IO$S_FCODE 0x0006
  8063. #endif
  8064. #define   IO$_SOCKET      (IO$_ACCESS | (0 << IO$S_FCODE))
  8065. #define   IO$_BIND        (IO$_ACCESS | (1 << IO$S_FCODE))
  8066. #define   IO$_LISTEN      (IO$_ACCESS | (2 << IO$S_FCODE))
  8067. #define   IO$_ACCEPT      (IO$_ACCESS | (3 << IO$S_FCODE))
  8068. #define   IO$_CONNECT     (IO$_ACCESS | (4 << IO$S_FCODE))
  8069. #define   IO$_SETSOCKOPT  (IO$_ACCESS | (5 << IO$S_FCODE))
  8070. #define   IO$_GETSOCKOPT  (IO$_ACCESS | (6 << IO$S_FCODE))
  8071. #define   IO$_IOCTL       (IO$_ACCESS | (8 << IO$S_FCODE))
  8072. #define   IO$_ACCEPT_WAIT (IO$_ACCESS | (10 << IO$S_FCODE))
  8073. #define   IO$_NETWORK_PTY (IO$_ACCESS | (11 << IO$S_FCODE))
  8074. #define   IO$_SHUTDOWN    (IO$_ACCESS | (12 << IO$S_FCODE))
  8075. #define   IO$_GETSOCKNAME (IO$_ACCESS | (13 << IO$S_FCODE))
  8076. #define      SETCHAR_HANDOFF (1<<2)
  8077.  
  8078. #define   NFB$C_DECLNAME   0x15
  8079.  
  8080. #define TIMER_EFN 1
  8081. #define TERM_EFN  2
  8082. #define BUF_SIZE 2000
  8083.  
  8084. #define INITIALISED 0
  8085. #define ACTIVE_CONNECTION 1
  8086. #define PASSIVE_CONNECTION 2
  8087. #define LISTENING 3
  8088. #define HANDED_OFF 4
  8089.  
  8090. static struct fd_entry
  8091. {
  8092.   unsigned short int channel;    /* vms channel assigned to this socket */
  8093.   unsigned short int iosb[4];    /* returned status block */
  8094.   int fd_buff_size;        /* number of chrs in buffer still to be read */
  8095.   int accept_pending;        /* a call is waiting to be accepted */
  8096.   int connect_pending;        /* a connect is outstanding*/
  8097.   int connected;        /* this descriptor is connected */
  8098.   unsigned char *fd_buff;    /* pointer to buffer dyn assigned */
  8099.   unsigned char *fd_leftover;    /* pointer to any chrs still to be read */
  8100.   FILE *fptr;            /* we need to assgn a file ptr for stream io */
  8101.   int s;            /* socket number - needed in the ast's */
  8102.   int namelen;            /* our socket address name */
  8103.   union socket_addr name;
  8104.   short int fromdummy;        /* wg - accept wants an int - recvfrom wants a short!!*/
  8105.   short int fromlen;        /* the from socket address name */
  8106.   union socket_addr from;
  8107.   int tolen;            /* wg - sendto wants an int*/
  8108.   union socket_addr to;        /* the to socket address name */
  8109.   int passive;            /* still needed because of x25 close ambig */
  8110.   int backlog;            /* backlog - not handled well! */
  8111.   int domain;            /* domain of socket AF_INET or AF_X25 */
  8112.   int type;            /* type of socket stream or datagram */
  8113.   int protocol;            /* protocol of socket - ignored */
  8114.   int mbx_channel;        /* mailbox channel - needed for x25 */
  8115.   unsigned char mbx_buff[255];    /* mailbox buffer */
  8116.   unsigned short int miosb[4];    /* mailbox status block */
  8117.   int ncb_size;            /* x25 connection information */
  8118.   unsigned char ncb[128];
  8119.   unsigned char masklen;    /* x25 user data mask */
  8120.   unsigned char mask[16];
  8121.   int need_header;        /* x25 header field gives data status if req*/
  8122.   int send_type;        /* x25 data packet type eg more bit set etc */
  8123.   int status;            /* status of socket */
  8124.   int closed_by_remote;        /* flag for remote dropouts */
  8125.   int read_outstanding;        /* flag so we don't hang two reads */
  8126.   int cmu_open;            /* flag to say whether a cmu open was hung */
  8127.   int x25_listener;        /* flag to say we are an x25 listener */
  8128.   int oob_type;            /* handles interrupt messages */
  8129.   int mother;            /* mother socket for X25 accepts */
  8130.   int child;            /* child socket for X25 accepts */
  8131.   int no_more_accepts;        /* don't accept anymore calls */
  8132.   char int_data;        /* interrupt data - only 1 char supported */
  8133.   int non_blocking;        /* don't block on a read if no data */
  8134.   int sig_req;            /* generate SIGIO on data ready */
  8135.   struct itemlist rhost;    /* descriptor pointing to "p[].from" info for UCX */
  8136.   unsigned short ucx_accept_chan;    /* Channel returned by a UCX accept via hang_an_accept */
  8137. } p[32];
  8138.  
  8139. /* So we can handle select on terminal input.  */
  8140. static struct term_entry
  8141. {
  8142.   int chan;
  8143.   short int iosb[4];
  8144.   short int char_available;
  8145.   short int read_outstanding;
  8146.   char c[1];
  8147. } terminal =
  8148.  
  8149. {
  8150.   -1, 0, 0, 0, 0, 0, 0
  8151. };
  8152.  
  8153. #define CMU 1
  8154. #define WG  2
  8155. #define NONE 3
  8156. #define TGV 4
  8157. #define UCX 5
  8158. static int tcp_make = 0;
  8159.  
  8160. struct descriptor
  8161. {
  8162.   int size;
  8163.   char *ptr;
  8164. };
  8165.  
  8166. /* Initialize certain things 1st time thru.  */
  8167. static int p_initialised = 0;
  8168.  
  8169. /* A routine to point SIGALRM and SIGURG at.  */
  8170. static int 
  8171. si_dummy ()
  8172. {
  8173. }
  8174. static int (*alarm_function) () = si_dummy;
  8175. static int (*sigurg_function) () = si_dummy;
  8176.  
  8177. FILE *fdopen ();
  8178. static set_tcp_make ();
  8179. static char *getdevicename ();
  8180. $EOD
  8181. $!
  8182. $CREATE [.archie.vms]multi.opt
  8183. $DECK
  8184. sys$library:vaxcrtl.exe/share
  8185. multinet:multinet_socket_library.exe/share
  8186. $EOD
  8187. $!
  8188. $CREATE [.archie.vms]wall.opt
  8189. $DECK
  8190. sys$library:vaxcrtl.exe/share
  8191. twg$tcp:[netdist.lib]twglib.olb/lib
  8192. $EOD
  8193. $ write sys$output "Ok, now enter the ARCHIE directory and type @MAKE ."
  8194.