home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / misc / volume33 / archie / part02 < prev    next >
Encoding:
Text File  |  1992-11-10  |  53.9 KB  |  1,987 lines

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