IPStack - Bugfixing (and testing IRC client)
[tpg/acess2.git] / Usermode / Applications / irc_src / main.c
1 /*\r
2  * Acess2 IRC Client\r
3  */\r
4 #include <acess/sys.h>\r
5 #include <stdlib.h>\r
6 #include <stdio.h>\r
7 #include <string.h>\r
8 #include <net.h>\r
9 \r
10 #define BUFSIZ  1023\r
11 \r
12 // === TYPES ===\r
13 typedef struct sServer {\r
14          int    FD;\r
15         char    InBuf[BUFSIZ+1];\r
16          int    ReadPos;\r
17 } tServer;\r
18 \r
19 // === PROTOTYPES ===\r
20  int    ParseArguments(int argc, const char *argv[]);\r
21 void    ProcessIncoming(tServer *Server);\r
22  int    writef(int FD, const char *Format, ...);\r
23  int    OpenTCP(const char *AddressString, short PortNumber);\r
24 \r
25 // === GLOBALS ===\r
26 char    *gsUsername = "root";\r
27 char    *gsHostname = "acess";\r
28 char    *gsRemoteAddress = NULL;\r
29 char    *gsRealName = "Acess2 IRC Client";\r
30 char    *gsNickname = "acess";\r
31 short   giRemotePort = 6667;\r
32 \r
33 // ==== CODE ====\r
34 int main(int argc, const char *argv[], const char *envp[])\r
35 {\r
36          int    tmp;\r
37         tServer srv;\r
38         \r
39         memset(&srv, 0, sizeof(srv));\r
40         \r
41         // Parse Command line\r
42         // - Sets the server configuration globals\r
43         if( (tmp = ParseArguments(argc, argv)) ) {\r
44                 return tmp;\r
45         }\r
46         \r
47         // Connect to the remove server\r
48         srv.FD = OpenTCP( gsRemoteAddress, giRemotePort );\r
49         if( srv.FD == -1 ) {\r
50                 fprintf(stderr, "Unable to create socket\n");\r
51                 return -1;\r
52         }\r
53         \r
54         printf("Connection opened\n");\r
55         ProcessIncoming(&srv);\r
56         \r
57         writef(srv.FD, "USER %s %s %s : %s\n", gsUsername, gsHostname, gsRemoteAddress, gsRealName);\r
58         writef(srv.FD, "NICK %s\n", gsNickname);\r
59         \r
60         printf("Processing\n");\r
61         \r
62         for( ;; )\r
63         {\r
64                 ProcessIncoming(&srv);\r
65         }\r
66         \r
67         close(srv.FD);\r
68         return 0;\r
69 }\r
70 \r
71 /**\r
72  * \todo Actually implement correctly :)\r
73  */\r
74 int ParseArguments(int argc, const char *argv[])\r
75 {\r
76         gsRemoteAddress = "130.95.13.18";       // irc.ucc.asn.au\r
77         \r
78         return 0;\r
79 }\r
80 \r
81 void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message)\r
82 {\r
83         printf("%p: %s => %s\t%s\n", Server, Src, Dest, Message);\r
84 }\r
85 \r
86 /**\r
87  * \brief Read a space-separated value from a string\r
88  */\r
89 char *GetValue(char *Src, int *Ofs)\r
90 {\r
91          int    pos = *Ofs;\r
92         char    *ret = Src + pos;\r
93         char    *end;\r
94         \r
95         if( !Src )      return NULL;\r
96         \r
97         while( *ret == ' ' )    ret ++;\r
98         \r
99         end = strchr(ret, ' ');\r
100         if( end ) {\r
101                 *end = '\0';\r
102         }\r
103         else {\r
104                 end = ret + strlen(ret) - 1;\r
105         }\r
106         *Ofs = end - Src + 1;\r
107         \r
108         return ret;\r
109 }\r
110 \r
111 /**\r
112  */\r
113 void ParseServerLine(tServer *Server, char *Line)\r
114 {\r
115          int    pos = 0;\r
116         char    *ident, *cmd;\r
117         if( *Line == ':' ) {\r
118                 // Message\r
119                 ident = GetValue(Line, &pos);\r
120                 pos ++; // Space\r
121                 cmd = GetValue(Line, &pos);\r
122                 \r
123                 if( strcmp(cmd, "PRIVMSG") == 0 ) {\r
124                         char    *dest, *message;\r
125                         pos ++;\r
126                         dest = GetValue(Line, &pos);\r
127                         pos ++;\r
128                         if( Line[pos] == ':' ) {\r
129                                 message = Line + pos + 1;\r
130                         }\r
131                         else {\r
132                                 message = GetValue(Line, &pos);\r
133                         }\r
134                         Cmd_PRIVMSG(Server, dest, ident, message);\r
135                 }\r
136         }\r
137         else {\r
138                 // Command to client\r
139         }\r
140 }\r
141 \r
142 /**\r
143  * \brief Process incoming lines from the server\r
144  */\r
145 void ProcessIncoming(tServer *Server)\r
146 {       \r
147         char    *ptr, *newline;\r
148          int    len;\r
149         \r
150         // While there is data in the buffer, read it into user memory and \r
151         // process it line by line\r
152         // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer\r
153         // - Used to avoid blocking\r
154         #if NON_BLOCK_READ\r
155         while( (len = ioctl(Server->FD, 8, NULL)) > 0 )\r
156         {\r
157         #endif\r
158                 // Read data\r
159                 len = read(Server->FD, BUFSIZ - Server->ReadPos, &Server->InBuf[Server->ReadPos]);\r
160                 Server->InBuf[Server->ReadPos + len] = '\0';\r
161                 \r
162                 // Break into lines\r
163                 ptr = Server->InBuf;\r
164                 while( (newline = strchr(ptr, '\n')) )\r
165                 {\r
166                         *newline = '\0';\r
167                         printf("%s\n", ptr);\r
168                         ParseServerLine(Server, ptr);\r
169                         ptr = newline + 1;\r
170                 }\r
171                 \r
172                 // Handle incomplete lines\r
173                 if( ptr - Server->InBuf < len + Server->ReadPos ) {\r
174                         // Update the read position\r
175                         // InBuf ReadPos    ptr          ReadPos+len\r
176                         // | old | new used | new unused |\r
177                         Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf);\r
178                         // Copy stuff back (moving "new unused" to the start of the buffer)\r
179                         memcpy(Server->InBuf, ptr, Server->ReadPos);\r
180                 }\r
181                 else {\r
182                         Server->ReadPos = 0;\r
183                 }\r
184         #if NON_BLOCK_READ\r
185         }\r
186         #endif\r
187 }\r
188 \r
189 /**\r
190  * \brief Write a formatted string to a file descriptor\r
191  * \r
192  */\r
193 int writef(int FD, const char *Format, ...)\r
194 {\r
195         va_list args;\r
196          int    len;\r
197         \r
198         va_start(args, Format);\r
199         len = vsnprintf(NULL, 1000, Format, args);\r
200         va_end(args);\r
201         \r
202         {\r
203                 char    buf[len+1];\r
204                 va_start(args, Format);\r
205                 vsnprintf(buf, len+1, Format, args);\r
206                 va_end(args);\r
207                 \r
208                 return write(FD, len, buf);\r
209         }\r
210 }\r
211 \r
212 /**\r
213  * \brief Initialise a TCP connection to \a AddressString on port \a PortNumber\r
214  */\r
215 int OpenTCP(const char *AddressString, short PortNumber)\r
216 {\r
217          int    fd, addrType;\r
218         char    *iface;\r
219         char    addrBuffer[8];\r
220         \r
221         // Parse IP Address\r
222         addrType = Net_ParseAddress(AddressString, addrBuffer);\r
223         if( addrType == 0 ) {\r
224                 fprintf(stderr, "Unable to parse '%s' as an IP address\n", AddressString);\r
225                 return -1;\r
226         }\r
227         \r
228         // Finds the interface for the destination address\r
229         iface = Net_GetInterface(addrType, addrBuffer);\r
230         if( iface == NULL ) {\r
231                 fprintf(stderr, "Unable to find a route to '%s'\n", AddressString);\r
232                 return -1;\r
233         }\r
234         \r
235         printf("iface = '%s'\n", iface);\r
236         \r
237         // Open client socket\r
238         // TODO: Move this out to libnet?\r
239         {\r
240                  int    len = snprintf(NULL, 100, "/Devices/ip/%s/tcpc", iface);\r
241                 char    path[len+1];\r
242                 snprintf(path, 100, "/Devices/ip/%s/tcpc", iface);\r
243                 fd = open(path, OPENFLAG_READ|OPENFLAG_WRITE);\r
244         }\r
245         \r
246         free(iface);\r
247         \r
248         if( fd == -1 ) {\r
249                 fprintf(stderr, "Unable to open TCP Client for reading\n");\r
250                 return -1;\r
251         }\r
252         \r
253         // Set remote port and address\r
254         printf("Setting port and remote address\n");\r
255         ioctl(fd, 5, &PortNumber);\r
256         ioctl(fd, 6, addrBuffer);\r
257         \r
258         // Connect\r
259         printf("Initiating connection\n");\r
260         if( ioctl(fd, 7, NULL) == 0 ) {\r
261                 // Shouldn't happen :(\r
262                 fprintf(stderr, "Unable to start connection\n");\r
263                 return -1;\r
264         }\r
265         \r
266         // Return descriptor\r
267         return fd;\r
268 }\r

UCC git Repository :: git.ucc.asn.au