home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume26 / archie / part02 < prev    next >
Encoding:
Text File  |  1991-11-23  |  53.8 KB  |  1,893 lines

  1. Newsgroups: comp.sources.misc
  2. From: brendan@cs.widener.edu (Brendan Kehoe)
  3. Subject:  v26i047:  archie - A Prospero client for Archie, v1.2, Part02/05
  4. Message-ID: <1991Nov24.045405.4663@sparky.imd.sterling.com>
  5. X-Md4-Signature: ce9ece1d8ad12dfddf462244243abda8
  6. Date: Sun, 24 Nov 1991 04:54:05 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: brendan@cs.widener.edu (Brendan Kehoe)
  10. Posting-number: Volume 26, Issue 47
  11. Archive-name: archie/part02
  12. Environment: UNIX, VMS
  13. Supersedes: archie: Volume 22, Issue 35-39
  14.  
  15. #! /bin/sh
  16. # into a shell via "sh file" or similar.  To overwrite existing files,
  17. # type "sh file -c".
  18. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  19. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  20. # Contents:  ./dirsend.c ./make.com ./support.c ./vms/multi.opt
  21. # Wrapped by kent@sparky on Wed Nov 20 18:23:43 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 2 (of 5)."'
  25. if test -f './dirsend.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'./dirsend.c'\"
  27. else
  28.   echo shar: Extracting \"'./dirsend.c'\" \(29425 characters\)
  29.   sed "s/^X//" >'./dirsend.c' <<'END_OF_FILE'
  30. X/*
  31. X * Copyright (c) 1989, 1990, 1991 by the University of Washington
  32. X *
  33. X * For copying and distribution information, please see the file
  34. X * <copyright.h>.
  35. X *
  36. X * v1.2.4 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  37. X * v1.2.3 - 11/04/91 (bcn) - removed host comparison and replaced with check
  38. X *                 for connection id (undoes effect of v1.2.2.).
  39. X * v1.2.2 - 11/02/91 (gf)  - removed extra inet_ntoa() calls and stuff for
  40. X *                 multi-interface nets (lmjm@doc.imperial.ac.uk)
  41. X * v1.2.1 - 10/20/91 (gf)  - asynch implementation
  42. X * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  43. X * v1.1.2 - 08/30/91 (bpk) - added VMS support
  44. X * v1.1.1 - 08/29/91 (bcn) - changed backoff handling
  45. X * v1.1.0 - 08/13/91 (gf)  - added XArchie status calls
  46. X *
  47. X * gf: 20 Oct 1991:
  48. X *  Broken into pieces so that under X dirsend() doesn't block in select()
  49. X *  but rather uses Xt calls to allow continued event processing. If
  50. X *  XARCHIE is not defined, can still be used since processEvent() will
  51. X *  use select() in this case.
  52. X */
  53. X
  54. X#include <copyright.h>
  55. X#include <stdio.h>
  56. X#include <errno.h>
  57. X
  58. X#ifdef VMS
  59. X# ifdef WALLONGONG
  60. X#  include "twg$tcp:[netdist.include]netdb.h"
  61. X# else /* Multinet */
  62. X#  include "multinet_root:[multinet.include]netdb.h"
  63. X# endif
  64. X# include <vms.h>
  65. X#else /* not VMS */
  66. X# include <sys/types.h> /* this may/will define FD_SET etc */
  67. X# include <pmachine.h>
  68. X# ifdef NEED_TIME_H
  69. X#  include <time.h>
  70. X# else
  71. X#  include <sys/time.h>
  72. X# endif
  73. X# ifdef NEED_STRING_H
  74. X#  include <string.h>
  75. X# else
  76. X#  include <strings.h>
  77. X# endif
  78. X# include <netdb.h>
  79. X# include <sys/socket.h>
  80. X# ifdef NEED_SELECT_H
  81. X#  include <sys/select.h>
  82. X# endif /* NEED_SELECT_H */
  83. X# ifndef IN_H
  84. X#  include <netinet/in.h>
  85. X#  define IN_H
  86. X# endif
  87. X# ifndef hpux
  88. X#  include <arpa/inet.h>
  89. X# endif
  90. X#endif /* !VMS */
  91. X
  92. X#include <pfs.h>
  93. X#include <pprot.h>
  94. X#include <pcompat.h>
  95. X#include <perrno.h>
  96. X
  97. X/* Gnu C currently fails to pass structures on Sparcs properly.  This directly
  98. X   effects the calling of inet_ntoa().  To get around it, we use this hack;
  99. X   take the address of what's being called to inet_ntoa, so it gets it
  100. X   properly.  This won't be necessary with gcc 2.0.  */
  101. X#if defined(sun) && defined(__GNUC__) && !defined(__GNU_LIBRARY__)
  102. X# define SUN_GNU_FIX &
  103. X#else
  104. X# define SUN_GNU_FIX
  105. X#endif
  106. X
  107. Xstatic int notprived = 0;
  108. X#ifndef MSDOS
  109. Xextern int errno;
  110. X#endif
  111. Xextern int perrno;
  112. Xextern int rdgram_priority;
  113. X#ifdef DEBUG
  114. Xextern int pfs_debug;
  115. X#endif
  116. Xextern int pfs_disable_flag;
  117. X
  118. Xchar    *nlsindex();
  119. X
  120. X#define max(X, Y)  ((X) > (Y) ? (X) : (Y))
  121. X
  122. Xstatic int        dir_udp_port = 0;    /* Remote UDP port number */
  123. X
  124. Xstatic unsigned short    next_conn_id = 0;
  125. X
  126. X#ifdef XARCHIE
  127. Xint client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  128. Xint client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  129. X#else /* !XARCHIE */
  130. Xstatic int client_dirsrv_timeout = CLIENT_DIRSRV_TIMEOUT;
  131. Xstatic int client_dirsrv_retry = CLIENT_DIRSRV_RETRY; 
  132. X#endif /* XARCHIE */
  133. X
  134. X/* These were parameters to dirsend() */
  135. Xstatic PTEXT pkt;
  136. Xstatic char *hostname;
  137. Xstatic struct sockaddr_in *hostaddr;
  138. X
  139. X/* These were locals in dirsend(). Note that the initializations here
  140. X * are really meaningless since we have to redo them for each call to
  141. X * dirsend() since they were formerly automatically initialized.
  142. X */
  143. Xstatic PTEXT        first = NULL;    /* First returned packet     */
  144. Xstatic PTEXT        next;        /* The one we are waiting for      */
  145. Xstatic PTEXT        vtmp;           /* For reorganizing linked list  */
  146. Xstatic PTEXT        comp_thru;    /* We have all packets though    */
  147. Xstatic int        lp = -1;    /* Opened UDP port             */
  148. Xstatic int        hdr_len;    /* Header Length                 */
  149. Xstatic int        nd_pkts;    /* Number of packets we want     */
  150. Xstatic int        no_pkts;    /* Number of packets we have     */
  151. Xstatic int        pkt_cid;        /* Packet connection identifier  */
  152. Xstatic unsigned short    this_conn_id;    /* Connection ID we are using    */
  153. Xstatic unsigned short    recvd_thru;    /* Received through              */
  154. Xstatic short        priority;    /* Priority for request          */
  155. Xstatic short        one = 0;    /* Pointer to value 1            */
  156. Xstatic short        zero = 0;    /* Pointer to value 0         */
  157. Xstatic char        *seqtxt;    /* Pointer to text w/ sequence # */
  158. Xstatic struct sockaddr_in  us;        /* Our address                   */
  159. Xstatic struct sockaddr_in  to;        /* Address to send query     */
  160. Xstatic struct sockaddr_in  from;    /* Reply received from         */
  161. Xstatic int        from_sz;    /* Size of from structure     */
  162. Xstatic struct hostent    *host;        /* Host info from gethostbyname  */
  163. Xstatic long        newhostaddr;    /* New host address from *host   */
  164. Xstatic int        req_udp_port=0; /* Requested port (optional)     */
  165. Xstatic char        *openparen;    /* Delimits port in name         */
  166. Xstatic char        hostnoport[500];/* Host name without port        */
  167. Xstatic int        ns;        /* Number of bytes actually sent */
  168. Xstatic int        nr;        /* Number of bytes received      */
  169. Xstatic fd_set        readfds;    /* Used for select         */
  170. Xstatic int        tmp;
  171. Xstatic char        *ctlptr;    /* Pointer to control field      */
  172. Xstatic short        stmp;        /* Temp short for conversions    */
  173. Xstatic int        backoff;    /* Server requested backoff      */
  174. Xstatic unsigned char    rdflag11;    /* First byte of flags (bit vect)*/
  175. Xstatic unsigned char    rdflag12;    /* Second byte of flags (int)    */
  176. Xstatic int        scpflag = 0;    /* Set if any sequencd cont pkts */
  177. Xstatic int        ackpend = 0;    /* Acknowledgement pending      */
  178. Xstatic int        gaps = 0;    /* Gaps present in recvd pkts   */
  179. Xstatic struct timeval    timeout;    /* Time to wait for response    */
  180. Xstatic struct timeval    ackwait;    /* Time to wait before acking   */
  181. Xstatic struct timeval    gapwait;    /* Time to wait b4 filling gaps */
  182. Xstatic struct timeval    *selwait;    /* Time to wait for select      */
  183. Xstatic int        retries;    /* was = client_dirsrv_retry    */
  184. Xchar   to_hostname[512];        /* lmjm: saves inet_ntoa() str  */
  185. X
  186. X/* These are added so dirsend() "blocks" properly */
  187. Xstatic PTEXT dirsendReturn;
  188. Xstatic int dirsendDone;
  189. X
  190. X/* And here are the values for dirsendDone */
  191. X#define DSRET_DONE        1
  192. X#define DSRET_SEND_ERROR    -1
  193. X#define DSRET_RECV_ERROR    -2
  194. X#define DSRET_SELECT_ERROR    -3
  195. X#define DSRET_TIMEOUT        -4
  196. X#define DSRET_ABORTED        -5
  197. X
  198. X/* New procedures to break up dirsend() */
  199. Xstatic int initDirsend();
  200. Xstatic void retryDirsend(), keepWaitingDirsend();
  201. Xstatic void timeoutProc();
  202. Xstatic void readProc();
  203. X
  204. X/* Wrappers around X calls to allow non-X usage */
  205. Xstatic void addInputSource(), removeInputSource();
  206. Xstatic void addTimeOut(), removeTimeOut();
  207. Xstatic void processEvent();
  208. X
  209. X/* Extra stuff for the asynchronous X version of dirsend() */
  210. X#ifdef XARCHIE
  211. X#include <X11/Intrinsic.h>
  212. Xextern XtAppContext appContext;
  213. X#else
  214. Xtypedef char *XtPointer;
  215. Xtypedef char *XtInputId;
  216. Xtypedef char *XtIntervalId;
  217. X#endif
  218. Xstatic XtInputId inputId;
  219. Xstatic XtIntervalId timerId = (XtIntervalId)0;
  220. X
  221. X/*
  222. X * dirsend - send packet and receive response
  223. X *
  224. X *   DIRSEND takes a pointer to a structure of type PTEXT, a hostname,
  225. X *   and a pointer to a host address.  It then sends the supplied
  226. X *   packet off to the directory server on the specified host.  If
  227. X *   hostaddr points to a valid address, that address is used.  Otherwise,
  228. X *   the hostname is looked up to obtain the address.  If hostaddr is a
  229. X *   non-null pointer to a 0 address, then the address will be replaced
  230. X *   with that found in the hostname lookup.
  231. X *
  232. X *   DIRSEND will wait for a response and retry an appropriate
  233. X *   number of times as defined by timeout and retries (both static
  234. X *   variables).  It will collect however many packets form the reply, and
  235. X *   return them in a structure (or structures) of type PTEXT.
  236. X *
  237. X *   DIRSEND will free the packet that it is presented as an argument.
  238. X *   The packet is freed even if dirsend fails.
  239. X */
  240. XPTEXT
  241. Xdirsend(pkt_p,hostname_p,hostaddr_p)
  242. X    PTEXT pkt_p;
  243. X    char *hostname_p;
  244. X    struct sockaddr_in    *hostaddr_p;
  245. X{
  246. X    /* copy parameters to globals since other routines use them */
  247. X    pkt = pkt_p;
  248. X    hostname = hostname_p;
  249. X    hostaddr = hostaddr_p;
  250. X    /* Do the initializations of formerly auto variables */
  251. X    first = NULL;
  252. X    lp = -1;
  253. X    one = 0;
  254. X    zero = 0;
  255. X    req_udp_port=0;
  256. X    scpflag = 0;
  257. X    ackpend = 0;
  258. X    gaps = 0;
  259. X    retries = client_dirsrv_retry;
  260. X
  261. X    if (initDirsend() < 0)
  262. X    return(NULL);
  263. X    addInputSource();
  264. X    /* set the first timeout */
  265. X    retryDirsend();
  266. X
  267. X    dirsendReturn = NULL;
  268. X    dirsendDone = 0;
  269. X    /* Until one of the callbacks says to return, keep processing events */
  270. X    while (!dirsendDone)
  271. X    processEvent();
  272. X    /* Clean up event generators */
  273. X    removeTimeOut();
  274. X    removeInputSource();
  275. X#ifdef XARCHIE
  276. X    /* Set status if needed (has to be outside of loop or X will crash) */
  277. X    switch (dirsendDone) {
  278. X    case DSRET_SEND_ERROR: status0("Send error"); break;
  279. X    case DSRET_RECV_ERROR: status0("Recv error"); break;
  280. X        case DSRET_TIMEOUT:
  281. X        status1("Connection to %s timed out",to_hostname);
  282. X        break;
  283. X        case DSRET_ABORTED: status0("Aborted"); break;
  284. X    }
  285. X#endif
  286. X    /* Return whatever we're supposed to */
  287. X    return(dirsendReturn);
  288. X}
  289. X
  290. X
  291. X/*    -    -    -    -    -    -    -    -    */
  292. X/* This function does all the initialization that used to be done at the
  293. X * start of dirsend(), including opening the socket descriptor "lp". It
  294. X * returns the descriptor if successful, otherwise -1 to indicate that
  295. X * dirsend() should return NULL immediately.
  296. X */
  297. Xstatic int
  298. XinitDirsend()
  299. X{
  300. X#ifdef XARCHIE
  301. X    status0("Initializing");
  302. X#endif
  303. X
  304. X    if(one == 0) one = htons((short) 1);
  305. X
  306. X    priority = htons(rdgram_priority);
  307. X
  308. X    timeout.tv_sec = client_dirsrv_timeout;
  309. X    timeout.tv_usec = 0;
  310. X
  311. X    ackwait.tv_sec = 0;
  312. X    ackwait.tv_usec = 500000;
  313. X
  314. X    gapwait.tv_sec = (client_dirsrv_timeout < 5 ? client_dirsrv_timeout : 5);
  315. X    gapwait.tv_usec = 0;
  316. X
  317. X    comp_thru = NULL;
  318. X    perrno = 0;
  319. X    nd_pkts = 0;
  320. X    no_pkts = 0;
  321. X    pkt_cid = 0;
  322. X
  323. X    /* Find first connection ID */
  324. X    if(next_conn_id == 0) {
  325. X    srand(getpid()+time(0));
  326. X    next_conn_id = rand();
  327. X    }
  328. X
  329. X
  330. X    /* If necessary, find out what udp port to send to */
  331. X    if (dir_udp_port == 0) {
  332. X        register struct servent *sp;
  333. X    tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  334. X#ifdef USE_ASSIGNED_PORT
  335. X        if ((sp = getservbyname("prospero","udp")) == 0) {
  336. X#ifdef DEBUG
  337. X        if (pfs_debug)
  338. X        fprintf(stderr, "dirsrv: udp/prospero unknown service - using %d\n", 
  339. X            PROSPERO_PORT);
  340. X#endif
  341. X        dir_udp_port = htons((u_short) PROSPERO_PORT);
  342. X        }
  343. X#else
  344. X        if ((sp = getservbyname("dirsrv","udp")) == 0) {
  345. X#ifdef DEBUG
  346. X        if (pfs_debug)
  347. X        fprintf(stderr, "dirsrv: udp/dirsrv unknown service - using %d\n", 
  348. X            DIRSRV_PORT);
  349. X#endif
  350. X        dir_udp_port = htons((u_short) DIRSRV_PORT);
  351. X        }
  352. X#endif
  353. X    else dir_udp_port = sp->s_port;
  354. X    pfs_enable = tmp;
  355. X#ifdef DEBUG
  356. X        if (pfs_debug > 3)
  357. X            fprintf(stderr,"dir_udp_port is %d\n", ntohs(dir_udp_port));
  358. X#endif
  359. X    }
  360. X
  361. X    /* If we were given the host address, then use it.  Otherwise  */
  362. X    /* lookup the hostname.  If we were passed a host address of   */
  363. X    /* 0, we must lookup the host name, then replace the old value */
  364. X    if(!hostaddr || (hostaddr->sin_addr.s_addr == 0)) {
  365. X    /* I we have a null host name, return an error */
  366. X    if((hostname == NULL) || (*hostname == '\0')) {
  367. X#ifdef DEBUG
  368. X            if (pfs_debug)
  369. X                fprintf(stderr, "dirsrv: Null hostname specified\n");
  370. X#endif
  371. X        perrno = DIRSEND_BAD_HOSTNAME;
  372. X        ptlfree(pkt);
  373. X            /* return(NULL); */
  374. X        return(-1);
  375. X    }
  376. X    /* If a port is included, save it away */
  377. X    if(openparen = index(hostname,'(')) {
  378. X        sscanf(openparen+1,"%d",&req_udp_port);
  379. X        strncpy(hostnoport,hostname,400);
  380. X        if((openparen - hostname) < 400) {
  381. X        *(hostnoport + (openparen - hostname)) = '\0';
  382. X        hostname = hostnoport;
  383. X        }
  384. X    }
  385. X    tmp = pfs_enable; pfs_enable = PMAP_DISABLE;
  386. X        if((host = gethostbyname(hostname)) == NULL) {
  387. X        pfs_enable = tmp;
  388. X        /* Check if a numeric address */
  389. X        newhostaddr = inet_addr(hostname);
  390. X        if(newhostaddr == -1) {
  391. X#ifdef DEBUG
  392. X        if (pfs_debug)
  393. X          fprintf(stderr, "dirsrv: Can't resolve host %s\n",hostname);
  394. X#endif
  395. X        perrno = DIRSEND_BAD_HOSTNAME;
  396. X        ptlfree(pkt);
  397. X        /* return(NULL); */
  398. X        return(-1);
  399. X        }
  400. X        bzero((char *)&to, S_AD_SZ);
  401. X        to.sin_family = AF_INET;
  402. X        bcopy(&newhostaddr, (char *)&to.sin_addr, 4);
  403. X        if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  404. X    }
  405. X    else {
  406. X        pfs_enable = tmp;
  407. X        bzero((char *)&to, S_AD_SZ);
  408. X        to.sin_family = host->h_addrtype;
  409. X        bcopy(host->h_addr, (char *)&to.sin_addr, host->h_length);
  410. X        if(hostaddr) bcopy(&to,hostaddr, S_AD_SZ);
  411. X    }
  412. X    }
  413. X    else bcopy(hostaddr,&to, S_AD_SZ);
  414. X    /* lmjm: Save away the hostname */
  415. X    strncpy(to_hostname,
  416. X        inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&to.sin_addr),
  417. X        sizeof(to_hostname)-1);
  418. X
  419. X    if(req_udp_port) to.sin_port = htons(req_udp_port);
  420. X    else to.sin_port = dir_udp_port;
  421. X
  422. X    /* If a port was specified in hostaddr, use it, otherwise fill it in */
  423. X    if(hostaddr) {
  424. X    if(hostaddr->sin_port) to.sin_port = hostaddr->sin_port;
  425. X    else hostaddr->sin_port = to.sin_port;
  426. X    }
  427. X
  428. X    /* Must open a new port each time. we do not want to see old */
  429. X    /* responses to messages we are done with                    */
  430. X    if ((lp = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
  431. X#ifdef DEBUG
  432. X        if (pfs_debug)
  433. X            fprintf(stderr,"dirsrv: Can't open socket\n");
  434. X#endif
  435. X    perrno = DIRSEND_UDP_CANT;
  436. X    ptlfree(pkt);
  437. X        /* return(NULL); */
  438. X    return(-1);
  439. X    }
  440. X
  441. X    /* Try to bind it to a privileged port - loop through candidate */
  442. X    /* ports trying to bind.  If failed, that's OK, we will let the */
  443. X    /* system assign a non-privileged port later                    */
  444. X    if(!notprived) {
  445. X    for(tmp = PROS_FIRST_PRIVP; tmp < PROS_FIRST_PRIVP+PROS_NUM_PRIVP; 
  446. X        tmp++) {
  447. X        bzero((char *)&us, sizeof(us));
  448. X        us.sin_family = AF_INET;
  449. X        us.sin_port = htons((u_short) tmp);
  450. X        if (bind(lp, (struct sockaddr *)&us, sizeof(us))) {
  451. X        if(errno != EADDRINUSE) {
  452. X            notprived++;
  453. X            break;
  454. X        }
  455. X        }
  456. X        else break;
  457. X    }
  458. X    }
  459. X
  460. X#ifndef USE_V3_PROT
  461. X    /* Add header */
  462. X    if(rdgram_priority) {
  463. X    pkt->start -= 15;
  464. X    pkt->length += 15;
  465. X    *(pkt->start) = (char) 15;
  466. X    bzero(pkt->start+9,4);
  467. X    *(pkt->start+11) = 0x02;
  468. X    bcopy(&priority,pkt->start+13,2);
  469. X    }
  470. X    else {
  471. X    pkt->start -= 9;
  472. X    pkt->length += 9;
  473. X    *(pkt->start) = (char) 9;
  474. X    }
  475. X    this_conn_id = htons(next_conn_id++);
  476. X    if(next_conn_id == 0) next_conn_id++;
  477. X    bcopy(&this_conn_id,pkt->start+1,2);
  478. X    bcopy(&one,pkt->start+3,2);
  479. X    bcopy(&one,pkt->start+5,2);
  480. X    bzero(pkt->start+7,2);
  481. X#endif
  482. X
  483. X#ifdef DEBUG
  484. X    if (pfs_debug > 2) {
  485. X#ifndef USE_V3_PROT
  486. X        if (to.sin_family == AF_INET) {
  487. X        if(req_udp_port) 
  488. X        fprintf(stderr,"Sending message to %s+%d(%d)...",
  489. X            to_hostname, req_udp_port, ntohs(this_conn_id));
  490. X        else fprintf(stderr,"Sending message to %s(%d)...",
  491. X             to_hostname, ntohs(this_conn_id));
  492. X    }
  493. X#else
  494. X        if (to.sin_family == AF_INET) 
  495. X        fprintf(stderr,"Sending message to %s...", to_hostname);
  496. X#endif
  497. X        else
  498. X            fprintf(stderr,"Sending message...");
  499. X        (void) fflush(stderr);
  500. X    }
  501. X#endif
  502. X
  503. X    first = ptalloc();
  504. X    next = first;
  505. X
  506. X#ifdef XARCHIE
  507. X    status1("Connecting to %s",to_hostname);
  508. X#endif
  509. X    return(lp);
  510. X}
  511. X
  512. X/*    -    -    -    -    -    -    -    -    */
  513. X/*
  514. X * This used to be a label to goto to retry the last packet. Now we resend
  515. X * the packet and call keepWaitingDirsend() to wait for a reply. (We
  516. X * call keepWaitingDirsend() because formerly the code dropped through
  517. X * the keep_waiting label.)
  518. X */
  519. Xstatic void
  520. XretryDirsend()
  521. X{
  522. X    gaps = ackpend = 0;
  523. X
  524. X    ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  525. X    if(ns != pkt->length) {
  526. X#ifdef DEBUG
  527. X    if (pfs_debug) {
  528. X    fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  529. X        perror("");
  530. X    }
  531. X#endif
  532. X    close(lp);
  533. X    perrno = DIRSEND_NOT_ALL_SENT;
  534. X    ptlfree(first);
  535. X    ptlfree(pkt);
  536. X    /* return(NULL); */
  537. X    dirsendReturn = NULL;
  538. X    dirsendDone = DSRET_SEND_ERROR;
  539. X    }
  540. X#ifdef DEBUG
  541. X    if (pfs_debug > 2) fprintf(stderr,"Sent.\n");
  542. X#endif
  543. X    keepWaitingDirsend();
  544. X}
  545. X
  546. X/*    -    -    -    -    -    -    -    -    */
  547. X/*
  548. X * This used to be a label to goto to set the appropriate timeout value
  549. X * and blocked in select(). Now we set selwait and the fd_sets to the
  550. X * appropriate values, and in X register a new timeout, then return to
  551. X * allow event processing.
  552. X */
  553. Xstatic void
  554. XkeepWaitingDirsend()
  555. X{
  556. X    /* We come back to this point (by a goto) if the packet */
  557. X    /* received is only part of the response, or if the     */
  558. X    /* response came from the wrong host            */
  559. X
  560. X#ifdef DEBUG
  561. X    if (pfs_debug > 2) fprintf(stderr,"Waiting for reply...");
  562. X#endif
  563. X    FD_ZERO(&readfds);
  564. X    FD_SET(lp, &readfds);
  565. X
  566. X    if(ackpend) selwait = &ackwait;
  567. X    else if(gaps) selwait = &gapwait;
  568. X    else selwait = &timeout;
  569. X
  570. X    addTimeOut();
  571. X}
  572. X
  573. X/*    -    -    -    -    -    -    -    -    */
  574. X/*
  575. X * This routine is called when a timeout occurs. It includes the code that
  576. X * was formerly used when select() returned 0 (indicating a timeout).
  577. X */
  578. X/*ARGSUSED*/
  579. Xstatic void
  580. XtimeoutProc(client_data,id)
  581. XXtPointer client_data;
  582. XXtIntervalId *id;
  583. X{
  584. X    if (gaps || ackpend) { /* Send acknowledgment */
  585. X    /* Acks are piggybacked on retries - If we have received */
  586. X    /* an ack from the server, then the packet sent is only  */
  587. X    /* an ack and the rest of the message will be empty      */
  588. X#ifdef DEBUG
  589. X    if (pfs_debug > 2) {
  590. X            fprintf(stderr,"Acknowledging (%s).\n",
  591. X            (ackpend ? "requested" : "gaps"));
  592. X    }    
  593. X#endif
  594. X    retryDirsend();
  595. X    return;
  596. X    }
  597. X
  598. X    if (retries-- > 0) {
  599. X    timeout.tv_sec = CLIENT_DIRSRV_BACKOFF(timeout.tv_sec);
  600. X#ifdef DEBUG
  601. X    if (pfs_debug > 2) {
  602. X            fprintf(stderr,"Timed out.  Setting timeout to %d seconds.\n",
  603. X            timeout.tv_sec);
  604. X    }
  605. X#endif
  606. X#ifdef XARCHIE
  607. X        status1("Timed out -- retrying (%d seconds)",timeout.tv_sec);
  608. X#endif
  609. X    retryDirsend();
  610. X    return;
  611. X    }
  612. X
  613. X#ifdef DEBUG
  614. X    if (pfs_debug) {
  615. X    fprintf(stderr, "select failed(timeoutProc): readfds=%x ",
  616. X        readfds);
  617. X    perror("");
  618. X    }
  619. X#endif
  620. X    close(lp);
  621. X    perrno = DIRSEND_SELECT_FAILED;
  622. X    ptlfree(first);
  623. X    ptlfree(pkt);
  624. X    /* return(NULL); */
  625. X    dirsendReturn = NULL;
  626. X    dirsendDone = DSRET_TIMEOUT;
  627. X}
  628. X
  629. X/*    -    -    -    -    -    -    -    -    */
  630. X/*
  631. X * This function is called whenever there's something to read on the
  632. X * connection. It includes the code that was run when select() returned
  633. X * greater than 0 (indicating read ready).
  634. X */
  635. X/*ARGSUSED*/
  636. Xstatic void
  637. XreadProc(client_data,source,id)
  638. XXtPointer client_data;
  639. Xint *source;
  640. XXtInputId *id;
  641. X{
  642. X    /* We got something to read, so clear the timer */
  643. X    removeTimeOut();
  644. X
  645. X    from_sz = sizeof(from);
  646. X    next->start = next->dat;
  647. X    if ((nr = recvfrom(lp, next->start, sizeof(next->dat), 0, (struct sockaddr *)&from, &from_sz)) < 0) {
  648. X#ifdef DEBUG
  649. X        if (pfs_debug) perror("recvfrom");
  650. X#endif
  651. X    close(lp);
  652. X    perrno = DIRSEND_BAD_RECV;
  653. X    ptlfree(first);
  654. X    ptlfree(pkt);
  655. X    /* return(NULL) */
  656. X    dirsendReturn = NULL;
  657. X    dirsendDone = DSRET_RECV_ERROR;
  658. X        return;
  659. X    }
  660. X
  661. X    next->length = nr;
  662. X    
  663. X    *(next->start + next->length) = NULL;
  664. X
  665. X#ifdef DEBUG
  666. X    if (pfs_debug > 2)
  667. X        fprintf(stderr,"Received packet from %s\n",
  668. X        inet_ntoa(SUN_GNU_FIX *(struct in_addr *)&from.sin_addr));
  669. X#endif
  670. X
  671. X#ifdef XARCHIE
  672. X    {
  673. X        static int num = 2;
  674. X    if (num == 2)
  675. X        status1("Connected to %s",to_hostname);
  676. X    else
  677. X        status1("Receiving...%c",(num?'+':'*'));
  678. X    num = !num;
  679. X    }
  680. X#endif
  681. X
  682. X    /* For the current format, if the first byte is less than             */
  683. X    /* 20, then the first two bits are a version number and the next six  */
  684. X    /* are the header length (including the first byte).                  */
  685. X    if((hdr_len = (unsigned char) *(next->start)) < 20) {
  686. X    ctlptr = next->start + 1;
  687. X    next->seq = 0;
  688. X    if(hdr_len >= 3) {     /* Connection ID */
  689. X        bcopy(ctlptr,&stmp,2);
  690. X        if(stmp) pkt_cid = ntohs(stmp);
  691. X        ctlptr += 2;
  692. X    }
  693. X    if(pkt_cid && this_conn_id && (pkt_cid != this_conn_id)) {
  694. X        /* The packet is not for us */
  695. X        /* goto keep_waiting; */
  696. X        keepWaitingDirsend();
  697. X        return;
  698. X    }
  699. X    if(hdr_len >= 5) {    /* Packet number */
  700. X        bcopy(ctlptr,&stmp,2);
  701. X        next->seq = ntohs(stmp);
  702. X        ctlptr += 2;
  703. X    }
  704. X    else { /* No packet number specified, so this is the only one */
  705. X        next->seq = 1;
  706. X        nd_pkts = 1;
  707. X    }
  708. X    if(hdr_len >= 7) {        /* Total number of packets */
  709. X        bcopy(ctlptr,&stmp,2);  /* 0 means don't know      */
  710. X        if(stmp) nd_pkts = ntohs(stmp);
  711. X        ctlptr += 2;
  712. X    }
  713. X    if(hdr_len >= 9) {    /* Receievd through */
  714. X        bcopy(ctlptr,&stmp,2);  /* 1 means received request */
  715. X#ifndef USE_V3_PROT
  716. X        if((stmp) && (ntohs(stmp) == 1)) {
  717. X        /* Future retries will be acks only */
  718. X        pkt->length = 9;
  719. X        bcopy(&zero,pkt->start+3,2);
  720. X#ifdef DEBUG
  721. X        if(pfs_debug > 2) 
  722. X            fprintf(stderr,"Server acked request - retries will be acks only\n");
  723. X#endif
  724. X        }
  725. X#endif
  726. X        ctlptr += 2;
  727. X    }
  728. X    if(hdr_len >= 11) {    /* Backoff */
  729. X        bcopy(ctlptr,&stmp,2);
  730. X        if(stmp) {
  731. X        backoff = ntohs(stmp);
  732. X#ifdef DEBUG
  733. X        if(pfs_debug > 2) 
  734. X            fprintf(stderr,"Backing off to %d seconds\n", backoff);
  735. X#endif
  736. X        timeout.tv_sec = backoff;
  737. X        if ((backoff > 60) && (first == next) && (no_pkts == 0)) {
  738. X            /* Probably a long queue on the server - don't give up */
  739. X            retries = client_dirsrv_retry;
  740. X        }
  741. X        }
  742. X        ctlptr += 2;
  743. X    }
  744. X    if(hdr_len >= 12) {    /* Flags (1st byte) */
  745. X        bcopy(ctlptr,&rdflag11,1);
  746. X        if(rdflag11 & 0x80) {
  747. X#ifdef DEBUG
  748. X        if(pfs_debug > 2) 
  749. X            fprintf(stderr,"Ack requested\n");
  750. X#endif
  751. X        ackpend++;
  752. X        }
  753. X        if(rdflag11 & 0x40) {
  754. X#ifdef DEBUG
  755. X        if(pfs_debug > 2) 
  756. X            fprintf(stderr,"Sequenced control packet\n");
  757. X#endif
  758. X        next->length = -1;
  759. X        scpflag++;
  760. X        }
  761. X        ctlptr += 1;
  762. X    }
  763. X    if(hdr_len >= 13) {    /* Flags (2nd byte) */
  764. X        /* Reserved for future use */
  765. X        bcopy(ctlptr,&rdflag12,1);
  766. X        ctlptr += 1;
  767. X    }
  768. X    if(next->seq == 0) {
  769. X        /* goto keep_waiting; */
  770. X        keepWaitingDirsend();
  771. X        return;
  772. X    }
  773. X    if(next->length >= 0) next->length -= hdr_len;
  774. X    next->start += hdr_len;
  775. X    goto done_old;
  776. X    }
  777. X
  778. X    pkt_cid = 0;
  779. X
  780. X    /* if intermediate format (between old and new), then process */
  781. X    /* and go to done_old                                         */
  782. X    ctlptr = next->start + max(0,next->length-20);
  783. X    while(*ctlptr) ctlptr++;
  784. X    /* Control fields start after the terminating null */
  785. X    ctlptr++;
  786. X    /* Until old version are gone, must be 4 extra bytes minimum */
  787. X    /* When no version 3 servers, can remove the -4              */
  788. X    if(ctlptr < (next->start + next->length - 4)) {
  789. X    /* Connection ID */
  790. X    bcopy(ctlptr,&stmp,2);
  791. X    if(stmp) pkt_cid = ntohs(stmp);
  792. X    ctlptr += 2;
  793. X    if(pkt_cid && this_conn_id && (pkt_cid != this_conn_id)) {
  794. X        /* The packet is not for us */
  795. X        /* goto keep_waiting; */
  796. X        keepWaitingDirsend();
  797. X        return;
  798. X    }
  799. X    /* Packet number */
  800. X    if(ctlptr < (next->start + next->length)) {
  801. X        bcopy(ctlptr,&stmp,2);
  802. X        next->seq = ntohs(stmp);
  803. X        ctlptr += 2;
  804. X    }
  805. X    /* Total number of packets */
  806. X    if(ctlptr < (next->start + next->length)) {
  807. X        bcopy(ctlptr,&stmp,2);
  808. X        if(stmp) nd_pkts = ntohs(stmp);
  809. X        ctlptr += 2;
  810. X    }
  811. X    /* Receievd through */
  812. X    if(ctlptr < (next->start + next->length)) {
  813. X        /* Not supported by clients */
  814. X        ctlptr += 2;
  815. X    }
  816. X    /* Backoff */
  817. X    if(ctlptr < (next->start + next->length)) {
  818. X        bcopy(ctlptr,&stmp,2);
  819. X        backoff = ntohs(stmp);
  820. X#ifdef DEBUG
  821. X        if(pfs_debug > 2) 
  822. X        fprintf(stderr,"Backing off to %d seconds\n", backoff);
  823. X#endif
  824. X        if(backoff) timeout.tv_sec = backoff;
  825. X        ctlptr += 2;
  826. X    }
  827. X    if(next->seq == 0) {
  828. X        /* goto keep_waiting; */
  829. X        keepWaitingDirsend();
  830. X        return;
  831. X    }
  832. X    goto done_old;
  833. X
  834. X    }
  835. X
  836. X    /* Notes that we have to start searching 11 bytes before the    */
  837. X    /* expected start of the MULTI-PACKET line because the message  */
  838. X    /* might include up to 10 bytes of data after the trailing null */
  839. X    /* The order of those bytes is two bytes each for Connection ID */
  840. X    /* Packet-no, of, Received-through, Backoff                     */
  841. X    seqtxt = nlsindex(next->start + max(0,next->length - 40),"MULTI-PACKET"); 
  842. X    if(seqtxt) seqtxt+= 13;
  843. X
  844. X    if((nd_pkts == 0) && (no_pkts == 0) && (seqtxt == NULL)) goto all_done;
  845. X
  846. X    tmp = sscanf(seqtxt,"%d OF %d", &(next->seq), &nd_pkts);
  847. X#ifdef DEBUG    
  848. X    if (pfs_debug && (tmp == 0)) 
  849. X    fprintf(stderr,"Cant read packet sequence number: %s", seqtxt);    
  850. X#endif
  851. X done_old:
  852. X#ifdef DEBUG
  853. X    if(pfs_debug > 2) fprintf(stderr,"Packet %d of %d\n",next->seq,nd_pkts);
  854. X#endif
  855. X    if ((first == next) && (no_pkts == 0)) {
  856. X    if(first->seq == 1) {
  857. X        comp_thru = first;
  858. X        /* If only one packet, then return it */
  859. X        if(nd_pkts == 1) goto all_done;
  860. X    }
  861. X    else gaps++;
  862. X    no_pkts = 1;
  863. X    next = ptalloc();
  864. X    /* goto keep_waiting; */
  865. X    keepWaitingDirsend();
  866. X    return;
  867. X    }
  868. X    
  869. X    if(comp_thru && (next->seq <= comp_thru->seq))
  870. X    ptfree(next);
  871. X    else if (next->seq < first->seq) {
  872. X    vtmp = first;
  873. X    first = next;
  874. X    first->next = vtmp;
  875. X    first->previous = NULL;
  876. X    vtmp->previous = first;
  877. X    if(first->seq == 1) comp_thru = first;
  878. X    no_pkts++;
  879. X    }
  880. X    else {
  881. X    vtmp = (comp_thru ? comp_thru : first);
  882. X    while (vtmp->seq < next->seq) {
  883. X        if(vtmp->next == NULL) {
  884. X        vtmp->next = next;
  885. X        next->previous = vtmp;
  886. X        next->next = NULL;
  887. X        no_pkts++;
  888. X        goto ins_done;
  889. X        }
  890. X        vtmp = vtmp->next;
  891. X    }
  892. X    if(vtmp->seq == next->seq)
  893. X        ptfree(next);
  894. X    else {
  895. X        vtmp->previous->next = next;
  896. X        next->previous = vtmp->previous;
  897. X        next->next = vtmp;
  898. X        vtmp->previous = next;
  899. X        no_pkts++;
  900. X    }
  901. X    }   
  902. X
  903. Xins_done:
  904. X    
  905. X    while(comp_thru && comp_thru->next && 
  906. X      (comp_thru->next->seq == (comp_thru->seq + 1))) {
  907. X    comp_thru = comp_thru->next;
  908. X#ifndef USE_V3_PROT
  909. X    recvd_thru = htons(comp_thru->seq);
  910. X    bcopy(&recvd_thru,pkt->start+7,2); /* Let server know we got it */
  911. X#endif
  912. X    /* We've made progress, so reset retry count */
  913. X    retries = client_dirsrv_retry;
  914. X    /* Also, next retry will be only an acknowledgement */
  915. X    /* but for now, we can't fill in the ack field      */
  916. X#ifdef DEBUG
  917. X    if(pfs_debug > 2) 
  918. X        fprintf(stderr,"Packets now received through %d\n",comp_thru->seq);
  919. X#endif
  920. X    }
  921. X
  922. X    /* See if there are any gaps */
  923. X    if(!comp_thru || comp_thru->next) gaps++;
  924. X    else gaps = 0;
  925. X
  926. X    if ((nd_pkts == 0) || (no_pkts < nd_pkts)) {
  927. X    next = ptalloc();
  928. X    /* goto keep_waiting; */
  929. X    keepWaitingDirsend();
  930. X    return;
  931. X    }
  932. X
  933. X all_done:
  934. X    if(ackpend) { /* Send acknowledgement if requested */
  935. X#ifdef DEBUG
  936. X    if (pfs_debug > 2) {
  937. X        if (to.sin_family == AF_INET)
  938. X        fprintf(stderr,"Acknowledging final packet to %s(%d)\n",
  939. X            to_hostname, ntohs(this_conn_id));
  940. X            else
  941. X                fprintf(stderr,"Acknowledging final packet\n");
  942. X        (void) fflush(stderr);
  943. X    }
  944. X#endif
  945. X    ns = sendto(lp,(char *)(pkt->start), pkt->length, 0, (struct sockaddr *)&to, S_AD_SZ);
  946. X    if(ns != pkt->length) {
  947. X#ifdef DEBUG
  948. X        if (pfs_debug) {
  949. X        fprintf(stderr,"\nsent only %d/%d: ",ns, pkt->length);
  950. X        perror("");
  951. X        }
  952. X#endif
  953. X    }
  954. X
  955. X    }
  956. X    close(lp);
  957. X    ptlfree(pkt);
  958. X
  959. X    /* Get rid of any sequenced control packets */
  960. X    if(scpflag) {
  961. X    while(first && (first->length < 0)) {
  962. X        vtmp = first;
  963. X        first = first->next;
  964. X        if(first) first->previous = NULL;
  965. X        ptfree(vtmp);
  966. X    }
  967. X    vtmp = first;
  968. X    while(vtmp && vtmp->next) {
  969. X        if(vtmp->next->length < 0) {
  970. X        if(vtmp->next->next) {
  971. X            vtmp->next = vtmp->next->next;
  972. X            ptfree(vtmp->next->previous);
  973. X            vtmp->next->previous = vtmp;
  974. X        }
  975. X        else {
  976. X            ptfree(vtmp->next);
  977. X            vtmp->next = NULL;
  978. X        }
  979. X        }
  980. X        vtmp = vtmp->next;
  981. X    }
  982. X    }
  983. X
  984. X    /* return(first); */
  985. X    dirsendReturn = first;
  986. X    dirsendDone = DSRET_DONE;
  987. X
  988. X}
  989. X/*    -    -    -    -    -    -    -    -    */
  990. X/* These routines allow dirsend() to run with or without X by providing
  991. X * wrappers around the calls that handle the asynchronous communication.
  992. X * All parameters are passed using globals.
  993. X * Under X: The input sources and timeouts are set using Xt calls, and
  994. X *        processEvent() just calls XtAppProcessEvent().
  995. X * Non-X: None of the input sources and timeouts are used, and
  996. X *      processEvent() calls select() to handle both timeouts and the
  997. X *      socket file descriptor. The return value of select() is used
  998. X *      to determine which callback routine to call.
  999. X */
  1000. X
  1001. Xstatic void
  1002. XaddInputSource()
  1003. X{
  1004. X#ifdef XARCHIE
  1005. X    inputId = XtAppAddInput(appContext,lp,XtInputReadMask,readProc,NULL);
  1006. X#endif
  1007. X}
  1008. X
  1009. Xstatic void
  1010. XremoveInputSource()
  1011. X{
  1012. X#ifdef XARCHIE
  1013. X    XtRemoveInput(inputId);
  1014. X#endif
  1015. X}
  1016. X
  1017. Xstatic void
  1018. XaddTimeOut()
  1019. X{
  1020. X#ifdef XARCHIE
  1021. X    unsigned long timeoutLen = selwait->tv_sec*1000 + selwait->tv_usec/1000;
  1022. X
  1023. X    /* old timeout can still be there if we are being called after the
  1024. X     * file descriptor was read, so we remove it just to be sure. */
  1025. X    removeTimeOut();
  1026. X    timerId = XtAppAddTimeOut(appContext,timeoutLen,timeoutProc,NULL);
  1027. X#endif
  1028. X}
  1029. X
  1030. Xstatic void
  1031. XremoveTimeOut()
  1032. X{
  1033. X#ifdef XARCHIE
  1034. X    if (timerId != (XtIntervalId)0) {
  1035. X    XtRemoveTimeOut(timerId);
  1036. X    timerId = (XtIntervalId)0;
  1037. X    }
  1038. X#endif
  1039. X}
  1040. X
  1041. Xstatic void
  1042. XprocessEvent()
  1043. X{
  1044. X#ifdef XARCHIE
  1045. X    XtAppProcessEvent(appContext,XtIMAll);
  1046. X#else
  1047. X    /* select - either recv is ready, or timeout */
  1048. X    /* see if timeout or error or wrong descriptor */
  1049. X    tmp = select(lp + 1, &readfds, (fd_set *)0, (fd_set *)0, selwait);
  1050. X    if (tmp == 0) {
  1051. X    timeoutProc(NULL,&timerId);
  1052. X    } else if ((tmp < 0) || !FD_ISSET(lp,&readfds)) {
  1053. X#ifdef DEBUG
  1054. X    if (pfs_debug) {
  1055. X        fprintf(stderr, "select failed(processEvent): readfds=%x ",
  1056. X            readfds);
  1057. X        perror("");
  1058. X    }
  1059. X#endif
  1060. X    close(lp);
  1061. X    perrno = DIRSEND_SELECT_FAILED;
  1062. X    ptlfree(first);
  1063. X    ptlfree(pkt);
  1064. X    /* return(NULL); */
  1065. X    dirsendReturn = NULL;
  1066. X    dirsendDone = DSRET_SELECT_ERROR;
  1067. X    } else {
  1068. X    readProc(NULL,&lp,&inputId);
  1069. X    }
  1070. X#endif /* XARCHIE */
  1071. X}
  1072. X
  1073. Xvoid
  1074. XabortDirsend()
  1075. X{
  1076. X    if (!dirsendDone) {
  1077. X    close(lp);
  1078. X    ptlfree(first);
  1079. X    ptlfree(pkt);
  1080. X    dirsendReturn = NULL;
  1081. X    dirsendDone = DSRET_ABORTED;
  1082. X    }
  1083. X    return;
  1084. X}
  1085. END_OF_FILE
  1086.   if test 29425 -ne `wc -c <'./dirsend.c'`; then
  1087.     echo shar: \"'./dirsend.c'\" unpacked with wrong size!
  1088.   fi
  1089.   # end of './dirsend.c'
  1090. fi
  1091. if test -f './make.com' -a "${1}" != "-c" ; then 
  1092.   echo shar: Will not clobber existing file \"'./make.com'\"
  1093. else
  1094.   echo shar: Extracting \"'./make.com'\" \(2797 characters\)
  1095.   sed "s/^X//" >'./make.com' <<'END_OF_FILE'
  1096. X$!
  1097. X$! MAKE.COM - build the Archie client for VMS (5.4-2, others?)
  1098. X$!            for MultiNet TCP/IP, v2.2 & 3.0, and Wallongong 5.xx+
  1099. X$!
  1100. X$! v1.2.1 - 11/12/91 (bpk) - use option files
  1101. X$! v1.2   - 09/25/91 (bpk) - ported to Wallongong
  1102. X$!        - 09/20/91 (bpk) - fixed up strings.h stuff, etc
  1103. X$! v1.1   - 09/17/91 (bpk) - works with 3.0 now
  1104. X$! v1.0   - 08/30/91 (bpk) - Original
  1105. X$!
  1106. X$! * If you're running Multinet 3.0, leave this alone.  If you're
  1107. X$! running any version of Multinet less than 3.0 (e.g. 2.2), comment
  1108. X$! it out.
  1109. X$ mdef := ,multinet_30=1
  1110. X$! * If you're running Wallongong TCP, uncomment this.
  1111. X$!wall := ,wallongong=1
  1112. X$! * Type @MAKE now.
  1113. X$!
  1114. X$!-----
  1115. X$ ve := f$verify(0)
  1116. X$ set noverify
  1117. X$ on error then goto hell
  1118. X$ echo := write sys$output
  1119. X$!
  1120. X$ cc := cc/opt=noinline
  1121. X$ deb := /define=(debug=1,funcs=1,noregex=1'mdef 'wall)
  1122. X$!cdeb := /debug
  1123. X$ if f$trnlnm("GNU_CC") .nes. "" then cc := gcc/optimize
  1124. X$!
  1125. X$ if f$search("strings.h") .nes. "" then delete/nolog/noconfirm []strings.h;*
  1126. X$ if "''cc'" .nes. "GCC" then copy/noconfirm sys$library:string.h []strings.h
  1127. X$!
  1128. X$ echo "Compiling aquery.c..."
  1129. X$ 'cc/include=([])'deb 'cdeb    aquery.c
  1130. X$ echo "Compiling archie.c..."
  1131. X$ 'cc/include=([])'deb 'cdeb    archie.c
  1132. X$ echo "Compiling atalloc.c..."
  1133. X$ 'cc/include=([])'deb 'cdeb    atalloc.c
  1134. X$! Expect one warning with dirsend.c.
  1135. X$ echo "Compiling dirsend.c (expect a warning) ..."
  1136. X$ 'cc/include=([])'deb 'cdeb    dirsend.c
  1137. X$ echo "Compiling get_pauth.c..."
  1138. X$ 'cc/include=([])'deb 'cdeb    get_pauth.c
  1139. X$ echo "Compiling get_vdir.c..."
  1140. X$ 'cc/include=([])'deb 'cdeb    get_vdir.c
  1141. X$ echo "Compiling perrmesg.c..."
  1142. X$ 'cc/include=([])'deb 'cdeb    perrmesg.c
  1143. X$ echo "Compiling procquery.c..."
  1144. X$ 'cc/include=([])'deb 'cdeb    procquery.c
  1145. X$ echo "Compiling ptalloc.c..."
  1146. X$ 'cc/include=([])'deb 'cdeb    ptalloc.c
  1147. X$ echo "Compiling regex.c..."
  1148. X$ 'cc/include=([])'deb 'cdeb    regex.c
  1149. X$ echo "Compiling stcopy.c..."
  1150. X$ 'cc/include=([])'deb 'cdeb    stcopy.c
  1151. X$ echo "Compiling support.c..."
  1152. X$ 'cc/include=([])'deb 'cdeb    support.c
  1153. X$ echo "Compiling vlalloc.c..."
  1154. X$ 'cc/include=([])'deb 'cdeb    vlalloc.c
  1155. X$ echo "Compiling vl_comp.c..."
  1156. X$ 'cc/include=([])'deb 'cdeb    vl_comp.c
  1157. X$ do_vs := ,
  1158. X$ if "''mdef'" .nes. "" then libs := [.vms]multi
  1159. X$ if "''wall'" .nes. "" then libs := [.vms]wall
  1160. X$ if "''mdef'" .eqs. "" .and. "''wall'" .eqs. "" then gosub dosup
  1161. X$!
  1162. X$ echo "Linking..."
  1163. X$ link'cdeb/exe=archie aquery+archie+atalloc+-
  1164. Xdirsend+get_pauth+get_vdir+-
  1165. Xperrmesg+procquery+ptalloc+regex+stcopy+support+vlalloc+vl_comp'do_vs-
  1166. X'libs/option
  1167. X$ out:
  1168. X$ echo "Done! Define the symbol ARCHIE & fire away."
  1169. X$!
  1170. X$ hell:
  1171. X$ if 've .eq. 1 then set verify
  1172. X$ exit
  1173. X$!
  1174. X$ dosup:
  1175. X$ echo "Compiling vms_support.c ..."
  1176. X$ 'cc/include=([])'deb 'cdeb    vms_support.c
  1177. X$ do_vs := +vms_support,
  1178. X$! Multinet 2.2 still needs to get the resolving stuff.
  1179. X$ libs := [.vms]multi
  1180. X$ return
  1181. END_OF_FILE
  1182.   if test 2797 -ne `wc -c <'./make.com'`; then
  1183.     echo shar: \"'./make.com'\" unpacked with wrong size!
  1184.   fi
  1185.   # end of './make.com'
  1186. fi
  1187. if test -f './support.c' -a "${1}" != "-c" ; then 
  1188.   echo shar: Will not clobber existing file \"'./support.c'\"
  1189. else
  1190.   echo shar: Extracting \"'./support.c'\" \(18043 characters\)
  1191.   sed "s/^X//" >'./support.c' <<'END_OF_FILE'
  1192. X/*
  1193. X * Copyright (c) 1989, 1990, 1991 by the University of Washington
  1194. X *
  1195. X * For copying and distribution information, please see the file
  1196. X * <copyright.h>.
  1197. X *
  1198. X * v1.2.2 - 11/19/91 (mmt) - added MSDOS & OS2 stuff
  1199. X * v1.2.1 - 09/23/91 (gf)  - made it use regex.h---much nicer
  1200. X * v1.2.0 - 09/17/91 (bpk) - added BULL & USG stuff, thanks to Jim Sillas
  1201. X * v1.1.1 - 08/30/91 (bpk) - added VMS support; cast index()
  1202. X */
  1203. X
  1204. X/*
  1205. X * Miscellaneous routines pulled from ~beta/lib/pfs and ~beta/lib/filters
  1206. X */
  1207. X
  1208. X#include <copyright.h>
  1209. X#include <stdio.h>
  1210. X
  1211. X#include <errno.h>
  1212. X
  1213. X#ifdef VMS
  1214. X# ifdef WALLONGONG
  1215. X#  include "twg$tcp:[netdist.include]netdb.h"
  1216. X# else /* Multinet */
  1217. X#  include "multinet_root:[multinet.include]netdb.h"
  1218. X# endif
  1219. X# include <vms.h>
  1220. X#else /* not VMS */
  1221. X# include <sys/types.h>
  1222. X# include <pmachine.h>
  1223. X# ifdef NEED_STRING_H
  1224. X#  include <string.h>
  1225. X# else
  1226. X#  include <strings.h>
  1227. X# endif
  1228. X# include <netdb.h>
  1229. X# if !defined(MSDOS) || defined(OS2)
  1230. X#  include <sys/file.h>
  1231. X#  include <sys/param.h>
  1232. X# endif
  1233. X#endif /* VMS */
  1234. X
  1235. X#include <pfs.h>
  1236. X#include <pprot.h>
  1237. X#include <perrno.h>
  1238. X#include <pcompat.h>
  1239. X#include <pauthent.h>
  1240. X
  1241. X#include "regex.h"
  1242. X
  1243. Xint    pfs_enable = PMAP_ATSIGN;
  1244. X
  1245. X#ifndef FALSE
  1246. X# define TRUE     1
  1247. X# define FALSE   0
  1248. X#endif
  1249. X
  1250. X/* 
  1251. X * wcmatch - Match string s against template containing widlcards
  1252. X *
  1253. X *         WCMATCH takes a string and a template, and returns
  1254. X *         true if the string matches the template, and 
  1255. X *         FALSE otherwise.
  1256. X *
  1257. X *    ARGS:  s        - string to be tested
  1258. X *           template - Template containing optional wildcards
  1259. X *
  1260. X * RETURNS:  TRUE (non-zero) on match.  FALSE (0) otherwise.
  1261. X *
  1262. X *    NOTE:  If template is NULL, will return TRUE.
  1263. X *
  1264. X */
  1265. Xint
  1266. Xwcmatch(s,template)
  1267. X    char    *s;
  1268. X    char    *template;
  1269. X    {
  1270. X    char    temp[200];
  1271. X    char    *p = temp;
  1272. X
  1273. X    if(!template) return(TRUE);
  1274. X    *p++ = '^';
  1275. X
  1276. X    while(*template) {
  1277. X        if(*template == '*') {*(p++)='.'; *(p++) = *(template++);}
  1278. X        else if(*template == '?') {*(p++)='.';template++;}
  1279. X        else if(*template == '.') {*(p++)='\\';*(p++)='.';template++;}
  1280. X        else if(*template == '[') {*(p++)='\\';*(p++)='[';template++;}
  1281. X        else if(*template == '$') {*(p++)='\\';*(p++)='$';template++;}
  1282. X        else if(*template == '^') {*(p++)='\\';*(p++)='^';template++;}
  1283. X        else if(*template == '\\') {*(p++)='\\';*(p++)='\\';template++;}
  1284. X        else *(p++) = *(template++);
  1285. X    }
  1286. X        
  1287. X    *p++ = '$';
  1288. X    *p++ = '\0';
  1289. X
  1290. X    if(re_comp(temp)) return(FALSE);
  1291. X
  1292. X#ifdef AUX
  1293. X    if (re_exec(s) == (char *)NULL)
  1294. X      return 0;
  1295. X    return 1;
  1296. X#else
  1297. X    return(re_exec(s));
  1298. X#endif
  1299. X    }
  1300. X
  1301. X/*
  1302. X * ul_insert - Insert a union link at the right location
  1303. X *
  1304. X *             UL_INSERT takes a directory and a union link to be added
  1305. X *             to a the list of union links in the directory.  It then
  1306. X *             inserts the union link in the right spot in the linked
  1307. X *             list of union links associated with that directory.
  1308. X *
  1309. X *           If an identical link already exists, then the link which
  1310. X *             would be evaluated earlier (closer to the front of the list)
  1311. X *             wins and the other one is freed.  If this happens, an error
  1312. X *             will also be returned.
  1313. X *        
  1314. X *    ARGS:    ul    - link to be inserted
  1315. X *           vd    - directory to get link
  1316. X *             p     - vl that this link will apper after
  1317. X *                     NULL - This vl will go at end of list
  1318. X *                     vd   - This vl will go at head of list
  1319. X *
  1320. X * RETURNS:    Success, or UL_INSERT_ALREADY_THERE or UL_INSERT_SUPERSEDING
  1321. X */
  1322. Xint
  1323. Xul_insert(ul,vd,p)
  1324. X    VLINK    ul;        /* Link to be inserted                   */
  1325. X    VDIR    vd;        /* Directory to receive link             */
  1326. X    VLINK    p;        /* Union link to appear prior to new one */
  1327. X    {
  1328. X    VLINK    current;
  1329. X
  1330. X    /* This is the first ul in the directory */
  1331. X    if(vd->ulinks == NULL) {
  1332. X        vd->ulinks = ul;
  1333. X        ul->previous = NULL;
  1334. X        ul->next = NULL;
  1335. X        return(PSUCCESS);
  1336. X    }
  1337. X
  1338. X    /* This ul will go at the head of the list */
  1339. X    if(p == (VLINK) vd) {
  1340. X        ul->next = vd->ulinks;
  1341. X        ul->next->previous = ul;
  1342. X        vd->ulinks = ul;
  1343. X        ul->previous = NULL;
  1344. X    }
  1345. X    /* Otherwise, decide if it must be inserted at all  */
  1346. X    /* If an identical link appears before the position */
  1347. X    /* at which the new one is to be inserted, we can   */
  1348. X    /* return without inserting it                 */
  1349. X    else {
  1350. X        current = vd->ulinks;
  1351. X
  1352. X        while(current) {
  1353. X        /* p == NULL means we insert after last link */
  1354. X        if(!p && (current->next == NULL))
  1355. X            p = current;
  1356. X
  1357. X        if(vl_comp(current,ul) == 0) {
  1358. X            vlfree(ul);
  1359. X            return(UL_INSERT_ALREADY_THERE);
  1360. X        }
  1361. X
  1362. X        if(current == p) break;
  1363. X        current = current->next;
  1364. X        }
  1365. X
  1366. X        /* If current is null, p was not found */
  1367. X        if(current == NULL)
  1368. X        return(UL_INSERT_POS_NOTFOUND);
  1369. X
  1370. X        /* Insert ul */
  1371. X        ul->next = p->next;
  1372. X        p->next = ul;
  1373. X        ul->previous = p;
  1374. X        if(ul->next) ul->next->previous = ul;
  1375. X    }
  1376. X
  1377. X    /* Check for identical links after ul */
  1378. X    current = ul->next;
  1379. X
  1380. X    while(current) {
  1381. X        if(vl_comp(current,ul) == 0) {
  1382. X        current->previous->next = current->next;
  1383. X        if(current->next)
  1384. X            current->next->previous = current->previous;
  1385. X        vlfree(current);
  1386. X        return(UL_INSERT_SUPERSEDING);
  1387. X        }
  1388. X        current = current->next;
  1389. X    }
  1390. X    
  1391. X    return(PSUCCESS);
  1392. X    }
  1393. X
  1394. X/*
  1395. X * vl_insert - Insert a directory link at the right location
  1396. X *
  1397. X *             VL_INSERT takes a directory and a link to be added to a 
  1398. X *             directory and inserts it in the linked list of links for
  1399. X *             that directory.  
  1400. X *
  1401. X *             If a link already exists with the same name, and if the
  1402. X *             information associated with the new link matches that in
  1403. X *             the existing link, an error is returned.  If the information
  1404. X *             associated with the new link is different, but the magic numbers
  1405. X *             match, then the new link will be added as a replica of the
  1406. X *             existing link.  If the magic numbers do not match, the new
  1407. X *             link will only be added to the list of "replicas" if the
  1408. X *             allow_conflict flag has been set.
  1409. X * 
  1410. X *             If the link is not added, an error is returned and the link
  1411. X *             is freed.  Ordering for the list of links is by the link name.  
  1412. X *        
  1413. X *             If vl is a union link, then VL_INSERT calls ul_insert with an
  1414. X *           added argument indicating the link is to be included at the
  1415. X *             end of the union link list.
  1416. X * 
  1417. X *    ARGS:    vl - Link to be inserted, vd - directory to get link
  1418. X *             allow_conflict - insert links with conflicting names
  1419. X *
  1420. X * RETURNS:    Success, or VL_INSERT_ALREADY_THERE
  1421. X */
  1422. Xint
  1423. Xvl_insert(vl,vd,allow_conflict)
  1424. X    VLINK    vl;        /* Link to be inserted               */
  1425. X    VDIR    vd;        /* Directory to receive link         */
  1426. X    int        allow_conflict;    /* Allow duplicate names             */
  1427. X    {
  1428. X    VLINK    current;    /* To step through list             */
  1429. X    VLINK    crep;        /* To step through list of replicas  */
  1430. X    int    retval;        /* Temp for checking returned values */
  1431. X
  1432. X    /* This can also be used to insert union links at end of list */
  1433. X    if(vl->linktype == 'U') return(ul_insert(vl,vd,NULL));
  1434. X
  1435. X    /* If this is the first link in the directory */
  1436. X    if(vd->links == NULL) {
  1437. X        vd->links = vl;
  1438. X        vl->previous = NULL;
  1439. X        vl->next = NULL;
  1440. X        vd->lastlink = vl;
  1441. X        return(PSUCCESS);
  1442. X    }
  1443. X
  1444. X    /* If no sorting is to be done, just insert at end of list */
  1445. X    if(allow_conflict == VLI_NOSORT) {
  1446. X        vd->lastlink->next = vl;
  1447. X        vl->previous = vd->lastlink;
  1448. X        vl->next = NULL;
  1449. X        vd->lastlink = vl;
  1450. X        return(PSUCCESS);
  1451. X    }
  1452. X
  1453. X    /* If it is to be inserted at start of list */
  1454. X    if(vl_comp(vl,vd->links) < 0) {
  1455. X        vl->next = vd->links;
  1456. X        vl->previous = NULL;
  1457. X        vl->next->previous = vl;
  1458. X        vd->links = vl;
  1459. X        return(PSUCCESS);
  1460. X    }
  1461. X
  1462. X    current = vd->links;
  1463. X
  1464. X    /* Otherwise, we must find the right spot to insert it */
  1465. X    while((retval = vl_comp(vl,current)) > 0) {
  1466. X        if(!current->next) {
  1467. X        /* insert at end */
  1468. X        vl->previous = current;
  1469. X        vl->next = NULL;
  1470. X        current->next = vl;
  1471. X        vd->lastlink = vl;
  1472. X        return(PSUCCESS);
  1473. X        }
  1474. X        current = current->next;
  1475. X    }
  1476. X
  1477. X    /* If we found an equivilant entry already in list */
  1478. X    if(!retval) {
  1479. X        if(vl_equal(vl,current)) {
  1480. X        vlfree(vl);
  1481. X        return(VL_INSERT_ALREADY_THERE);
  1482. X        }
  1483. X        if((allow_conflict == VLI_NOCONFLICT) &&
  1484. X           ((vl->f_magic_no != current->f_magic_no) ||
  1485. X        (vl->f_magic_no==0)))
  1486. X        return(VL_INSERT_CONFLICT);
  1487. X        /* Insert the link into the list of "replicas" */
  1488. X        /* If magic is 0, then create a pseudo magic number */
  1489. X        if(vl->f_magic_no == 0) vl->f_magic_no = -1;
  1490. X        crep = current->replicas;
  1491. X        if(!crep) {
  1492. X        current->replicas = vl;
  1493. X        vl->next = NULL;
  1494. X        vl->previous = NULL;
  1495. X        }
  1496. X        else {
  1497. X        while(crep->next) {
  1498. X            /* If magic was 0, then we need a unique magic number */
  1499. X            if((crep->f_magic_no < 0) && (vl->f_magic_no < 1))
  1500. X            (vl->f_magic_no)--;
  1501. X            crep = crep->next;
  1502. X        }
  1503. X        /* If magic was 0, then we need a unique magic number */
  1504. X        if((crep->f_magic_no < 0) && (vl->f_magic_no < 1))
  1505. X            (vl->f_magic_no)--;
  1506. X        crep->next = vl;
  1507. X        vl->previous = crep;
  1508. X        vl->next = NULL;
  1509. X        }
  1510. X        return(PSUCCESS);
  1511. X    }
  1512. X
  1513. X    /* We found the spot where vl is to be inserted */
  1514. X    vl->next = current;
  1515. X    vl->previous = current->previous;
  1516. X    current->previous = vl;
  1517. X    vl->previous->next = vl;
  1518. X    return(PSUCCESS);
  1519. X    }
  1520. X
  1521. X/*
  1522. X * nlsindex - Find first instance of string 2 in string 1 following newline
  1523. X *
  1524. X *          NLSINDEX scans string 1 for the first instance of string
  1525. X *          2 that immediately follows a newline.  If found, NLSINDEX
  1526. X *          returns a pointer to the first character of that instance.
  1527. X *          If no instance is found, NLSINDEX returns NULL (0).
  1528. X *
  1529. X *    NOTE:   This function is only useful for searching strings that
  1530. X *            consist of multiple lines.  s1 is assumed to be preceeded
  1531. X *           by a newline.  Thus, if s2 is at the start of s1, it will
  1532. X *          be found.
  1533. X *    ARGS:   s1 - string to be searched
  1534. X *            s2 - string to be found
  1535. X * RETURNS:   First instance of s2 in s1, or NULL (0) if not found
  1536. X */
  1537. Xchar *
  1538. Xnlsindex(s1,s2)
  1539. X    char    *s1;        /* String to be searched */
  1540. X    char    *s2;        /* String to be found    */
  1541. X    {
  1542. X    register int s2len = strlen(s2);
  1543. X    char    *curline = s1;    /* Pointer to start of current line */
  1544. X
  1545. X    /* In case s2 appears at start of s1 */
  1546. X    if(strncmp(curline,s2,s2len) == 0)
  1547. X        return(curline);
  1548. X
  1549. X    /* Check remaining lines of s1 */
  1550. X    while((curline = (char *) index(curline,'\n')) != NULL) {
  1551. X        curline++;
  1552. X        if(strncmp(curline,s2,s2len) == 0)
  1553. X        return(curline);
  1554. X    }
  1555. X
  1556. X    /* We didn't find it */
  1557. X    return(NULL);
  1558. X    }
  1559. X
  1560. X/*
  1561. X * month_sname - Return a month name from it's number
  1562. X *
  1563. X *               MONTH_SNAME takes a number in the range 0
  1564. X *               to 12 and returns a pointer to a string
  1565. X *               representing the three letter abbreviation
  1566. X *             for that month.  If the argument is out of 
  1567. X *         range, MONTH_SNAME returns a pointer to "Unk".
  1568. X *
  1569. X *       ARGS:   n - Number of the month
  1570. X *    RETURNS:   Abbreviation for selected month
  1571. X */
  1572. Xchar *month_sname(n)
  1573. X    int n;        /* Month number */
  1574. X{
  1575. X    static char *name[] = { "Unk",
  1576. X        "Jan","Feb","Mar","Apr","May","Jun",
  1577. X        "Jul","Aug","Sep","Oct","Nov","Dec"
  1578. X    };
  1579. X    return((n < 1 || n > 12) ? name[0] : name[n]);
  1580. X}
  1581. X
  1582. X/*
  1583. X * sindex - Find first instance of string 2 in string 1 
  1584. X *
  1585. X *          SINDEX scans string 1 for the first instance of string
  1586. X *          2.  If found, SINDEX returns a pointer to the first
  1587. X *          character of that instance.  If no instance is found, 
  1588. X *          SINDEX returns NULL (0).
  1589. X *
  1590. X *    ARGS:   s1 - string to be searched
  1591. X *            s2 - string to be found
  1592. X * RETURNS:   First instance of s2 in s1, or NULL (0) if not found
  1593. X */
  1594. Xchar *
  1595. Xsindex(s1,s2)
  1596. X    char    *s1;        /* String to be searched   */
  1597. X    char    *s2;        /* String to be found      */
  1598. X    {
  1599. X    register int s2len = strlen(s2);
  1600. X    char    *s = s1;    /* Temp pointer to string  */
  1601. X
  1602. X    /* Check for first character of s2 */
  1603. X    while((s = (char *) index(s,*s2)) != NULL) {
  1604. X        if(strncmp(s,s2,s2len) == 0)
  1605. X        return(s);
  1606. X        s++;
  1607. X    }
  1608. X
  1609. X    /* We didn't find it */
  1610. X    return(NULL);
  1611. X    }
  1612. X
  1613. Xint
  1614. Xscan_error(erst)
  1615. X    char    *erst;
  1616. X    {
  1617. X    *p_err_string = '\0';
  1618. X
  1619. X    if(strncmp(erst,"NOT-A-DIRECTORY",15) == 0) 
  1620. X        return(DIRSRV_NOT_DIRECTORY);
  1621. X
  1622. X    if(strncmp(erst,"UNIMPLEMENTED",13) == 0) {
  1623. X        perrno = DIRSRV_UNIMPLEMENTED;
  1624. X        sscanf(erst+13,"%*[^\n \t\r]%*[ \t]%[^\n]",p_err_string);
  1625. X        return(perrno);
  1626. X    }
  1627. X
  1628. X    if(strncmp(erst,"WARNING ",8) == 0) {
  1629. X        erst += 8;
  1630. X        *p_warn_string = '\0';
  1631. X        sscanf(erst,"%*[^\n \t\r]%*[ \t]%[^\n]",p_warn_string);
  1632. X        /* Return values for warnings are negative */
  1633. X        if(strncmp(erst,"OUT-OF-DATE",11) == 0) {
  1634. X        pwarn = PWARN_OUT_OF_DATE;
  1635. X        return(PSUCCESS);
  1636. X        }
  1637. X        if(strncmp(erst,"MESSAGE",7) == 0) {
  1638. X        pwarn = PWARN_MSG_FROM_SERVER;
  1639. X        return(PSUCCESS);
  1640. X        }
  1641. X        pwarn = PWARNING;
  1642. X        sscanf(erst,"%[^\n]",p_warn_string);
  1643. X        return(PSUCCESS);
  1644. X    }
  1645. X    else if(strncmp(erst,"ERROR",5) == 0) {
  1646. X        if(*(erst+5)) sscanf(erst+6,"%[^\n]",p_err_string);
  1647. X        perrno = DIRSRV_ERROR;
  1648. X        return(perrno);
  1649. X    }
  1650. X    /* The rest start with "FAILURE" */
  1651. X    else if(strncmp(erst,"FAILURE",7) != 0) {
  1652. X        /* Unrecognized - Give warning, but return PSUCCESS */
  1653. X        if(pwarn == 0) {
  1654. X        *p_warn_string = '\0';
  1655. X        pwarn = PWARN_UNRECOGNIZED_RESP;
  1656. X        sscanf(erst,"%[^\n]",p_warn_string);
  1657. X        }
  1658. X        return(PSUCCESS);
  1659. X    }
  1660. X
  1661. X    if(strncmp(erst,"FAILURE ",8) != 0) {
  1662. X        perrno = PFAILURE;
  1663. X        return(perrno);
  1664. X    }    
  1665. X    erst += 8;
  1666. X    
  1667. X    sscanf(erst,"%*[^\n \t\r]%*[ \t]%[^\n]",p_err_string);
  1668. X
  1669. X    /* Still to add               */
  1670. X    /* DIRSRV_AUTHENT_REQ     242 */
  1671. X    /* DIRSRV_BAD_VERS        245 */
  1672. X
  1673. X    if(strncmp(erst,"NOT-FOUND",9) == 0) 
  1674. X        perrno = DIRSRV_NOT_FOUND;
  1675. X    else if(strncmp(erst,"NOT-AUTHORIZED",13) == 0) 
  1676. X        perrno = DIRSRV_NOT_AUTHORIZED;
  1677. X    else if(strncmp(erst,"ALREADY-EXISTS",14) == 0) 
  1678. X        perrno = DIRSRV_ALREADY_EXISTS;
  1679. X    else if(strncmp(erst,"NAME-CONFLICT",13) == 0) 
  1680. X        perrno = DIRSRV_NAME_CONFLICT;
  1681. X    else if(strncmp(erst,"SERVER-FAILED",13) == 0) 
  1682. X        perrno = DIRSRV_SERVER_FAILED;
  1683. X     /* Use it whether it starts with FAILURE or not */
  1684. X    else if(strncmp(erst,"NOT-A-DIRECTORY",15) == 0) 
  1685. X        perrno = DIRSRV_NOT_DIRECTORY;
  1686. X    else perrno = PFAILURE;
  1687. X
  1688. X    return(perrno);
  1689. X    }
  1690. X
  1691. XPATTRIB 
  1692. Xparse_attribute(line)
  1693. X    char    *line;
  1694. X    {
  1695. X    char    l_precedence[MAX_DIR_LINESIZE];
  1696. X    char    l_name[MAX_DIR_LINESIZE];
  1697. X    char    l_type[MAX_DIR_LINESIZE];
  1698. X    char    l_value[MAX_DIR_LINESIZE];
  1699. X    PATTRIB    at;
  1700. X    int    tmp;
  1701. X
  1702. X    tmp = sscanf(line,"OBJECT-INFO %s %s %[^\n]", l_name, l_type, l_value);
  1703. X    
  1704. X    if(tmp < 3) {
  1705. X        tmp = sscanf(line,"LINK-INFO %s %s %s %[^\n]", l_precedence,
  1706. X             l_name, l_type, l_value);
  1707. X        if(tmp < 4) {
  1708. X        perrno = DIRSRV_BAD_FORMAT;
  1709. X        return(NULL);
  1710. X        }
  1711. X    }
  1712. X
  1713. X    at = atalloc();
  1714. X
  1715. X    if(tmp == 4) {
  1716. X        if(strcmp(l_precedence,"CACHED") == 0) 
  1717. X        at->precedence = ATR_PREC_CACHED;
  1718. X        else if(strcmp(l_precedence,"LINK") == 0) 
  1719. X        at->precedence = ATR_PREC_LINK;
  1720. X        else if(strcmp(l_precedence,"REPLACEMENT") == 0) 
  1721. X        at->precedence = ATR_PREC_REPLACE;
  1722. X        else if(strcmp(l_precedence,"ADDITIONAL") == 0) 
  1723. X        at->precedence = ATR_PREC_ADD;
  1724. X    }
  1725. X
  1726. X    at->aname = stcopy(l_name);
  1727. X    at->avtype = stcopy(l_type);
  1728. X    if(strcmp(l_type,"ASCII") == 0) 
  1729. X        at->value.ascii = stcopy(l_value);
  1730. X    else if(strcmp(l_type,"LINK") == 0) {
  1731. X        char        ftype[MAX_DIR_LINESIZE];
  1732. X        char        lname[MAX_DIR_LINESIZE];
  1733. X        char        htype[MAX_DIR_LINESIZE];
  1734. X        char        host[MAX_DIR_LINESIZE];
  1735. X        char        ntype[MAX_DIR_LINESIZE];
  1736. X        char        fname[MAX_DIR_LINESIZE];
  1737. X        VLINK        al;
  1738. X
  1739. X        al = vlalloc();
  1740. X        at->value.link = al;
  1741. X
  1742. X        tmp = sscanf(l_value,"%c %s %s %s %s %s %s %d %d",
  1743. X             &(al->linktype),
  1744. X             ftype,lname,htype,host,ntype,fname,
  1745. X             &(al->version),
  1746. X             &(al->f_magic_no));
  1747. X        if(tmp == 9) {
  1748. X        al->type = stcopyr(ftype,al->type);
  1749. X        al->name = stcopyr(unquote(lname),al->name);
  1750. X        al->hosttype = stcopyr(htype,al->hosttype);
  1751. X        al->host = stcopyr(host,al->host);
  1752. X        al->nametype = stcopyr(ntype,al->nametype);
  1753. X        al->filename = stcopyr(fname,al->filename);
  1754. X        }
  1755. X        else {
  1756. X        perrno = DIRSRV_BAD_FORMAT;
  1757. X        return(NULL);
  1758. X        }
  1759. X        
  1760. X    }
  1761. X
  1762. X    return(at);
  1763. X    }
  1764. X
  1765. X/*
  1766. X * nxtline - Find the next line in the string
  1767. X *
  1768. X *          NXTLINE takes a string and returns a pointer to
  1769. X *          the character immediately following the next newline.
  1770. X *
  1771. X *    ARGS:   s - string to be searched
  1772. X *
  1773. X * RETURNS:   Next line or NULL (0) on failure
  1774. X */
  1775. Xchar *
  1776. Xnxtline(s)
  1777. X    char    *s;        /* String to be searched */
  1778. X {
  1779. X    s = (char *) index(s,'\n');
  1780. X    if(s) return(++s);
  1781. X    else return(NULL);
  1782. X    }
  1783. X
  1784. X
  1785. X/*
  1786. X * unquote - unquote string if necessary
  1787. X *
  1788. X *          UNQUOTE takes a string and unquotes it if it has been quoted.
  1789. X *
  1790. X *    ARGS:   s - string to be unquoted
  1791. X *            
  1792. X * RETURNS:   The original string.  If the string has been quoted, then the
  1793. X *            result appears in static storage, and must be copied if 
  1794. X *            it is to last beyond the next call to quote.
  1795. X *
  1796. X */
  1797. Xchar *
  1798. Xunquote(s)
  1799. X    char    *s;        /* String to be quoted */
  1800. X    {
  1801. X    static char    unquoted[200];
  1802. X    char        *c = unquoted;
  1803. X
  1804. X    if(*s != '\'') return(s);
  1805. X
  1806. X    s++;
  1807. X
  1808. X    /* This should really treat a quote followed by other */
  1809. X    /* than a quote or a null as an error                 */
  1810. X    while(*s) {
  1811. X        if(*s == '\'') s++;
  1812. X        if(*s) *c++ = *s++;
  1813. X    }
  1814. X
  1815. X    *c++ = '\0';
  1816. X
  1817. X    return(unquoted);
  1818. X    }
  1819. X
  1820. X#if defined(DEBUG) && defined(STRSPN)
  1821. X/* needed for -D option parsing */
  1822. X/*
  1823. X * strspn - Count initial characters from chrs in s
  1824. X *
  1825. X *          STRSPN counts the occurances of chacters from chrs
  1826. X *            in the string s preceeding the first occurance of
  1827. X *            a character not in s.
  1828. X *
  1829. X *    ARGS:   s    - string to be checked
  1830. X *            chrs - string of characters we are looking for
  1831. X *
  1832. X * RETURNS:   Count of initial characters from chrs in s
  1833. X */
  1834. Xstrspn(s,chrs)
  1835. X    char    *s;    /* String to search                         */
  1836. X    char    *chrs; /* String of characters we are looking for  */
  1837. X    {
  1838. X    char    *cp;   /* Pointer to the current character in chrs */
  1839. X    int    count; /* Count of characters seen so far          */
  1840. X    
  1841. X    count = 0;
  1842. X
  1843. X    while(*s) {
  1844. X        for(cp = chrs;*cp;cp++)
  1845. X        if(*cp == *s) {
  1846. X            s++;
  1847. X            count++;
  1848. X            goto done;
  1849. X        }
  1850. X        return(count);
  1851. X    done:
  1852. X        ;
  1853. X    }
  1854. X    return(count);
  1855. X    }
  1856. X#endif
  1857. END_OF_FILE
  1858.   if test 18043 -ne `wc -c <'./support.c'`; then
  1859.     echo shar: \"'./support.c'\" unpacked with wrong size!
  1860.   fi
  1861.   # end of './support.c'
  1862. fi
  1863. if test -f './vms/multi.opt' -a "${1}" != "-c" ; then 
  1864.   echo shar: Will not clobber existing file \"'./vms/multi.opt'\"
  1865. else
  1866.   echo shar: Extracting \"'./vms/multi.opt'\" \(73 characters\)
  1867.   sed "s/^X//" >'./vms/multi.opt' <<'END_OF_FILE'
  1868. Xsys$library:vaxcrtl.exe/share
  1869. Xmultinet:multinet_socket_library.exe/share
  1870. END_OF_FILE
  1871.   if test 73 -ne `wc -c <'./vms/multi.opt'`; then
  1872.     echo shar: \"'./vms/multi.opt'\" unpacked with wrong size!
  1873.   fi
  1874.   # end of './vms/multi.opt'
  1875. fi
  1876. echo shar: End of archive 2 \(of 5\).
  1877. cp /dev/null ark2isdone
  1878. MISSING=""
  1879. for I in 1 2 3 4 5 ; do
  1880.     if test ! -f ark${I}isdone ; then
  1881.     MISSING="${MISSING} ${I}"
  1882.     fi
  1883. done
  1884. if test "${MISSING}" = "" ; then
  1885.     echo You have unpacked all 5 archives.
  1886.     rm -f ark[1-9]isdone
  1887. else
  1888.     echo You still must unpack the following archives:
  1889.     echo "        " ${MISSING}
  1890. fi
  1891. exit 0
  1892. exit 0 # Just in case...
  1893.