blob: c53d8c6487e72bd0ea5d73d1d96b610d8202f25d [file] [log] [blame]
adamdunkels2bd076e2004-09-03 08:11:09 +00001
2#include "contiki.h"
adamdunkels5a2df1c2004-09-01 19:11:42 +00003#include "ircc.h"
4
adamdunkels2bd076e2004-09-03 08:11:09 +00005#include "ircc-strings.h"
6
adamdunkels5a2df1c2004-09-01 19:11:42 +00007#include <string.h>
8
9#define PORT 6667
10
11#define SEND_STRING(s, str) SOCKET_SEND(s, str, strlen(str))
12
adamdunkels2bd076e2004-09-03 08:11:09 +000013#define ISO_space 0x20
14#define ISO_bang 0x21
15#define ISO_at 0x40
16#define ISO_cr 0x0d
17#define ISO_nl 0x0a
18#define ISO_colon 0x3a
19#define ISO_O 0x4f
20
adamdunkels5a2df1c2004-09-01 19:11:42 +000021enum {
22 COMMAND_NONE,
23 COMMAND_JOIN,
24 COMMAND_PART,
25 COMMAND_MSG,
adamdunkels8d8b7452004-09-09 21:05:56 +000026 COMMAND_ACTIONMSG,
adamdunkels5a2df1c2004-09-01 19:11:42 +000027 COMMAND_LIST,
adamdunkels2bd076e2004-09-03 08:11:09 +000028 COMMAND_QUIT
adamdunkels5a2df1c2004-09-01 19:11:42 +000029};
30
31/*---------------------------------------------------------------------------*/
32void
33ircc_init(void)
34{
35
36}
37/*---------------------------------------------------------------------------*/
38static char *
adamdunkels2bd076e2004-09-03 08:11:09 +000039copystr(char *dest, const char *src, int n)
adamdunkels5a2df1c2004-09-01 19:11:42 +000040{
41 int len;
42
43 len = strlen(src);
44 strncpy(dest, src, n);
45
46 if(len > n) {
47 return dest + n;
48 } else {
49 return dest + len;
50 }
51}
52/*---------------------------------------------------------------------------*/
53static
54PT_THREAD(setup_connection(struct ircc_state *s))
55{
56 char *ptr;
57
58
59 SOCKET_BEGIN(&s->s);
60
61 ptr = s->outputbuf;
adamdunkels2bd076e2004-09-03 08:11:09 +000062 ptr = copystr(ptr, ircc_nick, sizeof(s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +000063 ptr = copystr(ptr, s->nick, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels2bd076e2004-09-03 08:11:09 +000064 ptr = copystr(ptr, ircc_crnl_user, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +000065 ptr = copystr(ptr, s->nick, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels2bd076e2004-09-03 08:11:09 +000066 ptr = copystr(ptr, ircc_contiki, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +000067 ptr = copystr(ptr, s->server, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels2bd076e2004-09-03 08:11:09 +000068 ptr = copystr(ptr, ircc_colon_contiki, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +000069
70 SEND_STRING(&s->s, s->outputbuf);
71
72 SOCKET_END(&s->s);
73}
74/*---------------------------------------------------------------------------*/
75static
76PT_THREAD(join_channel(struct ircc_state *s))
77{
78 SOCKET_BEGIN(&s->s);
79
adamdunkels2bd076e2004-09-03 08:11:09 +000080 SEND_STRING(&s->s, ircc_join_);
adamdunkels5a2df1c2004-09-01 19:11:42 +000081 SEND_STRING(&s->s, s->channel);
adamdunkels2bd076e2004-09-03 08:11:09 +000082 SEND_STRING(&s->s, ircc_crnl);
adamdunkels5a2df1c2004-09-01 19:11:42 +000083
84 ircc_sent(s);
85
86 SOCKET_END(&s->s);
87}
88/*---------------------------------------------------------------------------*/
89static
90PT_THREAD(part_channel(struct ircc_state *s))
91{
92 SOCKET_BEGIN(&s->s);
93
adamdunkels2bd076e2004-09-03 08:11:09 +000094 SEND_STRING(&s->s, ircc_part_);
adamdunkels5a2df1c2004-09-01 19:11:42 +000095 SEND_STRING(&s->s, s->channel);
adamdunkels2bd076e2004-09-03 08:11:09 +000096 SEND_STRING(&s->s, ircc_crnl);
adamdunkels5a2df1c2004-09-01 19:11:42 +000097
98 ircc_sent(s);
99
100 SOCKET_END(&s->s);
101}
102/*---------------------------------------------------------------------------*/
103static
104PT_THREAD(list_channel(struct ircc_state *s))
105{
106 SOCKET_BEGIN(&s->s);
107
adamdunkels2bd076e2004-09-03 08:11:09 +0000108 SEND_STRING(&s->s, ircc_list_);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000109 SEND_STRING(&s->s, s->channel);
adamdunkels2bd076e2004-09-03 08:11:09 +0000110 SEND_STRING(&s->s, ircc_crnl);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000111
112 ircc_sent(s);
113
114 SOCKET_END(&s->s);
115}
116/*---------------------------------------------------------------------------*/
117static
118PT_THREAD(send_message(struct ircc_state *s))
119{
120 char *ptr;
121
122 SOCKET_BEGIN(&s->s);
123
124 ptr = s->outputbuf;
adamdunkels2bd076e2004-09-03 08:11:09 +0000125 ptr = copystr(ptr, ircc_privmsg, sizeof(s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +0000126 ptr = copystr(ptr, s->channel, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels2bd076e2004-09-03 08:11:09 +0000127 ptr = copystr(ptr, ircc_colon, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +0000128 ptr = copystr(ptr, s->msg, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels2bd076e2004-09-03 08:11:09 +0000129 ptr = copystr(ptr, ircc_crnl, sizeof(s->outputbuf) - (ptr - s->outputbuf));
adamdunkels5a2df1c2004-09-01 19:11:42 +0000130
131 SEND_STRING(&s->s, s->outputbuf);
132
133 ircc_sent(s);
134
135 SOCKET_END(&s->s);
136}
137/*---------------------------------------------------------------------------*/
adamdunkels8d8b7452004-09-09 21:05:56 +0000138static
139PT_THREAD(send_actionmessage(struct ircc_state *s))
140{
141 char *ptr;
142
143 SOCKET_BEGIN(&s->s);
144
145 ptr = s->outputbuf;
146 ptr = copystr(ptr, ircc_privmsg, sizeof(s->outputbuf));
147 ptr = copystr(ptr, s->channel, sizeof(s->outputbuf) - (ptr - s->outputbuf));
148 ptr = copystr(ptr, ircc_colon, sizeof(s->outputbuf) - (ptr - s->outputbuf));
149 ptr = copystr(ptr, ircc_action, sizeof(s->outputbuf) - (ptr - s->outputbuf));
150 ptr = copystr(ptr, s->msg, sizeof(s->outputbuf) - (ptr - s->outputbuf));
151 ptr = copystr(ptr, ircc_actioncrnl, sizeof(s->outputbuf) - (ptr - s->outputbuf));
152
153
154 SEND_STRING(&s->s, s->outputbuf);
155
156 ircc_sent(s);
157
158 SOCKET_END(&s->s);
159}
160/*---------------------------------------------------------------------------*/
adamdunkels5a2df1c2004-09-01 19:11:42 +0000161struct parse_result {
adamdunkels2bd076e2004-09-03 08:11:09 +0000162 char *msg;
163
adamdunkels5a2df1c2004-09-01 19:11:42 +0000164 char *user;
165 char *host;
166 char *name;
167 char *command;
168 char *middle;
169 char *trailing;
170};
adamdunkels2bd076e2004-09-03 08:11:09 +0000171static struct parse_result r;
172static void
173parse_whitespace(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000174{
adamdunkels2bd076e2004-09-03 08:11:09 +0000175 while(*r.msg == ISO_space) ++r.msg;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000176}
adamdunkels2bd076e2004-09-03 08:11:09 +0000177static void
178parse_word(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000179{
adamdunkels2bd076e2004-09-03 08:11:09 +0000180 char *ptr;
181 ptr = strchr(r.msg, ISO_space);
182 if(ptr != NULL) {
183 r.msg = ptr;
184 }
adamdunkels5a2df1c2004-09-01 19:11:42 +0000185}
adamdunkels2bd076e2004-09-03 08:11:09 +0000186static void
187parse_user(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000188{
adamdunkels2bd076e2004-09-03 08:11:09 +0000189 parse_whitespace();
190 r.user = r.msg;
191 parse_word();
192 *r.msg = 0;
193 ++r.msg;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000194}
adamdunkels2bd076e2004-09-03 08:11:09 +0000195static void
196parse_host(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000197{
adamdunkels2bd076e2004-09-03 08:11:09 +0000198 parse_whitespace();
199 r.host = r.msg;
200 parse_word();
201 *r.msg = 0;
202 ++r.msg;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000203}
204
adamdunkels2bd076e2004-09-03 08:11:09 +0000205static void
206parse_name(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000207{
adamdunkels2bd076e2004-09-03 08:11:09 +0000208 parse_whitespace();
209 r.name = r.msg;
210 parse_word();
211 *r.msg = 0;
212 ++r.msg;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000213}
214
adamdunkels2bd076e2004-09-03 08:11:09 +0000215static void
216parse_prefix(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000217{
adamdunkels2bd076e2004-09-03 08:11:09 +0000218 parse_name();
219 if(*r.msg == ISO_bang) {
220 ++r.msg;
221 parse_user();
adamdunkels5a2df1c2004-09-01 19:11:42 +0000222 }
adamdunkels2bd076e2004-09-03 08:11:09 +0000223 if(*r.msg == ISO_at) {
224 ++r.msg;
225 parse_host();
adamdunkels5a2df1c2004-09-01 19:11:42 +0000226 }
227}
228
229static void
adamdunkels2bd076e2004-09-03 08:11:09 +0000230parse_command(void)
adamdunkels5a2df1c2004-09-01 19:11:42 +0000231{
adamdunkels2bd076e2004-09-03 08:11:09 +0000232 parse_whitespace();
233 r.command = r.msg;
234 parse_word();
235 *r.msg = 0;
236 ++r.msg;
237}
238
adamdunkels8b1784b2004-09-05 07:13:05 +0000239/*static void
adamdunkels2bd076e2004-09-03 08:11:09 +0000240parse_trailing(void)
241{
242 r.trailing = r.msg;
243 while(*r.msg != 0 && *r.msg != ISO_cr && *r.msg != ISO_nl) ++r.msg;
244 *r.msg = 0;
245 ++r.msg;
adamdunkels8b1784b2004-09-05 07:13:05 +0000246}*/
adamdunkels2bd076e2004-09-03 08:11:09 +0000247
248static void
249parse_params(void)
250{
251 char *ptr;
252
253 parse_whitespace();
254 ptr = strchr(r.msg, ISO_colon);
255 if(ptr != NULL) {
256 r.trailing = ptr + 1;
257 ptr = strchr(ptr, ISO_cr);
258 if(ptr != NULL) {
259 *ptr = 0;
260 }
261 }
262}
263
264static void
265parse(char *msg, struct parse_result *dummy)
266{
267 r.msg = msg;
268 if(*r.msg == ISO_cr || *r.msg == ISO_nl) {
adamdunkels5a2df1c2004-09-01 19:11:42 +0000269 return;
270 }
adamdunkels2bd076e2004-09-03 08:11:09 +0000271 if(*r.msg == ISO_colon) {
272 ++r.msg;
273 parse_prefix();
adamdunkels5a2df1c2004-09-01 19:11:42 +0000274 }
275
adamdunkels2bd076e2004-09-03 08:11:09 +0000276 parse_command();
277 parse_params();
278
adamdunkels5a2df1c2004-09-01 19:11:42 +0000279}
adamdunkels2bd076e2004-09-03 08:11:09 +0000280
adamdunkels5a2df1c2004-09-01 19:11:42 +0000281/*---------------------------------------------------------------------------*/
282static
283PT_THREAD(handle_input(struct ircc_state *s))
284{
285 int i;
286 char *ptr;
adamdunkels2bd076e2004-09-03 08:11:09 +0000287 /* struct parse_result r;*/
adamdunkels5a2df1c2004-09-01 19:11:42 +0000288
289 SOCKET_BEGIN(&s->s);
290
adamdunkels2bd076e2004-09-03 08:11:09 +0000291 SOCKET_READTO(&s->s, ISO_nl);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000292
293 if(SOCKET_DATALEN(&s->s) > 0) {
294
295 s->inputbuf[SOCKET_DATALEN(&s->s)] = 0;
296
adamdunkels2bd076e2004-09-03 08:11:09 +0000297 if(strncmp(s->inputbuf, ircc_ping, 5) == 0) {
adamdunkels5a2df1c2004-09-01 19:11:42 +0000298 strncpy(s->outputbuf, s->inputbuf, sizeof(s->outputbuf));
299
300 /* Turn "PING" into "PONG" */
adamdunkels2bd076e2004-09-03 08:11:09 +0000301 s->outputbuf[1] = ISO_O;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000302 SEND_STRING(&s->s, s->outputbuf);
303 } else {
304
305 memset(&r, 0, sizeof(r));
306
307 parse(s->inputbuf, &r);
308
309 if(r.name != NULL) {
adamdunkels2bd076e2004-09-03 08:11:09 +0000310 ptr = strchr(r.name, ISO_bang);
311 if(ptr != NULL) {
312 *ptr = 0;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000313 }
314 }
315
adamdunkels2bd076e2004-09-03 08:11:09 +0000316 if(r.command != NULL && strncmp(r.command, ircc_join_, 4) == 0) {
adamdunkels5a2df1c2004-09-01 19:11:42 +0000317 ircc_text_output(s, "Joined channel", r.name);
adamdunkels2bd076e2004-09-03 08:11:09 +0000318 } else if(r.command != NULL && strncmp(r.command, ircc_part_, 4) == 0) {
adamdunkels5a2df1c2004-09-01 19:11:42 +0000319 ircc_text_output(s, "Left channel", r.name);
320 } else {
321 ircc_text_output(s, r.name, r.trailing);
322 }
323 }
324 }
325
326 SOCKET_END(&s->s);
327}
328/*---------------------------------------------------------------------------*/
329static
330PT_THREAD(data_or_command(struct ircc_state *s))
331{
332 SOCKET_BEGIN(&s->s);
333
334 SOCKET_WAIT_UNTIL(&s->s, s->command != COMMAND_NONE);
335
336 SOCKET_END(&s->s);
337}
338/*---------------------------------------------------------------------------*/
339static
340PT_THREAD(handle_connection(struct ircc_state *s))
341{
342 PT_BEGIN(&s->pt);
343
adamdunkels8b1784b2004-09-05 07:13:05 +0000344 SOCKET_INIT(&s->s, s->inputbuf, sizeof(s->inputbuf) - 1);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000345
346 PT_WAIT_THREAD(&s->pt, setup_connection(s));
347
348 while(1) {
349
350 PT_WAIT_UNTIL(&s->pt, data_or_command(s));
351
352 if(SOCKET_NEWDATA(&s->s)) {
353 PT_WAIT_THREAD(&s->pt, handle_input(s));
354 }
355
356 switch(s->command) {
357 case COMMAND_JOIN:
358 s->command = COMMAND_NONE;
359 PT_WAIT_THREAD(&s->pt, join_channel(s));
360 break;
361 case COMMAND_PART:
362 s->command = COMMAND_NONE;
363 PT_WAIT_THREAD(&s->pt, part_channel(s));
364 break;
365 case COMMAND_MSG:
366 s->command = COMMAND_NONE;
367 PT_WAIT_THREAD(&s->pt, send_message(s));
368 break;
adamdunkels8d8b7452004-09-09 21:05:56 +0000369 case COMMAND_ACTIONMSG:
370 s->command = COMMAND_NONE;
371 PT_WAIT_THREAD(&s->pt, send_actionmessage(s));
372 break;
adamdunkels5a2df1c2004-09-01 19:11:42 +0000373 case COMMAND_LIST:
374 s->command = COMMAND_NONE;
375 PT_WAIT_THREAD(&s->pt, list_channel(s));
376 break;
adamdunkels2bd076e2004-09-03 08:11:09 +0000377 case COMMAND_QUIT:
adamdunkels5a2df1c2004-09-01 19:11:42 +0000378 s->command = COMMAND_NONE;
adamdunkels2bd076e2004-09-03 08:11:09 +0000379 tcp_markconn(uip_conn, NULL);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000380 SOCKET_CLOSE(&s->s);
adamdunkels2bd076e2004-09-03 08:11:09 +0000381 ek_post(EK_PROC_ID(EK_CURRENT()), EK_EVENT_REQUEST_EXIT, NULL);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000382 PT_EXIT(&s->pt);
383 break;
384 default:
385 break;
386 }
387 }
388
389 PT_END(&s->pt);
390}
391/*---------------------------------------------------------------------------*/
392void
393ircc_appcall(void *s)
394{
395 if(uip_closed() || uip_aborted() || uip_timedout()) {
396 ircc_closed(s);
397 } else if(uip_connected()) {
398 ircc_connected(s);
399 PT_INIT(&((struct ircc_state *)s)->pt);
400 memset(((struct ircc_state *)s)->channel, 0,
401 sizeof(((struct ircc_state *)s)->channel));
402 ((struct ircc_state *)s)->command = COMMAND_NONE;
403 handle_connection(s);
adamdunkels2bd076e2004-09-03 08:11:09 +0000404 } else if(s != NULL) {
adamdunkels5a2df1c2004-09-01 19:11:42 +0000405 handle_connection(s);
406 }
407}
408/*---------------------------------------------------------------------------*/
409struct ircc_state *
410ircc_connect(struct ircc_state *s, char *servername, u16_t *ipaddr,
411 char *nick)
412{
413 s->conn = tcp_connect(ipaddr, HTONS(PORT), s);
414 if(s->conn == NULL) {
415 return NULL;
416 }
adamdunkels8d8b7452004-09-09 21:05:56 +0000417 uip_set_mss(s->conn, 120);
adamdunkels5a2df1c2004-09-01 19:11:42 +0000418 s->server = servername;
419 s->nick = nick;
420 return s;
421}
422/*---------------------------------------------------------------------------*/
423void
424ircc_list(struct ircc_state *s)
425{
426 s->command = COMMAND_LIST;
427}
428/*---------------------------------------------------------------------------*/
429void
430ircc_join(struct ircc_state *s, char *channel)
431{
432 strncpy(s->channel, channel, sizeof(s->channel));
433 s->command = COMMAND_JOIN;
434}
435/*---------------------------------------------------------------------------*/
436void
437ircc_part(struct ircc_state *s)
438{
439 s->command = COMMAND_PART;
440}
441/*---------------------------------------------------------------------------*/
442void
adamdunkels2bd076e2004-09-03 08:11:09 +0000443ircc_quit(struct ircc_state *s)
444{
445 s->command = COMMAND_QUIT;
446}
447/*---------------------------------------------------------------------------*/
448void
adamdunkels5a2df1c2004-09-01 19:11:42 +0000449ircc_msg(struct ircc_state *s, char *msg)
450{
451 s->msg = msg;
452 s->command = COMMAND_MSG;
453}
454/*---------------------------------------------------------------------------*/
adamdunkels8d8b7452004-09-09 21:05:56 +0000455void
456ircc_actionmsg(struct ircc_state *s, char *msg)
457{
458 s->msg = msg;
459 s->command = COMMAND_ACTIONMSG;
460}
461/*---------------------------------------------------------------------------*/