2026-06-01 09:16:39 +02:00
|
|
|
// #include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
|
#include <windows.h>
|
|
|
|
|
#include <conio.h>
|
2026-06-23 10:21:17 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdint.h>
|
2026-06-01 09:16:39 +02:00
|
|
|
#else
|
|
|
|
|
#include <termios.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/ioctl.h>
|
2026-06-23 10:21:17 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <stdint.h>
|
2026-06-01 09:16:39 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// Special key codes (unified across platforms)
|
|
|
|
|
#define KEY_ARROW_UP 1001
|
|
|
|
|
#define KEY_ARROW_DOWN 1002
|
|
|
|
|
#define KEY_ARROW_RIGHT 1003
|
|
|
|
|
#define KEY_ARROW_LEFT 1004
|
|
|
|
|
|
|
|
|
|
int terminkey();
|
|
|
|
|
void echooff();
|
|
|
|
|
void echoon();
|
|
|
|
|
int termwidth();
|
|
|
|
|
|
2026-06-23 10:21:17 +02:00
|
|
|
int ipc_init();
|
|
|
|
|
int ipc_check_message(uintptr_t buffer_ptr, int max_len);
|
|
|
|
|
void ipc_send_message(const char* message);
|
|
|
|
|
void ipc_cleanup();
|
|
|
|
|
void get_absolute_path(const char* rel_path, uintptr_t abs_path_ptr, int max_len);
|
|
|
|
|
|
2026-06-01 09:16:39 +02:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
|
2026-06-23 10:21:17 +02:00
|
|
|
static HANDLE hServerPipe = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
2026-06-01 09:16:39 +02:00
|
|
|
int terminkey() {
|
|
|
|
|
if (_kbhit()) {
|
|
|
|
|
int ch = _getch();
|
|
|
|
|
// Handle Windows arrow keys
|
|
|
|
|
if (ch == 224) {
|
|
|
|
|
int next = _getch();
|
|
|
|
|
switch (next) {
|
|
|
|
|
case 72: return KEY_ARROW_UP;
|
|
|
|
|
case 80: return KEY_ARROW_DOWN;
|
|
|
|
|
case 75: return KEY_ARROW_LEFT;
|
|
|
|
|
case 77: return KEY_ARROW_RIGHT;
|
|
|
|
|
default: return next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ch;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void echooff() {
|
|
|
|
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
|
|
|
|
DWORD mode = 0;
|
|
|
|
|
GetConsoleMode(hStdin, &mode);
|
|
|
|
|
SetConsoleMode(hStdin, mode & ~ENABLE_ECHO_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void echoon() {
|
|
|
|
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
|
|
|
|
DWORD mode = 0;
|
|
|
|
|
GetConsoleMode(hStdin, &mode);
|
|
|
|
|
SetConsoleMode(hStdin, mode | ENABLE_ECHO_INPUT);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int termwidth() {
|
|
|
|
|
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
|
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
|
|
|
|
if (GetConsoleScreenBufferInfo(hStdout, &csbi)) {
|
|
|
|
|
return csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-23 10:21:17 +02:00
|
|
|
int ipc_init() {
|
|
|
|
|
hServerPipe = CreateNamedPipe(
|
|
|
|
|
"\\\\.\\pipe\\cimp_ipc",
|
|
|
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE,
|
|
|
|
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT,
|
|
|
|
|
1,
|
|
|
|
|
4096,
|
|
|
|
|
4096,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
if (hServerPipe == INVALID_HANDLE_VALUE) {
|
|
|
|
|
DWORD err = GetLastError();
|
|
|
|
|
if (err == ERROR_ACCESS_DENIED || err == ERROR_PIPE_BUSY) {
|
|
|
|
|
return 0; // Already running
|
|
|
|
|
}
|
|
|
|
|
return -1; // Other error
|
|
|
|
|
}
|
|
|
|
|
ConnectNamedPipe(hServerPipe, NULL);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ipc_check_message(uintptr_t buffer_ptr, int max_len) {
|
|
|
|
|
if (hServerPipe == INVALID_HANDLE_VALUE) return 0;
|
|
|
|
|
|
|
|
|
|
char* buffer = (char*)buffer_ptr;
|
|
|
|
|
DWORD bytesRead = 0;
|
2026-06-23 12:22:51 +02:00
|
|
|
|
|
|
|
|
// Check if a client is connected (or already connected)
|
2026-06-23 10:21:17 +02:00
|
|
|
BOOL connected = ConnectNamedPipe(hServerPipe, NULL) ?
|
|
|
|
|
TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
|
|
|
|
|
|
|
|
|
|
if (connected) {
|
2026-06-23 12:22:51 +02:00
|
|
|
DWORD bytesAvail = 0;
|
|
|
|
|
// Sneak peek to see if data has safely arrived in the buffer yet
|
|
|
|
|
if (PeekNamedPipe(hServerPipe, NULL, 0, NULL, &bytesAvail, NULL)) {
|
|
|
|
|
if (bytesAvail > 0) {
|
|
|
|
|
// Data is ready, perform the read safely
|
|
|
|
|
BOOL success = ReadFile(hServerPipe, buffer, max_len - 1, &bytesRead, NULL);
|
|
|
|
|
if (success && bytesRead > 0) {
|
|
|
|
|
buffer[bytesRead] = '\0';
|
|
|
|
|
DisconnectNamedPipe(hServerPipe);
|
|
|
|
|
ConnectNamedPipe(hServerPipe, NULL); // Re-arm for next connection
|
|
|
|
|
return (int)bytesRead;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// If Peek fails because the client dropped out without sending anything
|
|
|
|
|
if (GetLastError() == ERROR_BROKEN_PIPE) {
|
|
|
|
|
DisconnectNamedPipe(hServerPipe);
|
|
|
|
|
ConnectNamedPipe(hServerPipe, NULL);
|
|
|
|
|
}
|
2026-06-23 10:21:17 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ipc_send_message(const char* message) {
|
|
|
|
|
HANDLE hPipe = CreateFile(
|
|
|
|
|
"\\\\.\\pipe\\cimp_ipc",
|
|
|
|
|
GENERIC_WRITE,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
OPEN_EXISTING,
|
|
|
|
|
0,
|
|
|
|
|
NULL
|
|
|
|
|
);
|
|
|
|
|
if (hPipe != INVALID_HANDLE_VALUE) {
|
|
|
|
|
DWORD bytesWritten = 0;
|
|
|
|
|
WriteFile(hPipe, message, strlen(message), &bytesWritten, NULL);
|
|
|
|
|
CloseHandle(hPipe);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ipc_cleanup() {
|
|
|
|
|
if (hServerPipe != INVALID_HANDLE_VALUE) {
|
|
|
|
|
CloseHandle(hServerPipe);
|
|
|
|
|
hServerPipe = INVALID_HANDLE_VALUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void get_absolute_path(const char* rel_path, uintptr_t abs_path_ptr, int max_len) {
|
|
|
|
|
char* abs_path = (char*)abs_path_ptr;
|
|
|
|
|
_fullpath(abs_path, rel_path, max_len);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 09:16:39 +02:00
|
|
|
#else
|
|
|
|
|
|
2026-06-23 10:21:17 +02:00
|
|
|
static int server_fd = -1;
|
|
|
|
|
static char socket_path[256] = "";
|
|
|
|
|
|
|
|
|
|
static void get_socket_path() {
|
|
|
|
|
if (socket_path[0] == '\0') {
|
|
|
|
|
uid_t uid = getuid();
|
|
|
|
|
snprintf(socket_path, sizeof(socket_path), "/tmp/cimp_ipc_%u.sock", (unsigned int)uid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 09:16:39 +02:00
|
|
|
int terminkey() {
|
|
|
|
|
struct termios oldt, newt;
|
|
|
|
|
int ch;
|
|
|
|
|
int oldf;
|
|
|
|
|
// Save existing terminal settings
|
|
|
|
|
tcgetattr(STDIN_FILENO, &oldt);
|
|
|
|
|
newt = oldt;
|
|
|
|
|
|
|
|
|
|
// Disable buffering and echoing
|
|
|
|
|
newt.c_lflag &= ~(ICANON | ECHO);
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
|
|
|
|
|
|
|
|
|
// Set STDIN to non-blocking
|
|
|
|
|
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
|
|
|
|
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
|
|
|
|
ch = getchar();
|
|
|
|
|
|
|
|
|
|
// Handle Unix arrow keys (ESC [ A/B/C/D)
|
|
|
|
|
if (ch == 27) {
|
|
|
|
|
int next1 = getchar();
|
|
|
|
|
if (next1 == '[') {
|
|
|
|
|
int next2 = getchar();
|
|
|
|
|
switch (next2) {
|
|
|
|
|
case 'A': ch = KEY_ARROW_UP; break;
|
|
|
|
|
case 'B': ch = KEY_ARROW_DOWN; break;
|
|
|
|
|
case 'C': ch = KEY_ARROW_RIGHT; break;
|
|
|
|
|
case 'D': ch = KEY_ARROW_LEFT; break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Restore terminal settings
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
|
|
|
|
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
|
|
|
|
return ch;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void echooff() {
|
|
|
|
|
struct termios tty;
|
|
|
|
|
tcgetattr(STDIN_FILENO, &tty);
|
|
|
|
|
tty.c_lflag &= ~ECHO;
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &tty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void echoon() {
|
|
|
|
|
struct termios tty;
|
|
|
|
|
tcgetattr(STDIN_FILENO, &tty);
|
|
|
|
|
tty.c_lflag |= ECHO;
|
|
|
|
|
tcsetattr(STDIN_FILENO, TCSANOW, &tty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int termwidth() {
|
|
|
|
|
struct winsize w;
|
|
|
|
|
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
|
|
|
|
|
return w.ws_col;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-23 10:21:17 +02:00
|
|
|
int ipc_init() {
|
|
|
|
|
get_socket_path();
|
|
|
|
|
|
|
|
|
|
int test_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
|
if (test_fd >= 0) {
|
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
|
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
|
|
|
|
if (connect(test_fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
|
|
|
|
|
close(test_fd);
|
|
|
|
|
return 0; // Already running
|
|
|
|
|
}
|
|
|
|
|
close(test_fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unlink(socket_path);
|
|
|
|
|
|
|
|
|
|
server_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
|
if (server_fd < 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int flags = fcntl(server_fd, F_GETFL, 0);
|
|
|
|
|
fcntl(server_fd, F_SETFL, flags | O_NONBLOCK);
|
|
|
|
|
|
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
|
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
|
|
|
|
|
|
|
|
|
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
|
|
|
|
|
close(server_fd);
|
|
|
|
|
server_fd = -1;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (listen(server_fd, 5) < 0) {
|
|
|
|
|
close(server_fd);
|
|
|
|
|
server_fd = -1;
|
|
|
|
|
unlink(socket_path);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ipc_check_message(uintptr_t buffer_ptr, int max_len) {
|
|
|
|
|
if (server_fd < 0) return 0;
|
|
|
|
|
|
|
|
|
|
char* buffer = (char*)buffer_ptr;
|
|
|
|
|
int client_fd = accept(server_fd, NULL, NULL);
|
|
|
|
|
if (client_fd < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int total_read = 0;
|
|
|
|
|
while (total_read < max_len - 1) {
|
|
|
|
|
int r = read(client_fd, buffer + total_read, max_len - 1 - total_read);
|
|
|
|
|
if (r <= 0) break;
|
|
|
|
|
total_read += r;
|
|
|
|
|
}
|
|
|
|
|
buffer[total_read] = '\0';
|
|
|
|
|
close(client_fd);
|
|
|
|
|
return total_read;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ipc_send_message(const char* message) {
|
|
|
|
|
get_socket_path();
|
|
|
|
|
int client_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
|
if (client_fd < 0) return;
|
|
|
|
|
|
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
|
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path) - 1);
|
|
|
|
|
|
|
|
|
|
if (connect(client_fd, (struct sockaddr*)&addr, sizeof(addr)) == 0) {
|
|
|
|
|
int total_written = 0;
|
|
|
|
|
int len = strlen(message);
|
|
|
|
|
while (total_written < len) {
|
|
|
|
|
int w = write(client_fd, message + total_written, len - total_written);
|
|
|
|
|
if (w <= 0) break;
|
|
|
|
|
total_written += w;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
close(client_fd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ipc_cleanup() {
|
|
|
|
|
if (server_fd >= 0) {
|
|
|
|
|
close(server_fd);
|
|
|
|
|
server_fd = -1;
|
|
|
|
|
}
|
|
|
|
|
get_socket_path();
|
|
|
|
|
unlink(socket_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void get_absolute_path(const char* rel_path, uintptr_t abs_path_ptr, int max_len) {
|
|
|
|
|
char* abs_path = (char*)abs_path_ptr;
|
|
|
|
|
char resolved[PATH_MAX];
|
|
|
|
|
if (realpath(rel_path, resolved) != NULL) {
|
|
|
|
|
strncpy(abs_path, resolved, max_len);
|
|
|
|
|
abs_path[max_len - 1] = '\0';
|
|
|
|
|
} else {
|
|
|
|
|
if (rel_path[0] == '/') {
|
|
|
|
|
strncpy(abs_path, rel_path, max_len);
|
|
|
|
|
abs_path[max_len - 1] = '\0';
|
|
|
|
|
} else {
|
|
|
|
|
char cwd[PATH_MAX];
|
|
|
|
|
if (getcwd(cwd, sizeof(cwd)) != NULL) {
|
|
|
|
|
snprintf(abs_path, max_len, "%s/%s", cwd, rel_path);
|
|
|
|
|
} else {
|
|
|
|
|
strncpy(abs_path, rel_path, max_len);
|
|
|
|
|
abs_path[max_len - 1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-01 09:16:39 +02:00
|
|
|
#endif
|