20 /* |
20 /* |
21 * PING <server1> [ <server2> ] |
21 * PING <server1> [ <server2> ] |
22 * |
22 * |
23 * Send a 'PONG <server1>` reply right away. |
23 * Send a 'PONG <server1>` reply right away. |
24 */ |
24 */ |
25 static void on_PING (struct irc_conn *conn, const struct irc_line *line) |
25 static void on_PING (struct irc_conn *conn, const struct irc_line *line, void *arg) |
26 { |
26 { |
27 // just reply |
27 // just reply |
28 irc_conn_PONG(conn, line->args[0]); |
28 irc_conn_PONG(conn, line->args[0]); |
29 } |
29 } |
30 |
30 |
31 /* |
31 /* |
32 * Our command handlers |
32 * Our command handlers |
33 */ |
33 */ |
34 struct irc_cmd_handler { |
34 struct irc_cmd_handler _cmd_handlers[] = { |
35 /* The command name */ |
|
36 const char *command; |
|
37 |
|
38 /* The handler function */ |
|
39 void (*func) (struct irc_conn *conn, const struct irc_line *line); |
|
40 |
|
41 } _cmd_handlers[] = { |
|
42 { IRC_RPL_WELCOME, on_RPL_WELCOME }, |
35 { IRC_RPL_WELCOME, on_RPL_WELCOME }, |
43 { "PING", on_PING }, |
36 { "PING", on_PING }, |
44 { NULL, NULL, }, |
37 { NULL, NULL, }, |
45 }; |
38 }; |
46 |
39 |
|
40 /* |
|
41 * Incoming line handler |
|
42 */ |
47 void irc_conn_on_line (char *line_buf, void *arg) |
43 void irc_conn_on_line (char *line_buf, void *arg) |
48 { |
44 { |
49 struct irc_conn *conn = arg; |
45 struct irc_conn *conn = arg; |
50 struct irc_line line; |
46 struct irc_line line; |
|
47 struct irc_cmd_chain *chain; |
51 struct irc_cmd_handler *handler; |
48 struct irc_cmd_handler *handler; |
52 int err; |
49 int err; |
53 |
50 |
54 // log |
51 // log |
55 log_debug("%s", line_buf); |
52 log_debug("%s", line_buf); |
56 |
53 |
57 // parse |
54 // parse |
58 if ((err = irc_line_parse(&line, line_buf))) { |
55 if ((err = irc_line_parse(&line, line_buf))) { |
59 printf("!!! Invalid line: %s: %s\n", line_buf, error_name(err)); |
56 log_warn("invalid line: %s: %s\n", line_buf, error_name(err)); |
60 |
|
61 return; |
57 return; |
62 } |
58 } |
|
59 |
|
60 // run each handler chain |
|
61 STAILQ_FOREACH(chain, &conn->handlers, node) { |
|
62 // look up appropriate handler |
|
63 for (handler = chain->handlers; handler->command; handler++) { |
|
64 // the command is alpha-only, so normal case-insensitive cmp is fine |
|
65 if (strcasecmp(handler->command, line.command) == 0) { |
|
66 // invoke the func |
|
67 handler->func(conn, &line, chain->arg); |
63 |
68 |
64 // look up appropriate handler |
69 // ...only one per chain |
65 for (handler = _cmd_handlers; handler->command; handler++) { |
70 break; |
66 // the command is alpha-only, so normal case-insensitive cmp is fine |
71 } |
67 if (strcasecmp(handler->command, line.command) == 0) { |
|
68 // invoke the func |
|
69 handler->func(conn, &line); |
|
70 break; |
|
71 } |
72 } |
72 } |
73 } |
73 } |
74 } |
74 |
75 |
75 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err) |
76 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_config *config, struct error_info *err) |
77 struct irc_conn *conn; |
78 struct irc_conn *conn; |
78 |
79 |
79 // alloc new state struct |
80 // alloc new state struct |
80 if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL) |
81 if ((conn = calloc(1, sizeof(struct irc_conn))) == NULL) |
81 return SET_ERROR(err, ERR_CALLOC); |
82 return SET_ERROR(err, ERR_CALLOC); |
|
83 |
|
84 // initialize command handlers |
|
85 STAILQ_INIT(&conn->handlers); |
|
86 |
|
87 // add the core handlers |
|
88 if ((ERROR_CODE(err) = irc_conn_register_handler_chain(conn, _cmd_handlers, NULL))) |
|
89 return ERROR_CODE(err); |
82 |
90 |
83 // create the line_proto, with our on_line handler |
91 // create the line_proto, with our on_line handler |
84 if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err)) |
92 if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &irc_conn_on_line, conn, err)) |
85 return ERROR_CODE(err); |
93 return ERROR_CODE(err); |
86 |
94 |
92 return ERROR_CODE(err); |
100 return ERROR_CODE(err); |
93 |
101 |
94 // ok |
102 // ok |
95 *conn_ptr = conn; |
103 *conn_ptr = conn; |
96 |
104 |
|
105 return SUCCESS; |
|
106 } |
|
107 |
|
108 err_t irc_conn_register_handler_chain (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg) |
|
109 { |
|
110 struct irc_cmd_chain *item; |
|
111 |
|
112 // allocate the chain item |
|
113 if ((item = calloc(1, sizeof(*item))) == NULL) |
|
114 return ERR_CALLOC; |
|
115 |
|
116 // store |
|
117 item->handlers = handlers; |
|
118 item->arg = arg; |
|
119 |
|
120 // append |
|
121 STAILQ_INSERT_TAIL(&conn->handlers, item, node); |
|
122 |
|
123 // ok |
97 return SUCCESS; |
124 return SUCCESS; |
98 } |
125 } |
99 |
126 |
100 err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line) |
127 err_t irc_conn_send (struct irc_conn *conn, const struct irc_line *line) |
101 { |
128 { |