-/*\r
- * Acess2 IRC Client\r
- */\r
-#include <acess/sys.h>\r
-#include <stdlib.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <net.h>\r
-\r
-#define BUFSIZ 1023\r
-\r
-// === TYPES ===\r
-typedef struct sServer {\r
- int FD;\r
- char InBuf[BUFSIZ+1];\r
- int ReadPos;\r
-} tServer;\r
-\r
-// === PROTOTYPES ===\r
- int ParseArguments(int argc, const char *argv[]);\r
-void ProcessIncoming(tServer *Server);\r
- int writef(int FD, const char *Format, ...);\r
- int OpenTCP(const char *AddressString, short PortNumber);\r
-\r
-// === GLOBALS ===\r
-char *gsUsername = "root";\r
-char *gsHostname = "acess";\r
-char *gsRemoteAddress = NULL;\r
-char *gsRealName = "Acess2 IRC Client";\r
-char *gsNickname = "acess";\r
-short giRemotePort = 6667;\r
-\r
-// ==== CODE ====\r
-int main(int argc, const char *argv[], const char *envp[])\r
-{\r
- int tmp;\r
- tServer srv;\r
- \r
- memset(&srv, 0, sizeof(srv));\r
- \r
- // Parse Command line\r
- // - Sets the server configuration globals\r
- if( (tmp = ParseArguments(argc, argv)) ) {\r
- return tmp;\r
- }\r
- \r
- // Connect to the remove server\r
- srv.FD = OpenTCP( gsRemoteAddress, giRemotePort );\r
- if( srv.FD == -1 ) {\r
- fprintf(stderr, "Unable to create socket\n");\r
- return -1;\r
- }\r
- \r
- printf("Connection opened\n");\r
- ProcessIncoming(&srv);\r
- \r
- writef(srv.FD, "USER %s %s %s : %s\n", gsUsername, gsHostname, gsRemoteAddress, gsRealName);\r
- writef(srv.FD, "NICK %s\n", gsNickname);\r
- \r
- printf("Processing\n");\r
- \r
- for( ;; )\r
- {\r
- ProcessIncoming(&srv);\r
- }\r
- \r
- close(srv.FD);\r
- return 0;\r
-}\r
-\r
-/**\r
- * \todo Actually implement correctly :)\r
- */\r
-int ParseArguments(int argc, const char *argv[])\r
-{\r
- gsRemoteAddress = "130.95.13.18"; // irc.ucc.asn.au\r
- \r
- return 0;\r
-}\r
-\r
-void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message)\r
-{\r
- printf("%p: %s => %s\t%s\n", Server, Src, Dest, Message);\r
-}\r
-\r
-/**\r
- * \brief Read a space-separated value from a string\r
- */\r
-char *GetValue(char *Src, int *Ofs)\r
-{\r
- int pos = *Ofs;\r
- char *ret = Src + pos;\r
- char *end;\r
- \r
- if( !Src ) return NULL;\r
- \r
- while( *ret == ' ' ) ret ++;\r
- \r
- end = strchr(ret, ' ');\r
- if( end ) {\r
- *end = '\0';\r
- }\r
- else {\r
- end = ret + strlen(ret) - 1;\r
- }\r
- *Ofs = end - Src + 1;\r
- \r
- return ret;\r
-}\r
-\r
-/**\r
- */\r
-void ParseServerLine(tServer *Server, char *Line)\r
-{\r
- int pos = 0;\r
- char *ident, *cmd;\r
- if( *Line == ':' ) {\r
- // Message\r
- ident = GetValue(Line, &pos);\r
- pos ++; // Space\r
- cmd = GetValue(Line, &pos);\r
- \r
- if( strcmp(cmd, "PRIVMSG") == 0 ) {\r
- char *dest, *message;\r
- pos ++;\r
- dest = GetValue(Line, &pos);\r
- pos ++;\r
- if( Line[pos] == ':' ) {\r
- message = Line + pos + 1;\r
- }\r
- else {\r
- message = GetValue(Line, &pos);\r
- }\r
- Cmd_PRIVMSG(Server, dest, ident, message);\r
- }\r
- }\r
- else {\r
- // Command to client\r
- }\r
-}\r
-\r
-/**\r
- * \brief Process incoming lines from the server\r
- */\r
-void ProcessIncoming(tServer *Server)\r
-{ \r
- char *ptr, *newline;\r
- int len;\r
- \r
- // While there is data in the buffer, read it into user memory and \r
- // process it line by line\r
- // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer\r
- // - Used to avoid blocking\r
- #if NON_BLOCK_READ\r
- while( (len = ioctl(Server->FD, 8, NULL)) > 0 )\r
- {\r
- #endif\r
- // Read data\r
- len = read(Server->FD, BUFSIZ - Server->ReadPos, &Server->InBuf[Server->ReadPos]);\r
- Server->InBuf[Server->ReadPos + len] = '\0';\r
- \r
- // Break into lines\r
- ptr = Server->InBuf;\r
- while( (newline = strchr(ptr, '\n')) )\r
- {\r
- *newline = '\0';\r
- printf("%s\n", ptr);\r
- ParseServerLine(Server, ptr);\r
- ptr = newline + 1;\r
- }\r
- \r
- // Handle incomplete lines\r
- if( ptr - Server->InBuf < len + Server->ReadPos ) {\r
- // Update the read position\r
- // InBuf ReadPos ptr ReadPos+len\r
- // | old | new used | new unused |\r
- Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf);\r
- // Copy stuff back (moving "new unused" to the start of the buffer)\r
- memcpy(Server->InBuf, ptr, Server->ReadPos);\r
- }\r
- else {\r
- Server->ReadPos = 0;\r
- }\r
- #if NON_BLOCK_READ\r
- }\r
- #endif\r
-}\r
-\r
-/**\r
- * \brief Write a formatted string to a file descriptor\r
- * \r
- */\r
-int writef(int FD, const char *Format, ...)\r
-{\r
- va_list args;\r
- int len;\r
- \r
- va_start(args, Format);\r
- len = vsnprintf(NULL, 1000, Format, args);\r
- va_end(args);\r
- \r
- {\r
- char buf[len+1];\r
- va_start(args, Format);\r
- vsnprintf(buf, len+1, Format, args);\r
- va_end(args);\r
- \r
- return write(FD, len, buf);\r
- }\r
-}\r
-\r
-/**\r
- * \brief Initialise a TCP connection to \a AddressString on port \a PortNumber\r
- */\r
-int OpenTCP(const char *AddressString, short PortNumber)\r
-{\r
- int fd, addrType;\r
- char *iface;\r
- char addrBuffer[8];\r
- \r
- // Parse IP Address\r
- addrType = Net_ParseAddress(AddressString, addrBuffer);\r
- if( addrType == 0 ) {\r
- fprintf(stderr, "Unable to parse '%s' as an IP address\n", AddressString);\r
- return -1;\r
- }\r
- \r
- // Finds the interface for the destination address\r
- iface = Net_GetInterface(addrType, addrBuffer);\r
- if( iface == NULL ) {\r
- fprintf(stderr, "Unable to find a route to '%s'\n", AddressString);\r
- return -1;\r
- }\r
- \r
- printf("iface = '%s'\n", iface);\r
- \r
- // Open client socket\r
- // TODO: Move this out to libnet?\r
- {\r
- int len = snprintf(NULL, 100, "/Devices/ip/%s/tcpc", iface);\r
- char path[len+1];\r
- snprintf(path, 100, "/Devices/ip/%s/tcpc", iface);\r
- fd = open(path, OPENFLAG_READ|OPENFLAG_WRITE);\r
- }\r
- \r
- free(iface);\r
- \r
- if( fd == -1 ) {\r
- fprintf(stderr, "Unable to open TCP Client for reading\n");\r
- return -1;\r
- }\r
- \r
- // Set remote port and address\r
- printf("Setting port and remote address\n");\r
- ioctl(fd, 5, &PortNumber);\r
- ioctl(fd, 6, addrBuffer);\r
- \r
- // Connect\r
- printf("Initiating connection\n");\r
- if( ioctl(fd, 7, NULL) == 0 ) {\r
- // Shouldn't happen :(\r
- fprintf(stderr, "Unable to start connection\n");\r
- return -1;\r
- }\r
- \r
- // Return descriptor\r
- return fd;\r
-}\r
+/*
+ * Acess2 IRC Client
+ */
+#include <acess/sys.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <net.h>
+#include <stdarg.h>
+#include <acess/devices/pty.h>
+
+#include "common.h"
+#include "input.h"
+#include "window.h"
+#include "server.h"
+
+// === TYPES ===
+
+// === PROTOTYPES ===
+ int main(int argc, const char *argv[], const char *envp[]);
+ int MainLoop(void);
+ int ParseArguments(int argc, const char *argv[]);
+// ---
+void Redraw_Screen(void);
+// --- Helpers
+void Exit(const char *Reason);
+ int writef(int FD, const char *Format, ...);
+ int OpenTCP(const char *AddressString, short PortNumber);
+char *GetValue(char *Str, int *Ofs);
+
+// === GLOBALS ===
+const char *gsExitReason = "No reason [BUG]";
+
+// ==== CODE ====
+void ExitHandler(void)
+{
+ printf("\x1B[?1047l");
+ printf("Quit: %s\n", gsExitReason);
+
+ // stty +echo,canon
+ struct ptymode mode = {.InputMode = 0, .OutputMode = 0};
+ mode.InputMode = PTYIMODE_CANON|PTYIMODE_ECHO;
+ _SysIOCtl(0, PTY_IOCTL_SETMODE, &mode);
+}
+
+void Exit(const char *Reason)
+{
+ gsExitReason = (Reason ? Reason : "User Requested");
+ exit( (Reason ? 1 : 0) );
+}
+
+int main(int argc, const char *argv[], const char *envp[])
+{
+ int tmp;
+
+ // Parse Command line
+ if( (tmp = ParseArguments(argc, argv)) ) return tmp;
+
+ atexit(ExitHandler);
+
+ ACurses_Init();
+
+ printf("\x1B[?1047h");
+ printf("\x1B[%i;%ir", 2, giTerminal_Height-2);
+
+ // HACK: Static server entry
+ // UCC (University [of Western Australia] Computer Club) IRC Server
+// tServer *starting_server = Server_Connect( "UCC", "130.95.13.18", 6667 );
+ // Freenode (#osdev)
+ tServer *starting_server = Server_Connect( "Freenode", "84.240.3.129", 6667 );
+ // Local servers
+// gWindow_Status.Server = Server_Connect( "VMHost", "10.0.2.2", 6667 );
+// gWindow_Status.Server = Server_Connect( "BitlBee", "192.168.1.39", 6667 );
+
+ Windows_SetStatusServer(starting_server);
+ Windows_RepaintCurrent();
+ SetCursorPos(giTerminal_Height-1, 1);
+ printf("[(status)] ");
+
+ MainLoop();
+
+ Servers_CloseAll("Client closing");
+
+ return 0;
+}
+
+int MainLoop(void)
+{
+ SetCursorPos(giTerminal_Height, 1);
+ printf("[(status)] ");
+ fflush(stdout);
+
+ // stty -echo,canon
+ struct ptymode mode = {.InputMode = 0, .OutputMode = 0};
+ _SysIOCtl(0, PTY_IOCTL_SETMODE, &mode);
+
+ for( ;; )
+ {
+ fd_set readfds, errorfds;
+ int nfds = 1;
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&errorfds);
+
+ Input_FillSelect(&nfds, &readfds);
+ Servers_FillSelect(&nfds, &readfds, &errorfds);
+
+ int rv = _SysSelect(nfds, &readfds, 0, &errorfds, NULL, 0);
+ if( rv < 0 ) break;
+
+ // user input
+ Input_HandleSelect(nfds, &readfds);
+
+ // Server response
+ Servers_HandleSelect(nfds, &readfds, &errorfds);
+ }
+ return 0;
+}
+
+/**
+ * \todo Actually implement correctly :)
+ */
+int ParseArguments(int argc, const char *argv[])
+{
+ return 0;
+}
+
+void Redraw_Screen(void)
+{
+ printf("\x1B[2J"); // Clear screen
+ printf("\x1B[H"); // Reset cursor
+
+ Windows_RepaintCurrent();
+}
+
+/**
+ * \brief Write a formatted string to a file descriptor
+ *
+ */
+int writef(int FD, const char *Format, ...)
+{
+ va_list args;
+ int len;
+
+ va_start(args, Format);
+ len = vsnprintf(NULL, 0, Format, args);
+ va_end(args);
+
+ {
+ char buf[len+1];
+ va_start(args, Format);
+ vsnprintf(buf, len+1, Format, args);
+ va_end(args);
+
+ return _SysWrite(FD, buf, len);
+ }
+}
+
+/**
+ * \brief Initialise a TCP connection to \a AddressString on port \a PortNumber
+ */
+int OpenTCP(const char *AddressString, short PortNumber)
+{
+ int fd, addrType;
+ char addrBuffer[8];
+
+ // Parse IP Address
+ addrType = Net_ParseAddress(AddressString, addrBuffer);
+ if( addrType == 0 ) {
+ fprintf(stderr, "Unable to parse '%s' as an IP address\n", AddressString);
+ _SysDebug("Unable to parse '%s' as an IP address\n", AddressString);
+ return -1;
+ }
+
+ // Finds the interface for the destination address
+ fd = Net_OpenSocket(addrType, addrBuffer, "tcpc");
+ if( fd == -1 ) {
+ fprintf(stderr, "Unable to open TCP Client to '%s'\n", AddressString);
+ _SysDebug("Unable to open TCP client to '%s'\n", AddressString);
+ return -1;
+ }
+
+ // Set remote port and address
+// printf("Setting port and remote address\n");
+ _SysIOCtl(fd, 5, &PortNumber);
+ _SysIOCtl(fd, 6, addrBuffer);
+
+ // Connect
+// printf("Initiating connection\n");
+ if( _SysIOCtl(fd, 7, NULL) == 0 ) {
+ // Shouldn't happen :(
+ fprintf(stderr, "Unable to start connection\n");
+ return -1;
+ }
+
+ // Return descriptor
+ return fd;
+}
+
+/**
+ * \brief Read a space-separated value from a string
+ */
+char *GetValue(char *Src, int *Ofs)
+{
+ int pos = *Ofs;
+ char *ret = Src + pos;
+ char *end;
+
+ if( !Src ) return NULL;
+
+ while( *ret == ' ' ) ret ++;
+
+ end = strchr(ret, ' ');
+ if( end ) {
+ *end = '\0';
+ }
+ else {
+ end = ret + strlen(ret) - 1;
+ }
+
+ end ++ ;
+ while( *ret == ' ' ) end ++;
+ *Ofs = end - Src;
+
+ return ret;
+}
+