Category : OS/2 Files
Archive   : APING12.ZIP
Filename : CPICPORT.C
*
* MODULE NAME: CPICPORT.C
*
* COPYRIGHTS:
* This module contains code made available by IBM
* Corporation on an AS IS basis. Any one receiving the
* module is considered to be licensed under IBM copyrights
* to use the IBM-provided source code in any way he or she
* deems fit, including copying it, compiling it, modifying
* it, and redistributing it, with or without
* modifications. No license under any IBM patents or
* patent applications is to be implied from this copyright
* license.
*
* A user of the module should understand that IBM cannot
* provide technical support for the module and will not be
* responsible for any consequences of use of the program.
*
* Any notices, including this one, are not to be removed
* from the module without the prior written consent of
* IBM.
*
* AUTHOR: Peter J. Schwaller
* VNET: PJS at RALVM6 Tie Line: 444-4376
* Internet: [email protected] (919) 254-4376
*
* FUNCTION: Contains procedures to that may have to be rewritten for
* different environments.
*
* AVAILABILITY:
* These sample programs and source are also available on
* CompuServe through the APPC Information Exchange. To get
* to the APPC forum just type 'GO APPC' from any CompuServe
* prompt. The samples are available in the Sample Programs
* library section. Just search on the keyword CPICPGMS to
* find all the samples in this series.
*
* Updates for the sample programs and support for many more
* CPI-C platforms will also be made available on CompuServe.
*
* RELATED FILES:
* CPICPORT.H
*
* PORTABILITY NOTES:
* This file is the home of all operating system specific
* functions. The following is a summary of the routines
* in this file and where they are used:
*
* write_output()
* displays a text string to normal output
*
* write_error()
* displays error text to error output
*
* write_log()
* logs text to an opened log file
* if the log file was not open, will display to error output
*
* display_message()
* Delivers a text message.
* Used by ATELLD.C.
*
* get_time()
* Returns time in milliseconds.
* Used by APING.C.
*
* alloc_cpic_buffer()
* Allocates the best memory buffer for CPI-C performance.
* Used by APING.C and APINGD.C.
*
* show_info()
* Displays an array of text strings.
* Used by all files with a main() function.
*
* get_machine_mode()
* For family API applications; determines whether we
* are running under OS/2 or DOS.
*
* get_password()
* Used to request that the user enter a password.
* If possible, the password will not display while the
* user types it.
* Used by CPICINIT.C
*
* execute_and_send_output()
* Execute the specified command and send the output back
* to the client side.
* This routine is called by AREXECD.C.
*
* do_exit()
* Exit properly for the environment. This is usually
* necessary for GUI environments.
*
* CHANGE HISTORY:
* Date Description
* 08/05/92 Version 2.31 of APING, ATELL and AREXEC released to CompuServe.
* This version was also distributed at the APPC/APPN Platform
* Developer's Conference held in Raleigh, NC.
* 08/13/92 Added the write_*() calls.
* Changed all printf and fprintf calls to use a write_*() call.
* 08/19/92 Added workaround for problem with system() returning non-null
* even when command succeeded. The fix is in DOS and FAPI
* versions of execute_and_send_output().
* 08/20/92 Fixed alloc_cpic_buffer() so it will use a shared buffer
* under OS/2 2.0.
* 08/23/92 Fixed extra rc definition for AS/400 definition of the
* execute_and_send_output() routine.
* 08/24/92 Version 2.32 released to CompuServe.
* 08/25/92 Changed DOS and AIX execute_and_send_output() to use the
* tempnam() function instead of the tmpnam() function. This
* results in tempfiles being written to the TMP directory.
* 09/22/92 Version 2.33 released to CompuServe.
*
*****************************************************************************/
/* if on OS/2, get the OS/2 include file
* needed for:
* DosAllocSeg
* DosAllocSharedMem
* DosCWait
* DosCreateThread
* DosDupHandle
* DosExecPgm
* DosGetMachineMode
* DosMakePipe
* DosRead
*/
#if defined(OS2) || defined(FAPI) || defined(OS2_20)
#define INCL_BASE
#include
#if defined(OS2)
/* specify the multitasking C runtime library for the Microsoft compiler */
#define _MT
#include
#endif
#endif
/* My CPI-C include file */
/* Hides CMC.H differences among platforms */
#include "cpiccmc.h"
#include "cpicerr.h"
/* Set up constant declarations */
#include "cpicdefs.h"
#include "cpicport.h"
/* standard C include files */
#include
#include
#include
#include
#if defined(OS2) || defined(DOS) || defined(FAPI)
#include
#endif
#ifndef AIX
#include
#else
#include
#endif
extern char ebcdic_to_ascii_table[];
extern char ascii_to_ebcdic_table[];
void write_error(char *fmt, ...)
{
/*=========================================================================
*
*=======================================================================*/
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
void write_output(char *fmt, ...)
{
/*=========================================================================
*
*=======================================================================*/
va_list args;
va_start(args, fmt);
vfprintf(stdout, fmt, args);
va_end(args);
}
void write_log(FILE * file, char *fmt, ...)
{
/*=========================================================================
*
*=======================================================================*/
va_list args;
va_start(args, fmt);
if (file == NULL) {
write_error(fmt, args);
} else {
vfprintf(file, fmt, args);
}
va_end(args);
}
/*
* display_message()
* delivers a text message
* used by ATELLD.C
*
* AIX
* Writes to the pts device that the specified user
* is logged onto.
*
* AS400
* Uses system() to call the AS/400 SNDMSG command to
* deliver the message to the specified user.
*
* MVS
* Uses system() to call the MVS SEND command to
* deliver the message to the specified user.
*
* VM
* If a userid is present, use system() to send the
* message using the TELL command. If no userid is
* present, display the message using write_output().
*
* default
* Uses C library functions to print the message.
*/
void
display_message(char * origin, char * dest_userid, char * message)
{
#if defined(AIX)
char timestamp[TIMELENGTH];
struct tm * newtime;
time_t ltime;
FILE * who_file;
FILE * ttyhandle;
char who_list[120];
char tty_name[120];
char user[80];
char tty[80];
int rc;
time(<ime);
newtime = localtime(<ime);
strcpy(timestamp, asctime(newtime));
/* eliminate new line character for display */
timestamp[strlen(timestamp)-1] = '\0';
if (dest_userid[0] != '\0') {
/* there was a user specified */
/* we'll need to get a tty name for that user! */
who_file = popen("who", "r");
if (who_file == NULL) {
write_error("Could not run the who command.\n");
tty_name[0] = '\0';
} else {
tty_name[0] = '\0';
while (fgets(who_list, sizeof(who_list)-1, who_file) != NULL) {
sscanf(who_list, "%s %s\n", user, tty);
if (strcmp(user, dest_userid) == 0) {
strcpy(tty_name, "/dev/");
strcat(tty_name, tty);
break;
}
} /* endwhile */
fclose(who_file);
}
} else {
strcpy(tty_name, "/dev/pts/1");
}
if (strlen(tty_name)) {
ttyhandle = fopen(tty_name, "w");
} else {
ttyhandle = NULL;
strcpy(tty_name, "User not found\n");
}
if (ttyhandle == NULL) {
write_error( "Could not open TTY: %s\n", tty_name);
ttyhandle = stderr;
}
fprintf(ttyhandle, "\n\nATELLD msg from %s ", origin);
if (dest_userid[0] != '\0') {
fprintf(ttyhandle, "to user %s ", dest_userid);
}
fprintf(ttyhandle, "on %s:", timestamp);
fprintf(ttyhandle, "\n\n %s\n\n",message);
#elif defined(OS400)
char buffer[MAX_MESSAGE_LENGTH + 100];
int result;
strcpy(buffer, "SNDMSG MSG('");
strcat(buffer, message);
strcat(buffer, "') TOUSR(");
strcat(buffer, dest_userid);
strcat(buffer, ")");
result = system(buffer);
#elif defined(MVS)
char buffer[MAX_MESSAGE_LENGTH + 100];
int result;
strcpy(buffer, "SEND '");
strcat(buffer, "Message from ");
strcat(buffer, origin);
strcat(buffer, " using ATELL: ");
strcat(buffer, message);
strcat(buffer, "' USER(");
strcat(buffer, dest_userid);
strcat(buffer, ")");
result = system(buffer);
#elif defined(VM)
char buffer[MAX_MESSAGE_LENGTH + 100];
int result;
if (dest_userid[0] != '\0') {
/* there was a user specified */
strcpy(buffer, "EXEC TELL ");
strcat(buffer, dest_userid);
strcat(buffer, " ");
strcat(buffer, "Message from ");
strcat(buffer, origin);
strcat(buffer, " using ATELL: ");
strcat(buffer, message);
result = system(buffer);
}
else {
char timestamp[TIMELENGTH];
struct tm * newtime;
time_t ltime;
time(<ime);
newtime = localtime(<ime);
strcpy(timestamp, asctime(newtime));
/* eliminate new line character for display */
timestamp[strlen(timestamp)-1] = '\0';
write_output("\n\n msg from %s ", origin);
if (dest_userid[0] != '\0') {
write_output("to user %s ", dest_userid);
}
write_output("on %s:", timestamp);
write_output("\n\n %s\n\n",message);
}
#else
char timestamp[TIMELENGTH];
struct tm * newtime;
time_t ltime;
time(<ime);
newtime = localtime(<ime);
strcpy(timestamp, asctime(newtime));
/* eliminate new line character for display */
timestamp[strlen(timestamp)-1] = '\0';
write_output("\n\n msg from %s ", origin);
if (dest_userid[0] != '\0') {
write_output("to user %s ", dest_userid);
}
write_output("on %s:", timestamp);
write_output("\n\n %s\n\n",message);
#endif
}
/*
* get_time()
* returns time in milliseconds
* used by APING.C
*
* OS/2 and DOS
* The C library routine clock() which returns milliseconds is used.
* Although the clock() routine is defined to return process CPU time,
* the returned value equals wall time in OS/2 and DOS.
*
* AIX
* Uses the gettimer() call which returns seconds and nanoseconds.
* These are converted to get a single value in milliseconds.
*
* default
* Uses the C library routine time() which returns the current
* time in seconds. This is multiplied times 1000 to return a
* value in milliseconds.
*/
unsigned long
get_time(void)
{
#if defined(OS2) || defined(FAPI) || defined(DOS)
/*
* clock() returns valid information on OS/2 and DOS since no distinction
* is made between process time and time of day.
*/
clock_t time;
time = clock();
return (time / (CLK_TCK / 1000));
#elif defined(AIX)
time_t ltime;
struct timestruc_t TimeStruct;
if (gettimer(TIMEOFDAY, &TimeStruct) == 0) {
return ((1000 * TimeStruct.tv_sec) + (TimeStruct.tv_nsec / 1000000));
} else {
time(<ime);
return 1000 * ltime;
}
#else
/*
* Other systems must use the time() calls to get the time of day in
* seconds. This results in very coarse timings.
*/
time_t ltime;
time(<ime);
return 1000 * ltime;
#endif
}
/*
* alloc_cpic_buffer()
* OS/2 can optimize performance if a special shared memory buffer is
* used as the data buffer on calls to CMSEND and CMRCV. To hide this
* special case from the calling program, this procedure should be
* called to allocate all CPI-C data buffers.
*
* OS/2 1.X
* returns a shared memory buffer allocated with DosAllocSeg
*
* OS/2 2.0
* returns a shared memory buffer allocated with DosAllocSharedMem
*
* default
* returns a memory buffer allocated with the C runtime malloc() call
*/
char CM_PTR
alloc_cpic_buffer (unsigned int size)
{
#if defined(OS2) || defined(FAPI) || defined(OS2_20)
#ifndef OS2_20
USHORT selector; /* selector from DosAllocSeg */
USHORT dos_rc; /* OS/2 return code */
char far *memory_pointer; /* return pointer to memory */
dos_rc = DosAllocSeg ((unsigned)size, /* size of memory to allocate */
(PSEL)&selector, /* returned: selector address */
(unsigned)1); /* shared, unmamed segment */
if (dos_rc == 0) { /* Non-zero OS/2 return code? */
SELECTOROF(memory_pointer) = selector; /* address = Selector:0 */
OFFSETOF(memory_pointer) = 0; /* set the offset to 0 */
return(memory_pointer);
} else {
return malloc(size);
}
#else
PVOID address;
ULONG dos_rc;
dos_rc = DosAllocSharedMem(&address,
NULL,
size,
fALLOCSHR);
if (dos_rc == 0) { /* Non-zero OS/2 return code? */
return(address);
} else {
return malloc(size);
}
#endif
#else
return malloc(size);
#endif
}
/*
* show_info()
*
* This procedure displays a block of text information on the the
* screen. The input argument is an array of strings to be output,
* one string per line. A NULL array element indicates the end of
* the strings.
*
* default
* print out all of the text strings in the array using the cpicport
* write_output() call.
*/
void
show_info(char * * text)
{
int i;
for ( i = 0; text[i] != NULL; i++ ) {
write_output("%s\n", text[i]);
}
return;
}
/*
* get_machine_mode()
*
* This procedure is only compiled if we are compiling a Family mode
* executable (runs in both OS/2 and DOS). It is not needed for any
* other operating systems or executable types.
*
* In OS/2 and DOS, this procedure indicates whether the machine is
* currently running in real (DOS) or protect (OS/2) mode.
* 1 - Protect (OS/2)
* 0 - Real (DOS)
*
*/
#if defined(FAPI)
int
get_machine_mode(void)
{
unsigned char mode;
USHORT dos_rc;
int rc;
dos_rc = DosGetMachineMode(&mode);
if (!dos_rc) {
rc = (int)mode;
} else {
rc = 0;
}
return rc;
}
#endif
/*
* get_password()
*
* Gets a password from the user. Where possible, this routine should
* disable echoing of keystrokes for security reasons.
*
* Returns
* 0 - password was successfully input
* 1 - password variable was not updated successfully
*/
int
get_password(char * password, int max_length)
{
int rc;
#if defined(OS2) || defined(FAPI)
STRINGINBUF stringinbuf;
set_echo(FALSE); /* keystrokes will not appear */
stringinbuf.cb = max_length+1; /* set the max input size */
/* this call will not allow the user to enter more than the specified */
/* maximum number of characters. */
KbdStringIn((unsigned char *)password, &stringinbuf, 0, 0);
password[stringinbuf.cchIn] = '\0'; /* ensure NULL termination */
set_echo(TRUE); /* turn echo of keystrokes on */
rc = 0;
#else
int length;
/* There is no portable way to disable echoing of input keystrokes. */
/* If a platform does support turning off echo, this section should be */
/* rewritten and ifdef'ed. */
if (NULL != fgets(password, max_length+1, stdin)) {
length = strlen(password);
if (length > 0 && length < max_length) {
if (password[length-1] == '\n') { /* remove the trailing */
password[length-1] = '\0'; /* newline if it exists */
}
rc = 0;
} else {
rc = 1;
}
} else {
rc = 1;
}
#endif
return rc;
}
/*
* set_echo()
*
* Internal call used by get_password() to turn off or turn on echo of
* keystrokes to the terminal. The parameter to set_echo() can be
* either 0 or 1.
* 0 - turn off echo, keystrokes will not appear on the screen.
* 1 - turn on echo, this is the normal mode of operation.
*/
void
set_echo(int mode)
{
#if defined(OS2) || defined(FAPI)
KBDINFO kbdinfo; /* keyboard status info */
kbdinfo.cb = 10;
KbdGetStatus(&kbdinfo, 0);
if (mode) {
/* Keystrokes will be displayed on the screen */
kbdinfo.fsMask |= 1; /* set echo on */
kbdinfo.fsMask &= 0xFD; /* turn on echo */
} else {
/* Keystrokes will not be displayed on the screen */
kbdinfo.fsMask |= 2; /* set echo off */
kbdinfo.fsMask &= 0xFE; /* turn off echo */
}
KbdSetStatus(&kbdinfo, 0);
#else
#endif
return;
}
/*
* do_exit()
*
* Exit properly for the environment we're running in.
*/
void
do_exit(int rc)
{
exit(rc);
}
/*
* Some platforms do not have the strupr C library routine, so we will
* define it here. strupr converts a string to uppercase.
*/
#if !defined(DOES_NOT_NEED_STRUPR)
int
strupr (char * string)
{
for (;*string;++string)
*string=toupper(*string);
return;
}
#endif
/*
* The ASCII<-->EBCDIC character set translation routines are implemented
* below. These procedures should never be called directly, but should
* be accessed through the convert_to_ascii() and convert_from_ascii()
* macros. This frees the application program from knowing whether
* it is being coded on an ASCII or EBCDIC computer (this must be
* determined in the macro definition in CPICPORT.H).
*/
void ascii_to_ebcdic_field (char * ascii_field,
unsigned int field_size)
{
unsigned int i;
for (i = 0;
i < field_size;
ascii_field[i] = ascii_to_ebcdic_table[(unsigned)ascii_field[i]],i++);
}
void ascii_to_ebcdic_string (char * ascii_string)
{
ascii_to_ebcdic_field(ascii_string, strlen(ascii_string));
}
void ebcdic_to_ascii_field (char * ebcdic_field,
unsigned int field_size)
{
unsigned int i;
for (i = 0;
i < field_size;
ebcdic_field[i] =
ebcdic_to_ascii_table[(unsigned)ebcdic_field[i]],i++);
}
void ebcdic_to_ascii_string (char * ebcdic_string)
{
ebcdic_to_ascii_field(ebcdic_string, strlen(ebcdic_string));
}
/* ASCII to EBCDIC translate table (only UGL character set) */
char ascii_to_ebcdic_table[] = {
"\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x15\x0B\x0C\x0D\x0E\x0F" /* 00-0F */
"\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x3F\x27\x22\x1D\x35\x1F" /* 10-1F */
"\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61" /* 20-2F */
"\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F" /* 30-3F */
"\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6" /* 40-4F */
"\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D" /* 50-5F */
"\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96" /* 60-6F */
"\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x4F\xD0\xA1\x07" /* 70-7F */
"\x43\x20\x21\x1C\x23\xEB\x24\x9B\x71\x28\x38\x49\x90\xBA\xEC\xDF" /* 80-8F */
"\x45\x29\x2A\x9D\x72\x2B\x8A\x9A\x67\x56\x64\x4A\x53\x68\x59\x46" /* 90-9F */
"\xEA\xDA\x2C\xDE\x8B\x55\x41\xFE\x58\x51\x52\x48\x69\xDB\x8E\x8D" /* A0-AF */
"\x73\x74\x75\xFA\x15\xB0\xB1\xB3\xB4\xB5\x6A\xB7\xB8\xB9\xCC\xBC" /* B0-BF */
"\xAB\x3E\x3B\x0A\xBF\x8F\x3A\x14\xA0\x17\xCB\xCA\x1A\x1B\x9C\x04" /* C0-CF */
"\x34\xEF\x1E\x06\x08\x09\x77\x70\xBE\xBB\xAC\x54\x63\x65\x66\x62" /* D0-DF */
"\x30\x42\x47\x57\xEE\x33\xB6\xE1\xCD\xED\x36\x44\xCE\xCF\x31\xAA" /* E0-EF */
"\xFC\x9E\xAE\x8C\xDD\xDC\x39\xFB\x80\xAF\xFD\x78\x76\xB2\x9F\xFF" /* F0-FF */
};
/* EBCDIC to ASCII translate table (only UGL character set) */
char ebcdic_to_ascii_table[] = {
"\x00\x01\x02\x03\xCF\x09\xD3\x7F\xD4\xD5\xC3\x0B\x0C\x0D\x0E\x0F" /* 00-0F */
"\x10\x11\x12\x13\xC7\x0A\x08\xC9\x18\x19\xCC\xCD\x83\x1D\xD2\x1F" /* 10-1F */
"\x81\x82\x1C\x84\x86\x0A\x17\x1B\x89\x91\x92\x95\xA2\x05\x06\x07" /* 20-2F */
"\xE0\xEE\x16\xE5\xD0\x1E\xEA\x04\x8A\xF6\xC6\xC2\x14\x15\xC1\x1A" /* 30-3F */
"\x20\xA6\xE1\x80\xEB\x90\x9F\xE2\xAB\x8B\x9B\x2E\x3C\x28\x2B\x7C" /* 40-4F */
"\x26\xA9\xAA\x9C\xDB\xA5\x99\xE3\xA8\x9E\x21\x24\x2A\x29\x3B\x5E" /* 50-5F */
"\x2D\x2F\xDF\xDC\x9A\xDD\xDE\x98\x9D\xAC\xBA\x2C\x25\x5F\x3E\x3F" /* 60-6F */
"\xD7\x88\x94\xB0\xB1\xB2\xFC\xD6\xFB\x60\x3A\x23\x40\x27\x3D\x22" /* 70-7F */
"\xF8\x61\x62\x63\x64\x65\x66\x67\x68\x69\x96\xA4\xF3\xAF\xAE\xC5" /* 80-8F */
"\x8C\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\x97\x87\xCE\x93\xF1\xFE" /* 90-9F */
"\xC8\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xEF\xC0\xDA\x5B\xF2\xF9" /* A0-AF */
"\xB5\xB6\xFD\xB7\xB8\xB9\xE6\xBB\xBC\xBD\x8D\xD9\xBF\x5D\xD8\xC4" /* B0-BF */
"\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xCB\xCA\xBE\xE8\xEC\xED" /* C0-CF */
"\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xA1\xAD\xF5\xF4\xA3\x8F" /* D0-DF */
"\x5C\xE7\x53\x54\x55\x56\x57\x58\x59\x5A\xA0\x85\x8E\xE9\xE4\xD1" /* E0-EF */
"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xB3\xF7\xF0\xFA\xA7\xFF" /* F0-FF */
};
/*
* execute_and_send_output()
*
* Execute the specified command and send the output back to the client
* side. This routine is called by AREXECD.C.
*/
/*
* OS2
* execute_and_send_output()
*/
#if defined(OS2)
HFILE popen(char * command, char * mode);
int my_read(HFILE handle, char * buffer, int length);
void
execute_and_send_output(char * command,
unsigned char * cm_conv_id,
struct error_handler_cpicerr * cpicerr)
{
/* My OS/2 implementation of popen requires an OS/2 file handle */
HFILE read_handle;
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
char buffer[800];
int done = 0;
int read_length; /* generic length variable */
read_handle = popen(command, "r");
if (read_handle == NULL) {
write_error( "POPEN failed\n");
strcpy(buffer, "AREXECD ERROR: The command failed to execute.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
done = 1;
}
while (!done) {
read_length = my_read(read_handle, buffer, 800);
if (!read_length) {
done = 1;
} else {
convert_to_ascii(buffer, read_length);
length = (CM_INT32)read_length;
if (length) {
if (*(buffer+length-1) == 0x27) {
done = 1;
length--;
}
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
} else {
done = 1;
}
}
}
}
TID SpyThreadId;
#define SPYSTACKSIZE (8000)
BYTE SpyThreadStack[SPYSTACKSIZE];
typedef struct wait_info {
HFILE write_handle;
PID childPID;
} WAIT_INFO;
WAIT_INFO wait_info;
/* function prototype */
void child_wait(WAIT_INFO * my_wait_info);
HFILE
popen(char * command, char * mode)
{
USHORT dos_rc;
HFILE childOut;
HFILE read_handle;
UCHAR Command[256];
RESULTCODES rcbuf;
UCHAR far * Args;
USHORT arg0len;
int length;
char * temp = mode; /* avoid warning */
dos_rc = DosMakePipe(&read_handle, &(wait_info.write_handle), 0);
if (dos_rc) { write_error("DosMakePipe error: %d\n", dos_rc); }
childOut = 1; /* stdout */
dos_rc = DosDupHandle( wait_info.write_handle, &childOut);
if (dos_rc) { write_error("DosDupHandle error: %d\n", dos_rc); }
length = strlen(command);
strcpy(Command, "cmd.exe");
arg0len = strlen(Command)+1;
Args = malloc(length+arg0len+20);
strcpy(Args, "cmd.exe");
strcpy(&Args[arg0len], "/c \"");
strcat(&Args[arg0len], command);
strcat(&Args[arg0len], " \" 2>&1");
Args[arg0len+strlen(&Args[arg0len])+1] = '\0';
dos_rc=DosExecPgm((PSZ)NULL, /* no buffer */
0, /* no buffer length */
EXEC_ASYNCRESULT, /* asynchronous exec */
(char far *)Args, /* pass arguments */
(char far *)NULL, /* copy parent env */
&rcbuf, /* return codes */
Command); /* pgm name */
wait_info.childPID = rcbuf.codeTerminate;
if (dos_rc) { write_error("DosExecPgm error: %d\n", dos_rc); }
_beginthread( child_wait, SpyThreadStack, SPYSTACKSIZE, (void*)&wait_info);
return read_handle;
}
void
child_wait(WAIT_INFO * my_wait_info)
{
PID pid;
RESULTCODES rcbuf;
USHORT bytes_written;
UCHAR eof = 0x27;
DosCwait(DCWA_PROCESS,
DCWW_WAIT,
&rcbuf,
&pid,
my_wait_info->childPID);
DosWrite( my_wait_info->write_handle, &eof, 1, &bytes_written);
}
int
my_read(HFILE handle, char * buffer, int length)
{
int read_length;
int dos_rc;
dos_rc = DosRead(handle, buffer, length, &read_length);
if (dos_rc == 0) {
return read_length;
} else {
return 0;
}
}
/* END of OS2 section */
/*
* VM
* execute_and_send_output()
*/
#elif defined(VM)
#define VM_TEMPFILE "arexecd.tmp"
char tempfile[L_tmpnam];
FILE * popen(char * command, char * mode);
void
execute_and_send_output(char * command,
unsigned char * cm_conv_id,
struct error_handler_cpicerr * cpicerr)
{
FILE * read_handle;
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
char buffer[800];
int done = 0;
int read_length; /* generic length variable */
read_handle = popen(command, "r");
if (read_handle == NULL) {
write_error( "POPEN failed\n");
strcpy(buffer, "AREXECD ERROR: The command failed to execute.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
done = 1;
}
while (!done) {
read_length = fread(buffer, 1, 800, read_handle);
if (!read_length) {
done = 1;
} else {
convert_to_ascii(buffer, read_length);
length = (CM_INT32)read_length;
if (length) {
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
} else {
done = 1;
}
}
}
fclose(read_handle);
remove(tempfile);
}
FILE *
popen(char * command, char * mode)
{
FILE * file;
char system_string[256];
strcpy(system_string, "EXEC POPEN ");
strcat(system_string, command);
strupr(system_string);
system(system_string);
return fopen(VM_TEMPFILE, mode);
}
/* END of VM section */
/*
* OS400
* execute_and_send_output()
*/
#elif defined(OS400)
char tempfile[L_tmpnam];
int popen(char * command, char * mode);
void
execute_and_send_output(char * command,
unsigned char * cm_conv_id,
struct error_handler_cpicerr * cpicerr)
{
int rc;
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
char buffer[800];
rc = system(command);
/*
* I haven't figured out how to capture the output on AS/400,
* so just send back a message saying the command succeeded or failed.
*/
if (rc != 0) {
write_error( "POPEN failed\n");
strcpy(buffer, "AREXECD ERROR: The command failed to execute.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
}
else {
strcpy(buffer, "AREXECD: The command succeeded.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
}
}
/* END of OS400 section */
/*
* AIX
* execute_and_send_output()
*/
#elif defined(AIX)
void
execute_and_send_output(char * command,
unsigned char * cm_conv_id,
struct error_handler_cpicerr * cpicerr)
{
FILE * read_handle;
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
char buffer[800];
int done = 0;
int read_length; /* generic length variable */
read_handle = popen(command, "r");
if (read_handle == NULL) {
write_error( "POPEN failed\n");
strcpy(buffer, "AREXECD ERROR: The command failed to execute.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
done = 1;
}
while (!done) {
read_length = fread(buffer, 1, 800, read_handle);
if (!read_length) {
done = 1;
} else {
convert_to_ascii(buffer, read_length);
length = (CM_INT32)read_length;
if (length) {
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
} else {
done = 1;
}
}
}
fclose(read_handle);
}
/* END of AIX section */
/*
* DOS and AIX
* execute_and_send_output()
*
* This implementation uses the non-ANSI tempnam() call instead of the
* ANSI tmpnam() call in order to make use of TMP directories and
* tempfile prefixes.
*/
#elif defined(BCC) || defined(DOS) || defined(FAPI)
char * tempfile;
FILE * my_popen(char * command, char * mode);
void
execute_and_send_output(char * command,
unsigned char * cm_conv_id,
struct error_handler_cpicerr * cpicerr)
{
FILE * read_handle;
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
char buffer[800];
int done = 0;
int read_length; /* generic length variable */
read_handle = my_popen(command, "r");
if (read_handle == NULL) {
write_error( "POPEN failed\n");
strcpy(buffer, "AREXECD ERROR: The command failed to execute.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
done = 1;
}
while (!done) {
read_length = fread(buffer, 1, 800, read_handle);
if (!read_length) {
done = 1;
} else {
convert_to_ascii(buffer, read_length);
length = (CM_INT32)read_length;
if (length) {
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
} else {
done = 1;
}
}
}
fclose(read_handle);
remove(tempfile);
}
FILE *
my_popen(char * command, char * mode)
{
int rc;
char tempbuffer[500];
tempfile = tempnam("\\", "ARXC");
strcpy(tempbuffer, command);
strcat(tempbuffer, " > ");
strcat(tempbuffer, tempfile);
rc = system(tempbuffer);
/*
* System() seems to return a non-zero return code on occasion even
* when the command completed successfully.
* So, we'll ignore the return value from system() and try to open
* the file anyway.
*/
return fopen(tempfile, mode);
}
/* END of DOS and Family API section */
/*
* Default
* execute_and_send_output()
*/
#else
char tempfile[L_tmpnam];
FILE * popen(char * command, char * mode);
void
execute_and_send_output(char * command,
unsigned char * cm_conv_id,
struct error_handler_cpicerr * cpicerr)
{
FILE * read_handle;
CM_INT32 cm_rc; /* CPI-C return code */
CM_INT32 length; /* generic length variable */
CM_INT32 rts_received; /* request to send received */
char buffer[800];
int done = 0;
int read_length; /* generic length variable */
read_handle = popen(command, "r");
if (read_handle == NULL) {
write_error( "POPEN failed\n");
strcpy(buffer, "AREXECD ERROR: The command failed to execute.\n");
length = strlen(buffer)+1;
convert_to_ascii(buffer, length);
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
done = 1;
}
while (!done) {
read_length = fread(buffer, 1, 800, read_handle);
if (!read_length) {
done = 1;
} else {
convert_to_ascii(buffer, read_length);
length = (CM_INT32)read_length;
if (length) {
cmsend(cm_conv_id,
(unsigned char *) buffer,
&length,
&rts_received,
&cm_rc);
if (cm_rc) cpicerr_handle_rc(cpicerr, MSG_CMSEND, cm_rc);
} else {
done = 1;
}
}
}
fclose(read_handle);
remove(tempfile);
}
FILE *
popen(char * command, char * mode)
{
int rc;
FILE * file1;
FILE * file2;
tmpnam(tempfile);
file1 = freopen(tempfile, "w", stdout);
file2 = freopen(tempfile, "w", stderr);
rc = system(command);
fclose(file1);
fclose(file2);
if (rc) {
return NULL;
} else {
return fopen(tempfile, mode);
}
}
/* END of Default section */
#endif
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/