1 /* TN5250 - An implementation of the 5250 telnet protocol.
2  * Copyright (C) 1997-2008 Michael Madore
3  *
4  * This file is part of TN5250.
5  *
6  * TN5250 is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1, or (at your option)
9  * any later version.
10  *
11  * TN5250 is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this software; see the file COPYING.  If not, write to
18  * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
19  * Boston, MA 02111-1307 USA
20  *
21  */
22 #include "tn5250-private.h"
23 
24 /* External declarations of initializers for each type of stream. */
25 extern int tn5250_telnet_stream_init (Tn5250Stream *This);
26 extern int tn3270_telnet_stream_init (Tn5250Stream *This);
27 #ifdef HAVE_LIBSSL
28 extern int tn5250_ssl_stream_init (Tn5250Stream *This);
29 #endif
30 #ifndef NDEBUG
31 extern int tn5250_debug_stream_init (Tn5250Stream *This);
32 #endif
33 
34 /* This structure and the stream_types[] array defines what types of
35  * streams we can create. */
36 struct _Tn5250StreamType {
37    const char *prefix;
38    int (* init) (Tn5250Stream *This);
39 };
40 
41 typedef struct _Tn5250StreamType Tn5250StreamType;
42 
43 static const Tn5250StreamType stream_types[] = {
44 #ifndef NDEBUG
45    { "debug:", tn5250_debug_stream_init },
46 #endif
47    { "telnet:", tn5250_telnet_stream_init },
48    { "tn5250:", tn5250_telnet_stream_init },
49 #ifdef HAVE_LIBSSL
50    { "ssl:", tn5250_ssl_stream_init },
51    { "telnet-ssl:", tn5250_ssl_stream_init },
52    { "telnets:", tn5250_ssl_stream_init },
53 #endif
54    { NULL, NULL }
55 };
56 
streamInit(Tn5250Stream * This,long timeout)57 static void streamInit(Tn5250Stream *This, long timeout)
58 {
59   This->options = 0;
60   This->status = 0;
61   This->config = NULL;
62   This->connect = NULL;
63   This->disconnect = NULL;
64   This->handle_receive = NULL;
65   This->send_packet = NULL;
66   This->destroy = NULL;
67   This->record_count = 0;
68   This->records = This->current_record = NULL;
69   This->sockfd = (SOCKET_TYPE) - 1;
70   This->msec_wait = timeout;
71   This->streamtype = TN5250_STREAM;
72   This->rcvbufpos = 0;
73   This->rcvbuflen = -1;
74   tn5250_buffer_init(&(This->sb_buf));
75 }
76 
77 /****f* lib5250/tn5250_stream_open
78  * NAME
79  *    tn5250_stream_open
80  * SYNOPSIS
81  *    ret = tn5250_stream_open (to);
82  * INPUTS
83  *    const char *         to         - `URL' of host to connect to.
84  *    Tn5250Config     *   config     - config to associate w/stream
85  * DESCRIPTION
86  *    Opens a 5250 stream to the specified host.  URL is of the format
87  *    [protocol]:host:[port], where protocol is currently one of the following:
88  *
89  *       telnet - connect using tn5250 protocol
90  *       tn5250 - connect using tn5250 protocol
91  *       debug  - read recorded session from debug file
92  *
93  *    This is maintained by a protocol -> function mapping.  Each protocol has
94  *    an associated function which is responsible for initializing the stream.
95  *    Stream initialization sets up protocol specific functions to handle
96  *    communication with the host system.
97  *
98  *    The next protocol to add is SNA.  This will allow the emulator to use
99  *    APPC (LU 6.2) to establish a session with the AS/400.
100  *****/
tn5250_stream_open(const char * to,Tn5250Config * config)101 Tn5250Stream *tn5250_stream_open (const char *to, Tn5250Config *config)
102 {
103    Tn5250Stream *This = tn5250_new(Tn5250Stream, 1);
104    const Tn5250StreamType *iter;
105    const char *postfix;
106    int ret;
107 
108    if (This != NULL) {
109 
110       streamInit(This, 0);
111 
112       if (config != NULL)
113            tn5250_stream_config(This, config);
114 
115       /* Figure out the stream type. */
116       iter = stream_types;
117       while (iter->prefix != NULL) {
118 	 if (strlen (to) >= strlen(iter->prefix)
119 	       && !memcmp (iter->prefix, to, strlen (iter->prefix))) {
120 	    /* Found the stream type, initialize it. */
121 	    ret = (* (iter->init)) (This);
122 	    if (ret != 0) {
123 	       tn5250_stream_destroy (This);
124 	       return NULL;
125 	    }
126 	    break;
127 	 }
128 	 iter++;
129       }
130 
131       /* If we haven't found a type, assume telnet. */
132       if (iter->prefix == NULL) {
133 	 ret = tn5250_telnet_stream_init (This);
134 	 if (ret != 0) {
135 	    tn5250_stream_destroy (This);
136 	    return NULL;
137 	 }
138 	 postfix = to;
139       } else
140 	 postfix = to + strlen (iter->prefix);
141 
142       /* Connect */
143       ret = (* (This->connect)) (This, postfix);
144       if (ret == 0)
145 	 return This;
146 
147       tn5250_stream_destroy (This);
148    }
149    return NULL;
150 }
151 
152 /****f* lib5250/tn5250_stream_host
153  * NAME
154  *    tn5250_stream_host
155  * SYNOPSIS
156  *    ret = tn5250_stream_host (masterSock);
157  * INPUTS
158  *    SOCKET_TYPE	masterSock	-	Master socket
159  * DESCRIPTION
160  *    DOCUMENT ME!!!
161  *****/
tn5250_stream_host(SOCKET_TYPE masterfd,long timeout,int streamtype)162 Tn5250Stream *tn5250_stream_host (SOCKET_TYPE masterfd, long timeout,
163 				  int streamtype)
164 {
165    Tn5250Stream *This = tn5250_new(Tn5250Stream, 1);
166    int ret;
167 
168    if (This != NULL) {
169       streamInit(This, timeout);
170       if(streamtype == TN5250_STREAM)
171 	{
172 	  /* Assume telnet stream type. */
173 	  ret = tn5250_telnet_stream_init (This);
174 	}
175       else
176 	{
177 	  ret = tn3270_telnet_stream_init (This);
178 	}
179       if (ret != 0) {
180          tn5250_stream_destroy (This);
181          return NULL;
182       }
183       /* Accept */
184       printf("masterfd = %d\n", masterfd);
185       ret = (* (This->accept)) (This, masterfd);
186       if (ret == 0)
187 	 return This;
188 
189       tn5250_stream_destroy (This);
190    }
191    return NULL;
192 }
193 
194 
195 /****f* lib5250/tn5250_stream_config
196  * NAME
197  *    tn5250_stream_config
198  * SYNOPSIS
199  *    tn5250_stream_config (This, config);
200  * INPUTS
201  *    Tn5250Stream *       This       - Stream object.
202  *    Tn5250Config *       config     - Configuration object.
203  * DESCRIPTION
204  *    Associates a stream with a configuration object.  The stream uses the
205  *    configuration object at run time to determine how to operate.
206  *****/
tn5250_stream_config(Tn5250Stream * This,Tn5250Config * config)207 int tn5250_stream_config (Tn5250Stream *This, Tn5250Config *config)
208 {
209    /* Always reference before unreferencing, in case it's the same
210     * object. */
211    tn5250_config_ref (config);
212    if (This->config != NULL)
213       tn5250_config_unref (This->config);
214    This->config = config;
215    return 0;
216 }
217 
218 /****f* lib5250/tn5250_stream_destroy
219  * NAME
220  *    tn5250_stream_destroy
221  * SYNOPSIS
222  *    tn5250_stream_destroy (This);
223  * INPUTS
224  *    Tn5250Stream *       This       -
225  * DESCRIPTION
226  *    DOCUMENT ME!!!
227  *****/
tn5250_stream_destroy(Tn5250Stream * This)228 void tn5250_stream_destroy(Tn5250Stream * This)
229 {
230    /* Call particular stream type's destroy handler. */
231    if (This->destroy)
232       (* (This->destroy)) (This);
233 
234    /* Free the environment. */
235    if (This->config != NULL)
236       tn5250_config_unref (This->config);
237    tn5250_buffer_free(&(This->sb_buf));
238    tn5250_record_list_destroy(This->records);
239    free(This);
240 }
241 
242 /****f* lib5250/tn5250_stream_get_record
243  * NAME
244  *    tn5250_stream_get_record
245  * SYNOPSIS
246  *    ret = tn5250_stream_get_record (This);
247  * INPUTS
248  *    Tn5250Stream *       This       -
249  * DESCRIPTION
250  *    DOCUMENT ME!!!
251  *****/
tn5250_stream_get_record(Tn5250Stream * This)252 Tn5250Record *tn5250_stream_get_record(Tn5250Stream * This)
253 {
254    Tn5250Record *record;
255    int offset;
256 
257    record = This->records;
258    TN5250_ASSERT(This->record_count >= 1);
259    TN5250_ASSERT(record != NULL);
260 
261    This->records = tn5250_record_list_remove(This->records, record);
262    This->record_count--;
263 
264    if(This->streamtype == TN5250_STREAM)
265      {
266        TN5250_ASSERT(tn5250_record_length(record)>= 10);
267        offset = 6 + tn5250_record_data(record)[6];
268      }
269    else
270      {
271        offset = 0;
272      }
273 
274    TN5250_LOG(("tn5250_stream_get_record: offset = %d\n", offset));
275    tn5250_record_set_cur_pos(record, offset);
276 
277    return record;
278 }
279 
280 /****f* lib5250/tn5250_stream_setenv
281  * NAME
282  *    tn5250_stream_setenv
283  * SYNOPSIS
284  *    tn5250_stream_setenv (This, name, value);
285  * INPUTS
286  *    Tn5250Stream *       This       -
287  *    const char *         name       -
288  *    const char *         value      -
289  * DESCRIPTION
290  *    Set an 'environment' string.  This is made to look like setenv().
291  *****/
tn5250_stream_setenv(Tn5250Stream * This,const char * name,const char * value)292 void tn5250_stream_setenv(Tn5250Stream * This, const char *name, const char *value)
293 {
294    char *name_buf;
295    if (This->config == NULL) {
296       This->config = tn5250_config_new ();
297       TN5250_ASSERT (This->config != NULL);
298    }
299    name_buf = (char*)malloc (strlen (name) + 10);
300    strcpy (name_buf, "env.");
301    strcat (name_buf, name);
302    tn5250_config_set (This->config, name_buf, value);
303    free (name_buf);
304 }
305 
306 /****f* lib5250/tn5250_stream_getenv
307  * NAME
308  *    tn5250_stream_getenv
309  * SYNOPSIS
310  *    ret = tn5250_stream_getenv (This, name);
311  * INPUTS
312  *    Tn5250Stream *       This       -
313  *    const char *         name       -
314  * DESCRIPTION
315  *    Retrieve the value of a 5250 environment string.
316  *****/
tn5250_stream_getenv(Tn5250Stream * This,const char * name)317 const char *tn5250_stream_getenv(Tn5250Stream * This, const char *name)
318 {
319    char *name_buf;
320    const char *val;
321 
322    if (This->config == NULL)
323       return NULL;
324 
325    name_buf = (char*)malloc (strlen (name) + 10);
326    strcpy (name_buf, "env.");
327    strcat (name_buf, name);
328    val = tn5250_config_get (This->config, name_buf);
329    free (name_buf);
330    return val;
331 }
332 
333 /****f* lib5250/tn5250_stream_unsetenv
334  * NAME
335  *    tn5250_stream_unsetenv
336  * SYNOPSIS
337  *    tn5250_stream_unsetenv (This, name);
338  * INPUTS
339  *    Tn5250Stream *       This       -
340  *    const char *         name       -
341  * DESCRIPTION
342  *    Unset a 5250 environment string.
343  *****/
tn5250_stream_unsetenv(Tn5250Stream * This,const char * name)344 void tn5250_stream_unsetenv(Tn5250Stream * This, const char *name)
345 {
346    char *name_buf;
347    if (This->config == NULL)
348       return; /* Nothing to unset. */
349 
350    name_buf = (char*)malloc (strlen (name) + 10);
351    strcpy (name_buf, "env.");
352    strcat (name_buf, name);
353    tn5250_config_unset (This->config, name_buf);
354    free (name_buf);
355 }
356 
tn5250_stream_socket_handle(Tn5250Stream * This)357 int tn5250_stream_socket_handle (Tn5250Stream *This)
358 {
359    return (int) This->sockfd;
360 }
361 
362 /* vi:set sts=3 sw=3: */
363