1 /* ========================================================================
2  * Copyright 1988-2008 University of Washington
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *
11  * ========================================================================
12  */
13 
14 /*
15  * Program:	Waterloo DOS TCP/IP routines
16  *
17  * Author:	Mark Crispin
18  *		Networks and Distributed Computing
19  *		Computing & Communications
20  *		University of Washington
21  *		Administration Building, AG-44
22  *		Seattle, WA  98195
23  *		Internet: MRC@CAC.Washington.EDU
24  *
25  * Date:	11 April 1989
26  * Last Edited:	13 January 2008
27  */
28 
29 
30 /* Global data */
31 
32 short sock_initted = 0;		/* global so others using net can see it */
33 
34 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
35 			       long *contd);
36 
37 /* TCP/IP manipulate parameters
38  * Accepts: function code
39  *	    function-dependent value
40  * Returns: function-dependent return value
41  */
42 
tcp_parameters(long function,void * value)43 void *tcp_parameters (long function,void *value)
44 {
45   return NIL;
46 }
47 
48 /* TCP/IP open
49  * Accepts: host name
50  *	    contact service name
51  *	    contact port number
52  * Returns: TCP/IP stream if success else NIL
53  */
54 
TCP_open(char * host,char * service,unsigned long port)55 TCPSTREAM *TCP_open (char *host,char *service,unsigned long port)
56 {
57   TCPSTREAM *stream = NIL;
58   tcp_Socket *sock;
59   char *s,tmp[MAILTMPLEN];
60   unsigned long adr,i,j,k,l;
61   port &= 0xffff;		/* erase flags */
62 				/* initialize if first time here */
63   if (!sock_initted++) sock_init();
64   /* The domain literal form is used (rather than simply the dotted decimal
65      as with other Unix programs) because it has to be a valid "host name"
66      in mailsystem terminology. */
67 				/* look like domain literal? */
68   if (host[0] == '[' && host[strlen (host)-1] == ']') {
69     if (((i = strtoul (s = host+1,&s,10)) <= 255) && *s++ == '.' &&
70 	((j = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
71 	((k = strtoul (s,&s,10)) <= 255) && *s++ == '.' &&
72 	((l = strtoul (s,&s,10)) <= 255) && *s++ == ']' && !*s)
73       adr = (i << 24) + (j << 16) + (k << 8) + l;
74     else {
75       sprintf (tmp,"Bad format domain-literal: %.80s",host);
76       mm_log (tmp,ERROR);
77       return NIL;
78     }
79   }
80   else {			/* lookup host name */
81     if (!(adr = resolve (host))) {
82       sprintf (tmp,"Host not found: %s",host);
83       mm_log (tmp,ERROR);
84       return NIL;
85     }
86   }
87 
88 				/* OK to instantiate socket now */
89   sock = (tcp_Socket *) fs_get (sizeof (tcp_Socket));
90 				/* open connection */
91   if (!tcp_open (sock,(word) 0,adr,(word) port,NULL)) {
92     sprintf (tmp,"Can't connect to %.80s,%ld",host,port);
93     mm_log (tmp,ERROR);
94     fs_give ((void **) &sock);
95     return NIL;
96   }
97 				/* create TCP/IP stream */
98   stream = (TCPSTREAM *) fs_get (sizeof (TCPSTREAM));
99   stream->host = cpystr (host);	/* official host name */
100   stream->localhost = cpystr (mylocalhost ());
101   stream->port = port;		/* port number */
102   stream->tcps = sock;		/* init socket */
103   stream->ictr = 0;		/* init input counter */
104   return stream;		/* return success */
105 }
106 
107 /* TCP/IP authenticated open
108  * Accepts: NETMBX specifier
109  *	    service name
110  *	    returned user name buffer
111  * Returns: TCP/IP stream if success else NIL
112  */
113 
tcp_aopen(NETMBX * mb,char * service,char * usrbuf)114 TCPSTREAM *tcp_aopen (NETMBX *mb,char *service,char *usrbuf)
115 {
116   return NIL;			/* always NIL on DOS */
117 }
118 
119 /* TCP receive line
120  * Accepts: TCP stream
121  * Returns: text line string or NIL if failure
122  */
123 
tcp_getline(TCPSTREAM * stream)124 char *tcp_getline (TCPSTREAM *stream)
125 {
126   unsigned long n,contd;
127   char *ret = tcp_getline_work (stream,&n,&contd);
128   if (ret && contd) {		/* got a line needing continuation? */
129     STRINGLIST *stl = mail_newstringlist ();
130     STRINGLIST *stc = stl;
131     do {			/* collect additional lines */
132       stc->text.data = (unsigned char *) ret;
133       stc->text.size = n;
134       stc = stc->next = mail_newstringlist ();
135       ret = tcp_getline_work (stream,&n,&contd);
136     } while (ret && contd);
137     if (ret) {			/* stash final part of line on list */
138       stc->text.data = (unsigned char *) ret;
139       stc->text.size = n;
140 				/* determine how large a buffer we need */
141       for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size;
142       ret = fs_get (n + 1);	/* copy parts into buffer */
143       for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next)
144 	memcpy (ret + n,stc->text.data,stc->text.size);
145       ret[n] = '\0';
146     }
147     mail_free_stringlist (&stl);/* either way, done with list */
148   }
149   return ret;
150 }
151 
152 /* TCP receive line or partial line
153  * Accepts: TCP stream
154  *	    pointer to return size
155  *	    pointer to return continuation flag
156  * Returns: text line string, size and continuation flag, or NIL if failure
157  */
158 
tcp_getline_work(TCPSTREAM * stream,unsigned long * size,long * contd)159 static char *tcp_getline_work (TCPSTREAM *stream,unsigned long *size,
160 			       long *contd)
161 {
162   unsigned long n;
163   char *s,*ret,c,d;
164   *contd = NIL;			/* assume no continuation */
165 				/* make sure have data */
166   if (!tcp_getdata (stream)) return NIL;
167   for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) {
168     d = *stream->iptr++;	/* slurp another character */
169     if ((c == '\015') && (d == '\012')) {
170       ret = (char *) fs_get (n--);
171       memcpy (ret,s,*size = n);	/* copy into a free storage string */
172       ret[n] = '\0';		/* tie off string with null */
173       return ret;
174     }
175   }
176 				/* copy partial string from buffer */
177   memcpy ((ret = (char *) fs_get (n)),s,*size = n);
178 				/* get more data from the net */
179   if (!tcp_getdata (stream)) fs_give ((void **) &ret);
180 				/* special case of newline broken by buffer */
181   else if ((c == '\015') && (*stream->iptr == '\012')) {
182     stream->iptr++;		/* eat the line feed */
183     stream->ictr--;
184     ret[*size = --n] = '\0';	/* tie off string with null */
185   }
186   else *contd = LONGT;		/* continuation needed */
187   return ret;
188 }
189 
190 /* TCP/IP receive buffer
191  * Accepts: TCP/IP stream
192  *	    size in bytes
193  *	    buffer to read into
194  * Returns: T if success, NIL otherwise
195  */
196 
tcp_getbuffer(TCPSTREAM * stream,unsigned long size,char * buffer)197 long tcp_getbuffer (TCPSTREAM *stream,unsigned long size,char *buffer)
198 {
199   unsigned long n;
200   char *bufptr = buffer;
201   while (size > 0) {		/* until request satisfied */
202     if (!tcp_getdata (stream)) return NIL;
203     n = min (size,stream->ictr);/* number of bytes to transfer */
204 				/* do the copy */
205     memcpy (bufptr,stream->iptr,(size_t) n);
206     bufptr += n;		/* update pointer */
207     stream->iptr +=n;
208     size -= n;			/* update # of bytes to do */
209     stream->ictr -=n;
210   }
211   bufptr[0] = '\0';		/* tie off string */
212   return T;
213 }
214 
215 
216 /* TCP/IP receive data
217  * Accepts: TCP/IP stream
218  * Returns: T if success, NIL otherwise
219  */
220 
tcp_getdata(TCPSTREAM * stream)221 long tcp_getdata (TCPSTREAM *stream)
222 {
223   int status;
224   if (!stream->tcps) return NIL;/* no-no nuked socket */
225   while (stream->ictr < 1) {	/* if buffer empty, block for input and read */
226     if (!_ip_delay1 (stream->tcps,600,NULL,&status))
227       stream->ictr = sock_fastread (stream->tcps,
228 				    stream->iptr = stream->ibuf,BUFLEN);
229     else if (status == 1) {	/* nuke the socket if closed */
230       sock_close (stream->tcps);
231       fs_give ((void **) &stream->tcps);
232       return NIL;
233     }
234   }
235   return T;
236 }
237 
238 /* TCP/IP send string as record
239  * Accepts: TCP/IP stream
240  * Returns: T if success else NIL
241  */
242 
tcp_soutr(TCPSTREAM * stream,char * string)243 long tcp_soutr (TCPSTREAM *stream,char *string)
244 {
245 				/* output the cruft */
246   sock_puts (stream->tcps,string);
247   return T;			/* all done */
248 }
249 
250 
251 /* TCP/IP send string
252  * Accepts: TCP/IP stream
253  *	    string pointer
254  *	    byte count
255  * Returns: T if success else NIL
256  */
257 
tcp_sout(TCPSTREAM * stream,char * string,unsigned long size)258 long tcp_sout (TCPSTREAM *stream,char *string,unsigned long size)
259 {
260   sock_write (stream->tcps,string,(int) size);
261   return T;
262 }
263 
264 
265 /* TCP/IP close
266  * Accepts: TCP/IP stream
267  */
268 
tcp_close(TCPSTREAM * stream)269 void tcp_close (TCPSTREAM *stream)
270 {
271   if (stream->tcps){ 		/* nuke the socket */
272     sock_close (stream->tcps);
273     _ip_delay2 (stream->tcps,0,NULL,NULL);
274   }
275   fs_give ((void **) &stream->tcps);
276 				/* flush host names */
277   fs_give ((void **) &stream->host);
278   fs_give ((void **) &stream->localhost);
279   fs_give ((void **) &stream);	/* flush the stream */
280 }
281 
282 /* TCP/IP get host name
283  * Accepts: TCP/IP stream
284  * Returns: host name for this stream
285  */
286 
tcp_host(TCPSTREAM * stream)287 char *tcp_host (TCPSTREAM *stream)
288 {
289   return stream->host;		/* return host name */
290 }
291 
292 
293 /* TCP/IP get remote host name
294  * Accepts: TCP/IP stream
295  * Returns: host name for this stream
296  */
297 
tcp_remotehost(TCPSTREAM * stream)298 char *tcp_remotehost (TCPSTREAM *stream)
299 {
300   return stream->host;		/* return host name */
301 }
302 
303 
304 /* TCP/IP return port for this stream
305  * Accepts: TCP/IP stream
306  * Returns: port number for this stream
307  */
308 
tcp_port(TCPSTREAM * stream)309 unsigned long tcp_port (TCPSTREAM *stream)
310 {
311   return stream->port;		/* return port number */
312 }
313 
314 
315 /* TCP/IP get local host name
316  * Accepts: TCP/IP stream
317  * Returns: local host name
318  */
319 
tcp_localhost(TCPSTREAM * stream)320 char *tcp_localhost (TCPSTREAM *stream)
321 {
322   return stream->localhost;	/* return local host name */
323 }
324 
325 
326 /* TCP/IP return canonical form of host name
327  * Accepts: host name
328  * Returns: canonical form of host name
329  */
330 
tcp_canonical(char * name)331 char *tcp_canonical (char *name)
332 {
333   return name;
334 }
335 
336 
337 /* TCP/IP get client host name (server calls only)
338  * Returns: client host name
339  */
340 
tcp_clienthost()341 char *tcp_clienthost ()
342 {
343   return "UNKNOWN";
344 }
345