From 52c3cacd9ed396cd870c0c272042df31d11ed4de Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Wed, 18 Feb 2026 18:35:34 +0100 Subject: [PATCH] feat: Sockets, user-mode networking, IRC client application --- kernel/src/Api/Syscall.cpp | 54 +- kernel/src/Api/Syscall.hpp | 10 + kernel/src/Net/Net.cpp | 2 + kernel/src/Net/Socket.cpp | 145 ++++ kernel/src/Net/Socket.hpp | 54 ++ kernel/src/Net/Tcp.cpp | 71 +- kernel/src/Net/Tcp.hpp | 3 + programs/bin/shell.elf | Bin 63792 -> 74904 bytes programs/include/Api/Syscall.hpp | 10 + programs/include/zenith/syscall.h | 26 + programs/man/syscalls.2 | 36 +- programs/obj/shell/main.o | Bin 129024 -> 156840 bytes programs/src/irc/main.cpp | 1079 +++++++++++++++++++++++++++++ programs/src/shell/main.cpp | 159 ++++- 14 files changed, 1635 insertions(+), 14 deletions(-) create mode 100644 kernel/src/Net/Socket.cpp create mode 100644 kernel/src/Net/Socket.hpp create mode 100644 programs/src/irc/main.cpp diff --git a/kernel/src/Api/Syscall.cpp b/kernel/src/Api/Syscall.cpp index fca5605..a91de18 100644 --- a/kernel/src/Api/Syscall.cpp +++ b/kernel/src/Api/Syscall.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -268,6 +269,40 @@ namespace Zenith { out->Second = dt.Second; } + // ---- Socket syscalls ---- + + static int Sys_Socket(int type) { + return Net::Socket::Create(type, Sched::GetCurrentPid()); + } + + static int Sys_Connect(int fd, uint32_t ip, uint16_t port) { + return Net::Socket::Connect(fd, ip, port, Sched::GetCurrentPid()); + } + + static int Sys_Bind(int fd, uint16_t port) { + return Net::Socket::Bind(fd, port, Sched::GetCurrentPid()); + } + + static int Sys_Listen(int fd) { + return Net::Socket::Listen(fd, Sched::GetCurrentPid()); + } + + static int Sys_Accept(int fd) { + return Net::Socket::Accept(fd, Sched::GetCurrentPid()); + } + + static int Sys_Send(int fd, const uint8_t* data, uint32_t len) { + return Net::Socket::Send(fd, data, len, Sched::GetCurrentPid()); + } + + static int Sys_Recv(int fd, uint8_t* buf, uint32_t maxLen) { + return Net::Socket::Recv(fd, buf, maxLen, Sched::GetCurrentPid()); + } + + static void Sys_CloseSock(int fd) { + Net::Socket::Close(fd, Sched::GetCurrentPid()); + } + static void Sys_Reset() { /* Triple fault for now; TODO: implement UEFI runtime function for clean reboot. @@ -364,6 +399,23 @@ namespace Zenith { case SYS_GETTIME: Sys_GetTime((DateTime*)frame->arg1); return 0; + case SYS_SOCKET: + return (int64_t)Sys_Socket((int)frame->arg1); + case SYS_CONNECT: + return (int64_t)Sys_Connect((int)frame->arg1, (uint32_t)frame->arg2, (uint16_t)frame->arg3); + case SYS_BIND: + return (int64_t)Sys_Bind((int)frame->arg1, (uint16_t)frame->arg2); + case SYS_LISTEN: + return (int64_t)Sys_Listen((int)frame->arg1); + case SYS_ACCEPT: + return (int64_t)Sys_Accept((int)frame->arg1); + case SYS_SEND: + return (int64_t)Sys_Send((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3); + case SYS_RECV: + return (int64_t)Sys_Recv((int)frame->arg1, (uint8_t*)frame->arg2, (uint32_t)frame->arg3); + case SYS_CLOSESOCK: + Sys_CloseSock((int)frame->arg1); + return 0; default: return -1; } @@ -390,7 +442,7 @@ namespace Zenith { Hal::WriteMSR(Hal::IA32_FMASK, 0x200); Kt::KernelLogStream(Kt::OK, "Syscall") << "SYSCALL/SYSRET initialized (LSTAR=" - << kcp::hex << (uint64_t)SyscallEntry << kcp::dec << ", 29 syscalls)"; + << kcp::hex << (uint64_t)SyscallEntry << kcp::dec << ", 37 syscalls)"; } } diff --git a/kernel/src/Api/Syscall.hpp b/kernel/src/Api/Syscall.hpp index 2077fb1..9b03f4a 100644 --- a/kernel/src/Api/Syscall.hpp +++ b/kernel/src/Api/Syscall.hpp @@ -40,6 +40,16 @@ namespace Zenith { static constexpr uint64_t SYS_RESET = 26; static constexpr uint64_t SYS_SHUTDOWN = 27; static constexpr uint64_t SYS_GETTIME = 28; + static constexpr uint64_t SYS_SOCKET = 29; + static constexpr uint64_t SYS_CONNECT = 30; + static constexpr uint64_t SYS_BIND = 31; + static constexpr uint64_t SYS_LISTEN = 32; + static constexpr uint64_t SYS_ACCEPT = 33; + static constexpr uint64_t SYS_SEND = 34; + static constexpr uint64_t SYS_RECV = 35; + static constexpr uint64_t SYS_CLOSESOCK = 36; + + static constexpr int SOCK_TCP = 1; struct DateTime { uint16_t Year; diff --git a/kernel/src/Net/Net.cpp b/kernel/src/Net/Net.cpp index ba16d03..23af4cd 100644 --- a/kernel/src/Net/Net.cpp +++ b/kernel/src/Net/Net.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -33,6 +34,7 @@ namespace Net { Icmp::Initialize(); Udp::Initialize(); Tcp::Initialize(); + Socket::Initialize(); // Hook E1000 RX to our Ethernet dispatcher Drivers::Net::E1000::SetRxCallback(Ethernet::OnFrameReceived); diff --git a/kernel/src/Net/Socket.cpp b/kernel/src/Net/Socket.cpp new file mode 100644 index 0000000..efa4452 --- /dev/null +++ b/kernel/src/Net/Socket.cpp @@ -0,0 +1,145 @@ +/* + * Socket.cpp + * Socket descriptor table wrapping kernel TCP layer + * Copyright (c) 2025 Daniel Hammer +*/ + +#include "Socket.hpp" +#include +#include +#include +#include + +using namespace Kt; + +namespace Net::Socket { + + static SocketEntry g_sockets[MAX_SOCKETS] = {}; + static uint16_t g_nextEphemeralPort = 49152; + + static uint16_t AllocEphemeralPort() { + uint16_t port = g_nextEphemeralPort++; + if (g_nextEphemeralPort == 0) g_nextEphemeralPort = 49152; + return port; + } + + static bool ValidFd(int fd, int pid) { + if (fd < 0 || fd >= MAX_SOCKETS) return false; + if (!g_sockets[fd].Active) return false; + if (g_sockets[fd].OwnerPid != pid) return false; + return true; + } + + void Initialize() { + for (int i = 0; i < MAX_SOCKETS; i++) { + g_sockets[i].Active = false; + } + KernelLogStream(OK, "Net") << "Socket table initialized"; + } + + int Create(int type, int pid) { + if (type != SOCK_TCP) return -1; + + for (int i = 0; i < MAX_SOCKETS; i++) { + if (!g_sockets[i].Active) { + g_sockets[i].Active = true; + g_sockets[i].Type = type; + g_sockets[i].OwnerPid = pid; + g_sockets[i].TcpConn = nullptr; + g_sockets[i].LocalPort = 0; + return i; + } + } + return -1; + } + + int Connect(int fd, uint32_t ip, uint16_t port, int pid) { + if (!ValidFd(fd, pid)) return -1; + if (g_sockets[fd].TcpConn != nullptr) return -1; + + uint16_t srcPort = AllocEphemeralPort(); + g_sockets[fd].LocalPort = srcPort; + + Tcp::Connection* conn = Tcp::Connect(ip, port, srcPort); + if (conn == nullptr) return -1; + + g_sockets[fd].TcpConn = conn; + return 0; + } + + int Bind(int fd, uint16_t port, int pid) { + if (!ValidFd(fd, pid)) return -1; + g_sockets[fd].LocalPort = port; + return 0; + } + + int Listen(int fd, int pid) { + if (!ValidFd(fd, pid)) return -1; + if (g_sockets[fd].LocalPort == 0) return -1; + if (g_sockets[fd].TcpConn != nullptr) return -1; + + Tcp::Connection* conn = Tcp::Listen(g_sockets[fd].LocalPort); + if (conn == nullptr) return -1; + + g_sockets[fd].TcpConn = conn; + return 0; + } + + int Accept(int fd, int pid) { + if (!ValidFd(fd, pid)) return -1; + if (g_sockets[fd].TcpConn == nullptr) return -1; + + Tcp::Connection* clientConn = Tcp::Accept(g_sockets[fd].TcpConn); + if (clientConn == nullptr) return -1; + + // Allocate a new socket entry for the accepted connection + for (int i = 0; i < MAX_SOCKETS; i++) { + if (!g_sockets[i].Active) { + g_sockets[i].Active = true; + g_sockets[i].Type = SOCK_TCP; + g_sockets[i].OwnerPid = pid; + g_sockets[i].TcpConn = clientConn; + g_sockets[i].LocalPort = g_sockets[fd].LocalPort; + return i; + } + } + + // No free socket slot — close the accepted connection + Tcp::Close(clientConn); + return -1; + } + + int Send(int fd, const uint8_t* data, uint32_t len, int pid) { + if (!ValidFd(fd, pid)) return -1; + if (g_sockets[fd].TcpConn == nullptr) return -1; + return Tcp::Send(g_sockets[fd].TcpConn, data, (uint16_t)len); + } + + int Recv(int fd, uint8_t* buf, uint32_t maxLen, int pid) { + if (!ValidFd(fd, pid)) return -1; + if (g_sockets[fd].TcpConn == nullptr) return -1; + return Tcp::ReceiveNonBlocking(g_sockets[fd].TcpConn, buf, (uint16_t)maxLen); + } + + void Close(int fd, int pid) { + if (!ValidFd(fd, pid)) return; + if (g_sockets[fd].TcpConn != nullptr) { + Tcp::Close(g_sockets[fd].TcpConn); + g_sockets[fd].TcpConn = nullptr; + } + g_sockets[fd].Active = false; + } + + void CleanupProcess(int pid) { + for (int i = 0; i < MAX_SOCKETS; i++) { + if (g_sockets[i].Active && g_sockets[i].OwnerPid == pid) { + if (g_sockets[i].TcpConn != nullptr) { + Tcp::Close(g_sockets[i].TcpConn); + g_sockets[i].TcpConn = nullptr; + } + g_sockets[i].Active = false; + } + } + } + +} diff --git a/kernel/src/Net/Socket.hpp b/kernel/src/Net/Socket.hpp new file mode 100644 index 0000000..f681bd6 --- /dev/null +++ b/kernel/src/Net/Socket.hpp @@ -0,0 +1,54 @@ +/* + * Socket.hpp + * Socket descriptor table for userspace TCP access + * Copyright (c) 2025 Daniel Hammer +*/ + +#pragma once +#include +#include + +namespace Net::Socket { + + static constexpr int SOCK_TCP = 1; + static constexpr int SOCK_UDP = 2; + static constexpr int MAX_SOCKETS = 64; + + struct SocketEntry { + bool Active; + int Type; + int OwnerPid; + Tcp::Connection* TcpConn; + uint16_t LocalPort; + }; + + void Initialize(); + + // Create a socket of the given type. Returns fd or -1. + int Create(int type, int pid); + + // Connect socket fd to remote ip:port. Returns 0 or -1. + int Connect(int fd, uint32_t ip, uint16_t port, int pid); + + // Bind socket fd to a local port. Returns 0 or -1. + int Bind(int fd, uint16_t port, int pid); + + // Start listening on a bound socket. Returns 0 or -1. + int Listen(int fd, int pid); + + // Accept an incoming connection. Returns new fd or -1. + int Accept(int fd, int pid); + + // Send data on a connected socket. Returns bytes sent or -1. + int Send(int fd, const uint8_t* data, uint32_t len, int pid); + + // Receive data from a connected socket. Returns bytes received, 0 on close, or -1. + int Recv(int fd, uint8_t* buf, uint32_t maxLen, int pid); + + // Close a socket. + void Close(int fd, int pid); + + // Close all sockets owned by a process (called on process exit). + void CleanupProcess(int pid); + +} diff --git a/kernel/src/Net/Tcp.cpp b/kernel/src/Net/Tcp.cpp index 85527e9..da2fe37 100644 --- a/kernel/src/Net/Tcp.cpp +++ b/kernel/src/Net/Tcp.cpp @@ -523,9 +523,11 @@ namespace Net::Tcp { return -1; } + // Phase 1: Send data segments with interrupts disabled (lock-safe) + uint64_t flags; + asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); conn->Lock.Acquire(); - // Send data in segments up to MSS (we use a simple 1460 byte MSS) constexpr uint16_t MSS = 1460; uint16_t sent = 0; @@ -538,6 +540,7 @@ namespace Net::Tcp { bool ok = SendSegment(conn, FLAG_ACK | FLAG_PSH, data + sent, segLen); if (!ok) { conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); return sent > 0 ? sent : -1; } @@ -554,30 +557,36 @@ namespace Net::Tcp { sent += segLen; } - // Simple wait for ACK with retransmission + conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); + + // Phase 2: Wait for ACK without holding the lock (interrupts enabled) uint64_t startTime = Timekeeping::GetMilliseconds(); while (conn->SendUnack != conn->SendNext) { uint64_t now = Timekeeping::GetMilliseconds(); if ((now - startTime) > (RETRANSMIT_TIMEOUT_MS * MAX_RETRANSMITS)) { - break; // Give up + break; } if ((now - conn->RetransmitTime) > RETRANSMIT_TIMEOUT_MS && conn->RetransmitLen > 0) { conn->RetransmitCount++; if (conn->RetransmitCount > MAX_RETRANSMITS) { break; } - // Retransmit: rewind SendNext temporarily + // Retransmit with brief interrupt-disabled window + asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); + conn->Lock.Acquire(); uint32_t savedNext = conn->SendNext; conn->SendNext = conn->SendUnack; SendSegment(conn, FLAG_ACK | FLAG_PSH, conn->RetransmitBuffer, conn->RetransmitLen); conn->SendNext = savedNext; - conn->RetransmitTime = now; + conn->RetransmitTime = Timekeeping::GetMilliseconds(); + conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); } Timekeeping::Sleep(10); } - conn->Lock.Release(); return sent; } @@ -588,6 +597,8 @@ namespace Net::Tcp { // Block until data is available or connection is closing while (true) { + uint64_t flags; + asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); conn->Lock.Acquire(); if (conn->RecvCount > 0) { @@ -603,6 +614,7 @@ namespace Net::Tcp { conn->RecvCount -= toRead; conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); return toRead; } @@ -610,19 +622,62 @@ namespace Net::Tcp { conn->CurrentState == State::Closed || conn->CurrentState == State::TimeWait) { conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); return 0; // Connection closed } conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); Timekeeping::Sleep(10); } } + int ReceiveNonBlocking(Connection* conn, uint8_t* buffer, uint16_t bufferSize) { + if (conn == nullptr) { + return -1; + } + + // Disable interrupts while holding the lock to prevent deadlock + // with OnPacketReceived (called from the network interrupt handler) + uint64_t flags; + asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); + + conn->Lock.Acquire(); + + int result; + if (conn->RecvCount > 0) { + uint16_t toRead = conn->RecvCount; + if (toRead > bufferSize) { + toRead = bufferSize; + } + + for (uint16_t i = 0; i < toRead; i++) { + buffer[i] = conn->RecvBuffer[conn->RecvHead]; + conn->RecvHead = (conn->RecvHead + 1) % RECV_BUFFER_SIZE; + } + conn->RecvCount -= toRead; + result = toRead; + } else if (conn->CurrentState == State::CloseWait || + conn->CurrentState == State::Closed || + conn->CurrentState == State::TimeWait) { + result = -1; // Connection closed + } else { + result = 0; // No data available + } + + conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); + + return result; + } + void Close(Connection* conn) { if (conn == nullptr) { return; } + uint64_t flags; + asm volatile("pushfq; pop %0; cli" : "=r"(flags) :: "memory"); conn->Lock.Acquire(); switch (conn->CurrentState) { @@ -631,6 +686,7 @@ namespace Net::Tcp { SendSegment(conn, FLAG_FIN | FLAG_ACK, nullptr, 0); conn->SendNext++; conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); // Wait for close to complete for (int i = 0; i < 100; i++) { @@ -649,6 +705,7 @@ namespace Net::Tcp { SendSegment(conn, FLAG_FIN | FLAG_ACK, nullptr, 0); conn->SendNext++; conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); // Wait for final ACK for (int i = 0; i < 100; i++) { @@ -666,11 +723,13 @@ namespace Net::Tcp { conn->CurrentState = State::Closed; conn->Active = false; conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); return; } default: conn->Lock.Release(); + asm volatile("push %0; popfq" :: "r"(flags) : "memory"); conn->Active = false; return; } diff --git a/kernel/src/Net/Tcp.hpp b/kernel/src/Net/Tcp.hpp index 24de7d8..c523394 100644 --- a/kernel/src/Net/Tcp.hpp +++ b/kernel/src/Net/Tcp.hpp @@ -71,6 +71,9 @@ namespace Net::Tcp { // Blocks until data is available or connection is closed. int Receive(Connection* conn, uint8_t* buffer, uint16_t bufferSize); + // Non-blocking receive. Returns bytes read, 0 if no data available, or -1 on closed/error. + int ReceiveNonBlocking(Connection* conn, uint8_t* buffer, uint16_t bufferSize); + // Close a TCP connection gracefully void Close(Connection* conn); diff --git a/programs/bin/shell.elf b/programs/bin/shell.elf index bee455188cbcbe9c832f13b29c9c1104ed7c8141..4719627ec0cf87651555ca365e6d0159df1cdabe 100755 GIT binary patch literal 74904 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�~>c*n}=)wT0FkteEq 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 Xd_|)ijl=b?tCElhyq$6F@Be=QXZt0= literal 63792 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 >_F}yKsQ9>L}r&#_GGe zU^uoyeiuUOI}lqHpw~=9tfpb>nM&JF>cZAwT7rUBkFi#T%Qsfv(*+NS)$Wk$3Sz4Q z^ptQEtn?A9BLGc+*y_T&wcneTJ`o*D(92L7dkl!ZWOziij zcq}$q{rzGV+ZxE9++6HgQ`{M1=ZKiAVjl+bFKaILl_{P!6w^vT?2l#vr~Dnw#g>^V zl$!oVK0rXA7%zc_ReKvPnk4~r6tKd~&+e*`+E zF^IlY&!0|30T7Icmb_vEQ0~=O8EGMheq?{H2@wjV+ zC@TbUl!`=3GYN^(qX6v-;wT*fCIK>0%0^E&L8X;&vN%m{cZC=|1wzw6Y*cVgGYK(T z1?XZB8(jrvCCC`%L&9^6QAY_EHU7|3{1x#gNZbHoivseR!NuaA0et|(7M}pq05TT+ zN74`F`aPmmHVv>)d}as0>1ND@`3^tM6N@ z!bQw@_(bRAbT)160I4DnTNR+EgcA|5ItOpH&IH~xjI%lm|oe8NK zAhs$%PYEX?V)ZwGE(Q6$3#JYfwEC^JDx6gOGoAC3SiK!m8$oPUfSwXgM8xV=K(~PW zeg(4|WUO|i8Cb{sXu{Xv4AJI1~)q%eAu}&9KZmM%zrv&owX-QBzMB*BxtDZl3*q&+H zy7XNLrpt|l>NytnmTKAu^_@{Q2W%0^^;tY`mRjY1qe_)r4PZhyL=z;TcB3lv(KoN^ zg@-UCmC$jLx(goI2U^?}(wDlN^}CjLxD=-6+Vrvxm!RNmolWxe{jE~knV#cY zdj|4Pg7W66YCq=yQvU$88VIRlyQ6aWj=UPDGpO;Udts`==iB1MsWqroIe-NKLdSTW zL$JQc?haBDmmY`n-i!oTH!$7yA3g$h6X70me@N`-NEJBpO zpf^wFt|p-n^vAJuwxNTaPXId_%uq^vjl>yXP62ro&CyI?FGK1=P`^SXRCusjykP;4y7JnA#f*Yx>GzZ=eiH#th90ce#6OqYbE1+9I{?rU+H^@v5Y;}ZP5QK{u zs|$5O4CBI|c_H;Kh^-3HQ^JXeSUn8rArM;);bcdFj8)z>jkQ*ViyEtobRqAWvLO)z zu|)xSN;rYbuBiyn_8_)c0;Ug0CPAKo=;noIAneAT!9>+lPxlgR^aW#D-%K|$JdgDB zXP?nfatw&)jeat3>{*^iv(i9+R#<@YIUpWcqB6waZ|nsR_C}rPyNH(oatX-q>vhJo zR>H|WaUWfQY(D$^pN?*7fsN1CV z0r~-yya(hvB)ScWAHjSN3a>_#ij2cwxC||AtFJ(A1`e3g=#c4pB-(>%O^M$lF%-;T zkar7AMDIh+Sft89)b<4!Q?J@u2$#Wy7)HAAH&mnZfI1ZtCxLh?D?mrx2d$xvJ^3u< zTof+?aeG&TSpo7GA&=~6Yw?Y>C!CC{!Mfl}vPZt&2-yuF_O$>VD=Z@7>n(sj0%F^{ z!O)Rga9pK_6Wl6C2`7VOh%T6e37@UL3#q*zwkklcnTS|D1nB1=wyJRO^%D|7t9jO{ zaN^scy5JvTH3rEH5L*=>zNlq{MMSK20kji{tquY+0A#FolK7Z#0^jF{me7rSs9FuL zK+uOGD>2#{kdZ{A`R)0vk7bRm-GfsStL zBuGeI!&jxI^ygKzwa!G}sjC555AvQtBCo2tTD8&H$AG7|rECOcu0}|8HabG;briMH z9n?|ya|KHD^|)*WZVSkvuotXrIcy~P6S}2{hrn}y{uR`Qh5(2DKahG0#8LkRn9o3F zz#n65YbBfv_;$M0d8h}6!%q}yiT^Yn(BnaDbvl?cKw^~!++u50I2k>0-Ri7< zrmaV0(7jfh)7#619UBjt=fV%=(|So$-N4}f?o5g3Lx zV50q56z>AD_BX-24)P+}now-xE^DI@MICjk?g&Hfxx>I80;JOi8dtRwo&0doY~##`3aJrjN~$inh-yQN&0uKm z3-TA6Lk6eu(}V;vv9R)$^cNhK7Mue7G!XZP0G(zc(wZtj7lXJptH7)Tnf_>f&k#H! zfsHJkvupr{$fHQNc?uVga(nCn=d9nnBKj7XTOoG?DEcuHJHTwA#6OWZ0OoyAzn_pu zgc18)&RP7{~1xh^-3H zYbGLA8vuO_#8&r!c^)KI={)M*P(sniv7B^vt}fh5R_WAjZydKWAhs$ZUNaHdU3~%Q zXCStE1k8`1;Na6{U^r^I!VjBt&asGK_G+vMYYm78hQK_v9x!QB7Zi5_vGze==up_Z zgAnqS3~E`flRy?={1cd#xCJE})S3yvj|Z_0fjJD57MzLV(?M)w5ts!a?-8gI8=XXu z1|J2{Tgge74hD9R!4TAt3%ZZ4zxB$>R5L@jG zrX$E$jfsj8aj(UzD;$B|4GZ36GgZP$AT% z-L9vWcS@%hH{yP!^LZZbb28RBh+#}5sY{f8m$xRV_#Hm@K9t)f3o-G2W*e|s^JZP3 z^auQVuPpqUU+E8d+tTF(X!s~fdb(!KQ+hw|Qo3f%RQdq_0t{Wwk<*gGhraT`cP5VN z_6E`~(qovc1u*_n=8Z^q*@nyCefD=659OIv{Rg13f9xAhpcG>O1@zH3Uy(p;(qYIS z`2^({_;UbgAf0{OZ;nD5E{xZq6@TWMFGA@YP@I1I^(ZU93CXKKz0azdt#)LPN}P}U zCVp%fhZc-@45iyZtv-WLmr_W71N~3sP=#MW{$D|H`Zdx{J|4;KfK>-n&Pk}A2~;m`VoXrn07X) zDG5$!ML##xy9;=V%j}2)2oR5Jf#4^EfXEcr7R9YW9Ob>h^ZW+0}_fxerZvC${N zJPwMIOWpzVHV7d@2WR(&#rSg+q#f@egRN2U1uzFe?EL!;ioSG#%C8y8M!Zg_4~UKA zgUJPXgkVb@ktzn^lkx-Z0}4{alyFk(=W^mlLyZTs{UA^R;&uwov9cl&x}+CZVFaKF z5LaOmn28{9F3sri6yK<0Iq9G0^R6YMw9d_d(3v1MDiU5Z37J~Y1#}UJjb0391xSoi zI1f&dmI^2PqQ4YGkAWbC(Rv7731XvybF8dLNEqD>=v^Q-x&_Q5prFx;6ltk&vLrlQ zutJQ!2%#51Y*cXg*@=-A2{F14(04#=^bnZOK|!NaQpBima+ABM;43kD1VTT8*r?z< zC7eiz(H5O?SO{XHUBGk#iBSrq#m1<%TvYj=Z3XjC9}c8rAT%7rMnwX*K}J?2B#@2= zv;xFN&j528$QbP;hs5f4pp_a;d`h~ovTq((=122L6RoNtq)ArxQDTJ@)CFW0%{UazoDU6APvtC5< zub@`7sKK~09E;CW%d!!0>PO^$0qTCXTE_1^IJyfC3P7qA{SbGykF90w1;}2^MH5kU zv0rovv}1>&z6zGaYFZHBsA3!)?73>pQh zEB1jv@iZeSN9_Vi;-L_b0uXmiS1_GH9wW>g&kvm*uqK3ym}>pL)%h^jhRks^NV%hg z6Qr0-z{1fWHaQW@@gNC7npQR&V~*uyTDha}Q)(McD`!IJbPyXA39p%iOe>23T>xUE zE5IxRiP1-n!*pznCb{mWg&Vr{gzNc-3|B&^p0v;p8SVzN5#+D3`KbxUc83m5I z4zP8(tw#bz&m|(=a3cxg=MwbXs+baAL*zIxBS0QW@Nf3A-2q$=z`)-AbvzK1k3Cpt&K;~clyQ1VXvZn!l z9Aq9d(ht&jD}9XWmXd-WN!25xOB%Sd^Ql!TvB1N*a-sv+6T01poU%PYq%KstEKXb3 zEZXqug(F3b~EiWfGNtGacEnn9gV(^Q%r^`NeFnCag!4C+Vu zxwD{I4=No?2B36sQt2?Bs&F?z54O6kK;^non{&@WQg`c|)YR>$q^54eL{oRxM71kP z>g;87cHRJW?a~QLdrP{TY1fuCW}&(58Lv8*qqHSI&84ABn3g>WqdND;1}U5Gh3Gq2 zsY|NSw(L$+mOGYemp#zOO#&{Jan5LPGn7tkPbH~mf$Pnfp=02pP?WxDST-24+g^c8 z84fztBbDeI`dWqh3;jBKAT&fK0j7%1!DS;&>SHO78lhT@MDpgm%@Dzwt>#j}rC|7? zM$oU)Z_NG-8RX2O?_uMb84 zH(4|V1(&>^g1a&*^{den0&DVnlR1=rk}Q}G+^Vc`a618W%8f*%E0Phy@dZ zs;9;wvj^eWPeo5b^YTC7at!5BGgQ$gT$XjmWwOP!c)`Wf->kj3l7e%kz-aj^s&U?8 z2(O_6va6;%fl7rIw@X0x?CmMespE3@GCzpoCUwD# z3y@EDu+T;^l>;`HZns01&>ahMDV8WE{M4_7J&HM7~vlH8Uqq)5FKo-G*T~HseR)Cyd6cQ0QLp-xDN?u z{k9d+EnupUGaq!~lSmvg(l{9BPd~^;pF+X4KwJq5QREk}C1|JeR96mKI4 zd0QZ^Y6Gb3AD>6@-$1_s2vW~ zOaw!gvx3L^wakKGCWyBv0(YCirN%{owg+*IOThF2nJo%DPCLQ|$M?p)>=Qt5rkgNb zf}(PO6QJmDB<6#e4f4N-V}z)pIB&r(D2|5=ZA|L{Sp!lojnhL0hX*)@!xvcjvr4yl zg=FX%{{6t;2jXY=&wzOvopfd11NeH67fFR5rc+RAhGh8`M92nIE*d;GZ6W`LHKA-mE?w6 zJTjsM?Dhwbs<+i8xs&wf5ni^=Ntu>*avJ@v-))>*q)+xvO4ERQc(wrHuq~h3LS#~G z9&3UORFO=?Q)BQa6>px13{4xBHYAObQL=C9k~T(#3YQn+xVgV_GKUs<02Q?#lUv%d zP1^jHc+l2gjfP03wE(NhI>pNMGQA>~Ol3hnU?aP?9-SL6a;PY$qe@FVI?c(%l8%~W zCTo(%LPdI*M>R85$|qaW5YzaACiYGHTJ+Y(w4`c>sBH@~sorF5N_R)$f67b z#5W1hBO-0;+JpNZwtI?%H^fTx>W$7ury*(^%L3m=a=7+b@j0fX>u4~Vx{^L>PNMKa z?u(-u0ZldfrI|j)15pt~;58D&!>H!^3}Za=j}w$6gek!GYs@MtPmr=_9Rs4S|q zFq2Fl#}UODV{%c3hgfJ2jXFRGP##hK;G$m?A>N(LG*W;_p;Em2AUQiqoC2FT zW_7_X9B)Rg>H6cj;f#ty%LMK~Q>!>znrMe`8ckogC!>&FrCZWyn#AMF!`){9#dF^j zTLB);>^-XZ)W-QV%CWJO5F*4$!63kF&9g1~O`U@2*HiE(KDf8#5BAI|EMN9_RcWa2 z2DfyQKHZ(QO6$|yRk~gy@p$-uQmEv*)OS<$=|;5ipYZ5df^+blEA54l0dZ zv?3Dk7>RdYk9YbcbQ`yHA_^x?Md9Y~U&G-48h$Q})C=JcD77c@uL%D9EAm}LpP)P) z)}Y~5b0jok0|d8+>F-P7*XS?S6Z#h!Wl%~_j9i%G*M<0Nl00w#%9}Y;^$C&XBGj~^ z$_W5N12!m31Uf9Du5we)Rgu9RBZE6{a9#3ANJr##oSC7a8}sxEq}H9#TJe>%;i-P~^=B{%lSCkOaQScq$Wr zo{IfG3xA%>x-J`k?#zArrY74JS29Lt&7Z?kHDx%L4J)$NXCW&PUU znauEOpF~LQ->_zE?VnG1KBaN(1E8og@|SAQa;ElevJ-6KfAf6+L$&{7va){d?@ng; zwND~QH+At4YlZ?gYakqXUCJ#fnvMoB&6Jm)?s;7s*4kb)7+dAsa+sH>Ws6s1Ay*NQMH-Do24MBOEZ{%${h=Y8dnH3>_ zC@639jl4|tDWYmdt3i!|F8+n@! z;vjF|BN=u22IXzOk+wE*YHYqXRvJ}Kv#VK9DDCv1FPWyDVla(zUI*l@gXlKd$mF(cvXKd3XdQUO)C`M~N~4U;$&9p?jS=Jl z9hP?#nsuO`zuRh*A9W^6gWZCDyh=r;=liWGZkn7(w+T8duMG@F*=ZDIQji_0Fi|Es zjiK9l@WP&A2zwIdFNgh zn?-or3^E%`GXNEpcaBA(&UWz>DYp5>kWB}1kS{7Qp@G{=u93|!4Yg?oP{)P)85vh~ z!us8*8+O0YG{oeh?tNL4%`lp5ngO^0k(ba#ST*iAYz9dL(@ER%?m1Vrh3&RQzU?K( zcBa_28OF9vi*0%1TNI0&^&3pueDYf`9mJ6r5NPs3Hy1zAx=5YN+p)aJx#}WST+(KP zo7d6gGQ2T9<6Py?|D;ME+QsEj#?#4+ypD|#kPfS`yflr%d?H3o%3>AW@3e)tJ-p64 zQ0m~_Uhq(aUhx$v1;AAiDQ=rdxqs{)Dg9&j)_?S;@HdSAQbI>_)Cv}6REoBuJ);i& z$FB6*fS;Ho^T}DkbP$KokXMl*Na_E2_2m(yHs1uPO$Tw1m$#QeUha-K!fd{gx9K1b z^74)|$kTrnYwg>7BX83|9K&_^o)*3!JSj6`Bt5cNIy=3MogGP_5uWD0SCf4kNvDig zk{Ri38Y5`@%Dc|6*`@zymOeZI*nFxoCIp)f;vg??F2iQ+-Jrb9H}W^Xs5n9Dp&tXo=9B(lI*5b5YU9n6 z&^Y#*ywVE#4%*(q3T5+2UoaiSL7%*A2+?tlm4|(sZ|Y;yK^%HV-W!DIkpJ9<2b9ex zdGwY|H^IqUfDj#vtbNqW=97Fdt_XMb^m%=`9jzLB@- zAP(~OB``s~uy6B?yiEsj2v|AFh5wR)jFrUZlYB58#37>O6)YJ|0@UV{JnCuFO>p+D zE5SgdEfa?(P&lnYPj@JTX0iKXitjhgJI> z=QD@Sg6LyTRKwFOq75Bex9JI7&r)ac3LI{a1i#j;cRBSx?t?B(QFuJ~ZAOArr~ziz ztW{XDTorW|>kV$S5VC~>h$kdl3(H$Z@P0V5)vg^d?K&~O(;(+uf#QgoDz8G}pKRsm z#56kU`i`aC??SbX z-$qm8b!iDwW&D>{%qEL_z~GzSUXLw>U?b2E?a&YHdcyzwK~utCMH9@^wsErCb~LK_ zkn@m(KYN|Mjvxur1RZr2$hdafcG1(^E`xC5H)u3CRxphf1W=^H#d>sdX2eC;#2J zQ0d8$hfKdE&z1=u7B~gT6gRH}^mph2?o#JcC+f7Zb@7(BZfr>$<;yVPd0sedIu5FWx)k*l!lDG%R-vOdxUB|; z`fYHB4dY%Jc079J_*0oDb$sZ_afG{i8%N4njC+6lgmW>h=EgbohPw|T4%=v%4$IqF z_`VD^a#MJH2=|5`7EY@ex5Eq$Z)QzV8WEwX%cx3fUTALIFwKmcMt(XX8Fw@Q$ z>xaB^1q*R|=_6V%Y(C8&!E_LZO51m)AOvB}CP^%qMlsO#eJ6AukK$z7U)_>vl$!yp z!qdG3bt1+O&rd@!0LCxHWxd{_q1SZJOBR)mK1^>3KzllP<)M{S!A}opXkqe|mylo= z^I+V!!IQ1cH5+brBy*YwHv-dSsROzv zQhV`y$hMZA-$gQf|4ME~XtW7L$#IpFx>)(o1~<44;Zesgjh5C?XIIbxHs3hFrkmj8 z9Ul>>LwDMw>3y5_YiHlcfvvi=1~Hp&#B4fdKPUzUiX&-@3 z5=}I;;9Pm*1)^(!Z7%xO<{RhQbPxx5d3Qz3#XT~Ikj=roMImL=J_0iHOk>cYV}mwr zzOiZ3K^)}el?}MjoEDU~`9|KRgE+{`dmWnIsM>rZZ_~jW)sR2rbvW6@t+5ccj-zwq zU7aP^5p*>p_mBw!_*Mn$Y4eR8n-1bALNJ6{hZ4kKTA2qc^Qy68-H-nq6N?i*ym$m4 zT@f2S=ixH1nidcOQUqZkX{>6hp41e=PfZbMNqd9C)oO{t3CrNp2y-3Kw9;zHy^Y1o7QWSUkF{)DI7*@8pq1ccHFXSn#8JVw8ctTd%K!0XK_Y=${@vuOrEVqH@S zn_(nuS|t9^RKjK$37cjKndcBNeZvWEL|~>nVFS%{wV}H))47{MFVKWXvlxBCcUXKD z0yS$LeW7HXzMXcqPw2OhNryW_`A>Fi(o9u0jbffulHG4_ z2M~bMjRP_BeP9O>g5TyFbv7NuAyjlkepegCwnIXO_AF3hi$Vi29R4>j^dx1?oa|Hfele)8t5a*3JVfjhw4^&g;q3o!j$lta5id?>hKX=Wg)u=hE7)T@lFKcpY^@7^E9I%q23OWtlx(>Bjd zErLu@Z#LR{7+S+0GO^WqDvyAlhw5;&;nq3VISjte`2!twXlxPSANk$2t9lUl*po7r z;l)2~I&60Pb)p6Qq_fhN*bELg`DHbBLoJIEY?Y(f=9_S{=_a`Qjk{9~&ZhnNk{>tA z`kPGq(VtAydZ;7HxWx-EQS{X=s*wMcu7kE;GjIcaA->VmD!QI9(aj;u@~zsL)FYH? z*F8{1y9xOja}HG#yAX*#+^zYZ`^38W48G65!n?)4&&L#_!hurXI2AKTQ&7|Lr5jvR zz7+F#IGmC~F(-Shq%K8$)cihw;6U!#fn(6mV@_nA)KM>s4*8igq<`i<|5cn{B=7U( z*UmT$K#fti+>SI@;q7p;2;UXh^&1=kbo9GT3OYKG1oz7XRU9+UVO3392=^x(()(HWSe6!B3z(j`N^+7ij4+4BW7h;6{!mMef)M{&%RXV0fj~ z+5=h>GqJCpIU54AYc<$E>t{5wpV2RCe>2CGRpACJg&$0~syi$1K9Y|GF|9cGZ-(Xf zV02J*f}7VfvP7MSQQUun+q19X`*9e%I>FT`3@t(9bR?O^@FH)7CC61+82Wf-ZoZ(J zRfyigm!pp|8uAf~)Ezd>4{@Q=X3$nJm}Y?ACX9dv$FGUm2#&?x@8q*_sa}RKFjKSR z3WhgUIVdhDrYJx~X+jMs$%f~$f9|Hrn8}Sge~A0qcp9@mv-0EDCPQ?Pp(8dO6bt72 zu__hhg`O%TKb|t%1#^TUxyd68$@#e>3>9f<+MNw6aIqv2@#~7E4e+eZHxX~sK^*N6 zjJg(4XO{H=8e{X#RBY2taQ0_MctB_6vA?wWBp*x%aj>3>YjIQSuGKI2W5sPNR8rT$o;njJ zVH!Q@EavNRhR)1w8ry=2?!)?VKmC+`meS9{zEg!K0&JcZ;mAQ#&0-oK$!NEgH}h`` zK4)!#bMuQfxL4}yp%&+?e}je)SJ?lCy;2EIP2j6iD^2=klb&t{qrCR6!KA-5?Uq4y zugIHfye9JItn3AomhHK`s!UcrdFzZkRoU(M0`f%e%T%MF$)9UelD`)4{%I)qOYUhmcJ2l{iZyo4>w zbz4kS-rF|qxdp9VykO(M%t|%0hO0a`nx{NDVRO}3ck(r`l*~wVQ`;%;QY#R4({lfF z`WB1#4KzyUpw+fqxhYXM0}W438472efY^}gfji>sQK{sCuyS)D@u)pdb=x4aKM<-K4Fv)vueQ;z$xvmQOT&+eSh zaUaA0R$g*Pb%uK#c1p^VJqUGpdRygPZa0sG?!;-zTW`}j?pQQUwue-&Xpbgo>OcEv z%XeM!QP*kiHmWf_;Zoj2`xLE%yV_apxcl)>d57#%nJo7u{aC1R&brVakaL?A?c_ch z+7@!3^}K|DlFoG7AWH@}wK1IT z=C*c=yZqmB2isqTMBK>su)7_0_!%mGC)}hs!!Ld<{5DGF zTAhfH0=H$nNmhoNU7)pV}h@E)&;)uIDayYw5Q6J?cf68(So@KrX zpZ2xCjp*xcPQklPyyR~^M)Qv~l$ZQz#Aug(0HM6(j}8Xn#|Xbij(nk(9GU{l@?}*{ z#}EzX8=*A&rR8Hho9|S*s@QFC@kV?v`PE2Y!<`o4OZ*T_V}$;vbb=vT$|5Lgw zfTxN1Kc!D?g8xtH4(3ZlG;x#+Q{I0{-)+Bb9mZDy6xPQCMk{{wmtxm;oig1lgJ+~P z8173aMV5qnb&70-UISECaGfI4^$VdCnKn0sQ)DLEosuF08vjApoR0p&JRPQSIPraE z2K~{L;*9pF7~XmZ8Vx!Tv;uTFXe%hB+lOM2{@^rUKBBxsxHv!3B@7*I4lZ6hT*6+7 zN)1UnTX|lt7t>xkew7z1^-{yT$AQoCq7`0dc&rx-<0jL~Q6U#k3%nTpEyZ*1#sGjnE#@P8I*uLF#T3!Mi1J{)#BgtI;G!^pib6FI?a3l)Wt*+|Us z(!!;%H#A&27K+aHT9an&hEV2ADvdk}>rNj^XFDZOt-U4FZC@O3T?aYOQ)bx=YPzz+Aigq_bJoK7j{ zs^yVV)8&*N>$Sk2PZ=WYUxjZCpW*v> zKS02?gKcMeBnJ;`PDB6q@=|+^MIVJawe(s*e|9MnRSI{V@8pN!=nN{F`XHA6_jP5{$$~j<)k6Q`3@Q+{62(Wu(o$lTS@TW z5Tst^Mi+&hRV(y5l)z0#@CBU^x^5+R9hl4fK8&2;`{^?>>38$qCe;d0!&4$2N~;iM z85`JPF96hyV&Mciu}R$ zRufr&utD$$>WqM4H+|271T8z7UR%LSB~hH7um&!gYT#T`+*WOWpT( zm`WYb4*MPI-jV$KJs6r7dxo9WsC26HH5JHbI!;H%;-8CZUCas_|^$W{^a59SYS+GV_wQ9r%M{|$Z|ug=rWcr zv=p7}<%H2Gc?`=piyb^S&d(Y~`H%Y9B(1pZiMHpr~mvftHk(cE>!O@qD)fXgG zX~9XIz)?iA(SH%DH-+>nioFYWvDDK|YiMSKuyd^muBVzH%#?kdDSom^F@o2h8MFga zp-geSY}=f>&=ZKSJm(N3lWQb~_-|3-5Anmxv4LsscyuZC1A^{n*T^erVET@q)MV`0 zB@*XpG$t@@W1vrutYW`|j})_`Cz$ErQI z?a6fRz#2py`1bPBFfV&#;(A^K+J>ESo?M*4)#UutTXS>S-Zr)aXKeQkLQxLZ3u?%4 zFXtp&-4LdlYKTO7`*Xq%_|N&gLK7^nVitl-q4Pf^Vs<-!fv(`pV|E9B03<7njb?7x zS&H^MQL1mYvjy-@G{;@%*TFU#IvMZ)@`LM~+0m`TqDJy#8e7BLDU8AOM!vi;zy#1$ zrgU`UQi-3ibG6n7*udDv^#j5fxKW#_trJac=2*n}%HI{|Ik%(U$pGsVcHTmXA7FQ` z_@Iv+F$3xPBu+`8b5e~L*QKO#9NWGZ$%8`=VIS*7uSU*T*hI3 zUE*QZ&8)_JTTQjh;QVQHMeO^tZeEi~x3ux3%M)L6(%l7Hc{J&*qQH9@b%pn`@EC=b zIl3!A#NM+4@rQXI0r_{l?j+T@Z$&k#D$~hpO0UgD<#9hTJp8QL!*IoDAJxy9J{BSy zSJ3vnE21<)i{7)`N2fOKMbpPCO&_1~GXW&KlyA`~{$_~{vF{M|@Z*_3tMhx{yBTO} z+R8eImt#+s>!s`PE*b+Tds*n_tnk=JsSuM2D?7chGPIx-4>S~}IzKJHm1Zq}TS7M* zyeD@uBecL^FWw1%obat)PyUOICjTup^={lNyqFzEMVzQ_d2VCN2w$_0JB*fKE<$Yq zJ~6V&YYDZyV53Usf8gI{VdPUk>+m{ULlIgfQ6X{wRfrcyRD39>OU<2`QDkn^Se&ID zyq1i`{Y5q@&Nqfw_x%bOxoWRqoR>o$F6A47jPUy0Ie zQY)mhLim4sF+H(Kd2AN&C&{(SJ}vj3L_2VdplI>f@x&Sk53 zzk!?m^hdo|Z@L{05C6HF{_y|T+tmljQB?7{Ox>EJNXU^O5)cnT|1fp8_m#T?E|??P zBx~+ty}dwkT5iqF&fN~#on2>UbC=WxFrhSBrRGpU6qA6TRR*+BAQcEGAQcjbKuJUt zD6NQrKP&-@Ld59rz3!f!9d1)lT5i=%&-8o!UibUz*F7^gpBJNC15t49f@i6LyZCgt zCB`MU#$#hDH=DmvnrYK(LaWM3y3zj{$1@ zy$2}rx0pUnv*DR~(}g!aWkX{hmy?19A|oy-tzZhYzd*`hM&H~%zh43Ld%(2` zX(j?Y$}%}`hlsW}Z{LHuvtkPy$sl6-QKhB@6-*N|ZI~B?9eZrt$ED`*QBL;9i@7^{ z@O>qrIgW>LyBd}GjpwYV#d{M0xCcA21gD-8P4Y)Zr(vU0g5>GxyQoQuWu1qNgR>M=2s&aa+-m(ImQz>oT$h+`}jO)l|=Y@J%mRk!q*}QEES?4`qiw@ zMi2rPk4Xx%+&sDG>$=a_QacA+QiSb#(q zEEXxr-s`Yexp*<_N`IU>r2nwezeD)>^ALTL5dHVi#}87PN}G9TFplONLv>^s#F*x7 z7}E>T?xNHev7v?ui}ifoCs_KoR5({YPyY*uE|9tMn;2NwWNJ4)InPAak0+()}C^e6l@dT3|?pH&sOAQgiXaA*ndWz_CKGDSk)x&Gq6v{`4%nu zcgD~o3h#)Y#F^atUCx5L|9`}=bJP!SkCk_#n{#f;%k5X%RTzfqM3V4xo$ZWsyQeEH zp<&NPh7H z>Uy-;v!(cP8kY{-zQ(14J!$r4BJm`#uIs>XqGtV1>_ftp_lUi`uq*F^A%PG~st%o4 zKOVO~O)S`j8F;obzeP@GcrFye*o&ZcJDgU=b*z8GK`k~ZcHoHdauKsGsl^D!-y^^m z*8%qm@Q3Sw`vmx+I^atMxTOyGG6DWj9q{D>d|@4MzW^hqhKC*uY=r<{PzQX40H0q6 z{BZ$ZS_h0fR|u%h`gwKW$nF{bfjaPqB>ddD;0^l2TElS)&lC=u>9!7>YHx*d$0dm6 zlh|v+Hj#cR68nRo-Hba(JQ4jXf+2(h@Cyun`<-A+63^j3r-KtrXZLlKREps7qrmL$ zVzU!Iftj$2I<-sYyO+oGH+ZGCps)gi#><1s$iwTME#gVK`0KR1ll|z;keZk zhGP=eUu1^2fnh-HsKmzhWEeZ3_PB&Er~`ijB(Z@^f=A*`bLB$pH%vk%;$Fg;wX>xd zXoLQ1NRCwXC}o_G97Om`j4#r2Qo>StTzM zt0R@&p*S9%zEr5)^e*OzPX~Sc1$RI{gm^P68jeE}wRe0s&NTr%#0~F2Si*)Fw&vOV zzlBt%lkDT9$axwsi|IFEDc7XGf<3{&KIpEA68DbnlyffBPvO>$689e?*-6mwEi_z$ zCv3s+{X#J1#zna4+~0TsPgNUv!6X*~l*7XGUk0%`jpCm&3x6@f?M;>ay&dZ2DNcO0_#s+)g^P!7!TRH)(Gvf&M(hQE(+490gogi4t{LIJHbvDr(*LUOLZ9%&ME@??nD zjobTij~v4M>pZ^ghj7Je`CX)O(9s=Le%aIW3tTC}Pxy-BcfR0vJR%q|z6SjU9o>Qv zV*;QhsYoy%uAD&KPPVzv!343ROoN8e(T++ro5A{n@L+JKK%VEpbMyxhhmgE4(Qgm| zX^Ya`LHrZ(#f!xa{_g`8wg3`QOvjU>?C(df^@Y$-A@07ShNXCS^}4zY0v1{?;HF2e zJtG)z7bSOx9khPeg8zL#4HrVmRNhZ?HpbX&cKc=bGRmtV?;4~81jef4*8Y|!t+ zv$!PgSI}N;0i5J};}nZ<_Xhhh99Pbfia3BQt|_*j6_GrRBCw1jJSbv=)I+oWbVTFf zgk+aob37Hn5hm53<3$+sB&K6-A=~FZ9gYpvyI{#bRH2kh%v2BPG|Eo4^zTG?+(q^f z(+|lm+!_J1VaD_aB>3AAFh&6kvCB%gEg(zWj%7ysBB+wmL8f$}ej~u)jiGI{$#M)& zqH}lPLrmnm5hC(N#l4aUg+V6rtca#C?wF2$8-hKKTO@@a%uNBAKNwu7Q)pufbR!*W zP^PdC%TK&_nZf6lGDhB>ax(e6W){niuT5FLZx<}hwLE-AsN@z4C11;o5BF@d9NW(= zFS)kkCsON8t&EeN?hIZj-fWjLUdb>mPc!pH&(hMH(wWp~a(GO`x1WdbO{ZzY_UWTi z1Q{H@qBGUPhqB|Ldsemu%(QjIvWqU!sb`s< z=36s9H{O&?46fF^t)6M*^X*KfT;gHKy3WuLdND*ZXSj(iAwER2I?7(xGP3v}9gQ=U z?#S3A7SG;hX`XMmzL%MXC_?z%){N~ZY(QP>v)rT6#K7thLZ9keqQKzvx(#EiN3I^8 z1EnKTC};)S@wB0$Q^TdVR2CgKHR^v?CuA?HSQ#BXsHhI2&&!qlY;oGbKuPY2jma@B zZJ9+UOT)?7&SX*R=&0I&ujOqA%G>HC2}EtyCdN|9)!Iba&Sx_aNTy_UWSdQ=7@SKUQzU7UAg;w;gvRuzDI!bt5!ceot@uhUpX)W}0<6yXEZpBPrPb*(J#n!&|uD)IXa9SwLh!fAVf|E{h=33d-ZAFLb%|bD2 zj!a6CV|V#+Bq$JWV7*RtRVP8Qm4X`KXZT$!6&5iWeo^ouSkMU9!W z%*`vDqQFWeSBVoBK}MWeGo}SsEjk{qC(DjW=dG{{RhKnRBoF1zswPB3aLT2ce zA*_-y?J#7`l|uumkhqsKh)fE;tW-LdT(v%}E{2kWgUNJa)yVMbw3Z<=>*(wYY)Ugq zwo(a4D8ttRdn2<7@#-ckN!Y0zj7S>K!06gEJ4?>Wm$Z`MdRE3RQG_k#w^+iZgb^$A zUNf3VXs{87?U4PNXk9&!WOtN4)vZz3(cr)-w}{~D!HOiy^@&Xy*__9Lfg=S$Mic48 z7-*KA%~gj&2eMg9#Af(=5RsEMkYIN4USHJ5e0ID%28r#mk3 zgLVTYTbrxV%*(z6`>UFVR zS+5?`Rj-ZFGv7pCJ$h-hxQIDNxZQn;$;!M+WeAKk#D9;8&-KYv) zPYWz8Gd{SS(SF<&mEvrXC}!ykMWNry&^eu6ggEb8tUAkdl_X^yiPGs4JlK4k|^Ls?i&pufTiQ--c zaI}tE-1i01Zl+O`>KMgc2SBuraJ#-NT6`uhN_C9l(tnYP))DS3IU;^fiXu2hai;)@ z))BICNHn?SeWFyyDDE@>(K^C?>k-jn^ChBG$0+Vj0H{u?TcK&z%i{EnI{X!#uheP( zsaHk&k19k-SzU(9!1g2#6}w&&7deTz0GA8#N47>kW!6nN4{VPi;_$cEMfrTFj!qR{ VRo#q}x!OPRcY(1-A<8n^{y+A?b}|3} diff --git a/programs/include/Api/Syscall.hpp b/programs/include/Api/Syscall.hpp index 2f5ec78..a56566f 100644 --- a/programs/include/Api/Syscall.hpp +++ b/programs/include/Api/Syscall.hpp @@ -40,6 +40,16 @@ namespace Zenith { static constexpr uint64_t SYS_RESET = 26; static constexpr uint64_t SYS_SHUTDOWN = 27; static constexpr uint64_t SYS_GETTIME = 28; + static constexpr uint64_t SYS_SOCKET = 29; + static constexpr uint64_t SYS_CONNECT = 30; + static constexpr uint64_t SYS_BIND = 31; + static constexpr uint64_t SYS_LISTEN = 32; + static constexpr uint64_t SYS_ACCEPT = 33; + static constexpr uint64_t SYS_SEND = 34; + static constexpr uint64_t SYS_RECV = 35; + static constexpr uint64_t SYS_CLOSESOCK = 36; + + static constexpr int SOCK_TCP = 1; struct DateTime { uint16_t Year; diff --git a/programs/include/zenith/syscall.h b/programs/include/zenith/syscall.h index 48d1065..a457071 100644 --- a/programs/include/zenith/syscall.h +++ b/programs/include/zenith/syscall.h @@ -157,6 +157,32 @@ namespace zenith { return (int32_t)syscall2(Zenith::SYS_PING, (uint64_t)ip, (uint64_t)timeoutMs); } + // Sockets + inline int socket(int type) { + return (int)syscall1(Zenith::SYS_SOCKET, (uint64_t)type); + } + inline int connect(int fd, uint32_t ip, uint16_t port) { + return (int)syscall3(Zenith::SYS_CONNECT, (uint64_t)fd, (uint64_t)ip, (uint64_t)port); + } + inline int bind(int fd, uint16_t port) { + return (int)syscall2(Zenith::SYS_BIND, (uint64_t)fd, (uint64_t)port); + } + inline int listen(int fd) { + return (int)syscall1(Zenith::SYS_LISTEN, (uint64_t)fd); + } + inline int accept(int fd) { + return (int)syscall1(Zenith::SYS_ACCEPT, (uint64_t)fd); + } + inline int send(int fd, const void* data, uint32_t len) { + return (int)syscall3(Zenith::SYS_SEND, (uint64_t)fd, (uint64_t)data, (uint64_t)len); + } + inline int recv(int fd, void* buf, uint32_t maxLen) { + return (int)syscall3(Zenith::SYS_RECV, (uint64_t)fd, (uint64_t)buf, (uint64_t)maxLen); + } + inline int closesocket(int fd) { + return (int)syscall1(Zenith::SYS_CLOSESOCK, (uint64_t)fd); + } + // Process management inline void waitpid(int pid) { syscall1(Zenith::SYS_WAITPID, (uint64_t)pid); } diff --git a/programs/man/syscalls.2 b/programs/man/syscalls.2 index 72f482f..7a5b101 100644 --- a/programs/man/syscalls.2 +++ b/programs/man/syscalls.2 @@ -3,7 +3,7 @@ syscalls - overview of ZenithOS system calls .SH DESCRIPTION - ZenithOS provides 29 system calls (numbers 0-28) for userspace + ZenithOS provides 37 system calls (numbers 0-36) for userspace programs. Syscalls use the x86-64 SYSCALL instruction with the following register convention: @@ -120,6 +120,40 @@ Send an ICMP echo request and wait for reply. int32_t zenith::ping(uint32_t ip, uint32_t timeoutMs); +.B SYS_SOCKET (29) + Create a socket. type=SOCK_TCP (1). Returns fd or -1. + int zenith::socket(int type); + +.B SYS_CONNECT (30) + Connect a TCP socket to a remote host. + int zenith::connect(int fd, uint32_t ip, uint16_t port); + +.B SYS_BIND (31) + Bind a socket to a local port for listening. + int zenith::bind(int fd, uint16_t port); + +.B SYS_LISTEN (32) + Start listening for incoming TCP connections. + int zenith::listen(int fd); + +.B SYS_ACCEPT (33) + Accept an incoming connection on a listening socket. + Returns a new socket fd for the client connection. + int zenith::accept(int fd); + +.B SYS_SEND (34) + Send data on a connected socket. Returns bytes sent. + int zenith::send(int fd, const void* data, uint32_t len); + +.B SYS_RECV (35) + Receive data from a connected socket. Returns bytes + received, 0 on connection close, or -1 on error. + int zenith::recv(int fd, void* buf, uint32_t maxLen); + +.B SYS_CLOSESOCK (36) + Close a socket and release its resources. + int zenith::closesocket(int fd); + .SH FRAMEBUFFER .B SYS_FBINFO (21) Get framebuffer dimensions and format. diff --git a/programs/obj/shell/main.o b/programs/obj/shell/main.o index cceca0a635ac3cd34d8ff5c80ea4452373acd6be..7c2be887c68224777d42f60d44844a70768fe121 100644 GIT binary patch literal 156840 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≧VSu|>zn+s37IWYsCV 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 z zJZs{m{nY=nR?zWsj@KvG<6(Qp`#C<=@#&5)c6>AWmpHC|=lHLVpC#ANyJjmMi!Zu; z)eAdbk^Bhy)4=i8j^9mQ3-6EjHZE@|G>p0z8)01bL#?0W_zdGVXQ6S)(f#}r$M=(0 z#r_#95p^tGIFTInLXOvPyghm2^iggK`SqCR!Q}e+>Ivjyk@GltJLJqKAAtJT9Dm>O zt>jgazstD1H8&(0R_vhh_`IS1l;anS+nnqrqd=X1#K#Jgzkn;QH!d&X$+1|L>c*u% zTHnO+Ta4SB&c-F@9SILhKgY*7K9&6aC?@ud<4YZ1P5uRPwvr!%A9FlUsi;8bS^wYG zb;j}5U%arqahV6Lujlwp#%<1R#wAA|=chV8)bWYrEo2~Jnd$gK$Cs1eg`D?{<1OfT z{zl`{f34r`_yOZK=eTjn(f?DgFJ$RG&e@-_ieN#-&|6yos$gF70alCda=vZgch-mz>jR z_awRgU+?sI@lLmwdTz%P9j{EDGks`0EH{wr|HW=;T=uJEDGtjW#-;yS-^=l##%<1c zJqs(f^NJ+3}{vv&CDAe)T5bfa^w+{{o*uuE+lcj=$;n zddE*Wo~dlq0hu4^zxF2|`S0jwqH(!DtqHGWTynI&q2n!#+nf%@B}e}cY;VU$IzE-W zfDAA!vy4l-t>PNKkJh-ftMzX>zSg+S*<@UD^zX;MHZJuY(e6Iuw*G|U=Z)K(tmUFW z-HshG-n_=8J_YR-H!kgJeO1RB7`Hh$8pPJ1-iYoJ}3D&

wfvg0?BKZ~4J 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 literal 129024 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 diff --git a/programs/src/irc/main.cpp b/programs/src/irc/main.cpp new file mode 100644 index 0000000..1221737 --- /dev/null +++ b/programs/src/irc/main.cpp @@ -0,0 +1,1079 @@ +/* + * main.cpp + * IRC client for ZenithOS + * Split-screen terminal UI with ANSI escape codes + * Copyright (c) 2025-2026 Daniel Hammer +*/ + +#include + +// ---- Minimal snprintf (no libc available) ---- + +using va_list = __builtin_va_list; +#define va_start __builtin_va_start +#define va_end __builtin_va_end +#define va_arg __builtin_va_arg + +struct PfState { + char* buf; + int pos; + int max; +}; + +static void pf_putc(PfState* st, char c) { + if (st->pos < st->max) st->buf[st->pos] = c; + st->pos++; +} + +static void pf_putnum(PfState* st, unsigned long val, int base, int width, char pad, int neg) { + char tmp[24]; + int i = 0; + const char* digits = "0123456789abcdef"; + if (val == 0) { tmp[i++] = '0'; } + else { while (val > 0) { tmp[i++] = digits[val % base]; val /= base; } } + int total = (neg ? 1 : 0) + i; + if (neg && pad == '0') pf_putc(st, '-'); + for (int w = total; w < width; w++) pf_putc(st, pad); + if (neg && pad != '0') pf_putc(st, '-'); + while (i > 0) pf_putc(st, tmp[--i]); +} + +static int vsnprintf(char* buf, int size, const char* fmt, va_list ap) { + PfState st; + st.buf = buf; + st.pos = 0; + st.max = size > 0 ? size - 1 : 0; + while (*fmt) { + if (*fmt != '%') { pf_putc(&st, *fmt++); continue; } + fmt++; + char pad = ' '; + if (*fmt == '0') { pad = '0'; fmt++; } + int width = 0; + while (*fmt >= '0' && *fmt <= '9') { width = width * 10 + (*fmt - '0'); fmt++; } + if (*fmt == 'l') fmt++; + switch (*fmt) { + case 'd': case 'i': { + long val = va_arg(ap, int); + int neg = 0; unsigned long uval; + if (val < 0) { neg = 1; uval = (unsigned long)(-val); } + else uval = (unsigned long)val; + pf_putnum(&st, uval, 10, width, pad, neg); + break; + } + case 'u': { unsigned val = va_arg(ap, unsigned); pf_putnum(&st, val, 10, width, pad, 0); break; } + case 'x': { unsigned val = va_arg(ap, unsigned); pf_putnum(&st, val, 16, width, pad, 0); break; } + case 's': { + const char* s = va_arg(ap, const char*); + if (!s) s = "(null)"; + int slen = 0; while (s[slen]) slen++; + for (int w = slen; w < width; w++) pf_putc(&st, ' '); + for (int j = 0; j < slen; j++) pf_putc(&st, s[j]); + break; + } + case 'c': { char c = (char)va_arg(ap, int); pf_putc(&st, c); break; } + case '%': pf_putc(&st, '%'); break; + default: pf_putc(&st, '%'); pf_putc(&st, *fmt); break; + } + if (*fmt) fmt++; + } + if (size > 0) { + if (st.pos < size) st.buf[st.pos] = '\0'; + else st.buf[size - 1] = '\0'; + } + return st.pos; +} + +static int snprintf(char* buf, int size, const char* fmt, ...) { + va_list ap; + va_start(ap, fmt); + int ret = vsnprintf(buf, size, fmt, ap); + va_end(ap); + return ret; +} + +// ---- String utilities ---- + +static int slen(const char* s) { + int n = 0; + while (s[n]) n++; + return n; +} + +static bool streq(const char* a, const char* b) { + while (*a && *b) { if (*a != *b) return false; a++; b++; } + return *a == *b; +} + +static bool starts_with(const char* str, const char* prefix) { + while (*prefix) { if (*str != *prefix) return false; str++; prefix++; } + return true; +} + +static const char* skip_spaces(const char* s) { + while (*s == ' ') s++; + return s; +} + +static void strcpy(char* dst, const char* src) { + while (*src) *dst++ = *src++; + *dst = '\0'; +} + +static void strncpy(char* dst, const char* src, int max) { + int i = 0; + while (src[i] && i < max - 1) { dst[i] = src[i]; i++; } + dst[i] = '\0'; +} + +static void memcpy(void* dst, const void* src, int n) { + auto d = (char*)dst; auto s = (const char*)src; + for (int i = 0; i < n; i++) d[i] = s[i]; +} + +static void memmove(void* dst, const void* src, int n) { + auto d = (char*)dst; auto s = (const char*)src; + if (d < s) { for (int i = 0; i < n; i++) d[i] = s[i]; } + else { for (int i = n - 1; i >= 0; i--) d[i] = s[i]; } +} + +// Case-insensitive comparison for IRC commands +static bool streqi(const char* a, const char* b) { + while (*a && *b) { + char ca = *a, cb = *b; + if (ca >= 'A' && ca <= 'Z') ca += 32; + if (cb >= 'A' && cb <= 'Z') cb += 32; + if (ca != cb) return false; + a++; b++; + } + return *a == *b; +} + +// ---- IP parsing (from shell) ---- + +static bool parse_ip(const char* s, uint32_t* out) { + uint32_t octets[4]; + int idx = 0; + uint32_t val = 0; + bool hasDigit = false; + for (int i = 0; ; i++) { + char c = s[i]; + if (c >= '0' && c <= '9') { + val = val * 10 + (c - '0'); + if (val > 255) return false; + hasDigit = true; + } else if (c == '.' || c == '\0') { + if (!hasDigit || idx >= 4) return false; + octets[idx++] = val; + val = 0; hasDigit = false; + if (c == '\0') break; + } else return false; + } + if (idx != 4) return false; + *out = octets[0] | (octets[1] << 8) | (octets[2] << 16) | (octets[3] << 24); + return true; +} + +static bool parse_uint16(const char* s, uint16_t* out) { + uint32_t val = 0; + if (*s == '\0') return false; + while (*s) { + if (*s < '0' || *s > '9') return false; + val = val * 10 + (*s - '0'); + if (val > 65535) return false; + s++; + } + *out = (uint16_t)val; + return true; +} + +// ---- Data structures ---- + +static constexpr int MAX_NICK_LEN = 32; +static constexpr int MAX_CHANNEL_LEN = 64; +static constexpr int MAX_LINE_LEN = 256; +static constexpr int MAX_DISPLAY_LINES = 512; +static constexpr int IRC_MAX_MSG = 512; + +struct IrcState { + int fd; + uint32_t serverIp; + uint16_t serverPort; + char nick[MAX_NICK_LEN]; + char channel[MAX_CHANNEL_LEN]; + bool registered; + bool connected; + bool inChannel; + int nickRetries; +}; + +struct RecvBuffer { + char buf[2048]; + int len; +}; + +struct DisplayLine { + char text[MAX_LINE_LEN]; + int len; +}; + +struct MessageBuffer { + DisplayLine lines[MAX_DISPLAY_LINES]; + int head; + int count; + int scrollOffset; +}; + +struct InputState { + char buf[512]; + int pos; + int len; +}; + +struct TermState { + int cols; + int rows; + int msgAreaRows; +}; + +// ---- Terminal helpers ---- + +static int int_to_buf(char* buf, int n) { + if (n == 0) { buf[0] = '0'; return 1; } + char tmp[12]; int i = 0; + while (n > 0) { tmp[i++] = '0' + (n % 10); n /= 10; } + for (int j = 0; j < i; j++) buf[j] = tmp[i - 1 - j]; + return i; +} + +// ---- Screen buffer for flicker-free rendering ---- + +static constexpr int SCREEN_BUF_SIZE = 32768; + +struct ScreenBuf { + char buf[SCREEN_BUF_SIZE]; + int pos; +}; + +static ScreenBuf screen; + +static void sb_reset() { screen.pos = 0; } + +static void sb_putc(char c) { + if (screen.pos < SCREEN_BUF_SIZE - 1) screen.buf[screen.pos++] = c; +} + +static void sb_puts(const char* s) { + while (*s && screen.pos < SCREEN_BUF_SIZE - 1) screen.buf[screen.pos++] = *s++; +} + +static void sb_cursor_to(int row, int col) { + sb_puts("\033["); + char tmp[12]; int n = int_to_buf(tmp, row); for (int i = 0; i < n; i++) sb_putc(tmp[i]); + sb_putc(';'); + n = int_to_buf(tmp, col); for (int i = 0; i < n; i++) sb_putc(tmp[i]); + sb_putc('H'); +} + +static void sb_flush() { + screen.buf[screen.pos] = '\0'; + zenith::print(screen.buf); +} + +// ---- Globals ---- + +static IrcState irc; +static RecvBuffer recvBuf; +static MessageBuffer msgBuf; +static InputState input; +static TermState term; +static bool running; +static bool dirty; + +// ---- Message buffer ---- + +static void msg_add(const char* text) { + int idx = (msgBuf.head + msgBuf.count) % MAX_DISPLAY_LINES; + if (msgBuf.count >= MAX_DISPLAY_LINES) { + // Overwrite oldest + msgBuf.head = (msgBuf.head + 1) % MAX_DISPLAY_LINES; + } else { + msgBuf.count++; + } + DisplayLine& line = msgBuf.lines[idx]; + int i = 0; + while (text[i] && i < MAX_LINE_LEN - 1) { + line.text[i] = text[i]; + i++; + } + line.text[i] = '\0'; + line.len = i; + + // Auto-scroll to bottom when new message arrives + if (msgBuf.scrollOffset == 0 || msgBuf.count <= term.msgAreaRows) { + msgBuf.scrollOffset = 0; + } + dirty = true; +} + +static void msg_add_fmt(const char* fmt, ...) { + char tmp[MAX_LINE_LEN]; + va_list ap; + va_start(ap, fmt); + vsnprintf(tmp, sizeof(tmp), fmt, ap); + va_end(ap); + msg_add(tmp); +} + +static void msg_clear() { + msgBuf.head = 0; + msgBuf.count = 0; + msgBuf.scrollOffset = 0; +} + +// ---- IRC send helpers ---- + +static void irc_send(const char* fmt, ...) { + char buf[IRC_MAX_MSG]; + va_list ap; + va_start(ap, fmt); + int len = vsnprintf(buf, sizeof(buf) - 2, fmt, ap); + va_end(ap); + // Ensure \r\n termination + if (len > IRC_MAX_MSG - 3) len = IRC_MAX_MSG - 3; + buf[len] = '\r'; + buf[len + 1] = '\n'; + buf[len + 2] = '\0'; + zenith::send(irc.fd, buf, len + 2); +} + +// ---- Sanitize incoming text (strip control chars) ---- + +static void sanitize(char* dst, const char* src, int maxLen) { + int j = 0; + for (int i = 0; src[i] && j < maxLen - 1; i++) { + unsigned char c = (unsigned char)src[i]; + if (c == 0x1B) { + // Skip ESC sequences entirely + continue; + } + if (c < 0x20 && c != ' ') continue; + dst[j++] = (char)c; + } + dst[j] = '\0'; +} + +// ---- IRC prefix parsing ---- + +// Extract nick from ":nick!user@host" prefix +static void parse_prefix_nick(const char* prefix, char* nick, int maxLen) { + int i = 0; + if (prefix[0] == ':') prefix++; + while (prefix[i] && prefix[i] != '!' && prefix[i] != '@' && prefix[i] != ' ' && i < maxLen - 1) { + nick[i] = prefix[i]; + i++; + } + nick[i] = '\0'; +} + +// ---- IRC protocol handlers ---- + +static void irc_handle_ping(const char* params) { + char buf[IRC_MAX_MSG]; + snprintf(buf, sizeof(buf), "PONG %s", params); + irc_send("%s", buf); +} + +static void irc_handle_privmsg(const char* prefix, const char* params) { + char senderNick[MAX_NICK_LEN]; + parse_prefix_nick(prefix, senderNick, sizeof(senderNick)); + + // Find the message text after " :" + const char* text = params; + // Skip target + while (*text && *text != ' ') text++; + text = skip_spaces(text); + if (*text == ':') text++; + + char clean[MAX_LINE_LEN]; + sanitize(clean, text, sizeof(clean)); + + // Check for CTCP ACTION (\001ACTION ... \001) + if (starts_with(clean, "\001ACTION ")) { + const char* action = clean + 8; + // Strip trailing \001 + char actionBuf[MAX_LINE_LEN]; + strncpy(actionBuf, action, sizeof(actionBuf)); + int alen = slen(actionBuf); + if (alen > 0 && actionBuf[alen - 1] == '\001') actionBuf[alen - 1] = '\0'; + msg_add_fmt("\033[35m* %s %s\033[0m", senderNick, actionBuf); + return; + } + + // Color own nick green, others cyan + if (streq(senderNick, irc.nick)) { + msg_add_fmt("\033[1;32m<%s>\033[0m %s", senderNick, clean); + } else { + msg_add_fmt("\033[1;36m<%s>\033[0m %s", senderNick, clean); + } +} + +static void irc_handle_notice(const char* prefix, const char* params) { + char senderNick[MAX_NICK_LEN]; + if (prefix[0]) { + parse_prefix_nick(prefix, senderNick, sizeof(senderNick)); + } else { + strcpy(senderNick, "*"); + } + + const char* text = params; + while (*text && *text != ' ') text++; + text = skip_spaces(text); + if (*text == ':') text++; + + char clean[MAX_LINE_LEN]; + sanitize(clean, text, sizeof(clean)); + msg_add_fmt("\033[1m-%s-\033[0m %s", senderNick, clean); +} + +static void irc_handle_join(const char* prefix, const char* params) { + char nick[MAX_NICK_LEN]; + parse_prefix_nick(prefix, nick, sizeof(nick)); + + const char* chan = params; + if (*chan == ':') chan++; + + if (streq(nick, irc.nick)) { + strncpy(irc.channel, chan, sizeof(irc.channel)); + irc.inChannel = true; + msg_add_fmt("\033[33m* Now talking in %s\033[0m", chan); + } else { + msg_add_fmt("\033[33m* %s has joined %s\033[0m", nick, chan); + } +} + +static void irc_handle_part(const char* prefix, const char* params) { + char nick[MAX_NICK_LEN]; + parse_prefix_nick(prefix, nick, sizeof(nick)); + + const char* chan = params; + while (*chan && *chan != ' ') chan++; // get channel text + // Actually parse channel from params start + chan = params; + char chanBuf[MAX_CHANNEL_LEN]; + int i = 0; + while (chan[i] && chan[i] != ' ' && i < MAX_CHANNEL_LEN - 1) { + chanBuf[i] = chan[i]; i++; + } + chanBuf[i] = '\0'; + + if (streq(nick, irc.nick)) { + irc.inChannel = false; + irc.channel[0] = '\0'; + msg_add_fmt("\033[33m* You have left %s\033[0m", chanBuf); + } else { + msg_add_fmt("\033[33m* %s has left %s\033[0m", nick, chanBuf); + } +} + +static void irc_handle_quit(const char* prefix, const char* params) { + char nick[MAX_NICK_LEN]; + parse_prefix_nick(prefix, nick, sizeof(nick)); + + const char* reason = params; + if (*reason == ':') reason++; + + char clean[MAX_LINE_LEN]; + sanitize(clean, reason, sizeof(clean)); + if (clean[0]) { + msg_add_fmt("\033[33m* %s has quit (%s)\033[0m", nick, clean); + } else { + msg_add_fmt("\033[33m* %s has quit\033[0m", nick); + } +} + +static void irc_handle_nick(const char* prefix, const char* params) { + char oldNick[MAX_NICK_LEN]; + parse_prefix_nick(prefix, oldNick, sizeof(oldNick)); + + const char* newNick = params; + if (*newNick == ':') newNick++; + + if (streq(oldNick, irc.nick)) { + strncpy(irc.nick, newNick, sizeof(irc.nick)); + msg_add_fmt("\033[33m* You are now known as %s\033[0m", newNick); + } else { + msg_add_fmt("\033[33m* %s is now known as %s\033[0m", oldNick, newNick); + } +} + +static void irc_handle_numeric(int num, const char* params) { + // Extract trailing text (after the last " :") + const char* text = params; + const char* lastColon = nullptr; + for (int i = 0; text[i]; i++) { + if (text[i] == ':' && (i == 0 || text[i - 1] == ' ')) { + lastColon = text + i + 1; + } + } + + switch (num) { + case 1: // RPL_WELCOME + irc.registered = true; + if (lastColon) { + char clean[MAX_LINE_LEN]; + sanitize(clean, lastColon, sizeof(clean)); + msg_add_fmt("\033[1m*** %s\033[0m", clean); + } + // Auto-join channel if specified + if (irc.channel[0]) { + irc_send("JOIN %s", irc.channel); + } + break; + + case 433: // ERR_NICKNAMEINUSE + if (irc.nickRetries < 3) { + int nlen = slen(irc.nick); + if (nlen < MAX_NICK_LEN - 2) { + irc.nick[nlen] = '_'; + irc.nick[nlen + 1] = '\0'; + } + irc.nickRetries++; + irc_send("NICK %s", irc.nick); + msg_add_fmt("\033[33m* Nick in use, trying %s\033[0m", irc.nick); + } else { + msg_add("\033[31m*** Could not find available nickname\033[0m"); + } + break; + + case 332: // RPL_TOPIC + case 353: // RPL_NAMREPLY + case 366: // RPL_ENDOFNAMES + case 372: // RPL_MOTD + case 375: // RPL_MOTDSTART + case 376: // RPL_ENDOFMOTD + default: + if (lastColon) { + char clean[MAX_LINE_LEN]; + sanitize(clean, lastColon, sizeof(clean)); + msg_add_fmt("\033[1m*** %s\033[0m", clean); + } + break; + } +} + +// ---- IRC line parser ---- + +static void irc_process_line(char* line) { + // Strip trailing \r\n + int len = slen(line); + while (len > 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) { + line[--len] = '\0'; + } + if (len == 0) return; + + char prefix[256] = ""; + char* cmd = line; + + // Parse optional prefix + if (line[0] == ':') { + cmd = line + 1; + int i = 0; + while (cmd[i] && cmd[i] != ' ') i++; + if (i > 0) { + memcpy(prefix, cmd, i < 255 ? i : 255); + prefix[i < 255 ? i : 255] = '\0'; + } + cmd += i; + while (*cmd == ' ') cmd++; + } + + // Extract command word + char command[32] = ""; + { + int i = 0; + while (cmd[i] && cmd[i] != ' ' && i < 31) { + command[i] = cmd[i]; i++; + } + command[i] = '\0'; + cmd += i; + while (*cmd == ' ') cmd++; + } + + // cmd now points to params + + // Handle PING first (highest priority) + if (streqi(command, "PING")) { + irc_handle_ping(cmd); + return; + } + + // Check for numeric command + bool isNumeric = true; + for (int i = 0; command[i]; i++) { + if (command[i] < '0' || command[i] > '9') { isNumeric = false; break; } + } + + if (isNumeric && command[0]) { + int num = 0; + for (int i = 0; command[i]; i++) num = num * 10 + (command[i] - '0'); + irc_handle_numeric(num, cmd); + return; + } + + if (streqi(command, "PRIVMSG")) irc_handle_privmsg(prefix, cmd); + else if (streqi(command, "NOTICE")) irc_handle_notice(prefix, cmd); + else if (streqi(command, "JOIN")) irc_handle_join(prefix, cmd); + else if (streqi(command, "PART")) irc_handle_part(prefix, cmd); + else if (streqi(command, "QUIT")) irc_handle_quit(prefix, cmd); + else if (streqi(command, "NICK")) irc_handle_nick(prefix, cmd); + else if (streqi(command, "PONG")) { /* Ignore PONG replies */ } + else if (streqi(command, "ERROR")) { + char clean[MAX_LINE_LEN]; + sanitize(clean, cmd, sizeof(clean)); + msg_add_fmt("\033[31m*** Error: %s\033[0m", clean); + } +} + +// ---- TCP recv with fragment assembly ---- + +static void recv_process() { + char tmp[512]; + int r = zenith::recv(irc.fd, tmp, sizeof(tmp)); + if (r < 0) { + irc.connected = false; + msg_add("\033[31m*** Connection lost\033[0m"); + return; + } + if (r == 0) return; + + // Append to recv buffer + int space = (int)sizeof(recvBuf.buf) - recvBuf.len; + if (r > space) r = space; + memcpy(recvBuf.buf + recvBuf.len, tmp, r); + recvBuf.len += r; + + // Scan for complete lines (\r\n) + int start = 0; + for (int i = 0; i < recvBuf.len - 1; i++) { + if (recvBuf.buf[i] == '\r' && recvBuf.buf[i + 1] == '\n') { + // Extract line [start..i) + int lineLen = i - start; + char lineStr[IRC_MAX_MSG]; + if (lineLen > IRC_MAX_MSG - 1) lineLen = IRC_MAX_MSG - 1; + memcpy(lineStr, recvBuf.buf + start, lineLen); + lineStr[lineLen] = '\0'; + irc_process_line(lineStr); + start = i + 2; + i++; // skip \n + } + } + + // Move unprocessed remainder to front + if (start > 0) { + int remaining = recvBuf.len - start; + if (remaining > 0) { + memmove(recvBuf.buf, recvBuf.buf + start, remaining); + } + recvBuf.len = remaining; + } + + // Prevent overflow if no \r\n found in a full buffer + if (recvBuf.len >= (int)sizeof(recvBuf.buf) - 1) { + recvBuf.len = 0; + } +} + +// ---- UI rendering (buffered, single flush) ---- + +static void ui_render() { + sb_reset(); + + // Hide cursor during redraw + sb_puts("\033[?25l"); + + // Status bar (row 1) + sb_cursor_to(1, 1); + sb_puts("\033[7m\033[2K"); + char status[256]; + if (irc.connected) { + if (irc.inChannel) { + snprintf(status, sizeof(status), " IRC | %s | %s | Connected ", irc.nick, irc.channel); + } else { + snprintf(status, sizeof(status), " IRC | %s | (no channel) | Connected ", irc.nick); + } + } else { + snprintf(status, sizeof(status), " IRC | %s | Disconnected ", irc.nick); + } + sb_puts(status); + int statusLen = slen(status); + for (int i = statusLen; i < term.cols; i++) sb_putc(' '); + sb_puts("\033[0m"); + + // Message area (rows 2..N-2) + int startLine; + if (msgBuf.count <= term.msgAreaRows) { + startLine = 0; + } else { + startLine = msgBuf.count - term.msgAreaRows - msgBuf.scrollOffset; + if (startLine < 0) startLine = 0; + } + for (int r = 0; r < term.msgAreaRows; r++) { + sb_cursor_to(r + 2, 1); + sb_puts("\033[2K"); + int msgIdx = startLine + r; + if (msgIdx < msgBuf.count) { + int realIdx = (msgBuf.head + msgIdx) % MAX_DISPLAY_LINES; + sb_puts(msgBuf.lines[realIdx].text); + } + } + + // Separator (row N-1) + sb_cursor_to(term.rows - 1, 1); + sb_puts("\033[2K\033[90m"); + for (int i = 0; i < term.cols; i++) sb_putc('-'); + sb_puts("\033[0m"); + + // Input line (row N) + sb_cursor_to(term.rows, 1); + sb_puts("\033[2K\033[1m>\033[0m "); + for (int i = 0; i < input.len; i++) sb_putc(input.buf[i]); + + // Position cursor at input insertion point + sb_cursor_to(term.rows, input.pos + 3); + + // Single flush — entire screen in one print call + sb_flush(); +} + +// ---- User command processing ---- + +static void handle_user_input() { + input.buf[input.len] = '\0'; + const char* text = input.buf; + + if (text[0] != '/') { + // Plain message to current channel + if (!irc.inChannel) { + msg_add("\033[31m*** Not in a channel. Use /join #channel\033[0m"); + return; + } + irc_send("PRIVMSG %s :%s", irc.channel, text); + // Echo own message + msg_add_fmt("\033[1;32m<%s>\033[0m %s", irc.nick, text); + return; + } + + // Parse command + const char* cmd = text + 1; + + if (starts_with(cmd, "join ") || starts_with(cmd, "JOIN ")) { + const char* chan = skip_spaces(cmd + 5); + if (*chan == '\0') { + msg_add("\033[31m*** Usage: /join #channel\033[0m"); + return; + } + strncpy(irc.channel, chan, sizeof(irc.channel)); + irc_send("JOIN %s", chan); + } + else if (starts_with(cmd, "part") && (cmd[4] == '\0' || cmd[4] == ' ')) { + if (!irc.inChannel) { + msg_add("\033[31m*** Not in a channel\033[0m"); + return; + } + const char* reason = cmd[4] ? skip_spaces(cmd + 5) : ""; + if (*reason) { + irc_send("PART %s :%s", irc.channel, reason); + } else { + irc_send("PART %s", irc.channel); + } + } + else if (starts_with(cmd, "msg ") || starts_with(cmd, "MSG ")) { + const char* rest = skip_spaces(cmd + 4); + char target[MAX_NICK_LEN]; + int i = 0; + while (rest[i] && rest[i] != ' ' && i < MAX_NICK_LEN - 1) { + target[i] = rest[i]; i++; + } + target[i] = '\0'; + const char* msg = skip_spaces(rest + i); + if (!target[0] || !*msg) { + msg_add("\033[31m*** Usage: /msg nick message\033[0m"); + return; + } + irc_send("PRIVMSG %s :%s", target, msg); + msg_add_fmt("\033[1;35m-> %s:\033[0m %s", target, msg); + } + else if (starts_with(cmd, "nick ") || starts_with(cmd, "NICK ")) { + const char* newNick = skip_spaces(cmd + 5); + if (!*newNick) { + msg_add("\033[31m*** Usage: /nick newnick\033[0m"); + return; + } + irc_send("NICK %s", newNick); + strncpy(irc.nick, newNick, sizeof(irc.nick)); + } + else if (starts_with(cmd, "quit") && (cmd[4] == '\0' || cmd[4] == ' ')) { + const char* reason = cmd[4] ? skip_spaces(cmd + 5) : ""; + if (*reason) { + irc_send("QUIT :%s", reason); + } else { + irc_send("QUIT :Leaving"); + } + irc.connected = false; + running = false; + } + else if (starts_with(cmd, "me ") || starts_with(cmd, "ME ")) { + if (!irc.inChannel) { + msg_add("\033[31m*** Not in a channel\033[0m"); + return; + } + const char* action = skip_spaces(cmd + 3); + irc_send("PRIVMSG %s :\001ACTION %s\001", irc.channel, action); + msg_add_fmt("\033[35m* %s %s\033[0m", irc.nick, action); + } + else if (starts_with(cmd, "raw ") || starts_with(cmd, "RAW ")) { + const char* raw = cmd + 4; + irc_send("%s", raw); + msg_add_fmt("\033[90m>> %s\033[0m", raw); + } + else if (streqi(cmd, "help") || starts_with(cmd, "help ")) { + msg_add("\033[1m--- Help ---\033[0m"); + msg_add(" /join #channel - Join a channel"); + msg_add(" /part [reason] - Leave current channel"); + msg_add(" /msg nick text - Send private message"); + msg_add(" /nick newnick - Change nickname"); + msg_add(" /quit [reason] - Disconnect and exit"); + msg_add(" /me action - Send action"); + msg_add(" /raw text - Send raw IRC line"); + msg_add(" /clear - Clear message area"); + msg_add(" /help - Show this help"); + msg_add(" Ctrl+Q - Quit"); + msg_add(" PgUp/PgDn - Scroll messages"); + } + else if (streqi(cmd, "clear")) { + msg_clear(); + } + else { + char cmdWord[32]; + int i = 0; + while (cmd[i] && cmd[i] != ' ' && i < 31) { cmdWord[i] = cmd[i]; i++; } + cmdWord[i] = '\0'; + msg_add_fmt("\033[31m*** Unknown command: /%s (try /help)\033[0m", cmdWord); + } +} + +// ---- Entry point ---- + +extern "C" void _start() { + // Parse arguments: [#channel] + char argbuf[256]; + zenith::getargs(argbuf, sizeof(argbuf)); + const char* arg = skip_spaces(argbuf); + + if (*arg == '\0') { + zenith::print("Usage: irc.elf [#channel]\n"); + zenith::print("Example: run irc.elf 10.0.68.1 6667 ZenithUser #general\n"); + return; + } + + // Parse IP + char ipStr[32]; + int i = 0; + while (arg[i] && arg[i] != ' ' && i < 31) { ipStr[i] = arg[i]; i++; } + ipStr[i] = '\0'; + arg = skip_spaces(arg + i); + + if (!parse_ip(ipStr, &irc.serverIp)) { + zenith::print("Invalid IP address: "); + zenith::print(ipStr); + zenith::putchar('\n'); + return; + } + + // Parse port + char portStr[16]; + i = 0; + while (arg[i] && arg[i] != ' ' && i < 15) { portStr[i] = arg[i]; i++; } + portStr[i] = '\0'; + arg = skip_spaces(arg + i); + + if (!parse_uint16(portStr, &irc.serverPort)) { + zenith::print("Invalid port: "); + zenith::print(portStr); + zenith::putchar('\n'); + return; + } + + // Parse nickname + i = 0; + while (arg[i] && arg[i] != ' ' && i < MAX_NICK_LEN - 1) { irc.nick[i] = arg[i]; i++; } + irc.nick[i] = '\0'; + arg = skip_spaces(arg + i); + + if (!irc.nick[0]) { + zenith::print("Missing nickname\n"); + return; + } + + // Parse optional channel + i = 0; + while (arg[i] && arg[i] != ' ' && i < MAX_CHANNEL_LEN - 1) { irc.channel[i] = arg[i]; i++; } + irc.channel[i] = '\0'; + + // Initialize state + irc.fd = -1; + irc.registered = false; + irc.connected = false; + irc.inChannel = false; + irc.nickRetries = 0; + recvBuf.len = 0; + msgBuf.head = 0; + msgBuf.count = 0; + msgBuf.scrollOffset = 0; + input.pos = 0; + input.len = 0; + running = true; + + // Get terminal size + zenith::termsize(&term.cols, &term.rows); + term.msgAreaRows = term.rows - 3; + if (term.msgAreaRows < 1) term.msgAreaRows = 1; + + // Enter alternate screen buffer, hide cursor + zenith::print("\033[?1049h"); + zenith::print("\033[?25l"); + + // Initial draw + msg_add("\033[1m*** ZenithOS IRC Client\033[0m"); + msg_add_fmt("*** Connecting to %s:%d as %s...", ipStr, (int)irc.serverPort, irc.nick); + ui_render(); + + // Create socket and connect + irc.fd = zenith::socket(Zenith::SOCK_TCP); + if (irc.fd < 0) { + msg_add("\033[31m*** Failed to create socket\033[0m"); + ui_render(); + // Wait for keypress then exit + while (!zenith::is_key_available()) zenith::yield(); + goto cleanup; + } + + if (zenith::connect(irc.fd, irc.serverIp, irc.serverPort) < 0) { + msg_add("\033[31m*** Connection failed\033[0m"); + ui_render(); + zenith::closesocket(irc.fd); + irc.fd = -1; + while (!zenith::is_key_available()) zenith::yield(); + goto cleanup; + } + + irc.connected = true; + msg_add("\033[32m*** Connected!\033[0m"); + + // Send IRC registration + irc_send("NICK %s", irc.nick); + irc_send("USER %s 0 * :%s", irc.nick, irc.nick); + + ui_render(); + + // ---- Main loop ---- + while (running && irc.connected) { + dirty = false; + + // Process incoming data + int prevCount = msgBuf.count; + recv_process(); + if (msgBuf.count != prevCount) dirty = true; + + // Poll keyboard + if (zenith::is_key_available()) { + Zenith::KeyEvent ev; + zenith::getkey(&ev); + + if (!ev.pressed) { + if (dirty) ui_render(); + continue; + } + + dirty = true; + + // Ctrl+Q to quit + if (ev.ctrl && (ev.ascii == 'q' || ev.ascii == 'Q')) { + if (irc.connected) { + irc_send("QUIT :Leaving"); + } + running = false; + continue; + } + + // Handle special keys by scancode + switch (ev.scancode) { + case 0x49: // Page Up + if (msgBuf.scrollOffset < msgBuf.count - term.msgAreaRows) { + msgBuf.scrollOffset += term.msgAreaRows / 2; + int maxScroll = msgBuf.count - term.msgAreaRows; + if (maxScroll < 0) maxScroll = 0; + if (msgBuf.scrollOffset > maxScroll) msgBuf.scrollOffset = maxScroll; + } + break; + case 0x51: // Page Down + msgBuf.scrollOffset -= term.msgAreaRows / 2; + if (msgBuf.scrollOffset < 0) msgBuf.scrollOffset = 0; + break; + case 0x47: // Home (scroll to top) + if (msgBuf.count > term.msgAreaRows) { + msgBuf.scrollOffset = msgBuf.count - term.msgAreaRows; + } + break; + case 0x4F: // End (scroll to bottom) + msgBuf.scrollOffset = 0; + break; + default: + if (ev.ascii == '\n') { + if (input.len > 0) { + input.buf[input.len] = '\0'; + handle_user_input(); + input.pos = 0; + input.len = 0; + } + } else if (ev.ascii == '\b') { + if (input.pos > 0) { + for (int j = input.pos - 1; j < input.len - 1; j++) { + input.buf[j] = input.buf[j + 1]; + } + input.pos--; + input.len--; + } + } else if (ev.ascii >= ' ' && ev.ascii <= '~') { + if (input.len < 510) { + for (int j = input.len; j > input.pos; j--) { + input.buf[j] = input.buf[j - 1]; + } + input.buf[input.pos] = ev.ascii; + input.pos++; + input.len++; + } + } else { + dirty = false; // Unhandled key, no redraw needed + } + break; + } + } else { + if (!dirty) { + zenith::yield(); + continue; + } + } + + if (dirty) ui_render(); + } + + if (irc.fd >= 0) { + zenith::closesocket(irc.fd); + } + +cleanup: + // Restore terminal + zenith::print("\033[?25h"); + zenith::print("\033[?1049l"); +} diff --git a/programs/src/shell/main.cpp b/programs/src/shell/main.cpp index 2593fb5..2181688 100644 --- a/programs/src/shell/main.cpp +++ b/programs/src/shell/main.cpp @@ -94,6 +94,7 @@ static void cmd_help() { zenith::print(" cat Display file contents\n"); zenith::print(" run Spawn a new process from an ELF file\n"); zenith::print(" ping Send ICMP echo requests\n"); + zenith::print(" tcpconnect Connect to a TCP server\n"); zenith::print(" date Show current date and time\n"); zenith::print(" uptime Show uptime in milliseconds\n"); zenith::print(" clear Clear the screen\n"); @@ -297,20 +298,162 @@ static void cmd_ping(const char* arg) { } } -static void cmd_run(const char* arg) { +static bool parse_uint16(const char* s, uint16_t* out) { + uint32_t val = 0; + if (*s == '\0') return false; + while (*s) { + if (*s < '0' || *s > '9') return false; + val = val * 10 + (*s - '0'); + if (val > 65535) return false; + s++; + } + *out = (uint16_t)val; + return true; +} + +static void cmd_tcpconnect(const char* arg) { arg = skip_spaces(arg); if (*arg == '\0') { - zenith::print("Usage: run \n"); + zenith::print("Usage: tcpconnect \n"); return; } - char path[128]; - resolve_path(arg, path, sizeof(path)); + // Parse IP address (up to first space) + char ipStr[32]; + int i = 0; + while (arg[i] && arg[i] != ' ' && i < 31) { + ipStr[i] = arg[i]; + i++; + } + ipStr[i] = '\0'; - int pid = zenith::spawn(path); + uint32_t ip; + if (!parse_ip(ipStr, &ip)) { + zenith::print("Invalid IP address: "); + zenith::print(ipStr); + zenith::putchar('\n'); + return; + } + + // Parse port + const char* portStr = skip_spaces(arg + i); + if (*portStr == '\0') { + zenith::print("Usage: tcpconnect \n"); + return; + } + uint16_t port; + if (!parse_uint16(portStr, &port)) { + zenith::print("Invalid port: "); + zenith::print(portStr); + zenith::putchar('\n'); + return; + } + + // Create socket + int fd = zenith::socket(Zenith::SOCK_TCP); + if (fd < 0) { + zenith::print("Error: failed to create socket\n"); + return; + } + + zenith::print("Connecting to "); + print_ip(ip); + zenith::putchar(':'); + print_int(port); + zenith::print("...\n"); + + if (zenith::connect(fd, ip, port) < 0) { + zenith::print("Error: connection failed\n"); + zenith::closesocket(fd); + return; + } + + zenith::print("Connected! Type to send, Ctrl+Q to disconnect.\n"); + + // Interactive send/receive loop + char sendBuf[256]; + int sendPos = 0; + uint8_t recvBuf[512]; + + while (true) { + // Poll for received data (non-blocking) + int r = zenith::recv(fd, recvBuf, sizeof(recvBuf) - 1); + if (r < 0) { + zenith::print("\nConnection closed by remote.\n"); + break; + } + if (r > 0) { + recvBuf[r] = '\0'; + zenith::print((const char*)recvBuf); + } + + // Poll keyboard + if (zenith::is_key_available()) { + Zenith::KeyEvent ev; + zenith::getkey(&ev); + + if (!ev.pressed) continue; + + // Ctrl+Q to quit + if (ev.ctrl && (ev.ascii == 'q' || ev.ascii == 'Q')) { + zenith::print("\nDisconnecting...\n"); + break; + } + + if (ev.ascii == '\n') { + sendBuf[sendPos++] = '\n'; + zenith::putchar('\n'); + zenith::send(fd, sendBuf, sendPos); + sendPos = 0; + } else if (ev.ascii == '\b') { + if (sendPos > 0) { + sendPos--; + zenith::putchar('\b'); + zenith::putchar(' '); + zenith::putchar('\b'); + } + } else if (ev.ascii >= ' ' && sendPos < 254) { + sendBuf[sendPos++] = ev.ascii; + zenith::putchar(ev.ascii); + } + } else { + // No key and no data — yield to avoid busy-spinning + zenith::yield(); + } + } + + zenith::closesocket(fd); +} + +static void cmd_run(const char* arg) { + arg = skip_spaces(arg); + if (*arg == '\0') { + zenith::print("Usage: run [args...]\n"); + return; + } + + // Split filename from arguments at first space + char filename[128]; + int i = 0; + while (arg[i] && arg[i] != ' ' && i < 127) { + filename[i] = arg[i]; + i++; + } + filename[i] = '\0'; + + const char* args = nullptr; + if (arg[i] == ' ') { + args = skip_spaces(arg + i); + if (*args == '\0') args = nullptr; + } + + char path[128]; + resolve_path(filename, path, sizeof(path)); + + int pid = zenith::spawn(path, args); if (pid < 0) { zenith::print("Error: failed to spawn '"); - zenith::print(arg); + zenith::print(filename); zenith::print("'\n"); } else { zenith::waitpid(pid); @@ -461,6 +604,10 @@ static void process_command(const char* line) { cmd_ping(line + 5); } else if (streq(line, "ping")) { cmd_ping(""); + } else if (starts_with(line, "tcpconnect ")) { + cmd_tcpconnect(line + 11); + } else if (streq(line, "tcpconnect")) { + cmd_tcpconnect(""); } else if (streq(line, "date")) { cmd_date(); } else if (streq(line, "uptime")) {