Made IRC use select()
[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                 fd_set  readfds;\r
65                  int    rv;\r
66                 \r
67                 FD_ZERO(&readfds);\r
68                 FD_SET(0, &readfds);    // stdin\r
69                 FD_SET(srv.FD, &readfds);\r
70                 \r
71                 rv = select(srv.FD, &readfds, 0, 0, NULL);\r
72                 if( rv == -1 )  break;\r
73                 \r
74                 if(FD_ISSET(0, &readfds))\r
75                 {\r
76                         // User input\r
77                 }\r
78                 \r
79                 // Server response\r
80                 if(FD_ISSET(srv.FD, &readfds))\r
81                 {\r
82                         ProcessIncoming(&srv);\r
83                 }\r
84         }\r
85         \r
86         close(srv.FD);\r
87         return 0;\r
88 }\r
89 \r
90 /**\r
91  * \todo Actually implement correctly :)\r
92  */\r
93 int ParseArguments(int argc, const char *argv[])\r
94 {\r
95         gsRemoteAddress = "130.95.13.18";       // irc.ucc.asn.au\r
96         \r
97         return 0;\r
98 }\r
99 \r
100 void Cmd_PRIVMSG(tServer *Server, const char *Dest, const char *Src, const char *Message)\r
101 {\r
102         printf("%p: %s => %s\t%s\n", Server, Src, Dest, Message);\r
103 }\r
104 \r
105 /**\r
106  * \brief Read a space-separated value from a string\r
107  */\r
108 char *GetValue(char *Src, int *Ofs)\r
109 {\r
110          int    pos = *Ofs;\r
111         char    *ret = Src + pos;\r
112         char    *end;\r
113         \r
114         if( !Src )      return NULL;\r
115         \r
116         while( *ret == ' ' )    ret ++;\r
117         \r
118         end = strchr(ret, ' ');\r
119         if( end ) {\r
120                 *end = '\0';\r
121         }\r
122         else {\r
123                 end = ret + strlen(ret) - 1;\r
124         }\r
125         *Ofs = end - Src + 1;\r
126         \r
127         return ret;\r
128 }\r
129 \r
130 /**\r
131  */\r
132 void ParseServerLine(tServer *Server, char *Line)\r
133 {\r
134          int    pos = 0;\r
135         char    *ident, *cmd;\r
136         if( *Line == ':' ) {\r
137                 // Message\r
138                 ident = GetValue(Line, &pos);\r
139                 pos ++; // Space\r
140                 cmd = GetValue(Line, &pos);\r
141                 \r
142                 if( strcmp(cmd, "PRIVMSG") == 0 ) {\r
143                         char    *dest, *message;\r
144                         pos ++;\r
145                         dest = GetValue(Line, &pos);\r
146                         pos ++;\r
147                         if( Line[pos] == ':' ) {\r
148                                 message = Line + pos + 1;\r
149                         }\r
150                         else {\r
151                                 message = GetValue(Line, &pos);\r
152                         }\r
153                         Cmd_PRIVMSG(Server, dest, ident, message);\r
154                 }\r
155         }\r
156         else {\r
157                 // Command to client\r
158         }\r
159 }\r
160 \r
161 /**\r
162  * \brief Process incoming lines from the server\r
163  */\r
164 void ProcessIncoming(tServer *Server)\r
165 {       \r
166         char    *ptr, *newline;\r
167          int    len;\r
168         \r
169         // While there is data in the buffer, read it into user memory and \r
170         // process it line by line\r
171         // ioctl#8 on a TCP client gets the number of bytes in the recieve buffer\r
172         // - Used to avoid blocking\r
173         #if NON_BLOCK_READ\r
174         while( (len = ioctl(Server->FD, 8, NULL)) > 0 )\r
175         {\r
176         #endif\r
177                 // Read data\r
178                 len = read(Server->FD, BUFSIZ - Server->ReadPos, &Server->InBuf[Server->ReadPos]);\r
179                 Server->InBuf[Server->ReadPos + len] = '\0';\r
180                 \r
181                 // Break into lines\r
182                 ptr = Server->InBuf;\r
183                 while( (newline = strchr(ptr, '\n')) )\r
184                 {\r
185                         *newline = '\0';\r
186                         printf("%s\n", ptr);\r
187                         ParseServerLine(Server, ptr);\r
188                         ptr = newline + 1;\r
189                 }\r
190                 \r
191                 // Handle incomplete lines\r
192                 if( ptr - Server->InBuf < len + Server->ReadPos ) {\r
193                         // Update the read position\r
194                         // InBuf ReadPos    ptr          ReadPos+len\r
195                         // | old | new used | new unused |\r
196                         Server->ReadPos = len + Server->ReadPos - (ptr - Server->InBuf);\r
197                         // Copy stuff back (moving "new unused" to the start of the buffer)\r
198                         memcpy(Server->InBuf, ptr, Server->ReadPos);\r
199                 }\r
200                 else {\r
201                         Server->ReadPos = 0;\r
202                 }\r
203         #if NON_BLOCK_READ\r
204         }\r
205         #endif\r
206 }\r
207 \r
208 /**\r
209  * \brief Write a formatted string to a file descriptor\r
210  * \r
211  */\r
212 int writef(int FD, const char *Format, ...)\r
213 {\r
214         va_list args;\r
215          int    len;\r
216         \r
217         va_start(args, Format);\r
218         len = vsnprintf(NULL, 1000, Format, args);\r
219         va_end(args);\r
220         \r
221         {\r
222                 char    buf[len+1];\r
223                 va_start(args, Format);\r
224                 vsnprintf(buf, len+1, Format, args);\r
225                 va_end(args);\r
226                 \r
227                 return write(FD, len, buf);\r
228         }\r
229 }\r
230 \r
231 /**\r
232  * \brief Initialise a TCP connection to \a AddressString on port \a PortNumber\r
233  */\r
234 int OpenTCP(const char *AddressString, short PortNumber)\r
235 {\r
236          int    fd, addrType;\r
237         char    *iface;\r
238         char    addrBuffer[8];\r
239         \r
240         // Parse IP Address\r
241         addrType = Net_ParseAddress(AddressString, addrBuffer);\r
242         if( addrType == 0 ) {\r
243                 fprintf(stderr, "Unable to parse '%s' as an IP address\n", AddressString);\r
244                 return -1;\r
245         }\r
246         \r
247         // Finds the interface for the destination address\r
248         iface = Net_GetInterface(addrType, addrBuffer);\r
249         if( iface == NULL ) {\r
250                 fprintf(stderr, "Unable to find a route to '%s'\n", AddressString);\r
251                 return -1;\r
252         }\r
253         \r
254         printf("iface = '%s'\n", iface);\r
255         \r
256         // Open client socket\r
257         // TODO: Move this out to libnet?\r
258         {\r
259                  int    len = snprintf(NULL, 100, "/Devices/ip/%s/tcpc", iface);\r
260                 char    path[len+1];\r
261                 snprintf(path, 100, "/Devices/ip/%s/tcpc", iface);\r
262                 fd = open(path, OPENFLAG_READ|OPENFLAG_WRITE);\r
263         }\r
264         \r
265         free(iface);\r
266         \r
267         if( fd == -1 ) {\r
268                 fprintf(stderr, "Unable to open TCP Client for reading\n");\r
269                 return -1;\r
270         }\r
271         \r
272         // Set remote port and address\r
273         printf("Setting port and remote address\n");\r
274         ioctl(fd, 5, &PortNumber);\r
275         ioctl(fd, 6, addrBuffer);\r
276         \r
277         // Connect\r
278         printf("Initiating connection\n");\r
279         if( ioctl(fd, 7, NULL) == 0 ) {\r
280                 // Shouldn't happen :(\r
281                 fprintf(stderr, "Unable to start connection\n");\r
282                 return -1;\r
283         }\r
284         \r
285         // Return descriptor\r
286         return fd;\r
287 }\r

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