source: trunk/third/kermit/ckcnet.c @ 10780

Revision 10780, 141.8 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10779, which included commits to RCS files with non-trunk default branches.
Line 
1char *cknetv = "Network support, 6.0.078, 6 Sep 1996";
2
3/*  C K C N E T  --  Network support  */
4
5/*
6  NOTE TO CONTRIBUTORS: This file, and all the other shared (ckc and cku)
7  C-Kermit source files, must be compatible with C preprocessors that support
8  only #ifdef, #else, #endif, #define, and #undef.  Please do not use #if,
9  logical operators, or other preprocessor features in any of the portable
10  C-Kermit modules.  You can, of course, use these constructions in
11  system-specific modules when you know they are supported.  Also, don't use
12  any ANSI C constructs except with #ifdef CK_ANSIC..#endif.
13*/
14
15/*
16  Authors:
17
18  Frank da Cruz (fdc@columbia.edu),
19    Columbia University Academic Information Systems, New York City.
20  netopen() routine for TCP/IP originally by Ken Yap, Rochester University
21    (ken@cs.rochester.edu) (no longer at that address).
22  Jeffrey E Altman (jaltman@columbia.edu) -- OS/2 & Windows, etc.
23  Missing pieces for Excelan sockets library from William Bader.
24  TELNET protocol by Frank da Cruz and Jeffrey Altman.
25  TGV MultiNet code by Frank da Cruz.
26  MultiNet code adapted to WIN/TCP by Ray Hunter of TWG.
27  MultiNet code adapted to DEC TCP/IP by Lee Tibbert of DEC and Frank da Cruz.
28  TCP/IP support adapted to IBM TCP/IP 1.2.1,2.0 for OS/2 by Kai Uwe Rommel.
29  CMU-OpenVMS/IP modifications by Mike O'Malley, Digital (DEC).
30  X.25 support by Marcello Frutig, Catholic University,
31    Rio de Janeiro, Brazil (frutig@rnp.impa.br) with fixes from:
32    Stefaan Eeckels, Eurokom, Luxembourg;
33    David Lane, Status Computer.
34  Other contributions as indicated below.
35
36  Copyright (C) 1985, 1996, Trustees of Columbia University in the City of New
37  York.  The C-Kermit software may not be, in whole or in part, licensed or
38  sold for profit as a software product itself, nor may it be included in or
39  distributed with commercial products or otherwise distributed by commercial
40  concerns to their clients or customers without written permission of the
41  Office of Kermit Development and Distribution, Columbia University.  This
42  copyright notice must not be removed, altered, or obscured.
43*/
44#include "ckcsym.h"
45#include "ckcdeb.h"
46#include "ckcker.h"
47#ifdef I386IX                           /* Has to come before ckcnet.h in */
48#include <errno.h>                      /* this version, but after in others */
49#endif /* I386IX */
50#include "ckcnet.h"
51
52#ifdef NETCONN
53/* Don't need these if there is no network support. */
54
55#ifdef CK_SOCKS                         /* SOCKS Internet relay package */
56#define accept  Raccept
57#define bind    Rbind
58#define connect Rconnect
59#define getsockname Rgetsockname
60#define listen Rlisten
61#endif /* CK_SOCKS */
62
63#ifdef DEC_TCPIP
64#include <time.h>
65#include <inet.h>
66#endif /* DEC_TCPIP */
67
68#ifdef CMU_TCPIP
69#include <time.h>
70#endif /* CMU_TCPIP */
71
72#ifdef WINTCP
73
74#include <setjmp.h>
75#include <signal.h>
76#include <sys/time.h>
77/*
78  The WIN/TCP code path is the same as that for MultiNet.
79  Only the routine names have changed ...
80*/
81#define socket_read     netread
82#define socket_ioctl    ioctl
83#define socket_write    netwrite
84#define socket_close    netclose
85
86#ifdef OLD_TWG                         /* some routines have evolved */
87        extern int vmserrno, uerrno;
88#define socket_errno    uerrno
89#define socket_perror   perror         /* which uses errno, not uerrno! */
90#else
91#define socket_errno    errno
92#define socket_perror   win$perror
93#endif /* OLD_TWG */
94
95#else /* Not WINTCP */
96
97#ifndef I386IX
98#include <errno.h>                      /* Already included above */
99#endif /* I386IX */
100
101#include <signal.h>                     /* Everybody needs this */
102
103#ifdef ZILOG                            /* Zilog has different name for this */
104#include <setret.h>
105#else /* !ZILOG */
106#include <setjmp.h>
107#ifdef CK_POSIX_SIG                     /* POSIX signal handling */
108#endif /* CK_POSIX_SIG */
109#endif /* ZILOG */
110
111#endif /* WINTCP */
112
113#ifdef datageneral                      /* Data General AOS/VS */
114#include <:usr:include:vs_tcp_errno.h>
115#include <:usr:include:sys:vs_tcp_types.h>
116#ifdef SELECT
117/*
118  NOTE: This can be compiled and linked OK with SELECT defined
119  but it doesn't work at all.  Anybody who cares and knows how
120  to fix it, feel free.
121*/
122#include <:usr:include:sys:vs_tcp_time.h>
123#endif /* SELECT */
124#include <:usr:include:sys:socket.h>
125#include <:usr:include:netinet:in.h>
126#include <:usr:include:netdb.h>
127#endif /* datageneral */
128
129extern
130#ifdef OS2
131SIGTYP (* volatile saval)();            /* For saving alarm handler */
132#else /* OS2 */
133SIGTYP (*saval)();                      /* For saving alarm handler */
134#endif /* OS2 */
135
136_PROTOTYP( VOID bgchk, (void) );
137_PROTOTYP( static VOID tn_debug, (char *) );
138
139#ifdef RLOGCODE
140#ifdef TCPIPLIB
141_PROTOTYP( static VOID rlog_oob, (CHAR *, int) );
142#else /* TCPIPLIB */
143_PROTOTYP( static SIGTYP rlogoobh, ( int ) );
144#endif /* TCPIPLIB */
145_PROTOTYP( static int rlog_ini, (VOID) );
146int rlog_mode = RL_COOKED;
147int rlog_stopped = 0;
148#endif /* RLOGCODE */
149
150/* NAWS state - used in both TELNET and RLOGIN */
151int nawsflg = 0;
152
153extern int                              /* External variables */
154  duplex, debses, seslog, sessft,
155  ttyfd, quiet, msgflg, what, nettype, ttmdm;
156
157#ifdef DEBUG
158extern int deblog;
159#else
160#define deblog 0
161#endif /* DEBUG */
162
163#ifdef OS2
164extern int tt_rows[], tt_cols[];
165extern int tt_status;
166#else /* OS2 */
167extern int tt_rows, tt_cols;            /* Everybody has this */
168#endif /* OS2 */
169
170
171#ifdef CK_TTGWSIZ
172_PROTOTYP( int ttgwsiz, (void) );
173#endif /* CK_TTGWSIZ */
174#ifdef CK_NAWS                          /* Negotiate About Window Size */
175_PROTOTYP( int tn_snaws, (void) );
176#ifdef RLOGCODE
177#ifndef OS2
178_PROTOTYP(static int rlog_naws, (void) );
179#else
180_PROTOTYP( int rlog_naws, (void) );
181#endif /* OS2 */
182#endif /* RLOGCODE */
183#endif /* CK_NAWS */
184
185#ifdef OS2                              /* For terminal type name string */
186#include "ckuusr.h"
187#ifndef NT
188#include <os2.h>
189#endif /* NT */
190#include "ckocon.h"
191extern int tt_type, max_tt;
192extern struct tt_info_rec tt_info[];
193extern char ttname[];
194extern int  scrninitialized[];
195#endif /* OS2 */
196
197#include "ckcsig.h"
198
199#ifndef OS2                             /* For timeout longjumps */
200static ckjmpbuf njbuf;
201#endif /* OS2 */
202
203#define NAMECPYL 100                    /* Local copy of hostname */
204#ifndef OS2                     
205static                                  /* OS2 needs access in ckonet.c */
206#endif /* OS2 */
207char namecopy[NAMECPYL];       
208
209char ipaddr[20] = { '\0' };             /* Global copy of IP address */
210char myipaddr[20] = { '\0' };           /* Global copy of my IP address */
211
212#endif /* NETCONN */
213
214int ttnet = NET_NONE;                   /* Network type */
215int ttnproto = NP_NONE;                 /* Network virtual terminal protocol */
216int tn_init = 0;                        /* Telnet protocol initialized flag */
217int tn_exit = 0;                        /* Exit on disconnect */
218int tn_duplex = 1;                      /* Initial echo status */
219char *tn_term = NULL;                   /* Terminal type override */
220int tn_nlm = TNL_CRLF;                  /* Telnet CR -> CR LF mode */
221int tn_binary = TN_BM_AC;               /* Binary negotiation accepted */
222int tn_b_nlm = TNL_CR;                  /* Telnet Binary CR RAW mode */
223int tn_b_meu = 0;                       /* Telnet Binary ME means U too */
224int tn_b_ume = 0;                       /* Telnet Binary U means ME too */
225#ifdef OS2
226int ttnum = -1;                         /* Last Telnet Terminal Type sent */
227int ttnumend = 0;                       /* Has end of list been found */
228#endif /* OS2 */
229
230#ifdef TNCODE
231#ifdef CK_ENVIRONMENT
232static char tn_msg[1024];               /* For debugging */
233static char hexbuf[1024];
234#else /* CK_ENVIRONMENT */
235static char tn_msg[128];                /* For debugging */
236static char hexbuf[6];
237#endif /* CK_ENVIRONMENT */
238#endif /* TNCODE */
239
240#ifdef NT
241extern int WSASafeToCancel;
242#endif /* NT */
243
244#ifndef NOTCPOPTS
245
246/* Skip all this if NOTCPOPTS specified. */
247
248#ifdef SOL_SOCKET
249#ifdef TCP_NODELAY
250int tcp_nodelay = 0;                    /* Nagle algorithm TCP_NODELAY */
251#endif /* TCP_NODELAY */
252
253#ifdef SO_LINGER
254int tcp_linger  = 0;                    /* SO_LINGER */
255int tcp_linger_tmo = 0;                 /* SO_LINGER timeout */
256#endif /* SO_LINGER */
257
258#ifdef HPUX                             /* But the data structures */
259#ifndef HPUX8                           /* needed for linger are not */
260#ifndef HPUX9                           /* defined in HP-UX versions */
261#ifndef HPUX10                          /* prior to 8.00. */
262#ifdef SO_LINGER
263#undef SO_LINGER
264#endif /* SO_LINGER */
265#endif /* HPUX10 */
266#endif /* HPUX9 */
267#endif /* HPUX8 */
268#endif /* HPUX */
269
270#ifdef SO_SNDBUF
271int tcp_sendbuf = -1;
272#endif /* SO_SNDBUF */
273#ifdef SO_RCVBUF
274int tcp_recvbuf = -1;
275#endif /* SO_RCVBUF */
276#ifdef SO_KEEPALIVE
277int tcp_keepalive = 1;
278#endif /* SO_KEEPALIVE */
279#endif /* SOL_SOCKET */
280
281#endif /* NOTCPOPTS */
282
283#ifndef NETCONN
284/*
285  Network support not defined.
286  Dummy functions here in case #ifdef's forgotten elsewhere.
287*/
288int                                     /* Open network connection */
289netopen(name, lcl, nett) char *name; int *lcl, nett; {
290    return(-1);
291}
292int                                     /* Close network connection */
293netclos() {
294    return(-1);
295}
296int                                     /* Check network input buffer */
297nettchk() {
298    return(-1);
299}
300int                                     /* Flush network input buffer */
301netflui() {
302    return(-1);
303}
304int                                     /* Send network BREAK */
305netbreak() {
306    return(-1);
307}
308int                                     /* Input character from network */
309netinc(timo) int timo; {
310    return(-1);
311}
312int                                     /* Output character to network */
313#ifdef CK_ANSIC
314nettoc(char c)
315#else
316nettoc(c) char c;
317#endif /* CK_ANSIC */
318/* nettoc */ {
319    return(-1);
320}
321int
322nettol(s,n) char *s; int n; {
323    return(-1);
324}
325
326#else /* NETCONN is defined (rest of this module...) */
327
328#ifdef VMS
329/*
330  In edit 190, we moved tn_ini() to be called from within netopen().
331  But tn_ini() calls ttol(), and ttol() checks to see if it's a net
332  connection, but the flag for that isn't set until after netopen()
333  is finished.  Since, in this module, we are always doing network
334  output anyway, we just call nettol() directly, instead of going thru
335  ttol().  Only needed for VMS, since UNIX, AOS/VS, and VOS can handle
336  net connections just like regular connections in ttol(), and OS/2
337  has a special routine for this.
338*/
339#define ttol nettol
340#endif /* VMS */
341
342extern int tn_binary;                   /* Binary mode enabled */
343int me_binary = 0;                      /* I'm not in TELNET binary mode */
344int u_binary = 0;                       /* You're not in TELNET binary mode */
345
346int tcpsrfd = -1;
347
348#ifdef TCPSOCKET
349#ifndef OS2
350#ifndef NOLISTEN                        /* For incoming connections */
351
352#ifndef INADDR_ANY
353#define INADDR_ANY 0           
354#endif /* INADDR_ANY */
355
356_PROTOTYP( int ttbufr, ( VOID ) );
357_PROTOTYP( int tcpsrv_open, (char *, int *, int, int ) );
358
359static unsigned short tcpsrv_port = 0;
360
361#endif /* NOLISTEN */
362#endif /* OS2 */
363#endif /* TCPSOCKET */
364
365#ifndef NOSIGWINCH
366#ifdef CK_NAWS                          /* Window size business */
367#ifdef SIGWINCH
368#ifdef UNIX
369static int sw_armed = 0;                /* SIGWINCH armed flag */
370SIGTYP
371winchh(foo) int foo; {
372    int x;
373    debug(F100,"SIGWINCH caught","",0);
374    signal(SIGWINCH,winchh);            /* Re-arm the signal */
375    if (ttyfd == -1)
376      return;
377    x = ttgwsiz();                      /* Get new window size */
378/*
379  This should be OK.  It might seem that sending this from
380  interrupt level could interfere with another TELNET IAC string
381  that was in the process of being sent.  But we always send
382  TELNET strings with a single write(), which should prevent mixups.
383*/
384    if (x > 0 && tt_rows > 0 && tt_cols > 0) {
385        tn_snaws();
386#ifdef RLOGCODE
387        rlog_naws();
388#endif /* RLOGCODE */
389    }
390    return;
391}
392#endif /* UNIX */
393#endif /* SIGWINCH */
394#endif /* CK_NAWS */
395#endif /* NOSIGWINCH */
396
397/*
398  TCPIPLIB means use separate socket calls for i/o, while on UNIX the
399  normal file system calls are used for TCP/IP sockets too.
400  Means "DEC_TCPIP or MULTINET or WINTCP or OS2" (defined in ckcnet.h).
401*/
402
403#ifdef TCPIPLIB
404
405/* For buffered network reads... */
406/*
407  If the buffering code is written right, it shouldn't matter
408  how long this buffer is.
409*/
410#ifdef OS2
411#define TTIBUFL 32767
412#else /* OS2 */
413#define TTIBUFL 8191                    /* Let's use 8K. */
414#endif /* OS2 */
415
416CHAR ttibuf[TTIBUFL+1];
417
418/*
419  select() is used in preference to alarm()/signal(), but different systems
420  use different forms of select()...
421*/
422#ifndef NOSELECT         /* Option to override BSDSELECT */
423#ifdef BELLV10
424/*
425  Note: Although BELLV10 does have TCP/IP support, and does use the unique
426  form of select() that is evident in this module (and in ckutio.c), it does
427  not have a sockets library and so we can't build Kermit TCP/IP support for
428  it.  For this, somebody would have to write TCP/IP streams code.
429*/
430#define BELLSELECT
431#ifndef FD_SETSIZE
432#define FD_SETSIZE 128
433#endif /* FD_SETSIZE */
434#else
435#ifdef WINTCP                           /* VMS with Wollongong WIN/TCP */
436#ifndef OLD_TWG                         /* TWG 3.2 has only select(read) */
437#define BSDSELECT
438#endif /* OLD_TWG */
439#else
440#ifdef CMU_TCPIP                        /* LIBCMU can do select */
441#define BSDSELECT
442#else
443#ifdef DEC_TCPIP
444#define BSDSELECT
445#else
446#ifdef OS2                              /* OS/2 with TCP/IP */
447#ifdef NT
448#define BSDSELECT
449#else /* NT */
450#define IBMSELECT
451#endif /* NT */
452#endif /* OS2 */
453#endif /* DEC_TCPIP */
454#endif /* CMU_TCPIP */
455#endif /* WINTCP */
456#endif /* BELLV10 */
457#endif /* NOSELECT */
458/*
459  Others (TGV, TCPware, ...) use alarm()/signal().  The BSDSELECT case does not
460  compile at all; the IBMSELECT case compiles and links but crashes at runtime.
461  NOTE: If any of these can be converted to select(), they should be for two
462  reasons: (1) It's a lot faster; (2) certain sockets libraries do not like
463  their socket_read() calls to be interrupted; subsequent socket_read()'s tend
464  to fail with EBUSY.  This happened in the UCX case before it was converted
465  to use select().
466*/
467#ifndef VMS
468static                                  /* These are used in CKVTIO.C */
469#endif /* VMS */
470int
471  ttibp = 0,
472  ttibn = 0;
473/*
474  Read bytes from network into internal buffer ttibuf[].
475  To be called when input buffer is empty, i.e. when ttibn == 0.
476
477  Other network reading routines, like ttinc, ttinl, ttxin, should check the
478  internal buffer first, and call this routine for a refill if necessary.
479
480  Returns -1 on error, 0 if nothing happens.  When data is read successfully,
481  returns number of bytes read, and sets global ttibn to that number and
482  ttibp (the buffer pointer) to zero.
483*/
484_PROTOTYP( int ttbufr, ( VOID ) );
485int
486ttbufr() {                              /* TT Buffer Read */
487    int count;
488
489    if (ttnet != NET_TCPB)              /* First make sure current net is */
490      return(-1);                       /* TCP/IP; if not, do nothing. */
491
492    if (ttibn > 0)                      /* Our internal buffer is not empty, */
493      return(ttibn);                    /* so keep using it. */
494#ifdef WINTCP
495    count = 512;                        /* This works for WIN/TCP */
496#else
497#ifdef DEC_TCPIP
498    count = 512;                        /* UCX */
499#else
500#ifdef OS2
501    count = TTIBUFL;
502#else                                   /* Multinet, etc. */
503    count = ttchk();                    /* Check network input buffer, */
504    if (ttibn > 0) return(ttibn);       /* which can put a char there! */
505    if (count < 0)                      /* Read error - connection closed */
506      return(-2);
507    else if (count > TTIBUFL)           /* Too many to read */
508      count = TTIBUFL;
509    else if (count == 0)                /* None, so force blocking read */
510      count = 1;
511#endif /* OS2 */
512#endif /* DEC_TCPIP */
513#endif /* WINTCP */
514    debug(F101,"ttbufr count 1","",count);
515
516#ifdef COMMENT
517/*
518 This is for nonblocking reads, which we don't do any more.  This code didn't
519 work anyway, in the sense that a broken connection was never sensed.
520*/
521    if ((count = socket_read(ttyfd,ttibuf,count)) < 1) {
522        if (count == -1 && socket_errno == EWOULDBLOCK) {
523            debug(F100,"ttbufr finds nothing","",0);
524            return(0);
525        } else {
526            debug(F101,"ttbufr socket_read error","",socket_errno);
527            return(-1);
528        }
529
530    } else if (count == 0) {
531        debug(F100,"ttbufr socket eof","",0);           
532        return(-1);
533    }
534#else /* COMMENT */
535
536/* This is for blocking reads */
537
538#ifndef VMS
539#ifdef SO_OOBINLINE
540    {
541        int outofband = 0;
542#ifdef BELLSELECT
543        if (select(128, NULL, NULL, efds, 0) > 0 && FD_ISSET(ttyfd, efds))
544          outofband = 1;
545#else
546#ifdef BSDSELECT
547        fd_set efds;
548        struct timeval tv;
549        FD_ZERO(&efds);
550        FD_SET(ttyfd, &efds);
551        tv.tv_sec  = tv.tv_usec = 0L;
552        debug(F100,"Out-of-Band BSDSELECT","",0);
553#ifdef NT
554        WSASafeToCancel = 1;
555#endif /* NT */
556        if (select(FD_SETSIZE, NULL, NULL, &efds, &tv) > 0 &&
557            FD_ISSET(ttyfd, &efds))
558          outofband = 1;
559#ifdef NT
560        WSASafeToCancel = 0;
561#endif /* NT */
562#else /* !BSDSELECT */
563#ifdef IBMSELECT
564/* Was used by OS/2, currently not used, but might come in handy some day... */
565/* ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set */
566/* and timeval stuff since this is the only place where it is used. */
567        int socket = ttyfd;
568        debug(F100,"Out-of-Band IBMSELECT","",0);
569        if ((select(&socket, 0, 0, 1, 0L) == 1) && (socket == ttyfd))
570          outofband = 1;
571#else /* !IBMSELECT */
572/*
573  If we can't use select(), then we use the regular alarm()/signal()
574  timeout mechanism.
575*/
576      debug(F101,"Out-of-Band data not supported","",0);
577      outofband = 0;
578
579#endif /* IBMSELECT */
580#endif /* BSDSELECT */
581#endif /* BELLSELECT */
582      if (outofband) {
583         /* Get the Urgent Data */
584         /* if OOBINLINE is disabled this should be only a single byte      */
585         /* MS Winsock has a bug in Windows 95.  Extra bytes are delivered  */
586         /* That were never sent.                                           */
587          if ((count = socket_recv(ttyfd,ttibuf,count,MSG_OOB)) <= 0) {
588              int s_errno = socket_errno;
589              debug(F101, "ttbufr socket_recv MSG_OOB","",count);
590              debug(F101, "ttbufr socket_errno","",s_errno);
591#ifndef OS2
592              netclos();                        /* *** *** */ 
593              return(-2);
594#else /* OS2 */
595              if (count == 0) {
596                  debug(F100,"ttbufr Closing Connection","",0);
597                  ttclos(0);            /* if the connection was  */
598                  if (ttname[0] == '*') { /* incoming, wait for another */
599                      int local;
600                      os2_netopen(ttname,&local,ttnet);
601                      debug(F101,
602                            "ttbufr returns zero - try again immediately",
603                            "",
604                            0
605                            );
606                      return 0;         /* try again immediately */
607                  } else {
608                      debug(F101, "ttbufr returns hard error","",-3);
609                      return -3;        /* return a hard error    */
610                  }
611              } else {
612#ifdef NT
613                  if (s_errno == WSAETIMEDOUT)
614                    debug(F100,"WSAETIMEDOUT","",0);
615#endif /* NT */
616                  switch (s_errno) {
617#ifdef NT
618                    case WSAETIMEDOUT:
619#else
620                    case SOCETIMEDOUT:   
621                    case SOCETIMEDOUT - SOCBASEERR:
622#endif /* NT */
623                      debug(F100,"ttbufr ETIMEDOUT","",0);
624                      return(-1);
625#ifdef NT
626                    case WSAECONNRESET:
627#else /* NT */
628                    case SOCECONNRESET:
629                    case SOCECONNRESET - SOCBASEERR:
630#endif /* NT */
631                      debug(F100,"ttbufr ECONRESET","",0);
632                      netclos();        /* *** *** */
633                      return(-2);       /* Connection is broken. */
634#ifdef NT
635                    case WSAECONNABORTED:
636#else /* NT */
637                    case SOCECONNABORTED:
638                    case SOCECONNABORTED - SOCBASEERR:
639#endif /* NT */
640                      debug(F100,"ttbufr ECONNABORTED","",0);
641                      netclos();        /* *** *** */
642                      return(-2);       /* Connection is broken. */
643#ifdef NT
644                    case WSAENETRESET: 
645#else /* NT */
646                    case SOCENETRESET:
647                    case SOCENETRESET - SOCBASEERR:
648#endif /* NT */
649                      debug(F100,"ttbufr ENETRESET","",0);
650                      netclos();        /* *** *** */
651                      return(-2);       /* Connection is broken. */
652#ifdef NT
653                    case WSAENOTCONN:
654#else /* NT */
655                    case SOCENOTCONN:
656                    case SOCENOTCONN - SOCBASEERR:
657#endif /* NT */
658                      debug(F100,"ttbufr ENOTCONN","",0);
659                      netclos();        /* *** *** */
660                      return(-2);       /* Connection is broken. */
661#ifdef NT
662                    case WSAEWOULDBLOCK:
663#else
664                    case SOCEWOULDBLOCK:
665                    case SOCEWOULDBLOCK - SOCBASEERR:
666#endif /* NT */
667                      debug(F100,"ttbufr EWOULDBLOCK","",0);
668                      count = 1;
669                      break;
670#ifdef NT
671                    case WSAEINVAL:
672#else /* NT */
673                    case SOCEINVAL:
674                    case SOCEINVAL - SOCBASEERR:
675#endif /* NT */
676                      case 0:
677                      case 23: /* ??? */
678                      /* These appear in OS/2 - don't know why   */
679                      /* ignore it and read as normal data       */
680                      /* and break, then we will attempt to read */
681                      /* the port using normal read() techniques */
682                      debug(F100,"ttbufr handing as in-band data","",0);
683                      count = 1;
684                      break;
685
686                    default:
687                      debug(F101, "ttbufr Unknown Error ","",s_errno);
688                      netclos();
689                      return -2;        /* Return a hard error */
690                  }
691              }   
692#endif /* OS2 */
693          } else {                      /* we got out-of-band data */
694              debug(F111,"ttbufr out-of-band chars","",count);
695#ifdef RLOGCODE                         /* blah */
696              if (ttnproto == NP_RLOGIN) {
697                  /*
698                    When urgent data is read with MSG_OOB and not OOBINLINE
699                    then urgent data and normal data are not mixed.  So
700                    treat the entire buffer as urgent data.
701                  */
702                  rlog_oob(ttibuf, count);
703                  return ttbufr();
704              } else
705#endif /* RLOGCODE */ /* blah */
706#ifdef COMMENT
707            /*
708               I haven't written this yet, nor do I know what it should do
709             */
710                if (ttnproto == NP_TELNET) {
711                    tn_oob();
712                    return 0;
713                } else
714#endif /* COMMENT */
715                  {
716                   /* For any protocols we don't have a special out-of-band  */
717                   /* handler for, just put the bytes in the normal buffer   */
718                   /* and return                                             */
719
720                      ttibp = 0;        /* Reset buffer pointer. */
721                      ttibn = count;
722#ifdef DEBUG
723                      /* Got some bytes. */
724                      debug(F101,"ttbufr count 2","",count);
725                      if (count > 0)
726                        ttibuf[count] = '\0';
727                      debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
728#endif /* DEBUG */
729                      return(ttibn);    /* Return buffer count. */
730                  }
731          }
732      }
733    }
734#endif /* SO_OOBINLINE */
735#endif /* VMS */
736
737    if ((count = socket_read(ttyfd,ttibuf,count)) <= 0) {
738        int s_errno = socket_errno;
739        debug(F101,"ttbufr socket_read","",count);
740        debug(F101,"ttbufr socket_errno","",s_errno);
741#ifndef OS2
742        netclos();                      /* *** *** */ 
743        return(-2);
744#else /* OS2 */
745        if (count == 0) {
746            debug(F100,"ttbufr Closing Connection","",0);
747            ttclos(0);                  /* if the connection was  */
748            if (ttname[0] == '*') {     /* incoming, wait for another */
749                int local;
750                os2_netopen(ttname,&local,ttnet);
751                debug(F101,
752                      "ttbufr returns zero - try again immediately","",0);
753                return 0;               /* try again immediately */
754            } else {
755                debug(F101, "ttbufr returns hard error","",-3);
756                return -3;              /* return a hard error    */
757            }
758        } else {
759#ifdef NT
760            if (s_errno == WSAETIMEDOUT)
761              debug(F100, "WSAETIMEDOUT","",0);
762#endif /* NT */
763            switch (s_errno) {
764#ifdef NT
765              case WSAETIMEDOUT:
766#else
767              case SOCETIMEDOUT:
768              case SOCETIMEDOUT - SOCBASEERR:
769#endif /* NT */
770                debug(F100,"ttbufr ETIMEDOUT","",0);
771                return(-1);
772#ifdef NT
773              case WSAECONNRESET:
774#else /* NT */
775              case SOCECONNRESET:
776              case SOCECONNRESET - SOCBASEERR:
777#endif /* NT */
778                debug(F100,"ttbufr ECONRESET","",0);
779                netclos();                      /* *** *** */
780                return(-2);                     /* Connection is broken. */
781#ifdef NT
782              case WSAECONNABORTED:
783#else /* NT */
784              case SOCECONNABORTED:
785              case SOCECONNABORTED - SOCBASEERR:
786#endif /* NT */
787                debug(F100,"ttbufr ECONNABORTED","",0);
788                netclos();                      /* *** *** */
789                return(-2);                     /* Connection is broken. */
790#ifdef NT
791              case WSAENETRESET: 
792#else /* NT */
793              case SOCENETRESET:
794              case SOCENETRESET - SOCBASEERR:
795#endif /* NT */
796                debug(F100,"ttbufr ENETRESET","",0);
797                netclos();                      /* *** *** */
798                return(-2);                     /* Connection is broken. */
799#ifdef NT
800              case WSAENOTCONN:
801#else /* NT */
802              case SOCENOTCONN:
803              case SOCENOTCONN - SOCBASEERR:
804#endif /* NT */
805                debug(F100,"ttbufr ENOTCONN","",0);
806                netclos();                      /* *** *** */
807                return(-2);                     /* Connection is broken. */
808#ifdef NT
809              case WSAEWOULDBLOCK:
810#else
811              case SOCEWOULDBLOCK:
812              case SOCEWOULDBLOCK - SOCBASEERR:
813#endif /* NT */
814                debug(F100,"ttbufr EWOULDBLOCK","",0);
815                break;
816            }
817            debug(F101, "ttbufr returns timeout","",-1);
818            return -1;                  /* Return a timeout */
819        }
820#endif /* OS2 */
821    }
822#endif /* COMMENT */
823    else {
824        ttibp = 0;                      /* Reset buffer pointer. */
825        ttibn = count;
826#ifdef DEBUG
827        debug(F101,"ttbufr count 2","",count); /* Got some bytes. */
828        if (count > 0)
829          ttibuf[count] = '\0';
830        debug(F111,"ttbufr ttibuf",ttibuf,ttibp);
831#endif /* DEBUG */
832        return(ttibn);                  /* Return buffer count. */
833    }
834}
835#endif /* TCPIPLIB */
836
837#ifndef IBMSELECT
838#ifndef BELLSELECT
839#ifndef BSDSELECT               /* Non-TCPIPLIB case */
840#ifdef SELECT
841#define BSDSELECT
842#endif /* SELECT */
843#endif /* BSDSELECT */
844#endif /* BELLSELECT */
845#endif /* IBMSELECT */
846
847#define TELNET_PORT 23          /* Should do lookup, but it won't change */
848#define RLOGIN_PORT 513
849#define KERMIT_PORT 1649
850
851/* This symbol is not known to, e.g., Ultrix 2.0 */
852#ifndef TELOPT_TTYPE
853#define TELOPT_TTYPE 24
854#endif /* TELOPT_TTYPE */
855
856/* This one seems to be not known to UCX */
857#ifndef TELOPT_BINARY
858#define TELOPT_BINARY 0
859#endif /* TELOPT_BINARY */
860
861/* Type needed as 5th argument (length) to get/setsockopt() */
862
863#ifndef SOCKOPT_T
864#define SOCKOPT_T int
865#ifdef UNIXWARE
866#undef SOCKOPT_T
867#define SOCKOPT_T size_t
868#else
869#ifdef VMS
870#ifdef DEC_TCPIP
871#ifdef __DECC_VER
872#undef SOCKOPT_T
873#define SOCKOPT_T size_t
874#endif /* __DECC_VER */
875#endif /* DEC_TCPIP */
876#endif /* VMS */
877#endif /* UNIXWARE */
878#endif /* SOCKOPT_T */
879
880/*
881  C-Kermit network open/close functions for BSD-sockets.
882  Much of this code shared by SunLink X.25, which also uses the socket library.
883*/
884
885/*  N E T O P N  --  Open a network connection.  */
886/*
887  Call with:
888    name of host (or host:service),
889    lcl - local-mode flag to be set if this function succeeds,
890    network type - value defined in ckunet.h.
891*/
892#ifdef TCPSOCKET
893#ifdef EXCELAN
894/*
895  Most other BSD sockets implementations define these in header files
896  and libraries.
897*/
898struct servent {
899    unsigned short s_port;
900};
901
902struct hostent {
903    short h_addrtype;
904    struct in_addr h_addr;
905    int h_length;
906};
907
908struct servent *
909getservbyname(service, connection) char *service,*connection; {
910    static struct servent servrec;
911    int port;
912
913    port = 0;
914    if (strcmp(service, "telnet") == 0) port = 23;
915    else if (strcmp(service, "smtp") == 0) port = 25;
916    else port = atoi(service);
917
918    debug(F101,"getservbyname return port ","",port);
919
920    if (port > 0) {
921        servrec.s_port = htons(port);
922        return(&servrec);
923    }
924    return((struct servent *) NULL);
925}
926
927struct hostent *
928gethostbyname(hostname) char *hostname; {
929    return((struct hostent *) NULL);
930}
931
932unsigned long
933inet_addr(name) char *name; {
934    unsigned long addr;
935
936    addr = rhost(&name);
937    debug(F111,"inet_addr ",name,(int)addr);
938    return(addr);
939}
940
941char *
942inet_ntoa(in) struct in_addr in; {
943    static char name[80];
944    sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno);
945    return(name);
946}
947#else
948#ifdef DEC_TCPIP                        /* UCX */
949#ifndef __DECC                          /* VAXC or GCC */
950
951#define getservbyname my_getservbyname
952
953#ifdef CK_ANSIC
954globalref int (*C$$GA_UCX_GETSERVBYNAME)();
955extern void C$$TRANSLATE();
956extern void C$$SOCK_TRANSLATE();
957#else
958globalref int (*C$$GA_UCX_GETSERVBYNAME)();
959extern VOID C$$TRANSLATE();
960extern VOID C$$SOCK_TRANSLATE();
961#endif /* CK_ANSIC */
962
963struct servent *
964my_getservbyname (service, proto) char *service, *proto; {
965    static struct servent sent;
966    struct iosb {
967        union {
968            unsigned long status;
969            unsigned short st[2];
970        } sb;
971        unsigned long spare;
972    } s;
973    struct {
974        struct iosb *s;
975        char *serv;
976        char *prot;
977    } par;
978    unsigned long e;
979    char sbuf[30], pbuf[30];
980    char *p;
981
982    debug(F111,"UCX getservbyname",service,(int)C$$GA_UCX_GETSERVBYNAME);
983
984    p = sbuf;
985    strcpy(p, service);
986    while (*p = toupper(*p), *p++) {}
987    p = pbuf;
988    strcpy(p, proto);
989    while (*p = toupper(*p), *p++) {}
990
991    par.s = &s;
992
993    par.serv = "";
994    par.prot = "";
995    /* reset file pointer or something like that!?!? */
996    e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
997    par.serv = sbuf;
998    par.prot = pbuf;            /* that is don't care */
999    e = (*C$$GA_UCX_GETSERVBYNAME)(&par, &sent, par.s);
1000    if ((long)e == -1L)
1001      return NULL;
1002    if ((e & 1) == 0L) {
1003        C$$TRANSLATE(e);
1004        return NULL;
1005    }
1006    if ((s.sb.st[0] & 1) == 0) {
1007        C$$SOCK_TRANSLATE(&s.sb.st[0]);
1008        return NULL;
1009    }
1010    /* sent.s_port is returned by UCX in network byte order. */
1011    /* Calling htons here swaps the bytes, which ruins everything. */
1012
1013    /* Oh yeah?  WHICH VERSION of UCX???  Let's try this... */
1014
1015#ifndef __alpha /* Maybe it should be __DECC, or some version thereof... */
1016/*
1017  Hunter says: "In fact, the "#ifndef __alpha" isn't even needed, since
1018  my_getservbyname() isn't included if "__DECC" is defined, and that's
1019  always defined on Alpha."  But if it doesn't hurt either, better not risk
1020  taking it out.
1021*/
1022#ifndef TCPWARE
1023#define DO_HTONS
1024#endif /* TCPWARE */
1025#endif /* __alpha */
1026
1027#ifdef DO_HTONS
1028    sent.s_port = htons(sent.s_port);
1029    debug(F111,"UCX getservbyname","port",ntohs(sent.s_port));
1030#else
1031    debug(F111,"UCX getservbyname","port",sent.s_port);
1032#endif /* DO_HTONS */
1033    return &sent;
1034}
1035#endif /* __DECC */
1036#endif /* DEC_TCPIP */
1037#endif /* EXCELAN */
1038#endif /* TCPSOCKET */
1039
1040#ifndef NOTCPOPTS
1041#ifndef datageneral
1042int
1043ck_linger(onoff, timo) int onoff; int timo; {
1044/*
1045  The following, from William Bader, turns off the socket linger parameter,
1046  which makes a close() block until all data is sent.  "I don't think that
1047  disabling linger can ever cause kermit to lose data, but you telnet to a
1048  flaky server (or to our modem server when the modem is in use), disabling
1049  linger prevents kermit from hanging on the close if you try to exit."
1050
1051  Modified by Jeff Altman to be generally useful.
1052*/
1053#ifdef SOL_SOCKET
1054#ifdef SO_LINGER
1055    struct linger linger_opt;
1056    SOCKOPT_T x;
1057
1058    if (ttyfd == -1 ||
1059        nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
1060        tcp_linger = onoff;
1061        tcp_linger_tmo = timo;
1062        return(1);
1063    }
1064    x = sizeof(linger_opt);
1065    if (getsockopt(ttyfd, SOL_SOCKET, SO_LINGER, (char *)&linger_opt, &x)) {
1066        perror("could not get SO_LINGER");   
1067    } else if (x != sizeof(linger_opt)) {
1068        debug(F101,"linger error: SO_LINGER len","",x);
1069        debug(F101,"linger SO_LINGER expected len","",sizeof(linger_opt));
1070    } else if (linger_opt.l_onoff != onoff || linger_opt.l_linger != timo) {
1071        linger_opt.l_onoff  = onoff;
1072        linger_opt.l_linger = timo;
1073        if (setsockopt(ttyfd,
1074                       SOL_SOCKET,
1075                       SO_LINGER,
1076                       (char *)&linger_opt,
1077                       sizeof(linger_opt))) {
1078            perror("error setting SO_LINGER");
1079         } else {
1080             debug(F101,"linger new SO_LINGER","",linger_opt.l_onoff);
1081             tcp_linger = onoff;
1082             tcp_linger_tmo = timo;
1083             return 1;
1084         }
1085    } else {
1086        debug(F101,"setlinger SO_LINGER unchanged","",linger_opt.l_onoff);
1087        tcp_linger = onoff;
1088        tcp_linger_tmo = timo;
1089        return 1;
1090    }
1091#else
1092    debug(F100,"SO_LINGER not defined","",0);
1093#endif /* SO_LINGER */
1094#else
1095    debug(F100,"SO_SOCKET not defined","",0);
1096#endif /* SOL_SOCKET */
1097    return(0);
1098}
1099
1100int
1101sendbuf(size) int size; {
1102/*
1103  The following, from William Bader, allows changing of socket buffer sizes,
1104  in case that might affect performance.
1105
1106  Modified by Jeff Altman to be generally useful.
1107*/
1108#ifdef SOL_SOCKET
1109#ifdef SO_SNDBUF
1110    int i, rc = 0;
1111    SOCKOPT_T x;
1112
1113    if (ttyfd == -1 ||
1114        nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
1115        tcp_sendbuf = size;
1116        return 1;
1117    }
1118    x = sizeof(i);
1119    if (getsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&i, &x)) {
1120        perror("could not get SO_SNDBUF");
1121    } else if (x != sizeof(i)) {
1122        debug(F101,"setsockbuf error: SO_SNDBUF len","",x);
1123        debug(F101,"setsockbuf SO_SNDBUF expected len","",sizeof(i));
1124    } else if (size <= 0) {
1125        tcp_sendbuf = i;
1126        debug(F101,"setsockbuf SO_SNDBUF retrieved","",i);
1127        return 1;
1128    } else if (i != size) {
1129        x = size;
1130        if (setsockopt(ttyfd, SOL_SOCKET, SO_SNDBUF, (char *)&x, sizeof(x))) {
1131            perror("error setting SO_SNDBUF");
1132        } else {
1133            debug(F101,"setsockbuf old SO_SNDBUF","",i);
1134            debug(F101,"setsockbuf new SO_SNDBUF","",x);
1135            tcp_sendbuf = size;
1136            return 1;
1137        }
1138    } else {
1139        debug(F101,"setsockbuf SO_SNDBUF unchanged","",i);
1140        tcp_sendbuf = size;
1141        return 1;
1142    }
1143#else
1144    debug(F100,"SO_SNDBUF not defined","",0);
1145#endif /* SO_SNDBUF */
1146#else
1147    debug(F100,"SO_SOCKET not defined","",0);
1148#endif /* SOL_SOCKET */
1149    return(0);
1150}
1151
1152int
1153recvbuf(size) int size; {
1154/*
1155  The following, from William Bader, allows changing of socket buffer sizes,
1156  in case that might affect performance.
1157
1158  Modified by Jeff Altman to be generally useful.
1159*/
1160#ifdef SOL_SOCKET
1161#ifdef SO_RCVBUF
1162    int i, rc = 0;
1163    SOCKOPT_T x;
1164
1165    if (ttyfd == -1 ||
1166        nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
1167        tcp_recvbuf = size;
1168        return(1);
1169    }
1170    x = sizeof(i);
1171    if (getsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&i, &x)) {
1172        perror("could not get SO_RCVBUF");
1173    } else if (x != sizeof(i)) {
1174        debug(F101,"setsockbuf error: SO_RCVBUF len","",x);
1175        debug(F101,"setsockbuf SO_RCVBUF expected len","",sizeof(i));
1176    } else if (size <= 0) {
1177        tcp_recvbuf = i;
1178        debug(F101,"setsockbuf SO_RCVBUF retrieved","",i);
1179        return 1;
1180    } else if (i != size) {
1181        x = size;
1182        if (setsockopt(ttyfd, SOL_SOCKET, SO_RCVBUF, (char *)&x, sizeof(x))) {
1183            perror("error setting SO_RCVBUF");
1184        } else {
1185            debug(F101,"setsockbuf old SO_RCVBUF","",i);
1186            debug(F101,"setsockbuf new SO_RCVBUF","",x);
1187            tcp_recvbuf = size;
1188            return 1;
1189        }
1190    } else {
1191        debug(F101,"setsockbuf SO_RCVBUF unchanged","",i);
1192        tcp_recvbuf = size;
1193        return 1;
1194    }
1195#else
1196    debug(F100,"SO_RCVBUF not defined","",0);
1197#endif /* SO_RCVBUF */
1198#else
1199    debug(F100,"SO_SOCKET not defined","",0);
1200#endif /* SOL_SOCKET */
1201    return 0;
1202}
1203
1204int
1205keepalive(onoff) int onoff; {
1206#ifdef SOL_SOCKET
1207#ifdef SO_KEEPALIVE
1208    int keepalive_opt;
1209    SOCKOPT_T x;
1210
1211    if (ttyfd == -1 ||
1212        nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
1213        tcp_keepalive = onoff;
1214        return 1;
1215    }
1216    x = sizeof(keepalive_opt);
1217    if (getsockopt(ttyfd,
1218                   SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive_opt, &x)) {
1219        perror("could not get SO_KEEPALIVE");
1220    } else if (x != sizeof(keepalive_opt)) {
1221        debug(F101,"setkeepalive error: SO_KEEPALIVE len","",x);
1222        debug(F101,"setkeepalive SO_KEEPALIVE expected len","",
1223              sizeof(keepalive_opt));
1224    } else if (keepalive_opt != onoff) {
1225        keepalive_opt = onoff;
1226        if (setsockopt(ttyfd,
1227                       SOL_SOCKET,
1228                       SO_KEEPALIVE,
1229                       (char *)&keepalive_opt,
1230                       sizeof(keepalive_opt))) {
1231            perror("error clearing SO_KEEPALIVE");
1232        } else {
1233            debug(F101,"setkeepalive new SO_KEEPALIVE","",keepalive_opt);
1234            tcp_keepalive = onoff;
1235            return 1;
1236        }
1237    } else {
1238        debug(F101,"setkeepalive SO_KEEPALIVE unchanged","",keepalive_opt);
1239        tcp_keepalive = onoff;
1240        return 1;
1241    }
1242#else
1243    debug(F100,"SO_KEEPALIVE not defined","",0);
1244#endif /* SO_KEEPALIVE */
1245#else
1246    debug(F100,"SO_SOCKET not defined","",0);
1247#endif /* SOL_SOCKET */
1248    return(0);
1249}
1250
1251int
1252no_delay(onoff)  int onoff; {
1253#ifdef SOL_SOCKET
1254#ifdef TCP_NODELAY
1255    int nodelay_opt;
1256    SOCKOPT_T x;
1257
1258    if (ttyfd == -1 ||
1259        nettype != NET_TCPA && nettype != NET_TCPB || ttmdm >= 0) {
1260        tcp_nodelay = onoff;
1261        return(1);
1262    }
1263    x = sizeof(nodelay_opt);
1264    if (getsockopt(ttyfd, SOL_SOCKET, TCP_NODELAY, (char *)&nodelay_opt, &x)) {
1265        perror("could not get TCP_NODELAY");
1266    } else if (x != sizeof(nodelay_opt)) {
1267        debug(F101,"setnodelay error: TCP_NODELAY len","",x);
1268        debug(F101,"setnodelay TCP_NODELAY expected len","",
1269              sizeof(nodelay_opt));
1270    } else if (nodelay_opt != onoff) {
1271        nodelay_opt = onoff;
1272        if (setsockopt(ttyfd,
1273                       SOL_SOCKET,
1274                       TCP_NODELAY,
1275                       (char *)&nodelay_opt,
1276                       sizeof(nodelay_opt))) {
1277            perror("error clearing TCP_NODELAY");
1278        } else {
1279            debug(F101,"setnodelay new TCP_NODELAY","",nodelay_opt);
1280            tcp_nodelay = onoff;
1281            return 1;
1282        }
1283    } else {
1284        debug(F101,"setnodelay TCP_NODELAY unchanged","",nodelay_opt);
1285        tcp_nodelay = onoff;
1286        return(1);
1287    }
1288#else
1289    debug(F100,"TCP_NODELAY not defined","",0);
1290#endif /* TCP_NODELAY */
1291#else
1292    debug(F100,"SO_SOCKET not defined","",0);
1293#endif /* SOL_SOCKET */
1294    return 0;
1295}
1296#endif /* datageneral */
1297#endif /* NOTCPOPTS */
1298
1299#ifdef SUNX25
1300#ifndef X25_WR_FACILITY
1301/* For Solaris 2.3 / SunLink 8.x - see comments in ckcnet.h */
1302void
1303bzero(s,n) char *s; int n; {
1304    memset(s,0,n);
1305}
1306#endif /* X25_WR_FACILITY */
1307#endif /* SUNX25 */
1308
1309#ifdef TCPSOCKET
1310#ifndef OS2
1311#ifndef NOLISTEN
1312
1313#ifdef BSDSELECT
1314#ifndef VMS
1315#ifndef BELLV10
1316#ifndef datageneral
1317#ifdef hp9000s500                       /* HP-9000/500 HP-U 5.21 */
1318#include <time.h>
1319#else
1320#include <sys/time.h>
1321#endif /* hp9000s500 */
1322#endif /* datageneral */
1323#endif /* BELLV10 */
1324#endif /* VMS */
1325#ifdef SELECT_H
1326#include <sys/select.h>
1327#endif /* SELECT_H */
1328#endif /* BSDSELECT */
1329
1330#ifdef SELECT
1331#ifdef CK_SCOV5
1332#include <sys/select.h>
1333#endif /* CK_SCOV5 */
1334#endif /* SELECT */
1335
1336#ifdef TCPSOCKET
1337#ifndef SO_OOBINLINE                    /* Hopefully only HP-UX 7.0 */
1338#define SO_OOBINLINE 0x0100
1339#endif /* SO_OOBINLINE */
1340#endif /* TCPSOCKET */
1341
1342#ifdef NOTUSED
1343
1344/* T C P S O C K E T _ O P E N -- Open a preexisting socket number */
1345
1346int
1347tcpsocket_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo {
1348    int on = 1;
1349    static struct servent *service, servrec;
1350    static struct hostent *host;
1351    static struct sockaddr_in saddr;
1352    static int saddrlen;
1353#ifdef BSDSELECT
1354    fd_set rfds;
1355    struct timeval tv;
1356#else
1357#ifdef BELLSELECT
1358    fd_set rfds;
1359#endif /* BELLSELECT */
1360#endif /* BSDSELECT */
1361
1362    debug(F101,"tcpsocket_open nett","",nett);
1363    *ipaddr = '\0';
1364
1365    if (nett != NET_TCPB)
1366      return(-1);                       /* BSD socket support */
1367
1368    netclos();                          /* Close any previous connection. */
1369    strncpy(namecopy, name, NAMECPYL);  /* Copy the hostname. */
1370    ttnproto = NP_NONE;                 /* No protocol selected yet. */
1371    debug(F110,"tcpsocket_open namecopy",namecopy,0);
1372
1373    /* Assign the socket number to ttyfd and then fill in tcp structures */
1374    ttyfd = atoi(&name[1]);
1375    debug(F111,"tcpsocket_open","ttyfd",ttyfd);
1376
1377#ifndef NOTCPOPTS
1378#ifdef SOL_SOCKET
1379    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
1380
1381#ifndef datageneral
1382#ifdef TCP_NODELAY
1383    no_delay(tcp_nodelay);
1384#endif /* TCP_NODELAY */
1385#ifdef SO_KEEPALIVE
1386    keepalive(tcp_keepalive);
1387#endif /* SO_KEEPALIVE */
1388#ifdef SO_LINGER
1389    ck_linger(tcp_linger, tcp_linger_tmo);
1390#endif /* SO_LINGER */
1391#ifdef SO_SNDBUF
1392    sendbuf(tcp_sendbuf);
1393#endif /* SO_SNDBUF */
1394#ifdef SO_RCVBUF
1395    recvbuf(tcp_recvbuf);
1396#endif /* SO_RCVBUF */
1397#endif /* datageneral */
1398#endif /* SOL_SOCKET */
1399#endif /* NOTCPOPTS */
1400
1401    /* Get the name of the host we are connected to */
1402
1403    saddrlen = sizeof(saddr);
1404    getpeername(ttyfd,(struct sockaddr *)&saddr,&saddrlen);
1405
1406    if ((host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) != NULL) {
1407        debug(F100,"tcpsocket_open gethostbyname != NULL","",0);
1408        strncpy(name, host->h_name, 79);
1409        strncat(name, ":", 80 - strlen(name));
1410#ifdef COMMENT
1411        itoa(ntohs(saddr.sin_port), name + strlen(name), 10);
1412#else
1413        sprintf(name + strlen(name),"%d",ntohs(saddr.sin_port));
1414#endif /* COMMENT */
1415        sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
1416        printf("%s connected on port %d\n",host->h_name,ntohs(saddr.sin_port));
1417    }
1418    ttnet = nett;                       /* TCP/IP (sockets) network */
1419
1420#ifdef RLOGCODE
1421    if ( ntohs(saddr.sin_port) == 23 )
1422        ttnproto = NP_LOGIN ;
1423    else
1424#endif /* RLOGCODE */
1425    /* Assume the service is TELNET. */
1426    {
1427        ttnproto = NP_TELNET;           /* Yes, set global flag. */
1428        tn_ini();                       /* Start TELNET negotiations. */
1429    }
1430
1431    if (*lcl < 0) *lcl = 1;             /* Local mode. */
1432
1433    return(0);                          /* Done. */
1434}
1435#endif /* NOTUSED */
1436
1437/*  T C P S R V _ O P E N  --  Open a TCP/IP Server connection  */
1438/*
1439  Calling conventions same as ttopen(), except third argument is network
1440  type rather than modem type.
1441*/
1442int
1443tcpsrv_open(name,lcl,nett,timo) char * name; int * lcl; int nett; int timo; {
1444    char *p;
1445    int i, x;
1446    SOCKOPT_T on = 1;
1447    int ready_to_accept = 0;
1448    static struct servent *service, servrec;
1449    static struct hostent *host;
1450    static struct sockaddr_in saddr;
1451    static SOCKOPT_T saddrlen;
1452
1453#ifdef BSDSELECT
1454    fd_set rfds;
1455    struct timeval tv;
1456#else
1457#ifdef BELLSELCT
1458    fd_set rfds;
1459#endif /* BELLSELECT */
1460#endif /* BSDSELECT */
1461
1462    debug(F101,"tcpsrv_open nett","",nett);
1463    *ipaddr = '\0';
1464
1465    if (nett != NET_TCPB)
1466      return(-1);                       /* BSD socket support */
1467
1468    netclos();                          /* Close any previous connection. */
1469    strncpy(namecopy, name, NAMECPYL);  /* Copy the hostname. */
1470    ttnproto = NP_NONE;                 /* No protocol selected yet. */
1471    debug(F110,"tcpsrv_open namecopy",namecopy,0);
1472
1473#ifdef COMMENT
1474    if (tcpsrfd != -1) {
1475        socket_close(tcpsrfd);
1476        tcpsrfd = -1;
1477        tcpsrv_port = 0;
1478    }
1479#endif /* COMMENT */
1480
1481    p = namecopy;                       /* Was a service requested? */
1482    while (*p != '\0' && *p != ':')
1483      p++; /* Look for colon */
1484    if (*p == ':') {                    /* Have a colon */
1485        *p++ = '\0';                    /* Get service name or number */
1486    } else {                            /* Otherwise use kermit */
1487        p = "kermit";
1488    }
1489    debug(F110,"tcpsrv_open service requested",p,0);
1490    if (isdigit(*p)) {                  /* Use socket number without lookup */
1491        service = &servrec;
1492        service->s_port = htons((unsigned short)atoi(p));
1493    } else {                            /* Otherwise lookup the service name */
1494        service = getservbyname(p, "tcp");
1495    }
1496    if (!service && !strcmp("kermit",p)) { /* Use Kermit service port */
1497        service = &servrec;
1498        service->s_port = htons(1649);
1499    }
1500#ifdef RLOGCODE
1501    if (service && !strcmp("login",p) && service->s_port != htons(513)) {
1502        fprintf(stderr,
1503                "  Warning: login service on port %d instead of port 513\n",
1504                 ntohs(service->s_port));
1505        fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
1506        debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
1507    }
1508#endif /* RLOGCODE */
1509    if (!service) {
1510        fprintf(stderr, "Cannot find port for service %s\n", p);
1511        debug(F101,"tcpsrv_open can't get service","",errno);
1512        errno = 0;                      /* rather than mislead */
1513        return(-1);
1514    }
1515
1516    /* If we currently have a listen active but port has changed then close */
1517
1518    debug(F101,"tcpsrv_open checking previous connection","",tcpsrfd);
1519    debug(F101,"tcpsrv_open previous tcpsrv_port","",tcpsrv_port);
1520    if (tcpsrfd != -1 &&
1521        tcpsrv_port != ntohs((unsigned short)service->s_port)) {
1522        debug(F100,"tcpsrv_open closing previous connection","",0);
1523#ifdef TCPIPLIB
1524        socket_close(tcpsrfd);
1525#else
1526        close(tcpsrfd);
1527#endif /* TCPIPLIB */
1528        tcpsrfd = -1;
1529    }
1530    debug(F100,"tcpsrv_open tcpsrfd","",tcpsrfd);
1531    if (tcpsrfd == -1) {
1532
1533        /* Set up socket structure and get host address */
1534
1535        bzero((char *)&saddr, sizeof(saddr));
1536        debug(F100,"tcpsrv_open bzero ok","",0);
1537        saddr.sin_family = AF_INET;
1538        saddr.sin_addr.s_addr = INADDR_ANY;
1539
1540        /* Get a file descriptor for the connection. */
1541
1542        saddr.sin_port = service->s_port;
1543        ipaddr[0] = '\0';
1544
1545        debug(F100,"tcpsrv_open calling socket","",0);
1546        if ((tcpsrfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
1547            perror("TCP socket error");
1548            debug(F101,"tcpsrv_open socket error","",errno);
1549            return (-1);
1550        }
1551        errno = 0;
1552
1553        /* Specify the Port may be reused */
1554
1555        debug(F100,"tcpsrv_open calling setsockopt","",0);
1556        x = setsockopt(tcpsrfd,
1557                       SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof on);
1558        debug(F101,"tcpsrv_open setsockopt","",x);
1559
1560#ifndef NOTCPOPTS
1561#ifndef datageneral
1562#ifdef SOL_SOCKET
1563#ifdef TCP_NODELAY
1564        no_delay(tcp_nodelay);
1565        debug(F101,"tcpsrv_open no_delay","",tcp_nodelay);
1566#endif /* TCP_NODELAY */
1567#ifdef SO_KEEPALIVE
1568        keepalive(tcp_keepalive);
1569        debug(F101,"tcpsrv_open keepalive","",tcp_keepalive);
1570#endif /* SO_KEEPALIVE */
1571#ifdef SO_LINGER
1572        ck_linger(tcp_linger, tcp_linger_tmo);
1573        debug(F101,"tcpsrv_open linger","",tcp_linger_tmo);
1574#endif /* SO_LINGER */
1575#ifdef SO_SNDBUF
1576        sendbuf(tcp_sendbuf);
1577        debug(F101,"tcpsrv_open sendbuf","",tcp_sendbuf);
1578#endif /* SO_SNDBUF */
1579#ifdef SO_RCVBUF
1580        recvbuf(tcp_recvbuf);
1581        debug(F101,"tcpsrv_open recvbuf","",tcp_recvbuf);
1582#endif /* SO_RCVBUF */
1583#endif /* SOL_SOCKET */
1584#endif /* datageneral */
1585#endif /* NOTCPOPTS */
1586
1587       /* Now bind to the socket */
1588        printf("\nBinding socket to port %d ...\n",
1589               ntohs((unsigned short)service->s_port));
1590        if (bind(tcpsrfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
1591            i = errno;                  /* Save error code */
1592            close(tcpsrfd);
1593            tcpsrfd = -1;
1594            tcpsrv_port = 0;
1595            ttyfd = -1;
1596            errno = i;                  /* and report this error */
1597            debug(F101,"tcpsrv_open bind errno","",errno);
1598            return(-1);
1599        }
1600        debug(F100,"tcpsrv_open bind OK","",0);
1601        printf("Listening ...\n");
1602        if (listen(tcpsrfd, 15) < 0) {
1603            i = errno;                  /* Save error code */
1604            close(tcpsrfd);
1605            tcpsrfd = -1;
1606            tcpsrv_port = 0;
1607            ttyfd = -1;
1608            errno = i;                  /* And report this error */
1609            debug(F101,"tcpsrv_open listen errno","",errno);
1610            return(-1);
1611        }
1612        debug(F100,"tcpsrv_open listen OK","",0);
1613        tcpsrv_port = ntohs((unsigned short)service->s_port);
1614    }
1615    printf("\nWaiting to Accept a TCP/IP connection on port %d ...\n",
1616           ntohs((unsigned short)service->s_port));
1617    saddrlen = sizeof(saddr);
1618
1619#ifdef BSDSELECT
1620    tv.tv_sec  = tv.tv_usec = 0L;
1621    if (timo < 0)
1622      tv.tv_usec = (long) -timo * 10000L;
1623    else
1624      tv.tv_sec = timo;
1625    debug(F101,"tcpsrv_open BSDSELECT","",timo);
1626#else
1627    debug(F101,"tcpsrv_open not BSDSELECT","",timo);
1628#endif /* BSDSELECT */
1629
1630    if (!timo) {
1631        while (!ready_to_accept) {
1632#ifdef BSDSELECT
1633            FD_ZERO(&rfds);
1634            FD_SET(tcpsrfd, &rfds);
1635            ready_to_accept =
1636              ((select(FD_SETSIZE,
1637#ifdef HPUX
1638#ifdef HPUX1010
1639                       (fd_set *)
1640#else
1641
1642                       (int *)
1643#endif /* HPUX1010 */
1644#else
1645#ifdef __DECC
1646                       (fd_set *)
1647#endif /* __DECC */
1648#endif /* HPUX */
1649                       &rfds, NULL, NULL, &tv) > 0) &&
1650               FD_ISSET(tcpsrfd, &rfds));
1651#else /* BSDSELECT */
1652#ifdef IBMSELECT
1653#define ck_sleepint 250
1654            ready_to_accept =
1655              (select(&tcpsrfd, 1, 0, 0,
1656                      timo < 0 ? -timo :
1657                      (timo > 0 ? timo * 1000L : ck_sleepint)) == 1
1658               );
1659#else
1660#ifdef BELLSELECT
1661            FD_ZERO(rfds);
1662            FD_SET(tcpsrfd, rfds);
1663            ready_to_accept =
1664              ((select(128, rfds, NULL, NULL, timo < 0 ? -timo :
1665                      (timo > 0 ? timo * 1000L)) > 0) &&
1666               FD_ISSET(tcpsrfd, rfds));
1667#else
1668SOME_FORM_OF_SELECT_IS_NEEDED_HERE
1669#endif /* BELLSELECT */
1670#endif /* IBMSELECT */
1671#endif /* BSDSELECT */
1672        }
1673    }
1674    if (ready_to_accept) {
1675        if ((ttyfd = accept(tcpsrfd,
1676                            (struct sockaddr *)&saddr,&saddrlen)) < 0) {
1677            i = errno;                  /* save error code */
1678            close(tcpsrfd);
1679            ttyfd = -1;
1680            tcpsrfd = -1;
1681            tcpsrv_port = 0;
1682            errno = i;                  /* and report this error */
1683            debug(F101,"tcpsrv_open accept errno","",errno);
1684            return(-1);
1685        }
1686        setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
1687
1688        ttnet = nett;                   /* TCP/IP (sockets) network */
1689        /* See if the service is TELNET. */
1690        if ((x = ntohs((unsigned short)service->s_port)) ==
1691            getservbyname("telnet", "tcp")->s_port) {
1692            ttnproto = NP_TELNET;       /* Yes, set global flag. */
1693            tn_ini();                   /* Start TELNET negotiations. */
1694        } else {
1695            tn_ini();                   /* Initialize TELNET negotiations. */
1696        }
1697        debug(F101,"tcpsrv_open service","",x);
1698        if (*lcl < 0)                   /* Set local mode. */
1699          *lcl = 1;
1700
1701#ifdef COMMENT
1702        close(tcpsrfd);
1703        tcpsrfd = -1;
1704        tcpsrv_port = 0;
1705#endif /* COMMENT */
1706
1707        if (host = gethostbyaddr((char *)&saddr.sin_addr,4,PF_INET)) {
1708            debug(F100,"tcpsrv_open gethostbyname != NULL","",0);
1709            name[0] = '*';
1710            strncpy(&name[1],host->h_name,79);
1711            strncat(name,":",80-strlen(name));
1712            strncat(name,p,80-strlen(name));
1713            sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
1714            printf("%s connected on port %s\n",host->h_name,p);
1715        }
1716        return(0);                      /* Done. */
1717    } else {
1718        i = errno;                      /* save error code */
1719        close(tcpsrfd);
1720        ttyfd = -1;
1721        tcpsrfd = -1;
1722        tcpsrv_port = 0;
1723        errno = i;                      /* and report this error */
1724        debug(F101,"tcpsrv_open accept errno","",errno);
1725        return(-1);
1726    }
1727}
1728#endif /* NOLISTEN */
1729#endif /* OS2 */
1730#endif /* TCPSOCKET */
1731
1732/*  N E T O P E N  --  Open a network connection  */
1733/*
1734  Calling conventions same as ttopen(), except third argument is network
1735  type rather than modem type.  Designed to be called from within ttopen.
1736*/
1737int
1738netopen(name, lcl, nett) char *name; int *lcl, nett; {
1739    char *p;
1740    int i, x;
1741#ifdef TCPSOCKET
1742    int isconnect = 0;
1743#ifdef SO_OOBINLINE
1744    int on = 1;
1745#endif /* SO_OOBINLINE */
1746    struct servent *service=NULL, servrec;
1747    struct hostent *host=NULL;
1748    struct sockaddr_in saddr;
1749#ifdef EXCELAN
1750    struct sockaddr_in send_socket;
1751#endif /* EXCELAN */
1752#endif /* TCPSOCKET */
1753
1754#ifdef SUNX25                           /* Code for SunLink X.25 support */
1755#define X29PID 1                        /* X.29 Protocol ID */
1756_PROTOTYP(SIGTYP x25oobh, (int) );
1757    CONN_DB x25host;
1758#ifndef X25_WR_FACILITY
1759    FACILITY x25facil;
1760#else
1761    FACILITY_DB x25facil;
1762#endif /* X25_WR_FACILITY */
1763    static int needh = 1;
1764    PID_T pid;
1765    extern int linkid, lcn, x25ver;
1766    extern int revcall, closgr, cudata;
1767    extern char udata[];
1768#endif /* SUNX25 */
1769
1770    debug(F101,"netopen nett","",nett);
1771    *ipaddr = '\0';                     /* Initialize IP address string */
1772
1773#ifdef SUNX25
1774    if (nett == NET_SX25) {             /* If network type is X.25 */
1775        netclos();                      /* Close any previous net connection */
1776        ttnproto = NP_NONE;             /* No protocol selected yet */
1777
1778        /* Set up host structure */
1779        bzero((char *)&x25host,sizeof(x25host));
1780        if ((x25host.hostlen = pkx121(name,x25host.host)) < 0) {
1781            fprintf (stderr,"Invalid X.121 host address %s\n",name);
1782            errno = 0;
1783            return (-1);
1784        }
1785        x25host.datalen = X29PIDLEN;
1786        x25host.data[0] = X29PID;
1787
1788        /* Set call user data if specified */
1789        if (cudata) {
1790            strncpy((char *)x25host.data+X29PIDLEN,udata,(int)strlen(udata));
1791            x25host.datalen += (int)strlen(udata);
1792        }
1793
1794        /* Open SunLink X.25 socket */
1795        if (!quiet && *name) printf(" Trying %s...\n", name);
1796        if ((ttyfd = socket(AF_X25, SOCK_STREAM, 0)) < 0) {
1797            debug(F101,"netopen socket error","",errno);
1798            perror ("X.25 socket error");
1799            return (-1);
1800        }
1801
1802        /* Setting X.25 out-of-band data handler */
1803        pid = getpid();
1804        if (ioctl(ttyfd,SIOCSPGRP,&pid)) {
1805            perror("X.25 set process group id error");
1806            return(-1);
1807        }
1808        (VOID) signal(SIGURG,x25oobh);
1809
1810        /* Set reverse charge call and closed user group if requested */
1811        bzero ((char *)&x25facil,sizeof(x25facil));
1812
1813#ifndef X25_WR_FACILITY
1814/*  New SunLink (7.0 or 8.0, not sure which)... */
1815        x25facil.type = T_REVERSE_CHARGE; /* Reverse Charge */
1816        x25facil.f_reverse_charge = revcall ? 1 : 0;
1817        if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
1818            perror ("Setting X.25 reverse charge");
1819            return (-1);
1820        }
1821        if (closgr > -1) {              /* Closed User Group (Outgoing) */
1822            bzero ((char *)&x25facil,sizeof(x25facil));
1823            x25facil.type = T_CUG;
1824            x25facil.f_cug_req = CUG_REQ_ACS;
1825            x25facil.f_cug_index = closgr;
1826            if (ioctl(ttyfd,X25_SET_FACILITY,&x25facil) < 0) {
1827                perror ("Setting X.25 closed user group");
1828                return (-1);
1829            }
1830        }
1831#else
1832/*  Old SunLink 6.0 (or 7.0?)... */
1833        if (revcall) x25facil.reverse_charge = revcall;
1834        if (closgr > -1) {
1835            x25facil.cug_req = 1;
1836            x25facil.cug_index = closgr;
1837        }
1838        if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) {
1839            perror ("Setting X.25 facilities");
1840            return (-1);
1841        }
1842#endif /* X25_WR_FACILITY */
1843
1844        /*  Need X.25 header with bits Q and M */
1845        if (ioctl (ttyfd,X25_HEADER,&needh) < 0) {
1846            perror ("Setting X.25 header");
1847            return (-1);
1848        }
1849
1850        /* Connects to remote host via SunLink X.25 */
1851        if (connect(ttyfd,(struct sockaddr *)&x25host,sizeof(x25host)) < 0) {
1852            i = errno;
1853            debug(F101,"netopen connect errno","",i);
1854            if (i) {
1855                perror("netopen x25 connect");
1856                x25diag();
1857            }
1858            (VOID) netclos();
1859            ttyfd = -1;
1860            ttnproto = NP_NONE;
1861            errno = i;
1862            return (-1);
1863        }
1864
1865        /* Get X.25 link identification used for the connection */
1866        if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) {
1867            perror ("Getting X.25 link id");
1868            return (-1);
1869        }
1870
1871        /* Get X.25 logical channel number used for the connection */
1872        if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) {
1873            perror ("Getting X.25 lcn");
1874            return (-1);
1875        }
1876
1877        /* Get SunLink X.25 version */
1878        if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) {
1879            perror ("Getting SunLink X.25 version");
1880            return (-1);
1881        }
1882        ttnet = nett;                   /* Sunlink X.25 network */
1883        ttnproto = NP_X3;               /* PAD X.3, X.28, X.29 protocol */
1884        if (*lcl < 0) *lcl = 1;         /* Local mode */
1885        return(0);
1886    } else /* Note that SUNX25 support can coexist with TCP/IP support. */
1887#endif /* SUNX25 */
1888
1889/*   Add support for other networks here. */
1890
1891      if (nett != NET_TCPB) return(-1); /* BSD socket support */
1892
1893#ifdef TCPSOCKET
1894    netclos();                          /* Close any previous connection. */
1895    strncpy(namecopy, name, NAMECPYL);  /* Copy the hostname. */
1896    ttnproto = NP_NONE;                 /* No protocol selected yet. */
1897    debug(F110,"netopen namecopy",namecopy,0);
1898
1899#ifndef NOLISTEN
1900    if (name[0] == '*')
1901      return(tcpsrv_open(name, lcl, nett, 0));
1902#endif /* NOLISTEN */
1903
1904    p = namecopy;                       /* Was a service requested? */
1905    while (*p != '\0' && *p != ':') p++; /* Look for colon */
1906    if (*p == ':') {                    /* Have a colon */
1907        *p++ = '\0';                    /* Get service name or number */
1908    } else {                            /* Otherwise use telnet */
1909        p = "telnet";
1910    }
1911    debug(F110,"netopen service requested",p,0);
1912    if (isdigit(*p)) {                  /* Use socket number without lookup */
1913        service = &servrec;
1914        service->s_port = htons((unsigned short)atoi(p));
1915    } else {                            /* Otherwise lookup the service name */
1916        service = getservbyname(p, "tcp");
1917    }
1918    if (!service) {
1919        fprintf(stderr, "Cannot find port for service %s\n", p);
1920#ifdef TGVORWIN
1921        debug(F101,"netopen can't get service","",socket_errno);
1922#else
1923        debug(F101,"netopen can't get service","",errno);
1924#endif /* TGVORWIN */
1925        errno = 0;                      /* rather than mislead */
1926        return(-1);
1927    }
1928
1929#ifdef RLOGCODE
1930    if (service && !strcmp("login",p) && service->s_port != htons(513)) {
1931        fprintf(stderr,
1932                "  Warning: login service on port %d instead of port 513\n",
1933                 ntohs(service->s_port));
1934        fprintf(stderr, "  Edit SERVICES file if RLOGIN fails to connect.\n");
1935        debug(F101,"tcpsrv_open login on port","",ntohs(service->s_port));
1936    }
1937#endif /* RLOGCODE */
1938
1939    /* Set up socket structure and get host address */
1940
1941    bzero((char *)&saddr, sizeof(saddr));
1942    debug(F100,"netopen bzero ok","",0);
1943    if (
1944#ifdef NT
1945        /* we found that Win95 tries to call the DNS  */
1946        /* when a numeric IP Address is specified.    */
1947        /* and of course the lookup fails resulting   */
1948        /* in a long delay.  So we test for the IP    */
1949        /* numeric value before calling gethostbyname */
1950        /* but only in Win32 so as not to             */
1951        /* alter current code that works properly     */
1952        /* everywhere else.                           */
1953        inet_addr(namecopy) == INADDR_NONE &&
1954#endif /* NT */
1955        (host = gethostbyname(namecopy)) != NULL) {
1956        debug(F100,"netopen gethostbyname != NULL","",0);
1957#ifdef OS2
1958        strncpy(name,host->h_name,80);
1959        strncat(name,":",80-strlen(name));
1960        strncat(name,p,80-strlen(name));
1961#endif /* OS2 */
1962        saddr.sin_family = host->h_addrtype;
1963#ifdef HADDRLIST
1964#ifdef h_addr
1965        /* This is for trying multiple IP addresses - see <netdb.h> */
1966        if (!(host->h_addr_list))
1967          return(-1);
1968        bcopy(host->h_addr_list[0], (caddr_t)&saddr.sin_addr, host->h_length);
1969#else
1970        bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
1971#endif /* h_addr */
1972#else  /* HADDRLIST */
1973        bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length);
1974#endif /* HADDRLIST */
1975#ifndef EXCELAN
1976        debug(F111,"BCOPY","host->h_addr",host->h_addr);
1977#endif /* EXCELAN */
1978        debug(F111,"BCOPY"," (caddr_t)&saddr.sin_addr",
1979              (caddr_t)&saddr.sin_addr);
1980        debug(F111,"BCOPY","host->h_length",host->h_length);
1981    } else {
1982#ifdef INADDRX
1983/* inet_addr() is of type struct in_addr */
1984        struct in_addr ina;
1985        unsigned long uu;
1986#ifdef datageneral
1987        extern struct in_addr inet_addr();
1988#endif /* datageneral */
1989        debug(F100,"netopen gethostbyname == NULL: INADDRX","",0);
1990        ina = inet_addr(namecopy);
1991        uu = *(unsigned long *)&ina;
1992#else /* Not INADDRX */
1993/* inet_addr() is unsigned long */
1994        unsigned long uu;
1995        debug(F100,"netopen gethostbyname == NULL: Not INADDRX","",0);
1996        uu = inet_addr(namecopy);
1997#endif /* INADDRX */
1998        debug(F101,"netopen uu","",uu);
1999        if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1))
2000          saddr.sin_family = AF_INET;
2001        else {
2002            fprintf(stderr, "Can't get address for %s\n", namecopy);
2003#ifdef TGVORWIN
2004            debug(F101,"netopen can't get address","",socket_errno);
2005#else
2006            debug(F101,"netopen can't get address","",errno);
2007#endif /* TGVORWIN */
2008            errno = 0;          /* Rather than mislead */
2009            return(-1);
2010        }
2011    }
2012
2013    /* Get a file descriptor for the connection. */
2014
2015    saddr.sin_port = service->s_port;
2016    sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
2017    debug(F110,"netopen trying",ipaddr,0);
2018    if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr);
2019
2020    /* Loop to try additional IP addresses, if any. */
2021 
2022    do {
2023#ifdef EXCELAN
2024        send_socket.sin_family = AF_INET;
2025        send_socket.sin_addr.s_addr = 0;
2026        send_socket.sin_port = 0;
2027        if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0,
2028                            &send_socket, SO_REUSEADDR)) < 0)
2029#else  /* EXCELAN */
2030#ifdef NT
2031#ifdef COMMENT
2032       /*
2033         Must make sure that all sockets are opened in
2034         Non-overlapped mode since we use the standard
2035         C RTL functions to read and write data.
2036         But it doesn't seem to work as planned.
2037       */
2038          {
2039              int optionValue = SO_SYNCHRONOUS_NONALERT;
2040              if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
2041                             (char *) &optionValue, sizeof(optionValue))
2042                  != NO_ERROR)
2043                return(-1);
2044          }
2045#endif /* COMMENT */
2046#endif /* NT */
2047
2048        if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
2049#endif /* EXCELAN */
2050            {
2051#ifdef EXCELAN
2052                experror("TCP socket error");
2053#else
2054#ifdef TGVORWIN
2055#ifdef OLD_TWG
2056                errno = socket_errno;
2057#endif /* OLD_TWG */
2058                socket_perror("TCP socket error");
2059                debug(F101,"netopen socket error","",socket_errno);
2060#else
2061                perror("TCP socket error");
2062                debug(F101,"netopen socket error","",errno);
2063#endif /* TGVORWIN */
2064#endif /* EXCELAN */
2065                return (-1);
2066            }
2067        errno = 0;
2068
2069#ifdef RLOGCODE                                                   
2070       /* Not part of the RLOGIN RFC, but the BSD implementation     */
2071       /* requires that the client port be a priviliged port (<1024) */
2072       /* on a Unix system this would require SuperUser permissions  */
2073       /* thereby saying that the root of the Unix system has given  */
2074       /* permission for this connection to be created               */
2075       if (service->s_port == htons((unsigned short)RLOGIN_PORT)) {
2076           struct sockaddr_in sin;
2077           static unsigned short lport = 1024;  /* max reserved port */
2078           int s_errno;
2079
2080           lport--;                     /* Make sure we do not reuse a port */
2081           if (lport == 512)
2082             lport = 1023;
2083
2084           sin.sin_family = AF_INET;
2085           sin.sin_addr.s_addr = INADDR_ANY;
2086           while (1) {
2087               sin.sin_port = htons(lport);
2088               if (bind(ttyfd, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
2089                 break;
2090#ifdef OS2
2091               s_errno = socket_errno;
2092               if (s_errno && /* OS2 bind fails with 0, if already in use */
2093#ifdef NT
2094                   s_errno != WSAEADDRINUSE
2095#else
2096                   s_errno != SOCEADDRINUSE &&
2097                   s_errno != (SOCEADDRINUSE - SOCBASEERR)
2098#endif /* NT */
2099                   )
2100#else /* OS2 */
2101#ifdef TGVORWIN
2102                 if (socket_errno != EADDRINUSE)
2103#else
2104                 if (errno != EADDRINUSE)
2105#endif /* TGVORWIN */
2106#endif /* OS2 */
2107                   {
2108                       printf("\nBind failed with errno %d  for port %d.\n",
2109#ifdef OS2
2110                              s_errno
2111#else
2112#ifdef TGVORWIN
2113                              socket_errno
2114#else
2115                              errno
2116#endif /* TGVORWIN */
2117#endif /* OS2 */
2118                              , lport
2119                              );
2120#ifdef OS2
2121                       debug(F101,"rlogin bind failed","",s_errno);
2122#else
2123#ifdef TGVORWIN
2124                       debug(F101,"rlogin bind failed","",socket_errno);
2125#ifdef OLD_TWG
2126                       errno = socket_errno;
2127#endif /* OLD_TWG */
2128                       socket_perror("rlogin bind");
2129#else
2130                       debug(F101,"rlogin bind failed","",errno);
2131                       perror("rlogin bind");
2132#endif /* TGVORWIN */
2133#endif /* OS2 */
2134                       netclos();
2135                       return -1;
2136                   }
2137               lport--;
2138               if (lport == 512 /* lowest reserved port to use */ ) {
2139                   printf("\nNo reserved ports available.\n");
2140                   netclos();
2141                   return -1;
2142               }
2143           }
2144           debug(F101,"rlogin lport","",lport);
2145           ttnproto = NP_RLOGIN;
2146       }
2147#endif /* RLOGCODE  */
2148
2149/* Now connect to the socket on the other end. */
2150
2151#ifdef EXCELAN
2152        if (connect(ttyfd, &saddr) < 0)
2153#else
2154#ifdef NT
2155          WSASafeToCancel = 1;
2156#endif /* NT */
2157        if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
2158#endif /* EXCELAN */
2159          {
2160#ifdef NT
2161              WSASafeToCancel = 0;
2162#endif /* NT */
2163#ifdef OS2
2164              i = socket_errno;
2165#else /* OS2 */
2166#ifdef TGVORWIN
2167              i = socket_errno;
2168#else
2169              i = errno;                /* Save error code */
2170#endif /* TGVORWIN */
2171#endif /* OS2 */
2172#ifdef RLOGCODE
2173              if (
2174#ifdef OS2
2175                 i && /* OS2 bind fails with 0, if already in use */
2176#ifdef NT
2177                 i == WSAEADDRINUSE
2178#else
2179                 (i == SOCEADDRINUSE ||
2180                 i == (SOCEADDRINUSE - SOCBASEERR))
2181#endif /* NT */
2182#else /* OS2 */
2183#ifdef TGVORWIN
2184                  socket_errno == EADDRINUSE
2185#else
2186                  errno == EADDRINUSE
2187#endif /* TGVORWIN */
2188#endif /* OS2 */
2189                  && ttnproto == NP_RLOGIN) {
2190#ifdef TCPIPLIB
2191                   socket_close(ttyfd); /* Close it. */
2192#else
2193                   close(ttyfd);
2194#endif /* TCPIPLIB */
2195                   continue;            /* Try a different lport */
2196               }
2197#endif /* RLOGCODE */
2198#ifdef HADDRLIST
2199#ifdef h_addr
2200              if (host && host->h_addr_list && host->h_addr_list[1]) {
2201                  perror("");
2202                  host->h_addr_list++;
2203                  bcopy(host->h_addr_list[0],
2204                        (caddr_t)&saddr.sin_addr,
2205                        host->h_length);
2206
2207                  sprintf(ipaddr,"%s", (char *)inet_ntoa(saddr.sin_addr));
2208                  debug(F110,"netopen h_addr_list",ipaddr,0);
2209                  if (!quiet && *ipaddr)
2210                    printf(" Trying %s...\n", ipaddr);
2211#ifdef TCPIPLIB
2212                  socket_close(ttyfd); /* Close it. */
2213#else
2214                  close(ttyfd);
2215#endif /* TCPIPLIB */
2216                  continue;
2217              }
2218#endif /* h_addr */
2219#endif  /* HADDRLIST */
2220              netclos();
2221              ttyfd = -1;
2222              ttnproto = NP_NONE;
2223              errno = i;                /* And report this error */
2224#ifdef EXCELAN
2225              if (errno) experror("netopen connect");
2226#else
2227#ifdef TGVORWIN
2228              debug(F101,"netopen connect error","",socket_errno);
2229              /* if (errno) socket_perror("netopen connect"); */
2230#ifdef OLD_TWG
2231              errno = socket_errno;
2232#endif /* OLD_TWG */
2233              socket_perror("netopen connect");
2234#else /* TGVORWIN */
2235              debug(F101,"netopen connect errno","",errno);
2236#ifdef DEC_TCPIP
2237              perror("netopen connect");
2238#endif /* DEC_TCPIP */
2239#ifdef CMU_TCPIP
2240              perror("netopen connect");
2241#endif /* CMU_TCPIP */
2242#endif /* TGVORWIN */
2243#endif /* EXCELAN */
2244              return(-1);
2245          }
2246#ifdef NT
2247        WSASafeToCancel = 0;
2248#endif /* NT */
2249        isconnect = 1;
2250    } while (!isconnect);
2251
2252#ifdef SO_OOBINLINE
2253/*
2254  The symbol SO_OOBINLINE is not known to Ultrix 2.0.
2255  It means "leave out of band data inline".  The normal value is 0x0100,
2256  but don't try this on systems where the symbol is undefined.
2257*/
2258/*
2259  Note from Jeff Altman: 12/13/95
2260  In implementing rlogin protocol I have come to the conclusion that it is
2261  a really bad idea to read out-of-band data inline. 
2262  At least Windows and OS/2 does not handle this well.
2263  And if you need to know that data is out-of-band, then it becomes
2264  absolutely pointless.
2265
2266  Therefore, at least on OS2 and Windows (NT) I have changed the value of
2267  on to 0, so that out-of-band data stays out-of-band.
2268
2269  12/18/95
2270  Actually, OOB data should be read inline when possible.  Especially with
2271  protocols that don't care about the Urgent flag.  This is true with Telnet.
2272  With Rlogin, you need to be able to catch OOB data.  However, the best
2273  way to do this is to set a signal handler on SIGURG.  This isn't possible
2274  on OS/2 and Windows.  But it is in UNIX.  We will also need OOB data for
2275  FTP so better create a general mechanism.
2276
2277  The reason for making OOB data be inline is that the standard ttinc/ttoc
2278  calls can be used for reading that data on UNIX systems.  If we didn't
2279  have the OOBINLINE option set then we would have to use recv(,MSG_OOB)
2280  to read it.
2281
2282*/
2283#ifdef RLOGCODE
2284#ifdef TCPIPLIB
2285    if (ttnproto == NP_RLOGIN || ttnproto == NP_FTP)
2286      on = 0;
2287#else /* TCPIPLIB */
2288    if (ttnproto == NP_RLOGIN) {
2289        debug(F100,"Installing rlogoobh on SIGURG","",0);
2290        signal(SIGURG, rlogoobh);
2291    } else
2292#ifdef FTPCODE
2293      if (ttnproto == NP_FTP) {
2294          signal(SIGURG, ftpoobh);
2295      } else
2296#endif /* FTPCODE */
2297        {
2298            signal(SIGURG, SIG_DFL);
2299        }
2300#endif /* TCPIPLIB */
2301#endif /* RLOGCODE */
2302
2303#ifdef datageneral
2304    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2305#else
2306#ifdef BSD43
2307    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2308#else
2309#ifdef OSF1
2310    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2311#else
2312#ifdef POSIX
2313    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2314#else
2315#ifdef MOTSV88R4
2316    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2317#else
2318#ifdef SOLARIS
2319/*
2320  Maybe this applies to all SVR4 versions, but the other (else) way has been
2321  compiling and working fine on all the others, so best not to change it.
2322*/
2323    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2324#else
2325#ifdef OSK
2326    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2327#else
2328#ifdef OS2
2329    {
2330        int rc;
2331        rc = setsockopt(ttyfd,
2332                        SOL_SOCKET,
2333                        SO_OOBINLINE,
2334                        (char *) &on,
2335                        sizeof on
2336                        );
2337        debug(F111,"setsockopt SO_OOBINLINE",on ? "on" : "off" ,rc);
2338    }
2339#else
2340#ifdef VMS /* or, at least, VMS with gcc */
2341    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE,(char *) &on, sizeof on);
2342#else
2343    setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
2344#endif /* VMS */
2345#endif /* OS2 */
2346#endif /* OSK */
2347#endif /* SOLARIS */
2348#endif /* MOTSV88R4 */
2349#endif /* POSIX */
2350#endif /* BSD43 */
2351#endif /* OSF1 */
2352#endif /* datageneral */
2353#endif /* SO_OOBINLINE */
2354
2355#ifndef NOTCPOPTS
2356#ifndef datageneral
2357#ifdef SOL_SOCKET
2358#ifdef TCP_NODELAY
2359    no_delay(tcp_nodelay);
2360#endif /* TCP_NODELAY */
2361#ifdef SO_KEEPALIVE
2362    keepalive(tcp_keepalive);
2363#endif /* SO_KEEPALIVE */
2364#ifdef SO_LINGER
2365    ck_linger(tcp_linger, tcp_linger_tmo);
2366#endif /* SO_LINGER */
2367#ifdef SO_SNDBUF
2368    sendbuf(tcp_sendbuf);
2369#endif /* SO_SNDBUF */
2370#ifdef SO_RCVBUF
2371    recvbuf(tcp_recvbuf);
2372#endif /* SO_RCVBUF */
2373#endif /* SOL_SOCKET */
2374#endif /* datageneral */
2375#endif /* NOTCPOPTS */
2376
2377    ttnet = nett;                       /* TCP/IP (sockets) network */
2378
2379    x = ntohs((unsigned short)service->s_port);
2380    /* See if the service is TELNET. */
2381    if (x == TELNET_PORT) {
2382        ttnproto = NP_TELNET;           /* Yes, set global flag. */
2383    }
2384#ifdef RLOGCODE
2385    else if (x == RLOGIN_PORT) {
2386        ttnproto = NP_RLOGIN;
2387        if (rlog_ini() < 0) {
2388            debug(F100,"rlogin initialization failed","",0);
2389            netclos();
2390            return -1;
2391        }
2392    }
2393#endif /* RLOGCODE */
2394#ifdef COMMENT /* not yet */
2395    else if (x == KERMIT_PORT) {
2396        ttnproto = NP_KERMIT;
2397    }
2398#endif /* COMMENT */
2399
2400#ifndef datageneral
2401/* Find out our own IP address */
2402    {
2403        struct sockaddr_in sa;
2404
2405#ifndef GSOCKNAME_T
2406#define GSOCKNAME_T int
2407#ifdef UNIXWARE
2408#undef GSOCKNAME_T
2409#define GSOCKNAME_T size_t
2410#else
2411#ifdef VMS
2412#ifdef DEC_TCPIP
2413#ifdef __DECC_VER
2414#undef GSOCKNAME_T
2415#define GSOCKNAME_T size_t
2416#endif /* __DECC_VER */
2417#endif /* DEC_TCPIP */
2418#endif /* VMS */
2419#endif /* UNIXWARE */
2420#endif /* GSOCKNAME_T */
2421
2422        GSOCKNAME_T slen;
2423
2424        slen = sizeof(sa);
2425#ifdef COMMENT
2426/* memset is not portable */
2427        memset(&sa, 0, slen);
2428#else
2429        bzero((char *)&sa, slen);
2430#endif /* COMMENT */
2431#ifndef EXCELAN
2432        if (!getsockname(ttyfd, (struct sockaddr *)&sa, &slen) ) {
2433            sprintf(myipaddr,"%s", (char *)inet_ntoa(sa.sin_addr));
2434            debug(F110,"getsockname",myipaddr,0);
2435        }
2436#endif /* EXCELAN */
2437    }
2438#endif /* datageneral */
2439    tn_ini();
2440    debug(F101,"netopen service","",x);
2441    if (*lcl < 0) *lcl = 1;             /* Local mode. */
2442#endif /* TCPSOCKET */
2443    return(0);                          /* Done. */
2444}
2445
2446/*  N E T C L O S  --  Close current network connection.  */
2447
2448int
2449netclos() {
2450    int x = 0;
2451    debug(F101,"netclos","",ttyfd);
2452    if (ttyfd == -1)                    /* Was open? */
2453      return(0);                        /* Wasn't. */
2454    if (ttyfd > -1) {                   /* Was. */
2455#ifdef VMS     
2456        ck_cancio();                    /* Cancel any outstanding reads. */
2457#endif /* VMS */
2458#ifdef TCPIPLIB
2459        x = socket_close(ttyfd);        /* Close it. */
2460#else
2461#ifndef OS2
2462        x = close(ttyfd);
2463#endif /* OS2 */
2464#endif /* TCPIPLIB */
2465    }
2466    ttyfd = -1;                         /* Mark it as closed. */
2467    ttnproto = NP_NONE;                 /* Reset the protocol type */
2468    debug(F100,"netclose setting tn_init = 0","",0);
2469    tn_init = 0;                        /* Remember about telnet protocol... */
2470    *ipaddr = '\0';                     /* Zero the IP address string */
2471#ifdef TCPIPLIB
2472/*
2473  Empty the internal buffers so they won't be used as invalid input on
2474  the next connect attempt (rlogin).
2475*/
2476    ttibp = 0;
2477    ttibn = 0;
2478#endif /* TCPIPLIB */
2479    return(x);
2480}
2481
2482/*  N E T T C H K  --  Check if network up, and how many bytes can be read */
2483/*
2484  Returns number of bytes waiting, or -1 if connection has been dropped.
2485*/
2486int                                     /* Check how many bytes are ready */
2487nettchk() {                             /* for reading from network */
2488#ifdef TCPIPLIB
2489    long count = 0;
2490    int x = 0;
2491    long y;
2492    char c;
2493
2494    debug(F101,"nettchk entry ttibn","",ttibn);
2495    debug(F101,"nettchk entry ttibp","",ttibp);
2496#ifndef OS2
2497    socket_errno = 0; /* This is a function call in NT */
2498#endif /* OS2 */
2499
2500    if (ttyfd == -1) {
2501        debug(F100,"nettchk socket is closed","",0);
2502        return(-1);
2503    }
2504/*
2505  Note: this socket_ioctl() call does NOT return an error if the
2506  connection has been broken.  (At least not in MultiNet.)
2507*/
2508#ifdef COMMENT
2509/*  Another trick that can be tried here is something like this: */
2510
2511    if (ttnet == NET_TCPB) {
2512        char dummy;
2513        x = read(ttyfd,&dummy,0);       /* Try to read nothing */
2514        if (x < 0) {                    /* "Connection reset by peer" */
2515            perror("TCP/IP");           /* or somesuch... */
2516            ttclos();                   /* Close our end too. */
2517            return(-1);
2518        }
2519    }
2520#endif /* COMMENT */
2521
2522    if (socket_ioctl(ttyfd,FIONREAD,
2523#ifdef COMMENT
2524    /* Now we've changed the ioctl(..,..,x) prototype for DECC to (void *) */
2525#ifdef __DECC
2526    /* NOTE: "&count" might need to be "(char *)&count" in some settings. */
2527                     /* Cast needed for DECC 4.1 & later? */                 
2528                     /* Maybe, but __DECC_VER only exists in 5.0 and later */
2529                     (char *)
2530#endif /* __DECC */
2531#endif /* COMMENT */
2532                     &count
2533                     ) < 0) {
2534        debug(F101,"nettchk socket_ioctl error","",socket_errno);
2535        if (ttibn < 1) {
2536            netclos();                  /* *** *** */
2537            return(-1);
2538        } else return(ttibn);
2539    }
2540    debug(F101,"nettchk count","",count);
2541/*
2542  The following code works well in most settings, but messes things up in
2543  others, including CMU/Tek TCP/IP and UCX 2.0, where it somehow manages to
2544  make it impossible to ever make a new connection to the same host again with
2545  CONNECT, once it has been logged out from the first time.  Not even if you
2546  HANGUP first, or SET HOST<CR>, or SET LINE<CR>.  Reportedly, however, it
2547  does work OK in later releases of UCX.  But there is no way we can
2548  accommodate both old and new -- we might have static linking or dynamic
2549  linking, etc etc.  If we have static, I only have access to 2.0, where this
2550  doesn't work, etc etc blah blah.
2551
2552  In the following lines, we define a symbol NOCOUNT for builds where we want
2553  to omit this code.  By default, it is omitted for CMU/Tek.  You can force
2554  omission of it for other combinations by defining NOCOUNT in CFLAGS.  You
2555  can force inclusion of this code, even for CMU/Tek, by including NONOCOUNT
2556  in CFLAGS.
2557*/
2558#ifdef NONOCOUNT
2559#ifdef NOCOUNT
2560#undef NOCOUNT
2561#endif /* NOCOUNT */
2562#else
2563#ifndef NOCOUNT
2564#ifdef CMU_TCPIP
2565#define NOCOUNT
2566#endif /* CMU_TCPIP */
2567#endif /* NOCOUNT */
2568#endif /* NONOCOUNT */
2569
2570    if (count == 0) {
2571#ifndef NOCOUNT
2572/*
2573  Here we need to tell the difference between a 0 count on an active
2574  connection, and a 0 count because the remote end of the socket broke the
2575  connection.  There is no mechanism in TGV MultiNet (or WIN/TCP?) to query
2576  the status of the connection, so we have to do a read.  -1 means there was
2577  no data available (socket_errno == EWOULDBLOCK), 0 means the connection is
2578  down.  But if, by chance, we actually get a character, we have to put it
2579  where it won't be lost.
2580*/
2581        y = 1;                          /* Turn on nonblocking reads */
2582        x = socket_ioctl(ttyfd,FIONBIO,&y);
2583        debug(F101,"nettchk FIONBIO","",x);
2584        x = socket_read(ttyfd,&c,1);    /* Returns -1 if no data */
2585        debug(F101,"nettchk socket_read","",x);
2586        if (x == -1) {
2587            int s_errno = socket_errno; /* socket_errno may be a function */
2588            debug(F101,"nettchk socket_read errno","",s_errno);
2589#ifdef OS2
2590            switch (s_errno) {
2591#ifdef NT
2592              case WSAECONNRESET:
2593#else /* NT */
2594              case SOCECONNRESET:
2595              case SOCECONNRESET - SOCBASEERR:
2596#endif /* NT */
2597                debug(F100,"nettchk ECONRESET","",0);
2598                netclos();              /* *** *** */
2599                return(-1);             /* Connection is broken. */
2600#ifdef NT
2601              case WSAECONNABORTED:
2602#else /* NT */
2603              case SOCECONNABORTED:
2604              case SOCECONNABORTED - SOCBASEERR:
2605#endif /* NT */
2606                debug(F100,"nettchk ECONNABORTED","",0);
2607                netclos();              /* *** *** */
2608                return(-1);             /* Connection is broken. */
2609#ifdef NT
2610              case WSAENETRESET: 
2611#else /* NT */
2612              case SOCENETRESET:
2613              case SOCENETRESET - SOCBASEERR:
2614#endif /* NT */
2615                debug(F100,"nettchk ENETRESET","",0);
2616                netclos();              /* *** *** */
2617                return(-1);             /* Connection is broken. */
2618#ifdef NT
2619              case WSAENOTCONN:
2620#else /* NT */
2621              case SOCENOTCONN:
2622              case SOCENOTCONN - SOCBASEERR:
2623#endif /* NT */
2624                debug(F100,"nettchk ENOTCONN","",0);
2625                netclos();              /* *** *** */
2626                return(-1);             /* Connection is broken. */
2627#ifdef NT
2628              case WSAEWOULDBLOCK:
2629#else
2630              case SOCEWOULDBLOCK:
2631              case SOCEWOULDBLOCK - SOCBASEERR:
2632#endif /* NT */
2633                debug(F100,"nettchk EWOULDBLOCK","",0);
2634                break;
2635            }
2636#endif /* OS2 */
2637        }
2638        y = 0;                          /* Turn them back off */
2639        socket_ioctl(ttyfd,FIONBIO,&y);
2640        if (x == 0) {
2641            debug(F100,"nettchk connection closed","",0);
2642            netclos();                  /* *** *** */
2643            return(-1);                 /* Connection is broken. */
2644        }
2645        if (x == 1) {                   /* Oops, actually got a byte? */
2646            debug(F101,"nettchk socket_read char","",c);
2647            debug(F101,"nettchk ttibp","",ttibp);
2648            debug(F101,"nettchk ttibn","",ttibn);
2649/*
2650  So put the byte we got into the buffer at the current position.
2651  Increment the buffer count, but DON'T increment the buffer pointer.
2652*/
2653            ttibuf[ttibp+ttibn] = c;
2654            ttibn++;
2655#ifdef DEBUG
2656            ttibuf[ttibp+ttibn] = '\0';
2657            debug(F111,"nettchk ttibn",ttibuf,ttibn);
2658#endif /* DEBUG */
2659        }
2660#else
2661        if (ttnet == NET_TCPB) {
2662            char dummy;
2663            x = read(ttyfd,&dummy,0);   /* Try to read nothing */
2664            if (x < 0) {                /* "Connection reset by peer" */
2665                perror("TCP/IP");       /* or somesuch... */
2666                ttclos();               /* Close our end too. */
2667                return(-1);
2668            }
2669        }
2670#endif /* NOCOUNT */
2671    }
2672    debug(F101,"nettchk returns","",count+ttibn);
2673    return(count + ttibn);
2674
2675#else /* Not TCPIPLIB */
2676/*
2677  UNIX just uses ttchk(), in which the ioctl() calls on the file descriptor
2678  seem to work OK.
2679*/
2680    return(0);
2681#endif /* TCPIPLIB */
2682/*
2683  But what about X.25?
2684*/
2685}
2686
2687#ifndef OS2
2688VOID
2689nettout(i) int i; {                     /* Catch the alarm interrupts */
2690    debug(F100,"nettout caught timeout","",0);
2691    ttimoff();
2692    cklongjmp(njbuf, -1);
2693}
2694#endif /* !OS2 */
2695
2696#ifdef TCPIPLIB
2697
2698VOID
2699#ifdef CK_ANSIC
2700donetinc(void * threadinfo)
2701#else /* CK_ANSIC */
2702donetinc(threadinfo) VOID * threadinfo;
2703#endif /* CK_ANSIC */
2704/* donetinc */ {
2705#ifdef NTSIG
2706    extern int TlsIndex;
2707    if (threadinfo) {                   /* Thread local storage... */
2708        TlsSetValue(TlsIndex,threadinfo);
2709    }
2710#endif /* NTSIG */
2711    while (1) {
2712        if (ttbufr() < 0)               /* Keep trying to refill it. */
2713          break;                        /* Till we get an error. */
2714        if (ttibn > 0)                  /* Or we get a character. */
2715          break;
2716    }
2717}
2718#endif /* TCPIPLIB */
2719
2720VOID
2721#ifdef CK_ANSIC
2722failnetinc(void * threadinfo)
2723#else /* CK_ANSIC */
2724failnetinc(threadinfo) VOID * threadinfo;
2725#endif /* CK_ANSIC */
2726/* failnetinc */ {
2727    ; /* Nothing to do on an error */
2728}
2729
2730/* N E T X I N -- Input block of characters from network */
2731
2732int
2733netxin(n,buf) int n; char * buf; {
2734    int len;
2735    int rc;
2736    int i, j;
2737    if (ttyfd == -1) {
2738        debug(F100,"netinc socket is closed","",0);
2739        return(-2);
2740    }
2741#ifdef TCPIPLIB
2742    if (!ttibn)
2743      if ((rc = ttbufr()) <= 0)
2744        return(rc);
2745
2746    if (ttibn <= n) {
2747        len = ttibn;
2748        memcpy(buf,&ttibuf[ttibp],len);
2749        ttibp += len;
2750        ttibn = 0;
2751    } else {
2752        /* Watch out, memcpy not portable... */
2753        memcpy(buf,&ttibuf[ttibp],n);
2754        ttibp += n;
2755        ttibn -= n;
2756        len = n;
2757    }
2758#else /* TCPIPLIB */
2759    for (i = 0; i < n; i++) {
2760        if ((j = netinc(0)) < 0) {
2761            if (j < -1)
2762              return(j);
2763            else
2764              break;
2765        }
2766        buf[i] = j;
2767    }
2768    len = i;
2769#endif /* TCPIPLIB */
2770    return(len);
2771}
2772
2773/*  N E T I N C --  Input character from network */
2774
2775int                     
2776netinc(timo) int timo; {
2777#ifdef TCPIPLIB
2778    int x; unsigned char c;             /* The locals. */
2779
2780    if (ttyfd == -1) {
2781        debug(F100,"netinc socket is closed","",0);
2782        return(-2);
2783    }
2784    if (ttibn > 0) {                    /* Something in internal buffer? */
2785#ifdef COMMENT
2786        debug(F100,"netinc char in buf","",0); /* Yes. */
2787#endif /* COMMENT */
2788        x = 0;                          /* Success. */
2789    } else {                            /* Else must read from network. */
2790        x = -1;                         /* Assume failure. */
2791#ifdef DEBUG
2792        debug(F101,"netinc goes to net, timo","",timo);
2793        ttibuf[ttibp+1] = '\0';
2794        debug(F111,"netinc ttibuf",ttibuf,ttibp);
2795#endif /* DEBUG */
2796        if (timo == 0) {                /* Untimed case. */
2797            while (1) {                 /* Wait forever if necessary. */
2798                if (ttbufr() < 0)       /* Refill buffer. */
2799                  break;                /* Error, fail. */
2800                if (ttibn > 0) {        /* Success. */
2801                    x = 0;
2802                    break;
2803                }
2804            }
2805        } else {                        /* Timed case... */
2806#ifdef BSDSELECT
2807            fd_set rfds;
2808            struct timeval tv;
2809            FD_ZERO(&rfds);
2810            FD_SET(ttyfd, &rfds);
2811            tv.tv_sec  = tv.tv_usec = 0L;
2812            if (timo < 0)
2813#ifdef NT
2814              tv.tv_usec = (long) -timo * 1000L;
2815#else  /* NT */
2816              tv.tv_usec = (long) -timo * 10000L;
2817#endif /* NT */
2818            else
2819              tv.tv_sec = timo;
2820            debug(F101,"netinc BSDSELECT","",timo);
2821#ifdef NT
2822            WSASafeToCancel = 1;
2823#endif /* NT */
2824            if (select(FD_SETSIZE,
2825#ifdef __DECC
2826                       (fd_set *)
2827#endif /* __DECC */
2828                       &rfds,
2829                       NULL, NULL, &tv) > 0 &&
2830                FD_ISSET(ttyfd, &rfds)) {
2831#ifdef NT
2832                WSASafeToCancel = 0;
2833#endif /* NT */
2834                while (1) {
2835                    if (ttbufr() < 0)   /* Keep trying to refill it. */
2836                      break;            /* Till we get an error. */
2837                    if (ttibn > 0) {    /* Or we get a character. */
2838                        x = 0;
2839                        break;
2840                    }
2841                }
2842            }   
2843#ifdef NT
2844            WSASafeToCancel = 0;
2845#endif /* NT */
2846#else /* !BSDSELECT */
2847#ifdef IBMSELECT
2848/*
2849  Was used by OS/2, currently not used, but might come in handy some day...
2850  ... and it came in handy!  For our TCP/IP layer, it avoids all the fd_set
2851  and timeval stuff since this is the only place where it is used.
2852*/
2853            int socket = ttyfd;
2854            debug(F101,"netinc IBMSELECT","",timo);
2855            if (select(&socket, 1, 0, 0,
2856                        timo < 0 ? -timo : timo * 1000L) == 1)
2857              while (1) {
2858                  if (ttbufr() < 0)     /* Keep trying to refill it. */
2859                    break;              /* Till we get an error. */
2860                  if (ttibn > 0) {      /* Or we get a character. */
2861                      x = 0;
2862                      break;
2863                  }
2864              }
2865#else /* !IBMSELECT */
2866#ifdef WINSOCK
2867       /* Actually, under WinSock we have a better mechanism than select() */
2868       /* for setting timeouts (SO_RCVTIMEO, SO_SNDTIMEO) */
2869            SOCKET socket = ttyfd;
2870            debug(F101,"netinc NTSELECT","",timo);
2871            if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&timo,
2872                            sizeof(timo))  == NO_ERROR)
2873              while (1) {
2874                  if (ttbufr() < 0)     /* Keep trying to refill it. */
2875                    break;              /* Till we get an error. */
2876                  if (ttibn > 0) {      /* Or we get a character. */
2877                      x = 0;
2878                      break;
2879                  }
2880              }
2881#else /* WINSOCK */
2882/*
2883  If we can't use select(), then we use the regular alarm()/signal()
2884  timeout mechanism.
2885*/
2886            debug(F101,"netinc alarm","",timo);
2887            x = alrm_execute(ckjaddr(njbuf),timo,nettout,donetinc,failnetinc);
2888            ttimoff();                  /* Timer off. */
2889#endif /* WINSOCK */
2890#endif /* IBMSELECT */
2891#endif /* BSDSELECT */
2892        }
2893    }
2894    if (x < 0) {                        /* Return -1 if we failed. */
2895        debug(F100,"netinc timed out","",0);
2896        return(-1);
2897    } else {                            /* Otherwise */
2898        ttibn--;                        /* Return what we got. */
2899        c = ttibuf[ttibp++];
2900        if (deblog) {
2901#ifdef COMMENT
2902            debug(F101,"netinc returning","",c);
2903#endif /* COMMENT */
2904            if (c == 0) {
2905                debug(F101,"netinc 0 ttibn","",ttibn);
2906                debug(F101,"netinc 0 ttibp","",ttibp);
2907            }
2908        }
2909        return((unsigned)(c & 0xff));
2910    }
2911#else /* Not using TCPIPLIB */
2912    return(-1);
2913#endif /* TCPIPLIB */
2914}
2915
2916/*  N E T T O L  --  Output a string of bytes to the network  */
2917/*
2918  Call with s = pointer to string, n = length.
2919  Returns number of bytes actually written on success, or
2920  -1 on i/o error, -2 if called improperly.
2921*/
2922
2923nettol(s,n) char *s; int n; {
2924#ifdef TCPIPLIB
2925    int count;
2926    if (ttyfd == -1) {
2927        debug(F100,"nettol socket is closed","",0);
2928        return -1;
2929    }
2930    debug(F101,"nettol TCPIPLIB ttnet","",ttnet);
2931    if (ttnet == NET_TCPB) {
2932#ifdef BSDSELECT
2933        fd_set wfds;
2934        struct timeval tv;
2935        FD_ZERO(&wfds);
2936        FD_SET(ttyfd, &wfds);
2937        tv.tv_sec  = tv.tv_usec = 0L;
2938        tv.tv_sec = 60;
2939        debug(F101,"nettol BSDSELECT","",0);
2940#ifdef NT
2941        WSASafeToCancel = 1;
2942#endif /* NT */
2943        if (!(select(FD_SETSIZE, NULL, &wfds, NULL, &tv) > 0 &&
2944               FD_ISSET(ttyfd, &wfds))) {
2945#ifdef NT
2946            WSASafeToCancel = 0;
2947#endif /* NT */
2948            debug(F101,"nettol select failed","",socket_errno);
2949            return(-1);
2950        }
2951#ifdef NT
2952        WSASafeToCancel = 0;
2953#endif /* NT */
2954#else /* BSDSELECT */
2955#ifdef IBMSELECT
2956        {
2957            int tries = 0;
2958            while (select(&ttyfd, 0, 1, 0, 1000) != 1) {
2959                if (tries++ >= 60) {
2960                    /* if after 60 seconds we can't get permission to write */
2961                    debug(F101,"nettol select failed","",socket_errno);
2962                    return(-1);
2963                }
2964#ifdef OS2
2965                {
2966                    char c;
2967                    socket_read(ttyfd,&c,0);
2968                }
2969#endif /* OS2 */
2970            }
2971        }
2972#endif /* IBMSELECT */
2973#endif /* BSDSELECT */
2974
2975        if ((count = socket_write(ttyfd,s,n)) < 1) {
2976            debug(F101,"nettol socket_write error","",socket_errno);
2977            return(-1);
2978        }
2979        debug(F111,"nettol socket_write",s,count);
2980        return(count);
2981    } else return(-2);
2982#else
2983    debug(F100,"nettol TCPIPLIB not defined","",0);
2984    return(-2);
2985#endif /* TCPIPLIB */
2986}
2987
2988/*  N E T T O C  --   Output character to network */
2989/*
2990  Call with character to be transmitted.
2991  Returns 0 if transmission was successful, or
2992  -1 upon i/o error, or -2 if called improperly.
2993*/
2994int                     
2995#ifdef CK_ANSIC
2996nettoc(char c)
2997#else
2998nettoc(c) char c;
2999#endif /* CK_ANSIC */
3000/* nettoc */ {
3001#ifdef UNIX
3002    return(ttoc(c));
3003#else
3004#ifdef TCPIPLIB
3005    unsigned char cc;
3006    if (ttyfd == -1) {
3007        debug(F100,"nettoc socket is closed","",0);
3008        return -1;
3009    }
3010    cc = c;
3011    debug(F101,"nettoc cc","",cc);
3012    if (ttnet == NET_TCPB) {
3013#ifdef BSDSELECT
3014        fd_set wfds;
3015        struct timeval tv;
3016        FD_ZERO(&wfds);
3017        FD_SET(ttyfd, &wfds);
3018        tv.tv_sec  = tv.tv_usec = 0L;
3019        tv.tv_sec = 60;
3020        debug(F101,"nettoc BSDSELECT","",0);
3021#ifdef NT
3022        WSASafeToCancel = 1;
3023#endif /* NT */
3024        if (!(select(FD_SETSIZE, NULL, &wfds, NULL, &tv) > 0 &&
3025               FD_ISSET(ttyfd, &wfds))) {
3026#ifdef NT
3027            WSASafeToCancel = 0;
3028#endif /* NT */
3029            debug(F100,"nettoc select failed","",0);
3030            return(-1);
3031        }
3032#ifdef NT
3033        WSASafeToCancel = 0;
3034#endif /* NT */
3035#else /* BSDSELECT */
3036#ifdef IBMSELECT
3037        if (select(&ttyfd, 0, 1, 0, 60) != 1) {
3038            debug(F100,"nettoc select failed","",0);
3039            return(-1);
3040        }
3041#endif /* IBMSELECT */
3042#endif /* BSDSELECT */
3043        if (socket_write(ttyfd,&cc,1) < 1) {
3044            debug(F101,"nettoc socket_write error","",socket_errno);
3045            return(-1);
3046        }
3047        debug(F101,"nettoc socket_write","", cc);
3048        return(0);
3049    } else return(-2);
3050#else
3051    return(-2);
3052#endif /* TCPIPLIB */
3053#endif /* UNIX */
3054}
3055
3056/*  N E T F L U I  --  Flush network input buffer  */
3057
3058int
3059netflui() {
3060    int n;
3061#ifdef TCPIPLIB
3062    ttibuf[ttibp+1] = '\0';
3063    debug(F111,"netflui 1",ttibuf,ttibn);
3064    ttibn = ttibp = 0;                  /* Flush internal buffer *FIRST* */
3065    if (ttyfd < 1)
3066      return(0);
3067    if ((n = nettchk()) > 0) {          /* Now see what's waiting on the net */
3068        if (n > TTIBUFL) n = TTIBUFL;   /* and sponge it up */
3069        debug(F101,"netflui 2","",n);   /* ... */
3070        n = socket_read(ttyfd,ttibuf,n); /* into our buffer */
3071        if (n >= 0) ttibuf[n] = '\0';
3072        debug(F111,"netflui 3",ttibuf,n);
3073        ttibuf[0] = '\0';
3074    }
3075#else
3076/*
3077  It seems the UNIX ioctl()s don't do the trick, so we have to read the
3078  stuff ourselves.  This should be pretty much portable, if not elegant.
3079*/
3080    if (ttyfd < 1)
3081      return(0);
3082    if ((n = ttchk()) > 0) {
3083        debug(F101,"netflui","",n);
3084        while ((n--) && ttinc(0) > -1); /* Don't worry, it's buffered. */
3085    }
3086#endif /* TCPIPLIB */
3087    return(0);
3088}
3089
3090#ifdef RLOGCODE                 /* TCP/IP RLOGIN protocol support code */
3091#ifndef OS2
3092static
3093#endif /* OS2 */
3094int
3095rlog_naws() {
3096    struct rlog_naws {
3097        char id[4];
3098        unsigned short rows, cols, ypix, xpix;
3099    } nawsbuf;
3100   
3101    if (ttnet != NET_TCPB)
3102      return 0;
3103    if (ttnproto != NP_RLOGIN)
3104      return 0;
3105    if (!nawsflg)
3106      return 0;
3107
3108    nawsbuf.id[0] = nawsbuf.id[1] = 0xFF;
3109    nawsbuf.id[2] = nawsbuf.id[3] = 's';
3110#ifdef OS2
3111    nawsbuf.rows = htons((unsigned short) VscrnGetHeight(VTERM)
3112                          -(tt_status?1:0));
3113    nawsbuf.cols = htons((unsigned short) VscrnGetWidth(VTERM));
3114#else /* OS2 */
3115    nawsbuf.rows = htons((unsigned short) tt_rows);
3116    nawsbuf.cols = htons((unsigned short) tt_cols);
3117#endif /* OS2 */
3118    nawsbuf.ypix = htons(0);            /* y pixels */
3119    nawsbuf.xpix = htons(0);            /* x pixels */
3120    if (ttol((CHAR *) &nawsbuf, 12) < 0)
3121      return -1;
3122    return 0;
3123}
3124
3125static int
3126rlog_ini() {
3127    int flag = 0;
3128#define TERMLEN 16
3129    extern char uidbuf[];
3130    char localuser[255];
3131    int userlen = 0;
3132    char terminal[TERMLEN+1];
3133#ifdef CONGSPD
3134#define CONSPDLEN 16
3135    char conspeed[CONSPDLEN+1];
3136    long conspd = -1L;
3137#endif /* CONGSPD */
3138#ifdef OS2
3139    extern int tt_type, max_tt;
3140    extern struct tt_info_rec tt_info[];
3141#endif /* OS2 */
3142    int i, n;
3143
3144    int rc = 0;
3145    nawsflg = 0;                        /* Assume no NAWS */
3146#ifdef CK_TTGWSIZ
3147/*
3148  But compute the values anyway before the first read since the out-
3149  of-band NAWS request would arrive before the first data byte (NULL).
3150*/
3151#ifdef OS2
3152    /* Console terminal screen rows and columns */
3153    debug(F101,"rlog_ini tt_rows 1","",VscrnGetHeight(VTERM)
3154           -(tt_status?1:0));
3155    debug(F101,"rlog_ini tt_cols 1","",VscrnGetWidth(VTERM));
3156    /* Not known yet */
3157    if (VscrnGetWidth(VTERM) < 0 ||
3158        VscrnGetHeight(VTERM)-(tt_status?1:0) < 0) {
3159        ttgwsiz();                      /* Try to get screen dimensions */
3160    }
3161    debug(F101,"rlog_ini tt_rows 2","",VscrnGetHeight(VTERM)-(tt_status?1:0));
3162    debug(F101,"rlog_ini tt_cols 2","",VscrnGetWidth(VTERM));
3163#else /* OS2 */
3164    debug(F101,"rlog_ini tt_rows 1","",tt_rows);
3165    debug(F101,"rlog_ini tt_cols 1","",tt_cols);
3166    if (tt_rows < 0 || tt_cols < 0) {   /* Not known yet */
3167        ttgwsiz();                      /* Try to find out */
3168    }
3169    debug(F101,"rlog_ini tt_rows 2","",tt_rows);
3170    debug(F101,"rlog_ini tt_cols 2","",tt_cols);
3171#endif /* OS2 */
3172#endif /* CK_TTGWSIZ */
3173
3174    rlog_mode = RL_COOKED;
3175    ttoc(0);                            /* Send an initial NUL as wake-up */
3176
3177    /* Followed by client username ... */
3178
3179    localuser[0] = '\0';
3180#ifdef NT
3181    {
3182        char localuid[64];
3183        unsigned long len = 64;
3184        localuid[0] = '\0';
3185        WNetGetUser(NULL, localuid, &len);
3186        ttol(localuid,strlen(localuid)+1);  /* strlen + 1 */
3187    }
3188#else /* NT */
3189    {
3190        char *s; char *p;
3191        char * user = getenv("USER");
3192        debug(F110,"rlogin local user",user,0);
3193        if (!user)
3194          user = "";
3195        userlen = strlen(user);
3196        s = user;
3197        p = (char *)localuser;
3198#ifdef VMS                              /* Convert username to lowercase */
3199        for (s = user; *s; s++,p++)
3200          *p = isupper(*s) ? tolower(*s) : *s;
3201        *p = '\0';
3202#else
3203        while (*p++ = *s++) ;
3204#endif /* VMS */
3205        ttol((CHAR *)localuser,userlen+1); /* strlen + 1 */
3206    }
3207#endif /* NT */
3208
3209    /* Then the server userid... */
3210
3211    if (uidbuf[0])
3212      ttol((CHAR *) uidbuf,strlen(uidbuf)+1); /* strlen + 1 */
3213    else if (localuser[0])
3214      ttol((CHAR *) localuser,userlen+1);
3215    else
3216      ttoc(0);
3217
3218    /* Finally the terminal type and speed */
3219
3220    terminal[0] = '\0';
3221    if (tn_term) {                      /* SET TELNET TERMINAL-TYPE value */
3222        if (*tn_term) {                 /* (if any) takes precedence. */
3223            strncpy(terminal, tn_term, TERMLEN);
3224            flag = 1;
3225        }
3226    } else {                            /* Otherwise the local terminal type */
3227#ifdef OS2
3228        /* In terminal-emulating versions, it's the SET TERM TYPE value */
3229        strncpy(terminal, (tt_type >= 0 && tt_type <= max_tt) ?
3230                tt_info[tt_type].x_name : "network", TERMLEN);
3231#else
3232        /* In the others, we just look at the TERM environment variable */
3233        {
3234            char *p = getenv("TERM");
3235            if (p)
3236              strncpy(terminal,p,TERMLEN);
3237            else
3238              terminal[0] = '\0';
3239#ifdef VMS
3240            for (p = (char *) terminal; *p; p++) {
3241                if (*p == '-' && (!strcmp(p,"-80") || !strcmp(p,"-132")))
3242                  break;
3243                else if (isupper(*p))
3244                  *p = tolower(*p);
3245            }
3246            *p = '\0';
3247#endif /* VMS */
3248        }
3249#endif /* OS2 */
3250    }
3251    n = strlen(terminal);
3252    if (n > 0) {                        /* We have a terminal type */
3253        if (!flag) {                    /* If not user-specified */
3254            for (i = 0; i < n; i++)     /* then lowercase it.    */
3255              if (isupper(terminal[i]))
3256                terminal[i] = tolower(terminal[i]);
3257        }
3258        ttol((CHAR *)terminal,n);
3259#ifdef CONGSPD
3260        /* conspd() is not yet defined in all ck*tio.c modules */
3261        conspd = congspd();
3262        if (conspd > 0L) {
3263            sprintf(conspeed,"/%ld",conspd);
3264            n = strlen(conspeed);
3265            ttol((CHAR *)conspeed,n+1);
3266        } else
3267#endif /* CONGSPD */
3268          ttol((CHAR *)"/19200",7);     /* strlen + 1 */
3269    } else {
3270        ttoc(0);
3271    }
3272
3273    /* Now we are supposed to get back a single zero byte as confirmation */
3274    errno = 0;
3275    rc = ttinc(60);
3276    debug(F101,"rlogin first ttinc","",rc);
3277    if (rc > 0) {
3278        debug(F101,"rlogin ttinc 1","",rc);
3279        printf("Rlogin protocol error - 0x%x received instead of 0x00\n", rc);
3280        return(-1);
3281    } else if (rc < 0) {
3282        debug(F101,"rlogin ttinc errno","",errno);
3283        /* printf("Network error: %d\n", errno); */
3284        return(-1);
3285    }   
3286    return(0);
3287}
3288
3289#ifdef TCPIPLIB
3290static VOID
3291rlog_oob(oobdata, count) CHAR * oobdata; int count; {
3292    int i;
3293
3294    for (i = 0; i<count; i++)   {
3295        debug(F101,"rlogin out_of_band","",oobdata[i]);
3296        if (oobdata[i] == 0x02) { /* Flush Buffered Data not yet displayed */
3297            debug(F101,"rlogin Flush Buffered Data command","",oobdata[i]);
3298            ttflui();
3299        }
3300        if (oobdata[i] & 0x10) {        /* Switch to RAW mode */
3301            debug(F101,"rlogin Raw Mode command","",oobdata[i]);
3302            rlog_mode = RL_RAW;
3303        }
3304
3305        if (oobdata[i] & 0x20) {        /* Switch to COOKED mode */
3306            debug(F101,"rlogin Cooked Mode command","",oobdata[i]);
3307            rlog_mode = RL_COOKED;
3308        }
3309        if (oobdata[i] & 0x80) {        /* Send Window Size Info */
3310            debug(F101,"rlogin Window Size command","",oobdata[i]);
3311            /* Remember to send WS Info when Window Size changes */
3312            nawsflg = 1;
3313            rlog_naws();
3314        }
3315    }
3316}
3317#else /* TCPIPLIB */
3318static SIGTYP
3319rlogoobh(sig) int sig; {
3320#ifdef SOLARIS
3321    char                                /* Or should it be char for all? */
3322#else
3323    CHAR
3324#endif /* SOLARIS */
3325      oobdata;
3326
3327    int  count = 0;
3328
3329    while (recv(ttyfd, &oobdata, 1, MSG_OOB) < 0) {
3330      /*
3331       * We need to do some special processing here.
3332       * Just in case the socket is blocked for input
3333       *
3334       */
3335        switch (errno) {
3336          case EWOULDBLOCK:
3337            break;
3338          default:
3339            return;
3340        }
3341    }
3342    debug(F101,"rlogin out_of_band","",oobdata);
3343    if (oobdata == 0x02) {      /* Flush Buffered Data not yet displayed */
3344        debug(F101,"rlogin Flush Buffered Data command","",oobdata);
3345        netflui();
3346    }
3347    if (oobdata & 0x10) {               /* Switch to raw mode */
3348        debug(F101,"rlogin Raw Mode command","",oobdata);
3349        rlog_mode = RL_RAW;
3350    }
3351    if (oobdata & 0x20) {               /* Switch to cooked mode */
3352        debug(F101,"rlogin Cooked Mode command","",oobdata);
3353        rlog_mode = RL_COOKED;
3354    }
3355    if (oobdata & 0x80) {                 /* Send Window Size Info */
3356        debug(F101,"rlogin Window Size command","",oobdata);
3357        nawsflg = 1; /* Remember to send WS Info when Window Size changes */
3358        rlog_naws();
3359    }
3360}
3361#endif /* TCPIPLIB */
3362#endif /* RLOGCODE */
3363
3364#ifdef TNCODE                           /* Compile in telnet support code */
3365
3366/* TCP/IP TELNET protocol negotiation support code */
3367
3368static int sgaflg = 0;                  /* SUPRRESS GO-AHEAD state */
3369static int ttyflg = 0;                  /* TERMINAL TYPE state */
3370
3371static int wnawsflg = 0;                /* Initial WILL NAWS sent, no reply */
3372static int wmebinflg = 0,  /* initial WILL BINARY sent, no reply */
3373           dubinflg  = 0;  /* initial DO BINARY sent, no reply */
3374
3375#ifndef TELCMDS
3376char *telcmds[] = {
3377    "SE", "NOP", "DMARK", "BRK",  "IP",   "AO", "AYT",  "EC",
3378    "EL", "GA",  "SB",    "WILL", "WONT", "DO", "DONT", "IAC"
3379};
3380int ntelcmds = sizeof(telcmds) / sizeof(char *);
3381#endif /* TELCMDS */
3382
3383/*
3384   The following list is current as of October 1994 ASSIGNED NUMBERS
3385   RFC 1700.
3386*/
3387
3388char *tnopts[] = {
3389    "BINARY",                           /* RFC 856 */
3390    "ECHO",                             /* RFC 857 */
3391    "RECONNECTION",                     /* NIC 50005 */
3392    "SUPPRESS-GO-AHEAD",                /* RFC 858 */
3393    "APPROX-MESSAGE-SIZE",              /* ETHERNET */
3394    "STATUS",                           /* RFC 859 */
3395    "TIMING-MARK",                      /* RFC 860 */
3396    "REMOTE-CONTROL-TRANS-ECHO",        /* RFC 726 */
3397    "OPTION-LINE-WIDTH",                /* NIC 50005 */
3398    "OPTION-PAGE-SIZE",                 /* NIC 50005 */
3399    "OUTPUT-CR-DISPOSITION",            /* RFC 652 */
3400    "OUTPUT-HORIZ-TABSTOPS",            /* RFC 653 */
3401    "OUTPUT-HORIZ-TAB-DISPOSITION",     /* RFC 654 */
3402    "OUTPUT-FF-DISPOSITION",            /* RFC 655 */
3403    "OUTPUT-VERT-TABSTOPS",             /* RFC 666 */
3404    "OUTPUT-VERT-TAB-DISPOSITION",      /* RFC 667 */
3405    "OUTPUT-LF-DISPOSITION",            /* RFC 668 */
3406    "EXTENDED-ASCII",                   /* RFC 698 */
3407    "LOGOUT",                           /* RFC 727 */
3408    "BYTE-MACRO",                       /* RFC 735 */
3409    "DATA-ENTRY-TERMINAL",              /* RFC 1043, RFC 732 */
3410    "SUPDUP",                           /* RFC 736, RFC 734 */
3411    "SUPDUP-OUTPUT",                    /* RFC 749 */
3412    "SEND-LOCATION",                    /* RFC 779 */
3413    "TERMINAL-TYPE",                    /* RFC 1091 */
3414    "END-OF-RECORD",                    /* RFC 885 */
3415    "TACACS-UID",                       /* RFC 927 */
3416    "OUTPUT-MARKING",                   /* RFC 933 */
3417    "TERMINAL-LOCATION-NUMBER",         /* RFC 946 */
3418    "TELNET-3270-REGIME",               /* RFC 1041 */
3419    "X.3-PAD",                          /* RFC 1053 */
3420    "NEGOTIATE-ABOUT-WINDOW-SIZE",      /* RFC 1073 */
3421    "TERMINAL-SPEED",                   /* RFC 1079 */
3422    "REMOTE-FLOW-CONTROL",              /* RFC 1372 */
3423    "LINEMODE",                         /* RFC 1184 */
3424    "X-DISPLAY-LOCATION",               /* RFC 1096 */
3425    "ENVIRONMENT",                      /* RFC 1408 */
3426    "AUTHENTICATION",                   /* RFC 1409 */
3427    "ENCRYPTION",                       /* No Reference */
3428    "NEW-ENVIRONMENT",                  /* RFC 1572 */
3429    "TN3270E"                           /* RFC 1647 */
3430#ifdef COMMENT
3431    "UNKNOWN",
3432    "UNKNOWN",
3433    "UNKNOWN",
3434    "UNKNOWN",
3435    "UNKNOWN",
3436    "UNKNOWN",
3437    "UNKNOWN",
3438    "UNKNOWN",
3439    "UNKNOWN",
3440    "UNKNOWN",
3441    "UNKNOWN",
3442    "UNKNOWN",
3443    "UNKNOWN",
3444    "UNKNOWN",
3445    "UNKNOWN",
3446    "UNKNOWN",
3447    "UNKNOWN",
3448    "UNKNOWN",
3449    "UNKNOWN",
3450    "UNKNOWN",
3451    "UNKNOWN",
3452    "UNKNOWN",
3453    "UNKNOWN",
3454    "UNKNOWN",
3455    "UNKNOWN",
3456    "UNKNOWN",
3457    "UNKNOWN",
3458    "UNKNOWN",
3459    "UNKNOWN",
3460    "UNKNOWN",
3461    "UNKNOWN",
3462    "UNKNOWN",
3463    "UNKNOWN",
3464    "UNKNOWN",
3465    "UNKNOWN",
3466    "UNKNOWN",
3467    "UNKNOWN",
3468    "UNKNOWN",
3469    "UNKNOWN",
3470    "UNKNOWN",
3471    "UNKNOWN",
3472    "UNKNOWN",
3473    "UNKNOWN",
3474    "UNKNOWN",
3475    "UNKNOWN",
3476    "UNKNOWN",
3477    "UNKNOWN",
3478    "UNKNOWN",
3479    "UNKNOWN",
3480    "UNKNOWN",
3481    "UNKNOWN",
3482    "UNKNOWN",
3483    "UNKNOWN",
3484    "UNKNOWN",
3485    "UNKNOWN",
3486    "UNKNOWN",
3487    "UNKNOWN",
3488    "UNKNOWN",
3489    "UNKNOWN",
3490    "UNKNOWN",
3491    "UNKNOWN",
3492    "UNKNOWN",
3493    "UNKNOWN",
3494    "UNKNOWN",
3495    "UNKNOWN",
3496    "UNKNOWN",
3497    "UNKNOWN",
3498    "UNKNOWN",
3499    "UNKNOWN",
3500    "UNKNOWN",
3501    "UNKNOWN",
3502    "UNKNOWN",
3503    "UNKNOWN",
3504    "UNKNOWN",
3505    "UNKNOWN",
3506    "UNKNOWN",
3507    "UNKNOWN",
3508    "UNKNOWN",
3509    "UNKNOWN",
3510    "UNKNOWN",
3511    "UNKNOWN",
3512    "UNKNOWN",
3513    "UNKNOWN",
3514    "UNKNOWN",
3515    "UNKNOWN",
3516    "UNKNOWN",
3517    "UNKNOWN",
3518    "UNKNOWN",
3519    "UNKNOWN",
3520    "UNKNOWN",
3521    "UNKNOWN",
3522    "UNKNOWN",
3523    "UNKNOWN",
3524    "UNKNOWN",
3525    "UNKNOWN",
3526    "UNKNOWN",
3527    "UNKNOWN",
3528    "UNKNOWN",
3529    "UNKNOWN",
3530    "UNKNOWN",
3531    "UNKNOWN",
3532    "UNKNOWN",
3533    "UNKNOWN",
3534    "UNKNOWN",
3535    "UNKNOWN",
3536    "UNKNOWN",
3537    "UNKNOWN",
3538    "UNKNOWN",
3539    "UNKNOWN",
3540    "UNKNOWN",
3541    "UNKNOWN",
3542    "UNKNOWN",
3543    "UNKNOWN",
3544    "UNKNOWN",
3545    "UNKNOWN",
3546    "UNKNOWN",
3547    "UNKNOWN",
3548    "UNKNOWN",
3549    "UNKNOWN",
3550    "UNKNOWN",
3551    "UNKNOWN",
3552    "UNKNOWN",
3553    "UNKNOWN",
3554    "UNKNOWN",
3555    "UNKNOWN",
3556    "UNKNOWN",
3557    "UNKNOWN",
3558    "UNKNOWN",
3559    "UNKNOWN",
3560    "UNKNOWN",
3561    "UNKNOWN",
3562    "UNKNOWN",
3563    "UNKNOWN",
3564    "UNKNOWN",
3565    "UNKNOWN",
3566    "UNKNOWN",
3567    "UNKNOWN",
3568    "UNKNOWN",
3569    "UNKNOWN",
3570    "UNKNOWN",
3571    "UNKNOWN",
3572    "UNKNOWN",
3573    "UNKNOWN",
3574    "UNKNOWN",
3575    "UNKNOWN",
3576    "UNKNOWN",
3577    "UNKNOWN",
3578    "UNKNOWN",
3579    "UNKNOWN",
3580    "UNKNOWN",
3581    "UNKNOWN",
3582    "UNKNOWN",
3583    "UNKNOWN",
3584    "UNKNOWN",
3585    "UNKNOWN",
3586    "UNKNOWN",
3587    "UNKNOWN",
3588    "UNKNOWN",
3589    "UNKNOWN",
3590    "UNKNOWN",
3591    "UNKNOWN",
3592    "UNKNOWN",
3593    "UNKNOWN",
3594    "UNKNOWN",
3595    "UNKNOWN",
3596    "UNKNOWN",
3597    "UNKNOWN",
3598    "UNKNOWN",
3599    "UNKNOWN",
3600    "UNKNOWN",
3601    "UNKNOWN",
3602    "UNKNOWN",
3603    "UNKNOWN",
3604    "UNKNOWN",
3605    "UNKNOWN",
3606    "UNKNOWN",
3607    "UNKNOWN",
3608    "UNKNOWN",
3609    "UNKNOWN",
3610    "UNKNOWN",
3611    "UNKNOWN",
3612    "UNKNOWN",
3613    "UNKNOWN",
3614    "UNKNOWN",
3615    "UNKNOWN",
3616    "UNKNOWN",
3617    "UNKNOWN",
3618    "UNKNOWN",
3619    "UNKNOWN",
3620    "UNKNOWN",
3621    "UNKNOWN",
3622    "UNKNOWN",
3623    "UNKNOWN",
3624    "UNKNOWN",
3625    "UNKNOWN",
3626    "UNKNOWN",
3627    "UNKNOWN",
3628    "UNKNOWN",
3629    "UNKNOWN",
3630    "UNKNOWN",
3631    "UNKNOWN",
3632    "UNKNOWN",
3633    "UNKNOWN",
3634    "UNKNOWN",
3635    "UNKNOWN",
3636    "UNKNOWN",
3637    "UNKNOWN",
3638    "UNKNOWN",
3639    "UNKNOWN",
3640    "UNKNOWN",
3641    "UNKNOWN",
3642    "UNKNOWN",
3643    "UNKNOWN",
3644    "UNKNOWN",
3645    "EXTENDED-OPTIONS-LIST"             /* 255, RFC 861 */
3646#endif /* COMMENT */
3647};
3648
3649/*
3650   Telnet Authentication Types
3651
3652   In [RFC1409], a list of authentication types is introduced.  Additions
3653   to the list are registerd by the IANA and documented here.
3654
3655   Type       Description                  Reference
3656     0        NULL                         [RFC1409]
3657     1        KERBEROS_V4                  [RFC1409]
3658     2        KERBEROS_V5                  [RFC1409]
3659     3        SPX                          [RFC1409]
3660     4-5      Unassigned
3661     6        RSA                          [RFC1409]
3662     7-9      Unassigned
3663    10        LOKI                         [RFC1409]
3664    11        SSA                          [Schoch]
3665*/
3666
3667/*
3668  In order to prevent an infinite telnet negotiation loop we maintain a
3669  count of the number of times the same telnet negotiation message is
3670  sent. When this count hits MAXTNCNT, we do not send any more of the
3671  message. The count is stored in the tncnts[][] array.
3672 
3673  The tncnts[][] array is indexed by negotiation option (SUPPRESS GO AHEAD,
3674  TERMINAL TYPE, NAWS, etc. - see the tnopts[] array) and the four
3675  negotiation message types (WILL, WONT, DO, DONT).  All telnet negotiations
3676  are kept track of in this way.
3677
3678  The count for a message is zeroed when the "opposite" message is sent.
3679  WILL is the opposite of WONT, and DO is the opposite of DONT.
3680  For example sending "WILL SGA" increments tncnts[TELOPT_SGA][0]
3681  and zeroes tncnts[TELOPT_SGA][1].
3682
3683  The code that does this is in tn_sopt().
3684
3685  rogersh@fsj.co.jp, 18/3/1995
3686*/
3687
3688#define MAXTNCNT 4      /* Permits 4 intermediate telnet firewalls/gateways */
3689
3690char tncnts[sizeof(tnopts) / sizeof(char *)][4];        /* counts */
3691char tnopps[4] = { 1,0,3,2 };                           /* opposites */
3692
3693int ntnopts = sizeof(tnopts) / sizeof(char *);
3694#endif /* TNCODE */
3695
3696/* Send network BREAK */
3697/*
3698  Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully.
3699*/
3700int
3701netbreak() {
3702    CHAR buf[3];
3703    if (ttnet == NET_TCPB) {
3704        if (ttnproto == NP_TELNET) {
3705#ifdef TNCODE
3706            buf[0] = (CHAR) IAC; buf[1] = (CHAR) BREAK; buf[2] = (CHAR) 0;
3707            if (
3708#ifdef OS2
3709                nettol((char *) buf, 2)
3710#else
3711                ttol(buf, 2)
3712#endif /* OS2 */
3713                < 2)
3714              return(-1);
3715            debug(F101,"telnet BREAK ok","",BREAK);
3716            return(1);
3717#else
3718            debug(F100,"netbreak no TNCODE","",0);
3719            return(0);
3720#endif /* TNCODE */
3721        }
3722        /* Insert other TCP/IP protocols here */
3723    }
3724    /* Insert other networks here */
3725    return(0);
3726}
3727
3728/* Send a telnet option, avoid loops. */
3729/* Returns 1 if command was sent, 0 if not, -1 on error */
3730
3731int
3732tn_sopt(cmd,opt) int cmd, opt; {        /* TELNET SEND OPTION */
3733    CHAR buf[5];
3734    int n,m;
3735
3736    if (ttnet != NET_TCPB) return(0);   /* Must be TCP/IP */
3737    if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */
3738#ifdef TNCODE
3739    n = cmd - SE;
3740    m = cmd - WILL;
3741    if (n < 0 || n > ntelcmds) return(0);
3742    if (m >= 0 && m < 4 && opt < ntnopts) {     /* See comment above about   */
3743        if (tncnts[opt][m] > MAXTNCNT) {        /* preventing infinite loops */
3744            if (debses || deblog) {
3745                sprintf(tn_msg,"TELNET negotiation loop %s %s",telcmds[n],
3746                        tnopts[opt]);
3747                debug(F101,tn_msg,"",opt);
3748                if (debses) tn_debug(tn_msg);
3749            }
3750            return(0);
3751        }
3752        tncnts[opt][m]++;
3753        tncnts[opt][tnopps[m]] = 0;
3754    }
3755    buf[0] = (CHAR) IAC;
3756    buf[1] = (CHAR) (cmd & 0xff);
3757    buf[2] = (CHAR) (opt & 0xff);
3758    buf[3] = (CHAR) 0;
3759    if (ttol(buf,3) < 3)
3760      return(-1);
3761    if ((debses || deblog) && cmd != SB) {
3762        sprintf(tn_msg,"TELNET SENT %s %s",telcmds[n],
3763                (opt < ntnopts) ? tnopts[opt] : "UNKNOWN");
3764        debug(F101,tn_msg,"",opt);
3765        if (debses) tn_debug(tn_msg);
3766    }
3767    return(1);
3768#else
3769    debug(F100,"tn_sopt no TNCODE","",0);
3770    return(0);
3771#endif /* TNCODE */
3772}
3773
3774/* Initialize a telnet connection. */
3775/* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */
3776
3777int
3778tn_ini() {
3779    int x,i,j;
3780#ifndef TNCODE
3781    debug(F100,"tn_ini no TNCODE","",0);
3782    return(0);
3783#else /* TELNET protocol support */
3784    debug(F101,"tn_ini ttnproto","",ttnproto);
3785    debug(F101,"tn_ini tn_init","",tn_init);
3786
3787    if (ttnet != NET_TCPB)              /* Make sure connection is TCP/IP */
3788      return(0);
3789    if (ttnproto == NP_RLOGIN)
3790      return(0);
3791    if (tn_init)                        /* Have we done this already? */
3792      return(0);                        /* Don't do it again. */
3793
3794    /* Reset the TELNET OPTIONS counts */
3795    for (i = 0; i < sizeof(tnopts) / sizeof(char *); i++)
3796        for (j = 0; j < 4; j ++)
3797            tncnts[i][j] = 0;
3798
3799    debug(F101,"tn_ini tn_duplex","",tn_duplex);
3800    duplex = tn_duplex;                 /* Assume local echo. */
3801    sgaflg = 0;                         /* Assume Go-Ahead suppressed. */
3802    nawsflg = 0;                        /* Assume NAWS should not be sent. */
3803    if (ttnproto == NP_NONE) {          /* If not talking to a telnet port, */
3804        ttnproto = NP_TELNET;           /* pretend it's telnet anyway, */
3805        tn_init = 1;                    /* but don't send initial options. */
3806        debug(F100,"tn_ini skipping telnet negotiations","",0);
3807        return(0);
3808    }
3809    debug(F100,"tn_ini about to send WILL TTYPE","",0);
3810/*
3811  Talking to TELNET port, so send WILL TERMINAL TYPE and DO SGA.
3812  Also send WILL NAWS if we know our screen dimensions.
3813*/
3814    if ((x = tn_sopt(WILL,TELOPT_TTYPE)) < 0) { /* Will send terminal type. */
3815        debug(F101,"tn_ini tn_sopt WILL TTYPE failed","",x);
3816        return(-1);
3817    }
3818    debug(F100,"tn_ini sent WILL TTYPE ok","",0);
3819    ttyflg = 1;                         /* Remember I said I would. */
3820#ifdef OS2
3821    ttnum = -1;
3822    ttnumend = 0;
3823#endif /* OS2 */
3824#ifdef CK_NAWS
3825    /* Console terminal screen rows and columns */
3826#ifdef OS2
3827    debug(F101,"tn_ini tt_rows 1","",VscrnGetHeight(VTERM)-(tt_status?1:0));
3828    debug(F101,"tn_ini tt_cols 1","",VscrnGetWidth(VTERM));
3829    /* Not known yet */
3830    if (VscrnGetWidth(VTERM) < 0 ||
3831        VscrnGetHeight(VTERM)-(tt_status?1:0) < 0) {
3832        ttgwsiz();                      /* Try to find out */
3833    }
3834    debug(F101,"tn_ini tt_rows 2","",VscrnGetHeight(VTERM)-(tt_status?1:0));
3835    debug(F101,"tn_ini tt_cols 2","",VscrnGetWidth(VTERM));
3836    /* Now do we know? */
3837    if (VscrnGetWidth(VTERM) > 0 &&
3838        VscrnGetHeight(VTERM)-(tt_status?1:0) > 0) {
3839        if (tn_sopt(WILL, TELOPT_NAWS) < 0)
3840          return(-1);
3841        wnawsflg = 1;                   /* OK, we sent an initial WILL NAWS. */
3842    }
3843#else /* OS2 */
3844    debug(F101,"tn_ini tt_rows 1","",tt_rows);
3845    debug(F101,"tn_ini tt_cols 1","",tt_cols);
3846    if (tt_rows < 0 || tt_cols < 0) {   /* Not known yet */
3847        ttgwsiz();                      /* Try to find out */
3848    }
3849    debug(F101,"tn_ini tt_rows 2","",tt_rows);
3850    debug(F101,"tn_ini tt_cols 2","",tt_cols);
3851    if (tt_rows > 0 && tt_cols > 0) {   /* Now do we know? */
3852        if (tn_sopt(WILL, TELOPT_NAWS) < 0)
3853          return(-1);
3854        wnawsflg = 1;                   /* Ok, we sent an initial WILL NAWS. */
3855    }
3856#endif /* OS2 */
3857#endif /* CK_NAWS */
3858
3859    if (tn_binary == TN_BM_RQ) {
3860        if (tn_sopt(WILL, TELOPT_BINARY) < 0)
3861          return(-1);
3862        wmebinflg = 1;                  /* We sent an initial WILL BINARY. */
3863        if (tn_sopt(DO, TELOPT_BINARY) < 0)
3864          return(-1);
3865        dubinflg = 1;                   /* We sent an initial DO BINARY. */
3866    }
3867    me_binary = 0;                      /* We are not in binary mode */
3868    u_binary = 0;
3869
3870
3871#ifdef CK_ENVIRONMENT
3872    /* Will send terminal environment. */
3873    if ((x = tn_sopt(WILL,TELOPT_NEWENVIRON)) < 0) {
3874        debug(F101,"tn_ini tn_sopt WILL NEWENVIRON failed","",x);
3875        return(-1);
3876    }
3877    debug(F100,"tn_ini sent WILL NEWENVIRON ok","",0);
3878#endif /* CK_ENVIRONMENT */
3879
3880    if (tn_sopt(DO,TELOPT_SGA) < 0)     /* Please suppress go-ahead. */
3881      return(-1);
3882
3883    tn_init = 1;                        /* Set telnet-initialized flag. */
3884
3885    /* Don't send anthing else! */
3886
3887    debug(F101,"tn_ini duplex","",duplex);
3888    debug(F101,"tn_ini done, tn_init","",tn_init);
3889    return(1);
3890#endif /* TNCODE */
3891}
3892
3893static VOID
3894tn_debug(s) char *s; {
3895#ifdef OS2
3896    void cwrite(unsigned short);
3897    char *p = s;
3898    _PROTOTYP (void os2bold, (void));
3899#endif /* OS2 */
3900
3901#ifdef OS2
3902    debug(F111,"tn_debug",s,0);
3903    if (debses == 0) /* Emulator is always active in OS/2 */
3904      return;
3905
3906    if (!scrninitialized[VTERM]) {
3907        USHORT x,y;
3908        checkscreenmode();
3909        GetCurPos(&y, &x);
3910        SaveCmdMode(x+1,y+1);
3911        scrninit();
3912        RestoreCmdMode();
3913    }
3914    os2bold();                          /* Toggle boldness */
3915    while (*p)
3916      cwrite((CHAR) *p++);              /* Go boldly ... */
3917    os2bold();                          /* Toggle boldness back */
3918    debses = 0;
3919    cwrite((CHAR) '\015');
3920    cwrite((CHAR) '\012');
3921    debses = 1;
3922#else
3923    debug(F111,"tn_debug",s,what);
3924    if (what != W_CONNECT || debses == 0) /* CONNECT command must be active */
3925      return;
3926    conoll(s);
3927#endif /* OS2 */
3928}
3929
3930/*
3931  Process in-band Telnet negotiation characters from the remote host.
3932  Call with the telnet IAC character and the current duplex setting
3933  (0 = remote echo, 1 = local echo), and a pointer to a function to call
3934  to read more characters.  Returns:
3935    3 if server has sent us a quoted IAC
3936    2 if local echo must be changed to remote
3937    1 if remote echo must be changed to local
3938    0 if nothing happens or no action necessary
3939   -1 on failure (= internal or i/o error)
3940*/
3941
3942#ifdef CK_ENVIRONMENT
3943#define TSBUFSIZ 1024
3944char tn_env_acct[64];
3945char tn_env_disp[64];
3946char tn_env_job[64];
3947char tn_env_prnt[64];
3948char tn_env_sys[64];
3949extern char uidbuf[];
3950#else /* CK_ENVIRONMENT */
3951#define TSBUFSIZ 41
3952#endif /* CK_ENVIRONMENT */
3953
3954unsigned char sb[TSBUFSIZ];             /* Buffer for subnegotiations */
3955
3956int
3957#ifdef CK_ANSIC                         /* TELNET DO OPTION */
3958tn_doop(CHAR z, int echo, int (*fn)(int))
3959#else
3960tn_doop(z, echo, fn) CHAR z; int echo; int (*fn)();
3961#endif /* CK_ANSIC */
3962/* tn_doop */ {
3963    int c, x, y, n, m, flag;
3964
3965#ifndef TNCODE
3966    debug(F100,"tn_doop no TNCODE","",0);
3967    return(0);
3968#else
3969    if (z != (CHAR) IAC) {
3970        debug(F101,"tn_doop bad call","",z);
3971        return(-1);
3972    }
3973    if (ttnet != NET_TCPB)              /* Check network type */
3974      return(0);
3975    if (ttnproto != NP_TELNET)          /* Check protocol */
3976      return(0);
3977
3978/* Have IAC, read command character. */
3979
3980    c = (*fn)(0) & 0xff;                /* Read command character */
3981    m = c - SE;                         /* Check validity */
3982    if (m < 0 || m > ntelcmds) {
3983        debug(F101,"tn_doop bad cmd","",c);
3984        return(0);
3985    }
3986    if (seslog && sessft) {             /* Copy to session log, if any. */
3987        if (zchout(ZSFILE, (char) z) < 0) /* Log IAC. */
3988          seslog = 0;
3989        else if (zchout(ZSFILE, (char) c) < 0) /* Log command */
3990          seslog = 0;
3991    }
3992    if (c == (CHAR) IAC)                /* Quoted IAC */
3993      return(3);
3994    if (c < SB)                         /* Other command with no arguments. */
3995      return(0);
3996
3997/* SB, WILL, WONT, DO, or DONT need more bytes... */
3998
3999    if ((x = (*fn)(0)) < 0)             /* Get the option. */
4000      return(-1);
4001    x &= 0xff;                          /* Trim to 8 bits. */
4002
4003    if (seslog && sessft)               /* Session log */
4004      if (zchout(ZSFILE, (char) x) < 0)
4005        seslog = 0;
4006
4007    if ((deblog || debses) && c != SB) {
4008        sprintf(tn_msg,"TELNET RCVD %s %s",telcmds[m],
4009                (x < ntnopts) ? tnopts[x] : "UNKNOWN");
4010        debug(F101,tn_msg,"",x);
4011        if (debses) tn_debug(tn_msg);
4012    }
4013
4014    /* Now handle the command */
4015
4016    switch (x) {
4017      case TELOPT_BINARY:               /* TELNET BINARY mode. */
4018        switch (c) {                    /* Command... */
4019          case WILL:
4020            if (tn_binary == TN_BM_RF) { /* If binary mode disabled */
4021                if (tn_sopt(DONT,x) < 0)
4022                  return(-1);
4023                else
4024                  return(0);
4025            } else if (!u_binary) {
4026                u_binary = 1;
4027                if (!dubinflg) {        /* Reply only if we did not initiate */
4028                    if (tn_sopt(DO,x) < 0)   
4029                      return -1;
4030                } else {
4031                    dubinflg = 0;
4032                }
4033                u_binary = 1;
4034            }
4035            return(0);
4036          case WONT:
4037            if (u_binary) {
4038                u_binary = 0;
4039                if (tn_sopt(DONT,x) < 0)
4040                  return (-1);
4041                else
4042                  return(0);
4043            } else return(0);
4044          case DO:
4045            if (tn_binary == TN_BM_RF) {
4046                if (tn_sopt(WONT,x) < 0)
4047                  return (-1);
4048                else
4049                  return (0);
4050            } else if (!me_binary) {
4051                if (!wmebinflg) {       /* Reply only if we did not initiate */
4052                    if (tn_sopt(WILL,x) < 0)   
4053                      return -1;
4054                } else {
4055                    wmebinflg = 0;
4056                }
4057                me_binary = 1;
4058                if (tn_binary == TN_BM_RQ && !u_binary) {
4059                    if (!dubinflg) {
4060                        if (tn_sopt(DO, TELOPT_BINARY) < 0)
4061                          return(-1);
4062                        dubinflg = 1;   /* We sent an initial DO BINARY. */
4063                    }
4064                }
4065            }
4066            return(0);
4067          case DONT:
4068            if (me_binary) {
4069                me_binary = 0;
4070                if (tn_sopt(WONT,x) < 0)
4071                  return(-1);
4072                else
4073                  return(0);
4074            } else
4075              return(0);
4076          default:
4077            return(0);
4078        }
4079
4080      case TELOPT_ECHO:                 /* ECHO mode. */
4081        switch (c) {                    /* Command... */
4082          case WILL:                    /* Host says it will echo.           */
4083            if (echo) {                 /* We're locally echoing right now,  */
4084                if (tn_sopt(DO,x) < 0)  /* so switch to remote.  */
4085                  return (-1);
4086                else
4087                  return(2);
4088            } else
4089              return(0);                /* We're already remote echoing.     */
4090          case WONT:                    /* Host says it won't echo.          */
4091            if (!echo) {                /* We're remote echoing right now,   */
4092                if (tn_sopt(DONT,x) < 0) /* so switch to local. */
4093                  return (-1);
4094                else
4095                  return (1);
4096            } else                      /* We're already locally echoing.    */
4097              return(0);
4098          case DO:                      /* Host wants me to echo.            */
4099          case DONT:                    /* Host doesn't want me to echo.     */
4100                                        /* ...But the client never echoes.   */
4101              if (tn_sopt(WONT,x) < 0)
4102                return (-1);
4103              else
4104                return (0);
4105
4106          default:
4107            return(0);
4108        }
4109
4110      case TELOPT_SGA:                  /* Suppress Go-Ahead */
4111        switch (c) {                    /* Command... */
4112          case WILL:                    /* Server says it will SGA.          */
4113#ifdef COMMENT
4114            if (sgaflg) {               /* Remember new SGA state, but       */
4115#endif /* COMMENT */
4116              sgaflg = 0;               /* don't change echo state.          */
4117              if (tn_sopt(DO,x) < 0)
4118                return(-1);
4119              else
4120                return(0);
4121#ifdef COMMENT
4122            } else return(0);
4123#endif /* COMMENT */
4124          case WONT:                    /* Server says it won't SGA.         */
4125#ifdef COMMENT
4126            if (!sgaflg) {              /* Remember new SGA state, and       */
4127#endif /* COMMENT */
4128              sgaflg = 1;               /* switch to local echo if needed.   */
4129              if (tn_sopt(DONT,x) < 0)
4130                return(-1);
4131#ifdef COMMENT
4132            }
4133#endif /* COMMENT */
4134            return(echo ? 0 : 1);
4135/*
4136  Note: The concerns expressed in the older comment below are now taken
4137  care of by the negotiation loop prevention code in tn_sopt() - see the
4138  comment about this near the definition of MAXTNCNT, above.
4139*/
4140/*
4141  Note: The following is proper behavior, and required for talking to the
4142  Apertus interface to the NOTIS library system, e.g. at Iowa State U:
4143  scholar.iastate.edu.  Without this reply, the server hangs forever.  This
4144  code should not be loop-inducing, since C-Kermit never sends WILL SGA as
4145  an initial bid, so if DO SGA comes, it is never an ACK.
4146*/
4147          case DO:                      /* Server wants me to SGA,           */
4148                                        /* so I will.                        */
4149          case DONT:                    /* Server wants me not to SGA,       */
4150                                        /* but I will anyway.                */
4151            if (tn_sopt(WILL,x) < 0)
4152              return(-1);
4153            else
4154              return (0);
4155
4156          default:
4157            return(0);
4158        }
4159
4160#ifdef TELOPT_TTYPE
4161      case TELOPT_TTYPE:                /* Terminal Type */
4162        switch (c) {
4163          case DONT:
4164            if (ttyflg) {
4165              ttyflg = 0;
4166              if (tn_sopt(WONT,x) < 0)
4167                return (-1);
4168              else
4169                return (0);
4170            } else return(0);
4171          case DO:
4172            if (!ttyflg) {
4173              ttyflg = 1;
4174              if (tn_sopt(WILL,x) < 0)
4175                return(-1);
4176              else
4177                return (0);
4178            } else
4179              return(0);
4180          case WILL:
4181          case WONT:
4182            if (!ttyflg) {
4183                ttyflg = 1;
4184                if (tn_sopt(DONT,x) < 0)
4185                  return(-1);
4186                else
4187                  return (0);
4188            } else
4189              return(0);
4190          case SB:
4191            n = flag = 0;               /* Flag for when done reading SB */
4192            while (n < TSBUFSIZ) {      /* Loop looking for IAC SE */
4193                if ((y = (*fn)(0)) < 0) /* Read a byte */
4194                  return(y);
4195                y &= 0xff;              /* Make sure it's just 8 bits. */
4196                sb[n++] = (char) y;     /* Deposit in buffer. */
4197                if (seslog && sessft)   /* Take care of session log */
4198                  if (zchout(ZSFILE, (char) y) < 0)
4199                    seslog = 0;
4200                if (y == IAC) {         /* If this is an IAC */
4201                    if (flag) {         /* If previous char was IAC */
4202                        n--;            /* it's quoted, keep one IAC */
4203                        flag = 0;       /* and turn off the flag. */
4204                    } else flag = 1;    /* Otherwise set the flag. */
4205                } else if (flag) {      /* Something else following IAC */
4206                    if (y == SE)        /* If not SE, it's a protocol error */
4207                      break;
4208                    else if ( y == DONT ) { /* Used DONT instead of SE */
4209                        debug(F100,
4210"TELNET Subnegotiation error - used DONT instead of SE!",
4211                              "",0);
4212                        if (debses)
4213                          tn_debug(
4214"TELNET Subnegotiation error - used DONT instead of SE!");
4215                        flag = 3;
4216                        break;
4217                    } else {            /* Other protocol error */
4218                        flag = 0;
4219                        break;
4220                    }
4221                } else if (!flag && y == SE) { /* Forgot the IAC ? */
4222                    flag = 2;
4223                    debug(F100,
4224"TELNET Subnegotiation error - forgot the IAC before SE!",
4225                          "",0);
4226                    if (debses)
4227                      tn_debug(
4228"TELNET Subnegotiation error - forgot the IAC before SE!");
4229                    break;
4230                }
4231            }
4232            if (!flag) {                /* Make sure we got a valid SB */
4233                debug(F100, "TELNET Subnegotiation prematurely broken", "",0);
4234                if (debses)
4235                  tn_debug("TELNET Subnegotiation prematurely broken");
4236                return(0);      /* Was -1 but that would be taken as */
4237                                /* an I/O error, so absorb it and go on. */
4238            }
4239            if (deblog || debses) {
4240                int i;
4241                sprintf(tn_msg,"TELNET RCVD SB %s %s ",tnopts[TELOPT_TTYPE],
4242                        sb[0] ? "SEND" : "IS");
4243                for (i = 1; i < n-2; i++) {
4244                    sprintf(hexbuf,"%c",sb[i]);
4245                    strcat(tn_msg,hexbuf);
4246                }
4247                if (flag == 2)
4248                  strcat(tn_msg," SE");
4249                else if (flag == 3)
4250                  strcat(tn_msg," IAC DONT");
4251                else
4252                  strcat(tn_msg," IAC SE");
4253                debug(F100,tn_msg,"",0);
4254                if (debses) tn_debug(tn_msg);
4255            }
4256            if (sb[0] == 1) {           /* SEND terminal type? */
4257                if (tn_sttyp() < 0)     /* Yes, so send it. */
4258                  return(-1);
4259            }
4260#ifdef OS2
4261            else {  /* IS terminal type -- host has chosen from the list */
4262                int i=0;
4263
4264                /* isolate the specified terminal type string */
4265                while (sb[i++] != IAC) {
4266                    if (i >= TSBUFSIZ)
4267                      return (-1);
4268                    if (sb[i] == IAC) {
4269                        sb[i] = '\0';
4270                        break;
4271                    }
4272                }
4273                strupr(&(sb[1])); /* Upper case it */
4274                for (i=0;i<=max_tt;i++) {    /* find it in our list */
4275                    if (!strcmp(&(sb[1]),tt_info[i].x_name)) {
4276                        /* Set terminal type to the one chosen */
4277                        settermtype(i,0);
4278                        break;
4279                    }
4280                }
4281            }
4282#endif /* OS2 */
4283          default:                      /* Others, ignore */
4284            return(0);
4285        }
4286#endif /* TELOPT_TTYPE */
4287
4288#ifdef CK_NAWS
4289      case TELOPT_NAWS:                 /* Terminal width and height */
4290        switch (c) {
4291          case DO:
4292            /* Get window size again in case it changed */
4293            if (ttgwsiz() > 0) {
4294                if (!wnawsflg) {        /* Reply WILL only if we */
4295                    if (tn_sopt(WILL,x) < 0) /* didn't initiate this */
4296                      return(-1);       /* negotiation with a WILL */
4297                } else
4298                    wnawsflg = 0;
4299
4300                nawsflg = 1;
4301#ifndef NOSIGWINCH
4302#ifdef SIGWINCH
4303#ifdef UNIX
4304                if (sw_armed++ < 1) {   /* Catch window-size changes. */
4305                    debug(F100,"tn_doop arming SIGWINCH","",0);
4306                    signal(SIGWINCH,winchh);
4307                }
4308#else
4309                debug(F100,"SIGWINCH defined but not used","",0);
4310#endif /* UNIX */   
4311#endif /* SIGWINCH */
4312#endif /* NOSIGWINCH */
4313                return((tn_snaws() < 0)
4314#ifdef RLOGCODE
4315                       || (rlog_naws() < 0)
4316#endif /* RLOGCODE */
4317                       ? -1 : 0); /* And now do it. */
4318            } else {
4319                nawsflg = 0;
4320                wnawsflg = 0;
4321                return((tn_sopt(WONT,x) < 0) ? -1 : 0);
4322            }
4323          case DONT:
4324            nawsflg = 0;
4325            wnawsflg = 0;
4326            return ((tn_sopt(WONT,x) < 0) ? -1 : 0);
4327          case WILL:    /* For when we are a server */
4328          case WONT:
4329            return ((tn_sopt(DONT,x) < 0) ? -1 : 0);
4330          default:
4331            return(0);
4332        }
4333#endif /* CK_NAWS */
4334
4335#ifdef CK_ENVIRONMENT
4336      case TELOPT_NEWENVIRON:           /* Telnet New-Environment */
4337        switch (c) {
4338          case DO:
4339            return ((tn_sopt(WILL,x) < 0) ? -1 : 0);
4340          case DONT:
4341            return ((tn_sopt(WONT,x) < 0) ? -1 : 0);
4342          case WILL: /* For when we are a server */
4343          case WONT:
4344            return ((tn_sopt(DONT,x) < 0) ? -1 : 0);
4345          case SB: {
4346              n = flag = 0;             /* Flag for when done reading SB */
4347              while (n < TSBUFSIZ) {    /* Loop looking for IAC SE */
4348                  if ((y = (*fn)(0)) < 0) /* Read a byte */
4349                    return(y);
4350                  y &= 0xff;            /* Make sure it's just 8 bits. */
4351                  sb[n++] = (char) y;   /* Deposit in buffer. */
4352                  if (seslog && sessft) /* Take care of session log */
4353                    if (zchout(ZSFILE, (char) y) < 0)
4354                      seslog = 0;
4355                  if (y == IAC) {       /* If this is an IAC */
4356                      if (flag) {       /* If previous char was IAC */
4357                          n--;          /* it's quoted, keep one IAC */
4358                          flag = 0;     /* and turn off the flag. */
4359                      } else flag = 1;  /* Otherwise set the flag. */
4360                  } else if (flag) {    /* Something else following IAC */
4361                      if (y == SE)      /* If not SE, it's a protocol error */
4362                        break;
4363                      else if (y == DONT) { /* Used DONT instead of SE */
4364                          debug(F100,
4365                          "TELNET SB error - got DONT instead of SE!",
4366                                 "",0);
4367                          if (debses)
4368                            tn_debug(
4369"TELNET Subnegotiation error - got DONT instead of SE!");
4370                          flag = 3;
4371                          break;
4372                      } else {          /* Other protocol error */
4373                          flag = 0;
4374                          break;
4375                      }
4376                  } else if (!flag && y == SE) { /* Forgot the IAC ? */
4377                      flag = 2;
4378                      debug(F100,
4379"TELNET Subnegotiation error - forgot the IAC before SE!",
4380                            "",0);
4381                      if (debses)
4382                        tn_debug(
4383"TELNET Subnegotiation error - forgot the IAC before SE!");
4384                      break;
4385                  }
4386              }
4387              if (!flag) {              /* Make sure we got a valid SB */
4388                  debug(F100,"TELNET Subnegotiation prematurely broken","",0);
4389                  if (debses)
4390                    tn_debug("TELNET Subnegotiation prematurely broken");
4391                  return(0);            /* Was -1 but that would be taken as */
4392                                        /* an I/O error, so absorb & go on. */
4393              }
4394              if (deblog || debses) {
4395                  int i;
4396                  sprintf(tn_msg,
4397                          "TELNET RCVD SB %s %s ",
4398                          tnopts[TELOPT_NEWENVIRON],
4399                          sb[0] == 1 ? "SEND" : sb[0] == 0 ? "IS" : "INFO"
4400                          );
4401                  for (i = 1; i < n-2; i++) {
4402                      sprintf(hexbuf,"%c",sb[i]);
4403                      strcat(tn_msg,hexbuf);
4404                  }
4405                  if (flag == 2)
4406                    strcat(tn_msg," SE");
4407                  else if (flag == 3)
4408                    strcat(tn_msg," IAC DONT");
4409                  else
4410                    strcat(tn_msg," IAC SE");
4411                  debug(F100,tn_msg,"",0);
4412                  if (debses) tn_debug(tn_msg);
4413              }
4414              switch (sb[0]) {
4415                case 0:                 /* IS */
4416                  /* Ignore, we're not a server - yet */
4417                  break;
4418                case 1:                 /* SEND */
4419                  /* We need to take the sb[] and build a structure */
4420                  /* containing all of the variables and types that */
4421                  /* we are supposed to keep track of and send to   */
4422                  /* the host, then call tn_snenv().                */
4423                  /* Or we can punt ...                             */
4424                  if (tn_snenv(&sb[1],n-3) < 0) /* Yes, so send it. */
4425                    return(-1);
4426                  break;
4427                case 2:                 /* INFO */
4428                  /* Ignore, we're not a server - yet */
4429                  break;
4430              }
4431          }
4432          default:
4433            return(0);
4434        }
4435#endif /* CK_ENVIRONMENT */
4436
4437      default:                          /* All others: refuse */
4438        switch(c) {
4439          case WILL:                    /* You will? */
4440            return((tn_sopt(DONT,x) < 0) ? -1 : 0); /* Please don't. */
4441          case WONT:                    /* You won't? */
4442            return(0);                  /* I didn't want you to. */
4443          case DO:                      /* You want me to? */
4444          case DONT:                    /* You don't want me to? */
4445            return((tn_sopt(WONT,x) < 0) ? -1 : 0); /* I won't */
4446          default:
4447            return(0);
4448        }
4449    }
4450#endif /* TNCODE */
4451}
4452
4453#ifdef CK_ENVIRONMENT
4454/* Telnet send new environment */
4455/* Returns -1 on error, 0 if nothing happens, 1 on success */
4456
4457int
4458#ifdef CK_ANSIC
4459tn_snenv(char * sb, int len)
4460#else
4461tn_snenv() char * sb; int len;
4462#endif /* CK_ANSIC */
4463/* tn_snenv */ {                        /* Send new environment */
4464#ifndef TNCODE
4465    debug(F100,"tn_snenv no TNCODE","",0);
4466    return(0);
4467#else
4468    char varname[16];
4469    char * reply = 0, * s = 0;
4470    int i,j,n;                          /* Worker. */
4471    int type = 0;       /* 0 for NONE, 1 for VAR, 2 for USERVAR in progress */
4472
4473    if (ttnet != NET_TCPB) return(0);
4474    if (ttnproto != NP_TELNET) return(0);
4475
4476    /* First determine the size of the buffer we will need */
4477    for (i = 0, j = 0, n = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
4478        switch (sb[i]) {
4479          case 0:                       /* VAR */
4480          case 3:                       /* USERVAR */
4481          case IAC:                     /* End of the list */
4482            switch (type) {
4483              case 0:                   /* Nothing in progress */
4484                /* If we get IAC only, then that means send all */
4485                /* VAR and USERVAR.  But since we don't support */
4486                /* USERVAR yet, we can just pass through        */
4487                if (!(j == 0 && sb[i] == IAC))
4488                  break;
4489              case 1:                   /* VAR in progress */
4490                varname[j] = '\0' ;
4491                if (!varname[0]) {      /* Send All */
4492                    if (uidbuf[0])
4493                      n += strlen(uidbuf) + 4 + 2;
4494                    if (tn_env_job[0])
4495                      n += strlen(tn_env_job) + 3 + 2;
4496                    if (tn_env_acct[0])
4497                      n += strlen(tn_env_acct) + 4 + 2;   
4498                    if (tn_env_prnt[0])
4499                      n += strlen(tn_env_prnt) + 7 + 2;
4500                    if (tn_env_sys[0])
4501                      n += strlen(tn_env_sys) + 10 + 2;
4502                    if (tn_env_disp[0])
4503                      n += strlen(tn_env_disp) + 7 + 2;
4504                } else if (!strcmp(varname,"USER") && uidbuf[0])
4505                  n += strlen(uidbuf) + 4 + 2;
4506                else if (!strcmp(varname,"JOB") && tn_env_job[0])
4507                  n += strlen(tn_env_job) + 3 + 2;
4508                else if (!strcmp(varname,"ACCT") && tn_env_acct[0])
4509                  n += strlen(tn_env_acct) + 4 + 2;
4510                else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0])
4511                  n += strlen(tn_env_prnt) + 7 + 2;
4512                else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0])
4513                  n += strlen(tn_env_sys) + 10 + 2;
4514                else if (!strcmp(varname,"DISPLAY") && tn_env_disp[0])
4515                  n += strlen(tn_env_disp) + 7 + 2;
4516                break;
4517              case 2:                   /* USERVAR in progress */
4518                break;                  /* We don't support this yet */
4519            }
4520            varname[0] = '\0';
4521            j = 0;
4522            type = (sb[i] == 3 ? 2 :    /* USERVAR */
4523                    sb[i] == 0 ? 1 :    /* VAR */
4524                    0
4525                   );
4526            break;
4527          case 1:                       /* VALUE */
4528            /* Protocol Error */
4529            debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
4530            if (debses)
4531              tn_debug("TELNET Subnegotiation error - VALUE in SEND");
4532            return(0);  /* Was -1 but that would be taken as */
4533                        /* an I/O error, so absorb it and go on. */
4534          case 2:       /* ESC */
4535            /* Not sure what this for.  Quote next character? */
4536            break;
4537          default:
4538            varname[j++] = sb[i];
4539        }
4540    }
4541    reply = (CHAR *) malloc(n + 7);     /* Leave room for IAC stuff */
4542    if (!reply) {
4543        debug(F100, "TELNET Subnegotiation error - malloc failed", "",0);
4544        if (debses)
4545          tn_debug("TELNET Subnegotiation error - malloc failed");
4546
4547        /* Send a return packet with no variables so that the host */
4548        /* may continue with additional negotiations               */
4549        sb[0] = (CHAR) IAC;             /* I Am a Command */
4550        sb[1] = (CHAR) SB;              /* Subnegotiation */
4551        sb[2] = TELOPT_NEWENVIRON;      /* New Environment */
4552        sb[3] = (CHAR) 0;               /* Is... */
4553        sb[4] = (CHAR) IAC;             /* End of Subnegotiation */
4554        sb[5] = (CHAR) SE;              /* marked by IAC SE */
4555        if (ttol((CHAR *)sb,6) < 0)     /* Send it. */
4556          return(-1);
4557        sb[4] = '\0';                   /* For debugging */
4558        if (deblog || debses) {
4559            sprintf(tn_msg,"TELNET SENT SB %s IS  IAC SE",
4560                     tnopts[TELOPT_NEWENVIRON]);
4561            debug(F100,tn_msg,"",0);
4562            if (debses) tn_debug(tn_msg);
4563        }
4564        return(0);     
4565    }
4566
4567    /* Now construct the real reply */
4568    reply[0] = (CHAR) IAC;                      /* I Am a Command */
4569    reply[1] = (CHAR) SB;                       /* Subnegotiation */
4570    reply[2] = TELOPT_NEWENVIRON;               /* New Environment */
4571    reply[3] = (CHAR) 0;                        /* Is... */
4572    n = 4;
4573/* Pairs of <type> [VAR=0, VALUE=1, ESC=2, USERVAR=3] <value> "unterminated" */
4574    /* follow here until done */
4575    for (i = 0, j = 0, type = 0, varname[0]= '\0'; i <= len; i++) {
4576        switch (sb[i]) {
4577          case 0:                       /* VAR */
4578          case 3:                       /* USERVAR */
4579          case IAC:                     /* End of the list */
4580            switch (type) {
4581              case 0:                   /* Nothing in progress */
4582                /* If we get IAC only, then that means send all */
4583                /* VAR and USERVAR.  But since we don't support */
4584                /* USERVAR yet, we can just pass through        */
4585                if (!(j == 0 && sb[i] == IAC))
4586                  break;
4587              case 1:                   /* VAR in progress */
4588                varname[j] = '\0';
4589                if (!varname[0]) {
4590                    /* Send All */
4591                    if ( uidbuf[0] ) {
4592                        reply[n] = 0;   /* VAR */
4593                        strcpy(&reply[n+1],"USER");
4594                        reply[n+5] = 1;         /* VALUE */
4595                        strcpy(&reply[n+6],uidbuf);
4596                        n += strlen(uidbuf) + 4 + 2;
4597                    }
4598                    if (tn_env_job[0]) {
4599                        reply[n] = 0;   /* VAR */
4600                        strcpy(&reply[n+1],"JOB");
4601                        reply[n+4] = 1; /* VALUE */
4602                        strcpy(&reply[n+5],tn_env_job);
4603                        n += strlen(tn_env_job) + 3 + 2;
4604                    }
4605                    if (tn_env_acct[0]) {
4606                        reply[n] = 0;   /* VAR */
4607                        strcpy(&reply[n+1],"ACCT");
4608                        reply[n+5] = 1; /* VALUE */
4609                        strcpy(&reply[n+6],tn_env_acct);
4610                        n += strlen(tn_env_acct) + 4 + 2;
4611                    }
4612                    if (tn_env_prnt[0]) {
4613                        reply[n] = 0;   /* VAR */
4614                        strcpy(&reply[n+1],"PRINTER");
4615                        reply[n+8] = 1; /* VALUE */
4616                        strcpy(&reply[n+9],tn_env_prnt);
4617                        n += strlen(tn_env_prnt) + 7 + 2;
4618                    }
4619                    if (tn_env_sys[0]) {
4620                        reply[n] = 0;   /* VAR */
4621                        strcpy(&reply[n+1],"SYSTEMTYPE");
4622                        reply[n+11] = 1; /* VALUE */
4623                        strcpy(&reply[n+12],tn_env_sys);
4624                        n += strlen(tn_env_sys) + 10 + 2;
4625                    }
4626                    if (tn_env_disp[0]) {
4627                        reply[n] = 0;   /* VAR */
4628                        strcpy(&reply[n+1],"DISPLAY");
4629                        reply[n+8] = 1; /* VALUE */
4630                        strcpy(&reply[n+9],tn_env_disp);
4631                        n += strlen(tn_env_disp) + 7 + 2;
4632                    }
4633                } else if (!strcmp(varname,"USER") && uidbuf[0]) {
4634                    reply[n] = 0;       /* VAR */
4635                    strcpy(&reply[n+1],"USER");
4636                    reply[n+5] = 1;     /* VALUE */
4637                    strcpy(&reply[n+6],uidbuf);
4638                    n += strlen(uidbuf) + 4 + 2;
4639                } else if (!strcmp(varname,"JOB") && tn_env_job[0]) {
4640                    reply[n] = 0;       /* VAR */
4641                    strcpy(&reply[n+1],"JOB");
4642                    reply[n+4] = 1;     /* VALUE */
4643                    strcpy(&reply[n+5],tn_env_job);
4644                    n += strlen(tn_env_job) + 3 + 2;
4645                } else if (!strcmp(varname,"ACCT") && tn_env_acct[0]) {
4646                    reply[n] = 0;       /* VAR */
4647                    strcpy(&reply[n+1],"ACCT");
4648                    reply[n+5] = 1;     /* VALUE */
4649                    strcpy(&reply[n+6],tn_env_acct);
4650                    n += strlen(tn_env_acct) + 4 + 2;
4651                } else if (!strcmp(varname,"PRINTER") && tn_env_prnt[0]) {
4652                    reply[n] = 0;       /* VAR */
4653                    strcpy(&reply[n+1],"PRINTER");
4654                    reply[n+8] = 1;     /* VALUE */
4655                    strcpy(&reply[n+9],tn_env_prnt);
4656                    n += strlen(tn_env_prnt) + 7 + 2;
4657                } else if (!strcmp(varname,"SYSTEMTYPE") && tn_env_sys[0]) {
4658                    reply[n] = 0;       /* VAR */
4659                    strcpy(&reply[n+1],"SYSTEMTYPE");
4660                    reply[n+11] = 1;    /* VALUE */
4661                    strcpy(&reply[n+12],tn_env_sys);
4662                    n += strlen(tn_env_sys) + 10 + 2;
4663                } else if (!strcmp(varname,"DISPLAY") && tn_env_disp[0]) {
4664                    reply[n] = 0;       /* VAR */
4665                    strcpy(&reply[n+1],"DISPLAY");
4666                    reply[n+8] = 1;     /* VALUE */
4667                    strcpy(&reply[n+9],tn_env_disp);
4668                    n += strlen(tn_env_disp) + 7 + 2;
4669                }
4670                break;
4671            case 2:     /* USERVAR in progress */
4672                /* we don't support this yet */
4673                break;
4674            }
4675            varname[0] = '\0';
4676            j = 0;
4677            type = (sb[i] == 3 ? 2 :    /* USERVAR */
4678                    sb[i] == 0 ? 1 :    /* VAR */
4679                    0
4680                   );
4681            break;
4682          case 1: /* VALUE */
4683            /* Protocol Error */
4684            debug(F100, "TELNET Subnegotiation error - VALUE in SEND", "",0);
4685            if (debses)
4686              tn_debug("TELNET Subnegotiation error - VALUE in SEND");
4687            return(0);  /* Was -1 but that would be taken as */
4688                        /* an I/O error, so absorb it and go on. */
4689          case 2:       /* ESC */
4690            /* Not sure what this for.  Quote next character? */
4691            break;
4692          default:
4693            varname[j++] = sb[i];
4694        }
4695    }
4696    reply[n++] = (CHAR) IAC;            /* End of Subnegotiation */
4697    reply[n++] = (CHAR) SE;             /* marked by IAC SE */
4698    if (ttol((CHAR *)reply,n) < 0) {    /* Send it. */
4699        free(reply);
4700        return(-1);
4701    }
4702    reply[n-2] = '\0';                  /* For debugging */
4703    if (deblog || debses) {
4704        int i;
4705        sprintf(tn_msg,"TELNET SENT SB %s %s ",
4706                 tnopts[TELOPT_NEWENVIRON],
4707                 reply[3] == 1 ? "SEND" : reply[3] == 0 ? "IS" : "INFO");
4708        for (i = 4; i < n-2; i++) {
4709            sprintf(hexbuf,"%c",reply[i]);
4710            strcat(tn_msg,hexbuf);
4711        }
4712        strcat(tn_msg," IAC SE");
4713        debug(F100,tn_msg,"",0);
4714        if (debses) tn_debug(tn_msg);
4715    }
4716    free(reply);
4717    return(1);
4718#endif /* TNCODE */
4719}
4720#endif /* CK_ENVIRONMENT */
4721
4722/* Telnet send terminal type */
4723/* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */
4724
4725int
4726tn_sttyp() {                            /* Send telnet terminal type. */
4727#ifndef TNCODE
4728    debug(F100,"tn_sttyp no TNCODE","",0);
4729    return(0);
4730#else
4731    char *ttn;                          /* Name of terminal type. */
4732    int i;                              /* Worker. */
4733    int tntermflg = 0;
4734
4735    if (ttnet != NET_TCPB) return(0);
4736    if (ttnproto != NP_TELNET) return(0);
4737
4738    ttn = NULL;
4739
4740#ifdef OS2
4741    if (ttnum == -1) {
4742        ttnum = tt_type;
4743    } else if (ttnumend) {
4744        ttnumend = 0;
4745    } else {
4746        if (--tt_type < 0)
4747          tt_type = max_tt;
4748        if (ttnum == tt_type)
4749          ttnumend = 1;
4750    }
4751    if (tt_type >= 0 && tt_type <= max_tt) {
4752        ttn = tt_info[tt_type].x_name;
4753        settermtype(tt_type,0);
4754    } else
4755      ttn = NULL;
4756#endif /* OS2 */
4757
4758    if (tn_term) {                      /* Terminal type override? */
4759        debug(F110,"tn_sttyp",tn_term,0);
4760        if (*tn_term) {
4761            ttn = tn_term;
4762            tntermflg = 1;
4763        }
4764    } else debug(F100,"tn_sttyp no term override","",0);
4765
4766#ifndef datageneral
4767    if (!ttn) {                         /* If no override, */
4768        ttn = getenv("TERM");           /* get it from the environment. */
4769    }
4770#endif /* datageneral */
4771    if ((ttn == ((char *)0)) || ((int)strlen(ttn) >= TSBUFSIZ))
4772      ttn = "UNKNOWN";
4773    sb[0] = (CHAR) IAC;                 /* I Am a Command */
4774    sb[1] = (CHAR) SB;                  /* Subnegotiation */
4775    sb[2] = TELOPT_TTYPE;               /* Terminal Type */
4776    sb[3] = (CHAR) 0;                   /* Is... */
4777    for (i = 4; *ttn; ttn++,i++) {      /* Copy and uppercase it */
4778#ifdef VMS
4779        if (!tntermflg && *ttn == '-' &&
4780            (!strcmp(ttn,"-80") || !strcmp(ttn,"-132")))
4781          break;
4782        else
4783#endif /* VMS */
4784        sb[i] = (char) ((!tntermflg && islower(*ttn)) ? toupper(*ttn) : *ttn);
4785    }
4786    ttn = (char *)sb;                   /* Point back to beginning */
4787    sb[i++] = (CHAR) IAC;               /* End of Subnegotiation */
4788    sb[i++] = (CHAR) SE;                /* marked by IAC SE */
4789    if (ttol((CHAR *)sb,i) < 0)         /* Send it. */
4790      return(-1);
4791    sb[i-2] = '\0';                     /* For debugging */
4792    if (deblog || debses) {
4793        sprintf(tn_msg,"TELNET SENT SB %s IS %s IAC SE",
4794        tnopts[TELOPT_TTYPE],sb+4);
4795        debug(F100,tn_msg,"",0);
4796        if (debses) tn_debug(tn_msg);
4797    }
4798    return(1);
4799#endif /* TNCODE */
4800}
4801
4802#ifdef CK_NAWS                  /*  NAWS = Negotiate About Window Size  */
4803int
4804tn_snaws() {                    /*  Send terminal width and height, RFC 1073 */
4805#ifndef TNCODE
4806    debug(F100,"tn_snaws no TNCODE","",0);
4807#else
4808    int i = 0;
4809#ifdef OS2
4810    int x = VscrnGetWidth(VTERM),
4811    y = VscrnGetHeight(VTERM) - (tt_status ? 1 : 0);
4812#else /* OS2 */
4813    int x = tt_cols, y = tt_rows;
4814#endif /* OS2 */
4815
4816    if (ttnet != NET_TCPB) return(0);
4817    if (ttnproto != NP_TELNET) return(0);
4818    if (!nawsflg) return(0);
4819
4820    if (x < 0) x = 0;
4821    if (y < 0) y = 0;
4822
4823    sb[i++] = (CHAR) IAC;               /* Send a subnegotiation */
4824    sb[i++] = (CHAR) SB;
4825    sb[i++] = TELOPT_NAWS;
4826    sb[i++] = (CHAR) (x >> 8) & 0xff;
4827    /* IAC in data must be doubled */
4828    if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
4829    sb[i++] = (CHAR) (x & 0xff);
4830    if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
4831    sb[i++] = (CHAR) (y >> 8) & 0xff;
4832    if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
4833    sb[i++] = (CHAR) (y & 0xff);
4834    if ((CHAR) sb[i-1] == (CHAR) IAC) sb[i++] = (CHAR) IAC;
4835    sb[i++] = (CHAR) IAC;
4836    sb[i++] = (CHAR) SE;
4837    if (ttol((CHAR *)sb,i) < 0)         /* Send it. */
4838      return(-1);
4839    if (deblog || debses) {
4840        sprintf(tn_msg,"TELNET SENT SB NAWS %d %d IAC SE",x,y);
4841        debug(F100,tn_msg,"",0);
4842        if (debses) tn_debug(tn_msg);
4843    }
4844#endif /* TNCODE */
4845    return (0);
4846}
4847#endif /* CK_NAWS */
4848
4849#ifdef SUNX25
4850/*
4851  SunLink X.25 support by Marcello Frutig, Catholic University,
4852  Rio de Janeiro, Brazil, 1990.
4853*/
4854
4855/* PAD X.3, X.28 and X.29 support */
4856
4857static CHAR x29err[MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' };
4858
4859/* Initialize PAD */
4860
4861extern CHAR padparms[];
4862
4863VOID
4864initpad() {
4865  padparms[PAD_BREAK_CHARACTER]        = 0;  /* Break character */
4866  padparms[PAD_ESCAPE]                 = 1;  /* Escape permitted */
4867  padparms[PAD_ECHO]                   = 1;  /* Kermit PAD does echo */
4868  padparms[PAD_DATA_FORWARD_CHAR]      = 2;  /* forward character CR */
4869  padparms[PAD_DATA_FORWARD_TIMEOUT]   = 0;  /* no timeout forward condition */
4870  padparms[PAD_FLOW_CONTROL_BY_PAD]    = 0;  /* not used */
4871  padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1;  /* allow PAD service signals */
4872  padparms[PAD_BREAK_ACTION]           = 21; /* brk action: INT pk + brk ind*/
4873  padparms[PAD_SUPPRESSION_OF_DATA]    = 0;  /* no supression of user data */
4874  padparms[PAD_PADDING_AFTER_CR]       = 0;  /* no padding after CR */
4875  padparms[PAD_LINE_FOLDING]           = 0;  /* no line fold */
4876  padparms[PAD_LINE_SPEED]             = 0;  /* line speed - don't care */
4877  padparms[PAD_FLOW_CONTROL_BY_USER]   = 0;  /* flow cont of PAD - not used */
4878  padparms[PAD_LF_AFTER_CR]            = 0;  /* no LF insertion after CR */
4879  padparms[PAD_PADDING_AFTER_LF]       = 0;  /* no padding after LF */
4880  padparms[PAD_EDITING]                = 1;  /* can edit */
4881  padparms[PAD_CHAR_DELETE_CHAR]       = 8;  /* character delete character */
4882  padparms[PAD_BUFFER_DELETE_CHAR]     = 21; /* buffer delete character */
4883  padparms[PAD_BUFFER_DISPLAY_CHAR]    = 18; /* buffer display character */
4884}
4885
4886/* Set PAD parameters */
4887
4888VOID
4889setpad(s,n) CHAR *s; int n; {
4890    int i;
4891    CHAR *ps = s;
4892
4893    if (n < 1) {
4894        initpad();
4895    } else {
4896        for (i = 0; i < n; i++) {
4897            if (*ps > MAXPADPARMS)
4898              x29err[i+2] = *ps;
4899            else
4900              padparms[*ps] = *(ps+1);
4901            ps += 2;
4902        }
4903    }
4904}
4905
4906/* Read PAD parameters */
4907
4908VOID
4909readpad(s,n,r) CHAR *s; int n; CHAR *r; {
4910    int i;
4911    CHAR *ps = s;
4912    CHAR *pr = r;
4913
4914    *pr++ = X29_PARAMETER_INDICATION;
4915    if (n > 0) {
4916        for (i = 0; i < n; i++, ps++) {
4917            if (*ps > MAXPADPARMS) {
4918                x29err[i+2] = *ps++;
4919            } else {
4920                *pr++ = *ps;
4921                *pr++ = padparms[*ps++];
4922            }
4923        }
4924    } else {
4925        for (i = 1; i < MAXPADPARMS; i++) {
4926            *pr++ = i;
4927            *pr++ = padparms[i];
4928        }
4929    }
4930}
4931
4932int
4933qbitpkt(s,n) CHAR *s; int n; {
4934    CHAR *ps = s;
4935    int x29cmd = *ps;
4936    CHAR *psa = s+1;
4937    CHAR x29resp[(MAXPADPARMS*2)+1];
4938
4939    switch (x29cmd) {
4940
4941        case X29_SET_PARMS:
4942            setpad (ps+1,n/2);
4943            if ((int)strlen((char *)x29err) > 2) {
4944                ttol(x29err,(int)strlen((char *)x29err));
4945                x29err[2] = '\0';
4946            }
4947            return (-2);
4948        case X29_READ_PARMS:
4949            readpad (ps+1,n/2,x29resp);
4950            setqbit ();
4951            ttol (x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
4952            if ((int)strlen((char *)x29err) > 2) {
4953                ttol(x29err,(int)strlen((char *)x29err));
4954                x29err[2] = '\0';
4955            }
4956            resetqbit();
4957            break;
4958        case X29_SET_AND_READ_PARMS:
4959            setpad (ps+1,n/2);
4960            readpad (ps+1,n/2,x29resp);
4961            setqbit();
4962            ttol (x29resp,(n>1)?(n+1):(2*MAXPADPARMS+1));
4963            if ((int)strlen((char *)x29err) > 2) {
4964                ttol (x29err,(int)strlen((char *)x29err));
4965                x29err [2] = '\0';
4966            }
4967            resetqbit();
4968            return (-2);
4969        case X29_INVITATION_TO_CLEAR:
4970            (VOID) x25clear();
4971            return (-1);
4972        case X29_INDICATION_OF_BREAK:
4973            break;
4974    }
4975    return (0);
4976}
4977
4978/* PAD break action processor */
4979
4980VOID
4981breakact() {
4982    extern char x25obuf[MAXOX25];
4983    extern int obufl;
4984    extern int active;
4985    extern unsigned char tosend;
4986    static CHAR indbrk[3] = {
4987        X29_INDICATION_OF_BREAK,
4988        PAD_SUPPRESSION_OF_DATA,
4989        1
4990    };
4991    CHAR intudat, cause, diag;
4992
4993    if (x25stat() < 0) return;  /* Ignore if no virtual call established */
4994
4995    if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */
4996        if (ttol((CHAR *)x25obuf,obufl) < 0) {
4997            perror ("\r\nCan't send characters");
4998            active = 0;
4999        } else {
5000            bzero (x25obuf,sizeof(x25obuf));
5001            obufl = 0;
5002            tosend = 0;
5003        };
5004
5005    switch (padparms[PAD_BREAK_ACTION]) {
5006
5007       case 0 : break;                  /* do nothing */
5008       case 1 : /* send interrupt packet with interrupt user data field = 1 */
5009                intudat = 1;
5010                x25intr (intudat);
5011                break;
5012       case 2 : /* send reset packet with cause and diag = 0 */
5013                cause = diag = 0;
5014                x25reset (cause,diag);
5015                break;
5016       case 5 : /* send interrupt packet with interrupt user data field = 0 */
5017                intudat = 0;
5018                x25intr (intudat);
5019                setqbit ();
5020                /* send indication of break without a parameter field */
5021                ttoc(X29_INDICATION_OF_BREAK);
5022                resetqbit ();
5023                break;
5024       case 8 : active = 0;             /* leave data transfer */
5025                conol ("\r\n");
5026                break;
5027       case 21: /* send interrupt packet with interrupt user data field = 0 */
5028                intudat = 0;
5029                x25intr (intudat);
5030                setpad (indbrk+1,2);    /* set pad to discard input */
5031                setqbit ();
5032                /* send indication of break with parameter field */
5033                ttol (indbrk,sizeof(indbrk));
5034                resetqbit ();
5035                break;
5036     }
5037}
5038
5039/* X.25 support functions */
5040
5041X25_CAUSE_DIAG diag;
5042
5043/*
5044  Convert a null-terminated string representing an X.121 address
5045  to a packed BCD form.
5046*/
5047int
5048pkx121(str,bcd) char *str; CHAR *bcd; {
5049    int i, j;
5050    u_char c;
5051
5052    i = j = 0;
5053    while (str[i]) {
5054        if (i >= 15 || str [i] < '0' || str [i] > '9')
5055          return (-1);
5056        c = str [i] - '0';
5057        if (i & 1)
5058          bcd [j++] |= c;
5059        else
5060          bcd [j] = c << 4;
5061        i++;
5062    }
5063    return (i);
5064}
5065
5066/* Reads and prints X.25 diagnostic */
5067
5068int
5069x25diag () {
5070    int i;
5071
5072    bzero ((char *)&diag,sizeof(diag));
5073    if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) {
5074        perror ("Reading X.25 diagnostic");
5075        return(-1);
5076    }
5077    if (diag.datalen > 0) {
5078        printf ("X.25 Diagnostic :");
5079        for (i = 0; i < (int)diag.datalen; i++)
5080          printf(" %02x",diag.data[i]);
5081        printf ("\r\n");
5082    }
5083    return(0);
5084}
5085
5086/* X.25 Out-of-Band Signal Handler */
5087
5088SIGTYP
5089x25oobh(foo) int foo; {
5090    int oobtype;
5091    u_char oobdata;
5092    int t;
5093
5094    (VOID) signal(SIGURG,x25oobh);
5095    do {
5096        if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) {
5097            perror ("Getting signal type");
5098            return;
5099        }
5100        switch (oobtype) {
5101          case INT_DATA:
5102            if (recv(ttyfd,(char *)&oobdata,1,MSG_OOB) < 0) {
5103                perror ("Receiving X.25 interrupt data");
5104                return;
5105            }
5106            t = oobdata;
5107            printf ("\r\nInterrupt received, data = %d\r\n", t);
5108            break;
5109          case VC_RESET:
5110            printf ("\r\nVirtual circuit reset\r\n");
5111            x25diag ();
5112            break;
5113          case N_RESETS:
5114            printf ("\r\nReset timeout\r\n");
5115            break;
5116          case N_CLEARS:
5117            printf ("\r\nClear timeout\r\n");
5118            break;
5119          case MSG_TOO_LONG:
5120            printf ("\r\nMessage discarded, too long\r\n");
5121            break;
5122          default:
5123            if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype);
5124            break;
5125        }
5126    } while (oobtype);
5127}
5128
5129/* Send a X.25 interrupt packet */
5130
5131int
5132#ifdef CK_ANSIC
5133x25intr(char intr)
5134#else
5135x25intr(intr) char intr;
5136#endif /* CK_ANSIC */
5137/* x25intr */ {
5138    if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1);
5139    debug(F100,"X.25 intr","",0);
5140    return(0);
5141}
5142
5143/* Reset X.25 virtual circuit */
5144int
5145#ifdef CK_ANSIC
5146x25reset(char cause, char diagn)
5147#else
5148x25reset(cause, diagn) char cause; char diagn;
5149#endif /* CK_ANSIC */
5150/* x25reset */ {
5151    bzero ((char *)&diag,sizeof(diag));
5152    diag.flags   = 0;
5153    diag.datalen = 2;
5154    diag.data[0] = cause;
5155    diag.data[1] = diagn;
5156    if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0)
5157      return(-1);
5158    debug(F100,"X.25 reset","",0);
5159    return(0);
5160}
5161
5162/* Clear X.25 virtual circuit */
5163int
5164x25clear() {
5165    int i;
5166    debug(F100,"X.25 clear","",0);
5167    bzero ((char *)&diag,sizeof(diag));
5168    diag.flags = (1 << DIAG_TYPE);
5169    diag.datalen = 2;
5170    diag.data[0] = 0;
5171    diag.data[1] = 0;
5172    ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */
5173    return(ttclos(0));                  /* Close socket */
5174}
5175
5176/* X.25 status */
5177int
5178x25stat() {
5179    if (ttyfd == -1) return (-1);
5180    return(0);
5181}
5182
5183/* Set Q_BIT on */
5184VOID
5185setqbit() {
5186    static int qbiton = 1 << Q_BIT;
5187    ioctl (ttyfd,X25_SEND_TYPE,&qbiton);
5188}
5189
5190/* Set Q_BIT off */
5191VOID
5192resetqbit() {
5193    static int qbitoff = 0;
5194    ioctl (ttyfd,X25_SEND_TYPE,&qbitoff);
5195}
5196
5197/* Read n characters from X.25 circuit into buf */
5198
5199int
5200x25xin(n,buf) int n; CHAR *buf; {
5201    register int x, c;
5202    int qpkt;
5203
5204    do {
5205        x = read(ttyfd,buf,n);
5206        if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */
5207            /* If return -1 : invitation to clear; -2 : PAD changes */
5208            if ((c=qbitpkt(buf+1,x-2)) < 0) return(c);
5209            qpkt = 1;
5210        } else qpkt = 0;
5211    } while (qpkt);
5212    if (x > 0) buf[x] = '\0';
5213    if (x < 1) x = -1;
5214    debug(F101,"x25xin x","",x);
5215
5216    return(x);
5217}
5218
5219#ifdef COMMENT /* NO LONGER NEEDED! */
5220/* X.25 read a line */
5221
5222int
5223#ifdef PARSENSE
5224#ifdef CK_ANSIC
5225x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start)
5226#else
5227x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start;
5228#endif /* CK_ANSIC */
5229#else /* not PARSENSE */
5230#ifdef CK_ANSIC
5231x25inl(CHAR *dest, int max,int timo, CHAR eol)
5232#else
5233x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol;
5234#endif /* __SDTC__ */
5235#endif /*PARSENSE */
5236 /* x25inl */ {
5237    CHAR *pdest;
5238    int pktype, goteol, rest, n;
5239    int i, flag = 0;
5240    extern int ttprty, ttpflg;
5241    int ttpmsk;
5242
5243    ttpmsk = (ttprty) ? 0177 : 0377;    /* Set parity stripping mask */
5244
5245    debug(F101,"x25inl max","",max);
5246    debug(F101,"x25inl eol","",eol);
5247    pdest  = dest;
5248    rest   = max;
5249    goteol = 0;
5250    do {
5251        n = read(ttyfd,pdest,rest);
5252        n--;
5253        pktype = *pdest & 0x7f;
5254        switch (pktype) {
5255          case 1 << Q_BIT:
5256            if (qbitpkt(pdest+1,--n) < 0) return(-2);
5257            break;
5258          default:
5259            if (flag == 0) { /* if not in packet, search start */
5260                for (i = 1; (i < n) &&
5261                     !(flag = ((dest[i] & 0x7f) == start));
5262                     i++);
5263                if (flag == 0) { /* not found, discard junk */
5264                    debug(F101,"x25inl skipping","",n);
5265                    continue;
5266                } else {                /* found, discard junk before start */
5267                    int k;
5268                    n = n - i + 1;
5269                    for (k = 1; k <= n; k++, i++) dest[k] = dest[i];
5270                }
5271            }
5272            for (i = 0; (i < n) && /* search for eol */
5273                 !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol));
5274                 i++,pdest++);
5275            *pdest = '\0';
5276            rest -= n;
5277        }
5278    } while ((rest > 0) && (!goteol));
5279
5280    if (goteol) {
5281        n = max - rest;
5282        debug (F111,"x25inl X.25 got",(char *) dest,n);
5283        if (timo) ttimoff();
5284        if (ttpflg++ == 0 && ttprty == 0) {
5285            if ((ttprty = parchk(dest,start,n)) > 0) {
5286                int j;
5287                debug(F101,"x25inl senses parity","",ttprty);
5288                debug(F110,"x25inl packet before",(char *)dest,0);
5289                ttpmsk = 0x7f;
5290                for (j = 0; j < n; j++)
5291                  dest[j] &= 0x7f; /* Strip parity from packet */
5292                debug(F110,"x25inl packet after ",dest,0);
5293            } else {
5294                debug(F101,"parchk","",ttprty);
5295                if (ttprty < 0) { ttprty = 0; n = -1; }
5296            }
5297        }
5298        ttimoff();
5299        return(n);
5300    }
5301    ttimoff();
5302    return(-1);
5303}
5304#endif /* COMMENT */
5305#endif /* SUNX25 */
5306
5307#endif /* NETCONN */
Note: See TracBrowser for help on using the repository browser.