/* 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"
#include "transmaps.h"
static char mapfix[256];
static char mapfix2[256];
static char mapfix3[256];
static char mapfix4[256];
#ifndef WIN32
/****f* lp5250d/tn5250_closeall
* NAME
* tn5250_closeall
* SYNOPSIS
* tn5250_closeall (fd);
* INPUTS
* int fd - The starting file descriptor.
* DESCRIPTION
* Closes all file descriptors >= a specified value.
*****/
void tn5250_closeall(int fd)
{
int fdlimit = sysconf(_SC_OPEN_MAX);
while (fd < fdlimit)
close(fd++);
}
/*
Signal handler for SIGCHLD. We use waitpid instead of wait, since there
is no way to tell wait not to block if there are still non-terminated child
processes.
*/
void
sig_child(int signum)
{
int pid;
int status;
while( pid = waitpid(-1, &status, WNOHANG) > 0);
return;
}
/****f* lp5250d/tn5250_daemon
* NAME
* tn5250_daemon
* SYNOPSIS
* ret = tn5250_daemon (nochdir, noclose);
* INPUTS
* int nochdir - 0 to perform chdir.
* int noclose - 0 to close all file handles.
* DESCRIPTION
* Detach process from user and disappear into the background
* returns -1 on failure, but you can't do much except exit in that
* case since we may already have forked. Believed to work on all
* Posix systems.
*****/
int tn5250_daemon(int nochdir, int noclose, int ignsigcld)
{
struct sigaction sa;
switch (fork())
{
case 0: break;
case -1: return -1;
default: _exit(0); /* exit the original process */
}
if (setsid() < 0) /* shoudn't fail */
return -1;
/* dyke out this switch if you want to acquire a control tty in */
/* the future -- not normally advisable for daemons */
switch (fork())
{
case 0: break;
case -1: return -1;
default: _exit(0);
}
if (!nochdir)
chdir("/");
if (!noclose)
{
tn5250_closeall(0);
open("/dev/null",O_RDWR);
dup(0); dup(0);
}
umask(0);
if(ignsigcld) {
sa.sa_handler = sig_child;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
#ifdef SIGCHLD
sigaction(SIGCHLD, &sa, NULL);
#else
#ifdef SIGCLD
sigaction(SIGCLD, &sa, NULL);
#endif
#endif
}
return 0;
}
#endif /* ifndef WIN32 */
int
tn5250_make_socket (unsigned short int port)
{
int sock;
int on = 1;
struct sockaddr_in name;
u_long ioctlarg = 0;
/* Create the socket. */
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0)
{
#ifndef WIN32
syslog(LOG_INFO, "socket: %s\n", strerror(errno));
#endif
exit (EXIT_FAILURE);
}
/* Give the socket a name. */
name.sin_family = AF_INET;
name.sin_port = htons (port);
name.sin_addr.s_addr = htonl (INADDR_ANY);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
TN_IOCTL(sock, FIONBIO, &ioctlarg);
if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
{
#ifndef WIN32
syslog(LOG_INFO, "bind: %s\n", strerror(errno));
#endif
exit (EXIT_FAILURE);
}
return sock;
}
/****f* lib5250/tn5250_char_map_to_remote
* NAME
* tn5250_char_map_to_remote
* SYNOPSIS
* ret = tn5250_char_map_to_remote (map,ascii);
* INPUTS
* Tn5250Char ascii - The local character to translate.
* DESCRIPTION
* Translate the specified character from local to remote.
*****/
Tn5250Char tn5250_char_map_to_remote(Tn5250CharMap *map, Tn5250Char ascii)
{
return map->to_remote_map[ascii];
}
/****f* lib5250/tn5250_char_map_to_local
* NAME
* tn5250_char_map_to_local
* SYNOPSIS
* local = tn5250_char_map_to_local (map, ebcdic);
* INPUTS
* Tn5250Char ebcdic - The remote character to translate.
* DESCRIPTION
* Translate the specified character from remote character to local.
*****/
Tn5250Char tn5250_char_map_to_local(Tn5250CharMap *map, Tn5250Char ebcdic)
{
switch (ebcdic) {
case 0x1C:
return '*'; /* This should be an overstriken asterisk (DUP) */
case 0:
return ' ';
default:
return map->to_local_map[ebcdic];
}
}
/****f* lib5250/tn5250_char_map_new
* NAME
* tn5250_char_map_new
* SYNOPSIS
* cmap = tn5250_char_map_new ("37");
* INPUTS
* const char * map - Name of the character translation map.
* DESCRIPTION
* Create a new translation map.
* NOTES
* Translation maps are currently statically allocated, although you should
* call tn5250_char_map_destroy (a no-op) for future compatibility.
*****/
Tn5250CharMap *tn5250_char_map_new (const char *map)
{
Tn5250CharMap *t;
/* XXX: HACK: These characters were reported wrong in transmaps.h.
Since that's a generated file, I'm overriding them here -SCK */
TN5250_LOG(("tn5250_char_map_new: map = \"%s\"\n", map));
if (!strcmp(map, "870") || !strcmp(map, "win870")) {
TN5250_LOG(("tn5250_char_map_new: Installing 870 workaround\n"));
memcpy(mapfix, windows_1250_to_ibm870, sizeof(mapfix));
memcpy(mapfix2, ibm870_to_windows_1250, sizeof(mapfix2));
memcpy(mapfix3, iso_8859_2_to_ibm870, sizeof(mapfix3));
memcpy(mapfix4, ibm870_to_iso_8859_2, sizeof(mapfix4));
mapfix[142] = 184;
mapfix[143] = 185;
mapfix[158] = 182;
mapfix[159] = 183;
mapfix[163] = 186;
mapfix[202] = 114;
mapfix[234] = 82;
mapfix2[82] = 234;
mapfix2[114] = 202;
mapfix2[182] = 158;
mapfix2[183] = 159;
mapfix2[184] = 142;
mapfix2[185] = 143;
mapfix2[186] = 163;
mapfix3[163] = 186;
mapfix3[172] = 185;
mapfix3[188] = 183;
mapfix3[202] = 114;
mapfix3[234] = 82;
mapfix4[82] = 234;
mapfix4[114] = 202;
mapfix4[183] = 188;
mapfix4[185] = 172;
mapfix4[186] = 163;
for (t = tn5250_transmaps; t->name; t++) {
if (!strcmp(t->name, "win870")) {
t->to_remote_map = (const char *)mapfix;
t->to_local_map = (const char *)mapfix2;
TN5250_LOG(("Workaround installed for map \"win870\"\n"));
}
else if (!strcmp(t->name, "870")) {
t->to_remote_map = (const char *)mapfix3;
t->to_local_map = (const char *)mapfix4;
TN5250_LOG(("Workaround installed for map \"870\"\n"));
}
}
}
/* Under Windows, we'll try the "winXXX" maps first, then fall back
to the standard (unix) versions */
#ifdef WIN32
{
char winmap[10];
_snprintf(winmap, sizeof(winmap)-1, "win%s", map);
for (t = tn5250_transmaps; t->name; t++) {
if (strcmp(t->name, winmap) == 0) {
TN5250_LOG(("Using map %s\n", t->name));
return t;
}
}
}
#endif
for (t = tn5250_transmaps; t->name; t++) {
if (strcmp(t->name, map) == 0)
return t;
}
return NULL;
}
/****f* lib5250/tn5250_char_map_destroy
* NAME
* tn5250_char_map_destroy
* SYNOPSIS
* tn5250_char_map_destroy (map);
* INPUTS
* Tn5250CharMap * map - The character map to destroy.
* DESCRIPTION
* Frees the character map's resources.
*****/
void tn5250_char_map_destroy (Tn5250CharMap *map)
{
/* NOOP */
}
/****f* lib5250/tn5250_char_map_printable_p
* NAME
* tn5250_char_map_printable_p
* SYNOPSIS
* if (tn5250_char_map_printable_p (map,ec))
* ;
* INPUTS
* Tn5250CharMap * map - the character map to use.
* Tn5250Char ec - the character to test.
* DESCRIPTION
* Determines whether the specified character is printable, which means
* either it is a displayable EBCDIC character, an ideographic control
* character, a NUL, or a few other odds and ends.
* SOURCE
*/
int tn5250_char_map_printable_p(Tn5250CharMap *map, Tn5250Char data)
{
switch (data)
{
/*
Ideographic Shift-In and Shift-Out.
case 0x0e:
case 0x0f:
*/
default:
break;
}
return 1;
}
/*******/
/****f* lib5250/tn5250_char_map_attribute_p
* NAME
* tn5250_char_map_attribute_p
* SYNOPSIS
* ret = tn5250_char_map_attribute_p (map,ec);
* INPUTS
* Tn5250CharMap * map - the translation map to use.
* Tn5250Char ec - the character to test.
* DESCRIPTION
* Determines whether the character is a 5250 attribute.
*****/
int tn5250_char_map_attribute_p(Tn5250CharMap *map, Tn5250Char data)
{
return ((data & 0xE0) == 0x20);
}
#ifndef NDEBUG
FILE *tn5250_logfile = NULL;
/****f* lib5250/tn5250_log_open
* NAME
* tn5250_log_open
* SYNOPSIS
* tn5250_log_open (fname);
* INPUTS
* const char * fname - Filename of tracefile.
* DESCRIPTION
* Opens the debug tracefile for this session.
*****/
void tn5250_log_open(const char *fname)
{
if (tn5250_logfile != NULL)
fclose(tn5250_logfile);
tn5250_logfile = fopen(fname, "w");
if (tn5250_logfile == NULL) {
perror(fname);
exit(1);
}
/* FIXME: Write $TERM, version, and uname -a to the file. */
#ifndef WIN32
/* Set file mode to 0600 since it may contain passwords. */
fchmod(fileno(tn5250_logfile), 0600);
#endif
setbuf(tn5250_logfile, NULL);
}
/****f* lib5250/tn5250_log_close
* NAME
* tn5250_log_close
* SYNOPSIS
* tn5250_log_close ();
* INPUTS
* None
* DESCRIPTION
* Close the current tracefile if one is open.
*****/
void tn5250_log_close()
{
if (tn5250_logfile != NULL) {
fclose(tn5250_logfile);
tn5250_logfile = NULL;
}
}
/****f* lib5250/tn5250_log_printf
* NAME
* tn5250_log_printf
* SYNOPSIS
* tn5250_log_printf (fmt, );
* INPUTS
* const char * fmt -
* DESCRIPTION
* This is an internal function called by the TN5250_LOG() macro. Use
* the macro instead, since it can be conditionally compiled.
*****/
void tn5250_log_printf(const char *fmt,...)
{
va_list vl;
if (tn5250_logfile != NULL) {
va_start(vl, fmt);
vfprintf(tn5250_logfile, fmt, vl);
va_end(vl);
}
}
/****f* lib5250/tn5250_log_assert
* NAME
* tn5250_log_assert
* SYNOPSIS
* tn5250_log_assert (val, expr, file, line);
* INPUTS
* int val -
* char const * expr -
* char const * file -
* int line -
* DESCRIPTION
* This is an internal function called by the TN5250_ASSERT() macro. Use
* the macro instead, since it can be conditionally compiled.
*****/
void tn5250_log_assert(int val, char const *expr, char const *file, int line)
{
if (!val) {
tn5250_log_printf("\nAssertion %s failed at %s, line %d.\n", expr, file, line);
fprintf (stderr,"\nAssertion %s failed at %s, line %d.\n", expr, file, line);
abort ();
}
}
#endif /* NDEBUG */
/****f* lib5250/tn5250_parse_color
* NAME
* tn5250_parse_color
* SYNOPSIS
* tn5250_parse_color (config, "green", &red, &green, &blue);
* INPUTS
* Tn5250Config * config -
* const char * colorname -
* int * red -
* int * green -
* int * blue -
* DESCRIPTION
* This loads a color from the TN5250 config object, and then
* parses it into it's red, green, blue components.
*****/
int tn5250_parse_color(Tn5250Config *config, const char *colorname,
int *red, int *green, int *blue) {
const char *p;
char colorspec[16];
int r, g, b;
if ((p=tn5250_config_get(config, colorname)) == NULL) {
return -1;
}
strncpy(colorspec, p, sizeof(colorspec));
colorspec[sizeof(colorspec)-1] = '\0';
if (*colorspec != '#') {
if (!strcasecmp(colorspec, "white")) {
r = 255; g = 255; b = 255;
} else if (!strcasecmp(colorspec, "yellow")) {
r = 255; g = 255; b = 0;
} else if (!strcasecmp(colorspec, "lightmagenta")) {
r = 255; g = 0; b = 255;
} else if (!strcasecmp(colorspec, "lightred")) {
r = 255; g = 0; b = 0;
} else if (!strcasecmp(colorspec, "lightcyan")) {
r = 0; g = 255; b = 255;
} else if (!strcasecmp(colorspec, "lightgreen")) {
r = 0; g = 255; b = 0;
} else if (!strcasecmp(colorspec, "lightblue")) {
r = 0; g = 0; b = 255;
} else if (!strcasecmp(colorspec, "lightgray")) {
r = 192; g = 192; b = 192;
} else if (!strcasecmp(colorspec, "gray")) {
r = 128; g = 128; b = 128;
} else if (!strcasecmp(colorspec, "brown")) {
r = 128; g = 128; b = 0;
} else if (!strcasecmp(colorspec, "red")) {
r = 128; g = 0; b = 0;
} else if (!strcasecmp(colorspec, "cyan")) {
r = 0; g = 128; b = 128;
} else if (!strcasecmp(colorspec, "green")) {
r = 0; g = 128; b = 0;
} else if (!strcasecmp(colorspec, "blue")) {
r = 0; g = 0; b = 128;
} else if (!strcasecmp(colorspec, "black")) {
r = 0; g = 0; b = 0;
}
}
else {
if (strlen(colorspec) != 7)
return -1;
if (sscanf(&colorspec[1], "%02x%02x%02x", &r, &g, &b)!=3)
return -1;
}
*red = r;
*green = g;
*blue = b;
return 0;
}
/****f* lib5250/tn5250_setenv
* NAME
* tn5250_setenv
* SYNOPSIS
* tn5250_setenv ("TN5250_CCSID", "37", 1);
* INPUTS
* const char * name -
* const char * value -
* int overwrite -
* DESCRIPTION
* This works just like setenv(3), but setenv(3) doesn't
* exist on all systems.
*****/
int tn5250_setenv(const char *name, const char *value, int overwrite) {
char *strval;
int ret;
if (!overwrite)
if (getenv(name)!=NULL) return 0;
strval = malloc(strlen(name)+strlen(value)+2);
TN5250_ASSERT(strval!=NULL);
strcpy(strval, name);
strcat(strval, "=");
strcat(strval, value);
ret = putenv(strval);
/* free(strval) on some systems, it continues to use our memory,
so we should not free it... */
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1