home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #26 / NN_1992_26.iso / spool / comp / sources / misc / 4056 < prev    next >
Encoding:
Text File  |  1992-11-05  |  54.1 KB  |  1,993 lines

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