#include "TPT.h"

/*
 * Only called here if there really is a character waiting
 * to be read. */

void                ReadSer(struct TPTSess *sess, unsigned short type)
{
	UBYTE               c;

	switch (type)
		{
		case SERCHAR:
			WaitIO((struct IORequest *) ReadSER);
			c = intrans[in_c];
			break;

		case CONCHAR:
			WaitIO((struct IORequest *) consoleReadMsg);
			c = intrans[cin_c];
			break;

		default:
			if (type < 256)
				c = intrans[(UBYTE) type];
			else
				c = 0;
		}

	if (!(tptflags & T_PASS_THRU))		/* pass-thru for
													 * file transfers */
		{
			if (tptflags & T_PAUSE)
				{
					if (c == 19)				/* ^S */
						{
							c = 0;

							if (!(tptflags & T_PAUSED) && (in_len < MAXLINESIZE))
								{
									if (tptflags & T_VERB_PAUSE)
										WriteSer("[PAUSED]", 8);
									tptflags |= T_PAUSED;
									if (!(tptflags & T_RPEND))
										num_times = 0;
								}
						}

					if ((c == 17) && (tptflags & T_PAUSED))	/* ^Q
																			 */
						{
							c = 0;
							if (tptflags & T_VERB_PAUSE)
								WriteSer("\010\010\010\010\010\010\010\010        \010\010\010\010\010\010\010\010", 24);
							tptflags &= ~T_PAUSED;
						}
				}

			if (tptflags & T_PAUSED)
				c = 0;							/* Eat chars if
													 * paused */

			switch (c)
				{
				case 3:							/* ^C typed so
													 * immediately send
													 * the signal */
					if (!(tptflags & T_RAW))
						c = 0;
					if (sess->creader && (tptflags & T_BREAK))
						Signal(sess->creader->task, SIGBREAKF_CTRL_C);
					break;

				case 4:							/* ^D, can it if
													 * CTLD is disabled */
					if (!(tptflags & T_CTLD))
						c = 0;
					break;

				case 5:							/* ^E, send the
													 * signal if not in
													 * raw mode */
					if (!(tptflags & T_RAW))
						c = 0;
					if (!(tptflags & T_RAW) && sess->creader)
						Signal(sess->creader->task, SIGBREAKF_CTRL_E);
					break;

				case 6:							/* ^F, send the
													 * signal if not in
													 * raw mode */
					if (!(tptflags & T_RAW))
						c = 0;
					if (!(tptflags & T_RAW) && sess->creader)
						Signal(sess->creader->task, SIGBREAKF_CTRL_F);
				}

			if (!(tptflags & T_RAW))
				switch (c)
					{
					case 28:					/* ^\ so wipe out
													 * line and force
													 * EOF */
						c = 0;
						in_len = 0;
						inline = FALSE;
						++aux_avail;
						break;

					case 13:					/* CR convert to LF
													 * if CRLF turned on
													 */
						if (tptflags & T_CRLF)
							c = 10;
						break;

					case 10:					/* ignore these */
						if (tptflags & T_CRLF)
							c = 0;
						break;

					case 8:						/* BS */
					case 127:					/* DEL */
						if (in_len && sess->auxbuf[in_len - 1] != 10)
							{
								--in_len;
								if ((tptflags & T_ECHO) && Printable(sess->auxbuf[in_len]))
									WriteSer("\010 \010", 3);
							}

						if ((!in_len) || (sess->auxbuf[in_len - 1] == 10))
							inline = FALSE;
						c = 0;
						break;

					case 24:					/* ^X */
					case 21:					/* ^U */
						while (in_len && sess->auxbuf[in_len - 1] != 10)
							{
								--in_len;
								if ((tptflags & T_ECHO) && Printable(sess->auxbuf[in_len]))
									WriteSer("\010 \010", 3);
							}
						inline = FALSE;
						c = 0;
						break;

					case 27:					/* <ESC> */
					case 155:
						c = 0;

					default:
						break;
					}

			if ((in_len >= MAXLINESIZE) && (c != 10))
				{
					if (!(tptflags & T_RAW) || (tptflags & T_TYPEAHEAD_FULL))
						c = 0;
					else
						{
							tptflags |= T_TYPEAHEAD_FULL;
							if ((type == SERCHAR) && consoleReadMsg)
								NiceAbort((struct IORequest *) consoleReadMsg);
							else if ((type == CONCHAR) && !localflag)
								NiceAbort((struct IORequest *) ReadSER);
						}
				}

			if (tptflags & T_ECHO)
				{
					if (tptflags & T_CRLF)
						if (c == 10)
							putc_both(13);

					putc_both(c);
				}
		}

	if (c == 10)
		{
			++aux_avail;						/* always done when
													 * CR received */
			inline = FALSE;
		}

	if (!(tptflags & T_TYPEAHEAD_FULL))
		{
			switch (type)
				{
				case SERCHAR:
					if (!localflag)
						set_read();
					break;

				case CONCHAR:
					set_con_read();
					break;
				}
		}

	if (c || (tptflags & T_PASS_THRU))
		{
			if (in_len < MAXLINESIZE)
				{
					sess->auxbuf[in_len++] = c;
					if (c != 10)
						inline = TRUE;
				}
#ifdef DO_DEBUG
			if (in_len >= MAXLINESIZE)
				TDebug(in_len, "Buffer overflow");
#endif
		}
}

/* Write out the buffer */
/* */

void                WriteSer(UBYTE * buf, long len)
{
	register long       bpos;
	register long       incount;
	register long       olen;

/* register long   scount; */

	register UBYTE     *obuf;
	register UBYTE     *oend;
	register UBYTE     *tbuf;

	register UBYTE      c;

	bpos = 0;
/* scount = 0; */

	while (bpos < len)
		{
			whichbuf = (whichbuf + 1) % 3;
			obuf = mybuf[whichbuf];

			olen = len - bpos;
			if (olen > AUXBUFSIZE - 15)
				olen = AUXBUFSIZE - 15;

			oend = obuf + olen;

			while (obuf < oend)
				{
					if (!(c = outtrans[buf[bpos++]]))
						{
							oend--;
							olen--;
							continue;
						}

/* if (scount) if (c != 32  ||  scount == 99) {if (scount >
 * 5) {*obuf++ =  27; *obuf++ = '['; *obuf++ = (scount/10)
 * + '0'; *obuf++ = (scount%10) + '0'; *obuf++ = 'C';
 *
 * scount -=  5; olen   -= scount; oend   -= scount; scount
 * =  0; } else {for(;scount; scount--) *obuf++ = ' '; } }
 * else {scount++; continue; } */

					switch (c)
						{
						case 27:
							*obuf++ = c;

							while (bpos < len)
								{
									if (obuf >= oend)
										olen++;
									c = buf[bpos++];

									if (c == '[' || (c >= '0' && c <= '9') || c == ';')
										*obuf++ = c;
									else
										{
											*obuf++ = c;
											break;
										}
								}
							break;

						case 10:
							if ((tptflags & T_CRLF) && !(tptflags & T_PASS_THRU))
								{
									*obuf++ = 13;
									*obuf++ = c;
									if (obuf > oend)
										{
											olen++;
											if (olen < AUXBUFSIZE - 14)
												oend++;
										}
									break;
								}

/* case 32:    if (tptflags & T_ANSIPOS) {scount++; break;
 * } */

						default:
							*obuf++ = c;
						}
				}

			if (!localflag)
				{
					if (tptflags & T_WRITE_PEND)
						WaitIO((struct IORequest *) WriteSER);

					WriteSER->IOSer.io_Length = olen;
					WriteSER->IOSer.io_Data = (APTR) mybuf[whichbuf];
					SendIO((struct IORequest *) WriteSER);
					tptflags |= T_WRITE_PEND;
				}

			if (consoleWriteMsg && !(tptflags & T_PASS_THRU))
				{
					if (TScrDepth == 1)
						{
							if (TScrn)
								{
									obuf = &mybuf[whichbuf][0];
									whichbuf = (whichbuf + 1) % 3;
									oend = &mybuf[whichbuf][0];

									for (incount = 0; incount < olen; incount++)
										{
											if (*obuf == 27)
												{
													tbuf = oend;
													*oend++ = *obuf++;
													incount++;

													while (*obuf == '[' || (*obuf >= '0' && *obuf <= '9') || *obuf == ';')
														{
															*oend++ = *obuf++;
															incount++;
														}

													if (*obuf == 'm')
														{
															obuf++;
															oend = tbuf;
															continue;
														}
												}

											*oend++ = *obuf++;
										}

									olen = oend - &mybuf[whichbuf][0];
								}
						}

					if (tptflags & T_CWRITE_PEND)
						WaitIO((struct IORequest *) consoleWriteMsg);
					consoleWriteMsg->io_Length = olen;
					consoleWriteMsg->io_Data = (APTR) mybuf[whichbuf];
					SendIO((struct IORequest *) consoleWriteMsg);
					tptflags |= T_CWRITE_PEND;
				}
		}
}


/* Write a character to the serial port (if not in local
 * mode) and to the console (if the window is open) */
void                putc_both(UBYTE c)
{
	if (!(tptflags & T_KILLED))
		{
			c = outtrans[c];

			if (!localflag && (c || (tptflags & T_PASS_THRU)))
				{
					if (tptflags & T_WRITE_PEND)
						{
							WaitIO((struct IORequest *) WriteSER);
							tptflags &= ~T_WRITE_PEND;
						}

					WriteSER->IOSer.io_Length = 1;
					WriteSER->IOSer.io_Data = (APTR) & c;
					DoIO((struct IORequest *) WriteSER);
				}

			if (c && consoleWriteMsg && !(tptflags & T_PASS_THRU))
				{
					if (tptflags & T_CWRITE_PEND)
						{
							WaitIO((struct IORequest *) consoleWriteMsg);
							tptflags &= ~T_CWRITE_PEND;
						}

					consoleWriteMsg->io_Data = (APTR) & c;
					consoleWriteMsg->io_Length = 1;
					DoIO((struct IORequest *) consoleWriteMsg);
				}
		}
}

