/* TN5250 - An implementation of the 5250 telnet protocol.
* Copyright (C) 1997 Michael Madore
*
* This file is part of TN5250.
*
* TN5250 is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1, or (at your option)
* any later version.
*
* TN5250 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this software; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307 USA
*
*/
#include "tn5250-private.h"
/* External declarations of initializers for each type of stream. */
extern int tn5250_telnet_stream_init (Tn5250Stream *This);
extern int tn3270_telnet_stream_init (Tn5250Stream *This);
#ifdef HAVE_LIBSSL
extern int tn5250_ssl_stream_init (Tn5250Stream *This);
#endif
#ifndef NDEBUG
extern int tn5250_debug_stream_init (Tn5250Stream *This);
#endif
/* This structure and the stream_types[] array defines what types of
* streams we can create. */
struct _Tn5250StreamType {
const char *prefix;
int (* init) (Tn5250Stream *This);
};
typedef struct _Tn5250StreamType Tn5250StreamType;
static const Tn5250StreamType stream_types[] = {
#ifndef NDEBUG
{ "debug:", tn5250_debug_stream_init },
#endif
{ "telnet:", tn5250_telnet_stream_init },
{ "tn5250:", tn5250_telnet_stream_init },
#ifdef HAVE_LIBSSL
{ "ssl:", tn5250_ssl_stream_init },
{ "telnet-ssl:", tn5250_ssl_stream_init },
{ "telnets:", tn5250_ssl_stream_init },
#endif
{ NULL, NULL }
};
static void streamInit(Tn5250Stream *This, long timeout)
{
This->options = 0;
This->status = 0;
This->config = NULL;
This->connect = NULL;
This->disconnect = NULL;
This->handle_receive = NULL;
This->send_packet = NULL;
This->destroy = NULL;
This->record_count = 0;
This->records = This->current_record = NULL;
This->sockfd = (SOCKET_TYPE) - 1;
This->msec_wait = timeout;
This->streamtype = TN5250_STREAM;
This->rcvbufpos = 0;
This->rcvbuflen = -1;
tn5250_buffer_init(&(This->sb_buf));
}
/****f* lib5250/tn5250_stream_open
* NAME
* tn5250_stream_open
* SYNOPSIS
* ret = tn5250_stream_open (to);
* INPUTS
* const char * to - `URL' of host to connect to.
* Tn5250Config * config - config to associate w/stream
* DESCRIPTION
* Opens a 5250 stream to the specified host. URL is of the format
* [protocol]:host:[port], where protocol is currently one of the following:
*
* telnet - connect using tn5250 protocol
* tn5250 - connect using tn5250 protocol
* debug - read recorded session from debug file
*
* This is maintained by a protocol -> function mapping. Each protocol has
* an associated function which is responsible for initializing the stream.
* Stream initialization sets up protocol specific functions to handle
* communication with the host system.
*
* The next protocol to add is SNA. This will allow the emulator to use
* APPC (LU 6.2) to establish a session with the AS/400.
*****/
Tn5250Stream *tn5250_stream_open (const char *to, Tn5250Config *config)
{
Tn5250Stream *This = tn5250_new(Tn5250Stream, 1);
const Tn5250StreamType *iter;
const char *postfix;
int ret;
if (This != NULL) {
streamInit(This, 0);
if (config != NULL)
tn5250_stream_config(This, config);
/* Figure out the stream type. */
iter = stream_types;
while (iter->prefix != NULL) {
if (strlen (to) >= strlen(iter->prefix)
&& !memcmp (iter->prefix, to, strlen (iter->prefix))) {
/* Found the stream type, initialize it. */
ret = (* (iter->init)) (This);
if (ret != 0) {
tn5250_stream_destroy (This);
return NULL;
}
break;
}
iter++;
}
/* If we haven't found a type, assume telnet. */
if (iter->prefix == NULL) {
ret = tn5250_telnet_stream_init (This);
if (ret != 0) {
tn5250_stream_destroy (This);
return NULL;
}
postfix = to;
} else
postfix = to + strlen (iter->prefix);
/* Connect */
ret = (* (This->connect)) (This, postfix);
if (ret == 0)
return This;
tn5250_stream_destroy (This);
}
return NULL;
}
/****f* lib5250/tn5250_stream_host
* NAME
* tn5250_stream_host
* SYNOPSIS
* ret = tn5250_stream_host (masterSock);
* INPUTS
* SOCKET_TYPE masterSock - Master socket
* DESCRIPTION
* DOCUMENT ME!!!
*****/
Tn5250Stream *tn5250_stream_host (SOCKET_TYPE masterfd, long timeout,
int streamtype)
{
Tn5250Stream *This = tn5250_new(Tn5250Stream, 1);
int ret;
if (This != NULL) {
streamInit(This, timeout);
if(streamtype == TN5250_STREAM)
{
/* Assume telnet stream type. */
ret = tn5250_telnet_stream_init (This);
}
else
{
ret = tn3270_telnet_stream_init (This);
}
if (ret != 0) {
tn5250_stream_destroy (This);
return NULL;
}
/* Accept */
printf("masterfd = %d\n", masterfd);
ret = (* (This->accept)) (This, masterfd);
if (ret == 0)
return This;
tn5250_stream_destroy (This);
}
return NULL;
}
/****f* lib5250/tn5250_stream_config
* NAME
* tn5250_stream_config
* SYNOPSIS
* tn5250_stream_config (This, config);
* INPUTS
* Tn5250Stream * This - Stream object.
* Tn5250Config * config - Configuration object.
* DESCRIPTION
* Associates a stream with a configuration object. The stream uses the
* configuration object at run time to determine how to operate.
*****/
int tn5250_stream_config (Tn5250Stream *This, Tn5250Config *config)
{
/* Always reference before unreferencing, in case it's the same
* object. */
tn5250_config_ref (config);
if (This->config != NULL)
tn5250_config_unref (This->config);
This->config = config;
return 0;
}
/****f* lib5250/tn5250_stream_destroy
* NAME
* tn5250_stream_destroy
* SYNOPSIS
* tn5250_stream_destroy (This);
* INPUTS
* Tn5250Stream * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
void tn5250_stream_destroy(Tn5250Stream * This)
{
/* Call particular stream type's destroy handler. */
if (This->destroy)
(* (This->destroy)) (This);
/* Free the environment. */
if (This->config != NULL)
tn5250_config_unref (This->config);
tn5250_buffer_free(&(This->sb_buf));
tn5250_record_list_destroy(This->records);
free(This);
}
/****f* lib5250/tn5250_stream_get_record
* NAME
* tn5250_stream_get_record
* SYNOPSIS
* ret = tn5250_stream_get_record (This);
* INPUTS
* Tn5250Stream * This -
* DESCRIPTION
* DOCUMENT ME!!!
*****/
Tn5250Record *tn5250_stream_get_record(Tn5250Stream * This)
{
Tn5250Record *record;
int offset;
record = This->records;
TN5250_ASSERT(This->record_count >= 1);
TN5250_ASSERT(record != NULL);
This->records = tn5250_record_list_remove(This->records, record);
This->record_count--;
if(This->streamtype == TN5250_STREAM)
{
TN5250_ASSERT(tn5250_record_length(record)>= 10);
offset = 6 + tn5250_record_data(record)[6];
}
else
{
offset = 0;
}
TN5250_LOG(("tn5250_stream_get_record: offset = %d\n", offset));
tn5250_record_set_cur_pos(record, offset);
return record;
}
/****f* lib5250/tn5250_stream_setenv
* NAME
* tn5250_stream_setenv
* SYNOPSIS
* tn5250_stream_setenv (This, name, value);
* INPUTS
* Tn5250Stream * This -
* const char * name -
* const char * value -
* DESCRIPTION
* Set an 'environment' string. This is made to look like setenv().
*****/
void tn5250_stream_setenv(Tn5250Stream * This, const char *name, const char *value)
{
char *name_buf;
if (This->config == NULL) {
This->config = tn5250_config_new ();
TN5250_ASSERT (This->config != NULL);
}
name_buf = (char*)malloc (strlen (name) + 10);
strcpy (name_buf, "env.");
strcat (name_buf, name);
tn5250_config_set (This->config, name_buf, value);
free (name_buf);
}
/****f* lib5250/tn5250_stream_getenv
* NAME
* tn5250_stream_getenv
* SYNOPSIS
* ret = tn5250_stream_getenv (This, name);
* INPUTS
* Tn5250Stream * This -
* const char * name -
* DESCRIPTION
* Retrieve the value of a 5250 environment string.
*****/
const char *tn5250_stream_getenv(Tn5250Stream * This, const char *name)
{
char *name_buf;
const char *val;
if (This->config == NULL)
return NULL;
name_buf = (char*)malloc (strlen (name) + 10);
strcpy (name_buf, "env.");
strcat (name_buf, name);
val = tn5250_config_get (This->config, name_buf);
free (name_buf);
return val;
}
/****f* lib5250/tn5250_stream_unsetenv
* NAME
* tn5250_stream_unsetenv
* SYNOPSIS
* tn5250_stream_unsetenv (This, name);
* INPUTS
* Tn5250Stream * This -
* const char * name -
* DESCRIPTION
* Unset a 5250 environment string.
*****/
void tn5250_stream_unsetenv(Tn5250Stream * This, const char *name)
{
char *name_buf;
if (This->config == NULL)
return; /* Nothing to unset. */
name_buf = (char*)malloc (strlen (name) + 10);
strcpy (name_buf, "env.");
strcat (name_buf, name);
tn5250_config_unset (This->config, name_buf);
free (name_buf);
}
int tn5250_stream_socket_handle (Tn5250Stream *This)
{
return (int) This->sockfd;
}
/* vi:set sts=3 sw=3: */
syntax highlighted by Code2HTML, v. 0.9.1