void AxWin3_int_SendIPCMessage(tAxWin_IPCMessage *Msg) { int size = sizeof(tAxWin_IPCMessage) + Msg->Size; switch(giConnectionType) { case CONNTYPE_SENDMESSAGE: _SysSendMessage(giConnectionNum, size, Msg); break; case CONNTYPE_UDP: { // Create UDP header char tmpbuf[giAxWin3_int_UDPHeaderLen + size]; memcpy(tmpbuf, gaAxWin3_int_UDPHeader, giAxWin3_int_UDPHeaderLen); memcpy(tmpbuf + giAxWin3_int_UDPHeaderLen, Msg, size); size_t rv = _SysWrite(giConnectionNum, tmpbuf, sizeof(tmpbuf)); if( rv == -1 ) { _SysDebug("AxWin3 SendIPCMessage: UDP Write Failed %s", strerror(errno)); exit(1); } } break; case CONNTYPE_IPCPIPE: case CONNTYPE_TCP: { size_t rv = _SysWrite(giConnectionNum, Msg, size); if( rv != size ) { _SysDebug("AxWin3 SendIPCMessage: Write Failed %s - sent %i want %i", strerror(errno), rv, size); exit(1); } } break; default: break; } }
int _fflush_int(FILE *fp) { int ret = 0; size_t len; // Check the buffer contains data if( fp->BufferPos == 0 ) return 0; switch(fp->Flags & FILE_FLAG_MODE_MASK) { // Read - Flush input buffer case FILE_FLAG_MODE_READ: fp->BufferPos = 0; break; // Append - Seek to end and write case FILE_FLAG_MODE_APPEND: _SysSeek(fp->FD, fp->BufferOfs, SEEK_SET); len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos); if( len != fp->BufferPos ) ret = 1; if( len <= fp->BufferPos ) { fp->BufferPos -= len; } fp->BufferOfs = _SysTell(fp->FD); break; // Write - Write buffer case FILE_FLAG_MODE_WRITE: //_SysDebug("Flushing to %i '%.*s'", fp->FD, fp->BufferPos, fp->Buffer); len = _SysWrite(fp->FD, fp->Buffer, fp->BufferPos); if( len != fp->BufferPos ) ret = 1; if( len <= fp->BufferPos ) { fp->BufferPos -= len; } //else { // _SysDebug("Flush of %i failed, %s", fp->FD, strerror(errno)); //} break; default: break; } return ret; }
bool ACurses_GetDims_SerialTermHack(void) { _SysDebug("ACurses_GetDims_SerialTermHack: Trying"); // Set cursor to 1000,1000 , request cursor position, reset cursor to 0,0 static const char req[] = "\033[1000;1000H\033[6n\033[H"; fflush(stdin); _SysWrite(1, req, sizeof(req)); int64_t timeout = 1000; fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); _SysSelect(1, &fds, NULL, NULL, &timeout, 0); if( !FD_ISSET(0, &fds) ) return false; if( fgetc(stdin) != '\x1b' ) return false; if( fgetc(stdin) != '[' ) return false; if( fscanf(stdin, "%i;%i", &giTerminal_Width, &giTerminal_Height) != 2 ) return false; if( fgetc(stdin) != 'R' ) return false; return true; }
size_t _fwrite_unbuffered(FILE *fp, size_t size, size_t num, const void *data) { size_t ret = 0, bytes; while( num -- ) { bytes = _SysWrite(fp->FD, data, size); if( bytes == (size_t)-1 ) { // Oops. // TODO: Set error flag break; } if( bytes != size ) { _SysDebug("_fwrite_unbuffered: Oops, rollback %i/%i bytes!", bytes, size); _SysSeek(fp->FD, -bytes, SEEK_CUR); break; } data = (char*)data + size; } fp->Pos += ret * size; return ret; }
// === CODE === int main(int argc, char *argv[], const char **envp) { AxWin3_Connect(NULL); // --- Build up window gMainWindow = AxWin3_RichText_CreateWindow(NULL, AXWIN3_RICHTEXT_READONLY); AxWin3_SetWindowTitle(gMainWindow, "Terminal"); // TODO: Update title with other info gMenuWindow = AxWin3_Menu_Create(gMainWindow); AxWin3_Menu_AddItem(gMenuWindow, "Copy\tWin+C", NULL, NULL, 0, NULL); AxWin3_Menu_AddItem(gMenuWindow, "Paste\tWin+V", NULL, NULL, 0, NULL); // TODO: Populate menu // TODO: Tabs? AxWin3_RichText_SetKeyHandler (gMainWindow, Term_KeyHandler); AxWin3_RichText_SetMouseHandler (gMainWindow, Term_MouseHandler); AxWin3_RichText_SetDefaultColour(gMainWindow, 0xFFFFFF); AxWin3_RichText_SetBackground (gMainWindow, 0x000000); AxWin3_RichText_SetFont (gMainWindow, "#monospace", 10); AxWin3_RichText_SetCursorPos (gMainWindow, 0, 0); AxWin3_RichText_SetCursorType (gMainWindow, AXWIN3_RICHTEXT_CURSOR_INV); AxWin3_RichText_SetCursorBlink (gMainWindow, 1); tTerminal *term = Display_Init(80, 25, 100); AxWin3_ResizeWindow(gMainWindow, 80*8, 25*16); AxWin3_MoveWindow(gMainWindow, 20, 50); AxWin3_ShowWindow(gMainWindow, 1); AxWin3_FocusWindow(gMainWindow); // Create PTY giPTYHandle = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE); if( giPTYHandle < 0 ) { perror("Unable to create/open PTY"); _SysDebug("Unable to create/open PTY: %s", strerror(errno)); return -1; } // - Initialise { _SysIOCtl(giPTYHandle, PTY_IOCTL_SETID, "gui0"); struct ptymode mode = {.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO, .OutputMode=0}; struct ptydims dims = {.W = 80, .H = 25}; _SysIOCtl(giPTYHandle, PTY_IOCTL_SETMODE, &mode); _SysIOCtl(giPTYHandle, PTY_IOCTL_SETDIMS, &dims); } // Spawn shell { int fd = _SysOpen("/Devices/pts/gui0", OPENFLAG_READ|OPENFLAG_WRITE); int fds[] = {fd, fd, fd}; const char *argv[] = {"CLIShell", NULL}; int pid = _SysSpawn("/Acess/Bin/CLIShell", argv, envp, 3, fds, NULL); if( pid < 0 ) _SysDebug("ERROR: Shell spawn failed: %s", strerror(errno)); _SysIOCtl(fd, PTY_IOCTL_SETPGRP, &pid); _SysClose(fd); } // Main loop for( ;; ) { fd_set fds; FD_ZERO(&fds); FD_SET(giPTYHandle, &fds); AxWin3_MessageSelect(giPTYHandle + 1, &fds); if( FD_ISSET(giPTYHandle, &fds) ) { _SysDebug("Activity on child stdout"); // Read and update screen char buf[512]; int len = _SysRead(giPTYHandle, buf, sizeof(buf)); if( len <= 0 ) break; Term_HandleOutput(term, len, buf); } } return 0; } int Term_KeyHandler(tHWND Window, int bPress, uint32_t KeySym, uint32_t Translated) { static int ctrl_state = 0; // Handle modifiers #define _bitset(var,bit,set) do{if(set)var|=1<<(bit);else var&=~(1<<(bit));}while(0) switch(KeySym) { case KEYSYM_LEFTCTRL: _bitset(ctrl_state, 0, bPress!=0); return 0; case KEYSYM_RIGHTCTRL: _bitset(ctrl_state, 1, bPress!=0); return 0; } #undef _bitset // Handle shortcuts // - Ctrl-A -- Ctrl-Z if( ctrl_state && KeySym >= KEYSYM_a && KeySym <= KEYSYM_z ) { Translated = KeySym - KEYSYM_a + 1; _SysDebug("Ctrl-%c: KS %x => Trans %x", 'A'+(KeySym-KEYSYM_a), KeySym, Translated); } // == 2 :: FIRE if( bPress == 2 ) { if( Translated ) { char buf[6]; int len; // Encode and send len = WriteUTF8(buf, Translated); _SysDebug("Keystroke %x:%x translated to '%.*s'", KeySym, Translated, len, buf); _SysWrite(giPTYHandle, buf, len); return 0; } // No translation, look for escape sequences to send const char *str = NULL; switch(KeySym) { case KEYSYM_LEFTARROW: str = "\x1b[D"; break; case KEYSYM_RIGHTARROW: str = "\x1b[C"; break; case KEYSYM_UPARROW: str = "\x1b[A"; break; case KEYSYM_DOWNARROW: str = "\x1b[B"; break; } if( str ) { _SysWrite(giPTYHandle, str, strlen(str)); } } return 0; } int Term_MouseHandler(tHWND Window, int bPress, int Button, int Row, int Col) { return 0; } void Term_HandleOutput(tTerminal *Term, int Len, const char *Buf) { // TODO: Handle graphical / accelerated modes //_SysDebug("Term_HandleOutput: %i \"%.*s\"", Len, Len, Buf); int ofs = 0; int esc_len = 0; while( ofs < Len ) { esc_len = Term_HandleVT100(Term, Len - ofs, Buf + ofs); if( esc_len < 0 ) { Display_AddText(Term, -esc_len, Buf + ofs); esc_len = -esc_len; } ofs += esc_len; //_SysDebug("Len = %i, ofs = %i", Len, ofs); } Display_Flush(Term); }
void Server_NewClient(int FD) { tClient *clt = NULL; // TODO: Is this done in the IPStack? if( giNumClients == giConfig_MaxClients ) { // Open, reject _SysClose( _SysOpenChild(FD, "", OPENFLAG_READ) ); return ; } // Allocate client structure and open socket for( int i = 0; i < giConfig_MaxClients; i ++ ) { if( gaClients[i].Socket == 0 ) { clt = &gaClients[i]; break; } } assert(clt); // Accept the connection clt->Socket = _SysOpenChild(FD, "", OPENFLAG_READ|OPENFLAG_WRITE); giNumClients ++; // Create PTY // TODO: Use PTYs clt->pty = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE); if( clt->pty < 0 ) { perror("Unable to create/open PTY"); _SysDebug("Unable to create/open PTY: %s", strerror(errno)); _SysClose(clt->Socket); clt->Socket = 0; return ; } // - Initialise { _SysIOCtl(clt->pty, PTY_IOCTL_SETID, "telnetd#"); struct ptymode mode = {.InputMode = 0, .OutputMode=0}; struct ptydims dims = {.W = 80, .H = 25}; _SysIOCtl(clt->pty, PTY_IOCTL_SETMODE, &mode); _SysIOCtl(clt->pty, PTY_IOCTL_SETDIMS, &dims); } // TODO: Arguments and envp { char pty_path[] = "/Devices/pts/telnetd000"; _SysIOCtl(clt->pty, PTY_IOCTL_GETID, pty_path+13); int clientfd = _SysOpen(pty_path, OPENFLAG_READ|OPENFLAG_WRITE); if(clientfd < 0) { perror("Unable to open login PTY"); _SysClose(clt->Socket); _SysClose(clt->pty); clt->Socket = 0; return ; } _SysDebug("Using client PTY %s", pty_path); int fds[3] = {clientfd, clientfd, clientfd}; const char *argv[] = {"login", NULL}; _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds, NULL); _SysClose(clientfd); } } void HandleServerBoundData(tClient *Client) { uint8_t buf[BUFSIZ]; size_t len; _SysDebug("Client %p", Client); len = _SysRead(Client->Socket, buf, BUFSIZ); _SysDebug("%i bytes for %p", len, Client); if( len == 0 ) return ; if( len == -1 ) { return ; } // handle options // int last_flush = 0; for( int i = 0; i < len; i ++ ) { switch(Client->Mode) { case MODE_IAC: Client->Mode = MODE_DATA; switch(buf[i]) { case 240: // End of subnegotiation parameters _SysDebug("End Subnegotiation"); break; case 241: // Nop break; case 242: // SYNCH case 243: // NVT Break case 244: // Function 'IP' (Ctrl-C) break; case 245: // Function 'AO' case 246: // Function 'AYT' case 247: // Function 'EC' case 248: // Function 'EL' case 249: // GA Signal break; case 250: // Subnegotation _SysDebug("Subnegotiation"); // TODO: Get option ID, and then cache until 'END SB' (240) Client->Mode = MODE_SUBNEG_OPTION; break; case 251: // WILL Client->Mode = MODE_WILL; break; case 252: // WONT Client->Mode = MODE_WONT; break; case 253: // DO Client->Mode = MODE_DO; break; case 254: // DONT Client->Mode = MODE_DONT; break; case 255: // Literal 255 _SysWrite(Client->pty, buf+i, 1); break; } break; case MODE_WILL: _SysDebug("Option %i WILL", buf[i]); HandleOptionRequest(Client, buf[i], true, false); Client->Mode = MODE_DATA; break; case MODE_WONT: _SysDebug("Option %i WONT", buf[i]); HandleOptionRequest(Client, buf[i], false, false); Client->Mode = MODE_DATA; break; case MODE_DO: _SysDebug("Option %i DO", buf[i]); HandleOptionRequest(Client, buf[i], true, true); Client->Mode = MODE_DATA; break; case MODE_DONT: _SysDebug("Option %i DONT", buf[i]); HandleOptionRequest(Client, buf[i], false, true); Client->Mode = MODE_DATA; break; case MODE_SUBNEG_OPTION: _SysDebug("Option %i subnegotation", buf[i]); Client->Mode = MODE_SUBNEG_DATA; break; case MODE_SUBNEG_IAC: switch(buf[i]) { case 240: // End subnegotation // TODO: Handle subnegotation data Client->Mode = MODE_DATA; break; case 255: // TODO: Literal 255 Client->Mode = MODE_SUBNEG_DATA; break; default: _SysDebug("Unexpected %i in SUBNEG IAC", buf[i]); Client->Mode = MODE_SUBNEG_DATA; break; } case MODE_SUBNEG_DATA: if( buf[i] == 255 ) Client->Mode = MODE_SUBNEG_IAC; else ;//_SysWrite(Client->pty, buf+i, 1); break; case MODE_DATA: if( buf[i] == 255 ) Client->Mode = MODE_IAC; else _SysWrite(Client->pty, buf+i, 1); break; } } } void HandleClientBoundData(tClient *Client) { char buf[BUFSIZ]; int len; len = _SysRead(Client->pty, buf, BUFSIZ); if( len <= 0 ) return ; _SysWrite(Client->Socket, buf, len); }
int Readline_int_ParseCharacter(tReadline *Info, char *Input) { int ofs = 0; char ch; if( Input[ofs] == 0 ) return 0; // Read In Command Line ch = Input[ofs++]; if(ch == '\n') { // printf("\n"); if(Info->CurBuffer) { // Cap String Info->CurBuffer[Info->BufferUsed] = '\0'; if( Info->UseHistory ) Readline_int_AddToHistory(Info, Info->CurBuffer); Info->OutputValue = strdup(Info->CurBuffer); } else Info->OutputValue = strdup(""); // Save and reset Info->BufferSize = 0; Info->BufferUsed = 0; Info->BufferWritePos = 0; Info->CurBuffer = 0; Info->HistoryPos = Info->NumHistory - 1; return 1; } switch(ch) { // Control characters case '\x1B': ch = Input[ofs++]; // Read control character switch(ch) { //case 'D': if(pos) pos--; break; //case 'C': if(pos<len) pos++; break; case '[': ch = Input[ofs++]; // Read control character switch(ch) { case 'A': // Up { int oldLen = Info->BufferUsed; int pos; if( Info->HistoryPos <= 0 ) break; // Move to the beginning of the line pos = oldLen; while(pos--) _SysWrite(STDOUT_FD, "\x1B[D", 3); // Update state Info->CurBuffer = Info->History[--Info->HistoryPos]; Info->BufferSize = Info->BufferUsed = strlen(Info->CurBuffer); _SysWrite(STDOUT_FD, Info->CurBuffer, Info->BufferUsed); Info->BufferWritePos = Info->BufferUsed; // Clear old characters (if needed) if( oldLen > Info->BufferWritePos ) { pos = oldLen - Info->BufferWritePos; while(pos--) _SysWrite(STDOUT_FD, " ", 1); pos = oldLen - Info->BufferWritePos; while(pos--) _SysWrite(STDOUT_FD, "\x1B[D", 3); } } break; case 'B': // Down { int oldLen = Info->BufferUsed; int pos; if( Info->HistoryPos >= Info->NumHistory - 1 ) break; // Move to the beginning of the line pos = oldLen; while(pos--) _SysWrite(STDOUT_FD, "\x1B[D", 3); // Update state Info->CurBuffer = Info->History[Info->HistoryPos++]; Info->BufferSize = Info->BufferUsed = strlen(Info->CurBuffer); // Write new line _SysWrite(STDOUT_FD, Info->CurBuffer, Info->BufferUsed); Info->BufferWritePos = Info->BufferUsed; // Clear old characters (if needed) if( oldLen > Info->BufferWritePos ) { pos = oldLen - Info->BufferWritePos; while(pos--) _SysWrite(STDOUT_FD, " ", 1); pos = oldLen - Info->BufferWritePos; while(pos--) _SysWrite(STDOUT_FD, "\x1B[D", 3); } } break; case 'D': // Left if(Info->BufferWritePos == 0) break; Info->BufferWritePos --; _SysWrite(STDOUT_FD, "\x1B[D", 3); break; case 'C': // Right if(Info->BufferWritePos == Info->BufferUsed) break; Info->BufferWritePos ++; _SysWrite(STDOUT_FD, "\x1B[C", 3); break; } break; case '\0': ofs --; break; } break; // Backspace case '\b': if(Info->BufferWritePos <= 0) break; // Protect against underflows // Write the backsapce _SysWrite(STDOUT_FD, &ch, 1); if(Info->BufferWritePos == Info->BufferUsed) // Simple case: End of string { Info->BufferUsed --; Info->BufferWritePos --; } else { // Have to delete the character, and reposition the text char buf[7] = "\x1B[000D"; int delta = Info->BufferUsed - Info->BufferWritePos + 1; buf[2] += (delta/100) % 10; buf[3] += (delta/10) % 10; buf[4] += (delta) % 10; // Write everything save for the deleted character _SysWrite(STDOUT_FD, &Info->CurBuffer[Info->BufferWritePos], Info->BufferUsed - Info->BufferWritePos ); ch = ' '; _SysWrite(STDOUT_FD, &ch, 1); ch = '\b'; // Clear old last character _SysWrite(STDOUT_FD, buf, 7); // Update Cursor // Alter Buffer memmove(&Info->CurBuffer[Info->BufferWritePos-1], &Info->CurBuffer[Info->BufferWritePos], Info->BufferUsed-Info->BufferWritePos ); Info->BufferWritePos --; Info->BufferUsed --; } break; // Tab case '\t': //TODO: Implement Tab-Completion //Currently just ignore tabs break; default: // Expand Buffer if(Info->BufferUsed + 1 > Info->BufferSize) { Info->BufferSize += 256; Info->CurBuffer = Info->History[Info->HistoryPos] = realloc(Info->CurBuffer, Info->BufferSize); if(!Info->CurBuffer) return 0; } // Editing inside the buffer if(Info->BufferWritePos < Info->BufferUsed) { char buf[7] = "\x1B[000D"; int delta = Info->BufferUsed - Info->BufferWritePos; buf[2] += (delta/100) % 10; buf[3] += (delta/10) % 10; buf[4] += (delta) % 10; _SysWrite(STDOUT_FD, &ch, 1); // Print new character _SysWrite(STDOUT_FD, &Info->CurBuffer[Info->BufferWritePos], Info->BufferUsed - Info->BufferWritePos ); _SysWrite(STDOUT_FD, buf, 7); // Update Cursor // Move buffer right memmove( &Info->CurBuffer[Info->BufferWritePos+1], &Info->CurBuffer[Info->BufferWritePos], Info->BufferUsed - Info->BufferWritePos ); } // Simple append else { _SysWrite(STDOUT_FD, &ch, 1); } Info->CurBuffer[ Info->BufferWritePos ++ ] = ch; Info->BufferUsed ++; break; } return ofs; }