1 #include "irc_conn.h" |
1 #include "irc_conn.h" |
2 #include "irc_cmd.h" |
2 #include "irc_cmd.h" |
|
3 #include "irc_nm.h" |
3 #include "log.h" |
4 #include "log.h" |
4 |
5 |
5 #include <stdlib.h> |
6 #include <stdlib.h> |
6 #include <string.h> |
7 #include <string.h> |
7 |
8 |
8 /* |
9 /** |
9 * "Welcome to the Internet Relay Network <nick>!<user>@<host>" |
10 * @group Forward-declerations |
10 */ |
11 * @{ |
11 static void on_RPL_WELCOME (struct irc_conn *conn, const struct irc_line *line, void *arg) |
12 */ |
12 { |
13 |
13 (void) line; |
14 /** |
14 (void) arg; |
15 * Handle an event-based error on this IRC connection. |
|
16 */ |
|
17 static void irc_conn_handle_error (struct irc_conn *conn, struct error_info *err); |
|
18 |
|
19 /** |
|
20 * Update irc_conn.nickname |
|
21 */ |
|
22 static err_t irc_conn_set_nickname (struct irc_conn *conn, const char *nickname) |
|
23 { |
|
24 struct error_info err; |
|
25 |
|
26 // strdup |
|
27 if ((conn->nickname = strdup(nickname)) == NULL) { |
|
28 SET_ERROR(&err, ERR_STRDUP); |
|
29 |
|
30 // notify |
|
31 irc_conn_handle_error(conn, &err); |
|
32 |
|
33 return ERROR_CODE(&err); |
|
34 } |
|
35 |
|
36 // ok |
|
37 return SUCCESS; |
|
38 } |
|
39 |
|
40 // @} |
|
41 |
|
42 /** |
|
43 * 001 <nick> :Welcome to the Internet Relay Network <nick>!<user>@<host> |
|
44 */ |
|
45 static void on_RPL_WELCOME (const struct irc_line *line, void *arg) |
|
46 { |
|
47 struct irc_conn *conn = arg; |
15 |
48 |
16 // update state |
49 // update state |
17 conn->registering = false; |
50 conn->registering = false; |
18 conn->registered = true; |
51 conn->registered = true; |
|
52 |
|
53 // set our real nickname from the message target |
|
54 if (irc_conn_set_nickname(conn, line->args[0])) |
|
55 return; |
19 |
56 |
20 // trigger callback |
57 // trigger callback |
21 if (conn->callbacks.on_registered) |
58 if (conn->callbacks.on_registered) |
22 conn->callbacks.on_registered(conn, conn->cb_arg); |
59 conn->callbacks.on_registered(conn, conn->cb_arg); |
23 } |
60 } |
24 |
61 |
25 /* |
62 /** |
26 * PING <server1> [ <server2> ] |
63 * PING <server1> [ <server2> ] |
27 * |
64 * |
28 * Send a 'PONG <server1>` reply right away. |
65 * Send a 'PONG <server1>` reply right away. |
29 */ |
66 */ |
30 static void on_PING (struct irc_conn *conn, const struct irc_line *line, void *arg) |
67 static void on_PING (const struct irc_line *line, void *arg) |
31 { |
68 { |
32 (void) arg; |
69 struct irc_conn *conn = arg; |
33 |
70 |
34 // just reply |
71 // just reply |
35 irc_conn_PONG(conn, line->args[0]); |
72 irc_conn_PONG(conn, line->args[0]); |
36 } |
73 } |
37 |
74 |
38 /* |
75 /** |
|
76 * NICK <nickname> |
|
77 * |
|
78 * If the prefix is us, then update our nickname |
|
79 */ |
|
80 static void on_NICK (const struct irc_line *line, void *arg) |
|
81 { |
|
82 struct irc_conn *conn = arg; |
|
83 char nickname[IRC_NICK_MAX]; |
|
84 |
|
85 // parse nickname, ignoring errors |
|
86 if (irc_prefix_parse_nick(line->prefix, nickname)) { |
|
87 log_warn("invalid prefix: %s", line->prefix); |
|
88 return; |
|
89 } |
|
90 |
|
91 // ignore if it's not us |
|
92 if (irc_cmp_nick(nickname, conn->nickname)) |
|
93 return; |
|
94 |
|
95 // update our nickname |
|
96 irc_conn_set_nickname(conn, nickname); |
|
97 } |
|
98 |
|
99 /** |
39 * Our command handlers |
100 * Our command handlers |
40 */ |
101 */ |
41 struct irc_cmd_handler _cmd_handlers[] = { |
102 static struct irc_cmd_handler _cmd_handlers[] = { |
42 { IRC_RPL_WELCOME, on_RPL_WELCOME }, |
103 { IRC_RPL_WELCOME, &on_RPL_WELCOME }, |
43 { "PING", on_PING }, |
104 { "PING", &on_PING }, |
44 { NULL, NULL, }, |
105 { "NICK", &on_NICK }, |
|
106 { NULL, NULL, }, |
45 }; |
107 }; |
46 |
108 |
47 /** |
109 /** |
48 * Incoming line handler |
110 * Incoming line handler |
49 */ |
111 */ |
50 void irc_conn_on_line (char *line_buf, void *arg) |
112 void irc_conn_on_line (char *line_buf, void *arg) |
51 { |
113 { |
52 struct irc_conn *conn = arg; |
114 struct irc_conn *conn = arg; |
53 struct irc_line line; |
115 struct irc_line line; |
54 struct irc_cmd_chain *chain; |
|
55 struct irc_cmd_handler *handler; |
|
56 int err; |
116 int err; |
57 |
117 |
58 // log |
118 // log |
59 log_debug("%s", line_buf); |
119 log_debug("%s", line_buf); |
60 |
120 |
61 // parse |
121 // parse |
62 if ((err = irc_line_parse(&line, line_buf))) { |
122 if ((err = irc_line_parse(&line, line_buf))) { |
63 log_warn("invalid line: %s: %s\n", line_buf, error_name(err)); |
123 log_warn("invalid line: %s: %s\n", line_buf, error_name(err)); |
64 return; |
124 return; |
65 } |
125 } |
66 |
126 |
67 // run each handler chain |
127 // invoke command handlers |
68 STAILQ_FOREACH(chain, &conn->handlers, node) { |
128 irc_cmd_invoke(&conn->handlers, &line); |
69 // look up appropriate handler |
|
70 for (handler = chain->handlers; handler->command; handler++) { |
|
71 // the command is alpha-only, so normal case-insensitive cmp is fine |
|
72 if (strcasecmp(handler->command, line.command) == 0) { |
|
73 // invoke the func |
|
74 handler->func(conn, &line, chain->arg); |
|
75 |
|
76 // ...only one per chain |
|
77 break; |
|
78 } |
|
79 } |
|
80 } |
|
81 } |
129 } |
82 |
130 |
83 /** |
131 /** |
84 * Transport failed |
132 * Transport failed |
85 */ |
133 */ |
87 { |
135 { |
88 struct irc_conn *conn = arg; |
136 struct irc_conn *conn = arg; |
89 |
137 |
90 // log |
138 // log |
91 log_err_info(err, "line_proto error"); |
139 log_err_info(err, "line_proto error"); |
92 |
140 |
93 // XXX: notify user |
141 // 'handle' |
|
142 irc_conn_handle_error(conn, err); |
94 } |
143 } |
95 |
144 |
96 static struct line_proto_callbacks _lp_callbacks = { |
145 static struct line_proto_callbacks _lp_callbacks = { |
97 .on_line = &irc_conn_on_line, |
146 .on_line = &irc_conn_on_line, |
98 .on_error = &irc_conn_on_error, |
147 .on_error = &irc_conn_on_error, |
99 }; |
148 }; |
100 |
149 |
|
150 static void irc_conn_handle_error (struct irc_conn *conn, struct error_info *err) |
|
151 { |
|
152 // XXX: notify user callback |
|
153 } |
|
154 |
101 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_callbacks *callbacks, |
155 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_callbacks *callbacks, |
102 void *cb_arg, struct error_info *err) |
156 void *cb_arg, struct error_info *err) |
103 { |
157 { |
104 struct irc_conn *conn; |
158 struct irc_conn *conn; |
105 |
159 |
110 // init state |
164 // init state |
111 conn->callbacks = *callbacks; |
165 conn->callbacks = *callbacks; |
112 conn->cb_arg = cb_arg; |
166 conn->cb_arg = cb_arg; |
113 |
167 |
114 // initialize command handlers |
168 // initialize command handlers |
115 STAILQ_INIT(&conn->handlers); |
169 irc_cmd_init(&conn->handlers); |
116 |
170 |
117 // add the core handlers |
171 // add the core handlers |
118 if ((ERROR_CODE(err) = irc_conn_register_handler_chain(conn, _cmd_handlers, NULL))) |
172 if ((ERROR_CODE(err) = irc_conn_add_cmd_handlers(conn, _cmd_handlers, conn))) |
119 goto error; |
173 goto error; |
120 |
174 |
121 // create the line_proto, with our on_line handler |
175 // create the line_proto, with our on_line handler |
122 if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &_lp_callbacks, conn, err)) |
176 if (line_proto_create(&conn->lp, sock, IRC_LINE_MAX * 1.5, &_lp_callbacks, conn, err)) |
123 goto error; |
177 goto error; |
134 return ERROR_CODE(err); |
188 return ERROR_CODE(err); |
135 } |
189 } |
136 |
190 |
137 void irc_conn_destroy (struct irc_conn *conn) |
191 void irc_conn_destroy (struct irc_conn *conn) |
138 { |
192 { |
139 struct irc_cmd_chain *next = STAILQ_FIRST(&conn->handlers); |
|
140 |
|
141 // release the line_proto |
193 // release the line_proto |
142 if (conn->lp) |
194 if (conn->lp) |
143 line_proto_release(conn->lp); |
195 line_proto_release(conn->lp); |
144 |
196 |
145 // clean up any handler chains |
197 // free the command handlers |
146 while (next) { |
198 irc_cmd_free(&conn->handlers); |
147 struct irc_cmd_chain *node = next; |
|
148 |
|
149 // update next |
|
150 next = STAILQ_NEXT(node, node); |
|
151 |
|
152 // free |
|
153 free(node); |
|
154 } |
|
155 |
199 |
156 // free the irc_conn itself |
200 // free the irc_conn itself |
157 free(conn); |
201 free(conn); |
158 } |
202 } |
159 |
203 |
160 err_t irc_conn_register_handler_chain (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg) |
204 err_t irc_conn_add_cmd_handlers (struct irc_conn *conn, struct irc_cmd_handler *handlers, void *arg) |
161 { |
205 { |
162 struct irc_cmd_chain *item; |
206 // use the irc_cmd stuff |
163 |
207 return irc_cmd_add(&conn->handlers, handlers, arg); |
164 // allocate the chain item |
|
165 if ((item = calloc(1, sizeof(*item))) == NULL) |
|
166 return ERR_CALLOC; |
|
167 |
|
168 // store |
|
169 item->handlers = handlers; |
|
170 item->arg = arg; |
|
171 |
|
172 // append |
|
173 STAILQ_INSERT_TAIL(&conn->handlers, item, node); |
|
174 |
|
175 // ok |
|
176 return SUCCESS; |
|
177 } |
208 } |
178 |
209 |
179 err_t irc_conn_register (struct irc_conn *conn, const struct irc_conn_register_info *info) |
210 err_t irc_conn_register (struct irc_conn *conn, const struct irc_conn_register_info *info) |
180 { |
211 { |
181 err_t err; |
212 err_t err; |