/*@ @{vccprg}
 */


#define	QEF_RUNNING	1

#if QEF_RUNNING

#include	<envir/system.h>
#include	<config/oasys.h>

/*S*/	SID(angpipe,"@(#)smrtpipe.c	3.1 - 97/01/04")

#include	<envir/stdio.h>
#include	<envir/stdlib.h>
#include	<envir/string.h>
#include	<envir/assert.h>
#include	<envir/errno.h>
#include        <sys/ipc.h>
#include        <sys/msg.h>
#include	<sys/unistd.h>

#else

#define	_HPUX_SOURCE	1

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<assert.h>
#include	<errno.h>
#include	<sys/types.h>
#include        <sys/ipc.h>
#include        <sys/msg.h>
#include	<sys/unistd.h>

#endif

char		useline[]="[-xX] file";

char *		flagsexpl[] ={
"pipe to and from a SmartWare Server",
"",
"-k key		specifiy key (default=1621)",
"-t type	specifiy message type (default=pid)",
"-h header	output header",
"-P		output header 'Content-type: text/plain'",
"-H		output header 'Content-type: text/html'",
"-1		first line to send to Smart",
"-b bytes	content length",
"-z		suppres trailer",
"-c		perform CGI conversions",
"-C		perform CGI conversions to stdout",
"-x		display this explanation",
"-X		see -x",
"file ...	input nodes file to be processed",
0
};

char*		progname;
static char**	arginterp	(int, char**);
static char*    key;
static char* def_key="1621";

static int send_it(int queue,long type, char* msg);
static int sendfile_conv(int queue,long mtype, FILE* f, unsigned int bytes);
static int convsend_it(int queue,long type, char* msg);
static char* get_it(int queue,long type);
static char* leafnm(char * sl);

static long msg_type;
static int conv=0;
static int ipc=1;
static char* header=(char*)0;
static unsigned int total_bytes;
static int trailer=1;
static char* line_one=(char*)0;

#define	MAX_READ	999
#define BUF_SIZE	(MAX_READ+sizeof(long)+1)

static void
do_it()
{
	int queue_tosw=0;
	int queue_fromsw=0;
	char buf[20];
	key_t key_num;
	char* result;

	key_num = atol(key);
	if (ipc) {
		if ((queue_tosw=msgget(key_num,0))<0) {
			printf("Error establishing a queue\n");
			exit(1);
		}
		if ((queue_fromsw=msgget(key_num+1,0))<0) {
			printf("Error establishing a queue\n");
			exit(1);
		}
		sprintf(buf,"PID=%ld",msg_type);
		send_it(queue_tosw,msg_type,buf);
	}
	if (header)
		printf("%s\n\n",header);
	if (line_one)
		send_it(queue_tosw, msg_type, line_one);


	if (conv) {
		sendfile_conv(queue_tosw,msg_type,stdin,total_bytes);
	} else {
		printf("No conversion not supported yet...\n");
	}
	if (trailer)
		send_it(queue_tosw,msg_type,"EOF");
	if (ipc) {
		sprintf(buf,"!%ld",msg_type);
		while ((result=get_it(queue_fromsw,msg_type))) {
			if (strcmp(result,buf)==0)
				break;
			printf("%s\n",result);
		}
	}
	exit(0);
}

static int
sendfile_conv(int queue,long mtype, FILE* f, unsigned int bytes)
{
	char send_buf[BUF_SIZE];
	unsigned int byte_count=0;
	int from=getc(f);

	FILE* trace = fopen("/u/ko/sw/o/cmds/out.txt","w");

	register char* to=send_buf;
	while (from!=EOF && byte_count<bytes) {
		fprintf(trace,"%d of %d, char=%c\n",bytes,byte_count,(char)from);
		switch (from) {
			case '&':
			case '\n':
				*to = '\0';
				if (!send_it(queue,mtype,send_buf))
					return 0;
				byte_count++;
				if (byte_count<bytes)
					from=getc(f);
				to = send_buf;
				break;
			case '%': {
				char numbuf[3];
				int ct=0;
				from=getc(f);
				byte_count++;
				while (from!=EOF && ct<=1) {
					numbuf[ct++]=(char)from;
					byte_count++;
					if (byte_count<bytes)
						from=getc(f);
				}
				numbuf[ct]='\0';
				*to++ = (char)strtol(numbuf,(char**)NULL,16);
				break;
			}
			case '+':
				*to++ = ' ';
				byte_count++;
				if (byte_count<bytes)
					from=getc(f);
				break;
			default:
				if (to-send_buf>MAX_READ) {
					printf("Line length overflow\n");
					if (!send_it(queue,mtype,send_buf))
						return 0;
					to = send_buf;
				}
				*to++=from;
				byte_count++;
				if (byte_count<bytes)
					from=getc(f);
				break;
		}
	}
	fclose(trace);
	if (to!=send_buf) {
		*to='\0';
		return send_it(queue,mtype,send_buf);
	}
	return 1;
}


static int
convsend_it(int queue,long type, char* message)
{
	char send_buf[BUF_SIZE];
	char* from=message;
	register char* to=send_buf;
	for (;*from; ) {
		switch (*from) {
			case '&':
				*to = '\0';
				if (!send_it(queue,type,send_buf))
					return 0;
				from++;
				to = send_buf;
				break;
			case '%': {
				char numbuf[3];
				int ct=0;
				from++;
				while (*from && ct<=1)
					numbuf[ct++]=*from++;
				numbuf[ct]='\0';
				*to++ = (char)strtol(numbuf,(char**)NULL,16);
				break;
			}
			case '+':
				*from = ' ';
				/* Fall through */
			default:
				*to++=*from++;
				break;
		}
	}
	if (to!=send_buf) {
		*to='\0';
		return send_it(queue,type,send_buf);
	}
	return 1;
}

static int
send_it(int queue,long type, char* message)
{
	static char ipc_buf[BUF_SIZE]="";
	int retval;
	int len = strlen(message);
	struct msgbuf* buffer=(struct msgbuf*)ipc_buf;

	if (ipc) {
		buffer->mtype=type;
		strcpy(buffer->mtext,message);
		retval = msgsnd(queue,buffer,sizeof(long)+len+1,0);
		if (!retval!=-1)
			return 1;
		printf("Error sending message (msg=%s,len=%d,queue=%d,type=%ld,errno=%d,retval=%d)\n",message,len,queue,type,errno,retval);
		return 0;
	} else {
		printf("%s\n",message);
	}
}

static char*
get_it(int queue, long type)
{
	int retval;
	static char ipc_buf[BUF_SIZE]="";
	struct msgbuf* buffer=(struct msgbuf*)ipc_buf;
	retval=msgrcv(queue,buffer,MAX_READ,type,0);
	if (retval==0)
		return (char*)0;
	buffer->mtext[retval-1]='\0';
	return (buffer->mtext);
}

void
main(argc, argv)
int argc;
char** argv;
{
	register char** av;
	msg_type = getpid();

	av = arginterp(argc, argv);
	do_it();
	exit(0);
}

#       define  NAME_SEP        '/'

static char *
leafnm(sl)
	register char * sl;
{
	register char * p;

	for (p = sl; *p; )
		if (*p++ == NAME_SEP)
			sl = p;
	return (sl);
}

static void
errexit (char* m1)
{
	if (progname != (char*)0)
		fprintf(stderr, "%s: ", progname);
	fprintf(stderr, m1);
	fprintf(stderr, "\n");
	exit(1);
}

void
explflags(char** flags)
{
	register char **p;

	if (useline != (char*)0)
		printf("%s %s\n\n", progname, useline);
	for (p = flags; *p != (char*)0;)
		puts(*p++);
}

static char**
arginterp(argc, argv)
int argc;
char** argv;
{
	register char *p;
	register int c;
	char* con_len;
	con_len = getenv("CONTENT_LENGTH");
	if (con_len)
		total_bytes = atoi(con_len);
	else
		total_bytes = 0xFFFFFFFF;

	progname = leafnm(*argv);
	for (argv++; --argc && **argv == '-'; argv++) {
		p = &argv[0][1];
		while ((c = *p++) != '\0') switch (c) {
		default: {
			char buffer[100];
			sprintf(buffer,"-%c: invalid flag", c);
			errexit(buffer);
			/* no return */
		}
		case 'c': conv++; continue;
		case 'z': trailer=0; continue;
		case 'C': ipc=0; conv++; continue;
		case 'H': header = "Content-type: text/html"; continue;
		case 'P': header = "Content-type: text/plain"; continue;
		case 'b':
			if (!--argc)
				errexit("-b: missing argument");

			total_bytes = atoi(*++argv);
			continue;
		case 'h':
			if (!--argc)
				errexit("-h: missing argument");

			header = *++argv;
			continue;
		case '1':
			if (!--argc)
				errexit("-1: missing argument");

			line_one = *++argv;
			continue;
		case 'k':
			if (!--argc)
				errexit("-k: missing argument");

			key = *++argv;
			continue;
		case 't':
			if (!--argc)
				errexit("-t: missing argument");
			msg_type = atol(*++argv);
			continue;
		case 'x': case 'X': case '?':
			explflags(flagsexpl);
			exit(1);
		}
	}
	if (!key)
		key = def_key;
	return (argv);
}
