]>
Commit | Line | Data |
---|---|---|
f1b54f23 DB |
1 | #include "definitions.h" |
2 | #include <assert.h> | |
3 | #include <ctype.h> | |
4 | static irc_callbacks_t irc_callbacks; | |
5 | static SCM irc_error_symbol; | |
6 | static scm_t_bits scm_t_irc_session_tag; | |
7 | ||
8 | void | |
9 | scm_throw_from_irc_session (irc_session_t * session) | |
10 | { | |
11 | int errno = irc_errno (session); | |
12 | const char *errmsg = irc_strerror (errno); | |
13 | SCM scm_errmsg = scm_from_locale_string (errmsg); | |
14 | scm_throw (irc_error_symbol, scm_list_1 (scm_errmsg)); | |
15 | } | |
16 | ||
17 | irc_session_t* | |
18 | scm_to_irc_session(SCM scm_session) | |
19 | { | |
20 | scm_assert_smob_type (scm_t_irc_session_tag, scm_session); | |
21 | struct scm_t_irc_session *scm_t_session = SCM_SMOB_DATA(scm_session); | |
22 | assert(scm_t_session); | |
23 | return scm_t_session->session; | |
24 | } | |
25 | ||
26 | char* | |
27 | guarded_scm_to_ascii_string (SCM string_or_false) | |
28 | { | |
29 | if (scm_is_false (string_or_false)) | |
30 | return NULL; | |
31 | ||
32 | char *str = scm_to_locale_string (string_or_false); | |
33 | scm_dynwind_free (str); | |
34 | return str; | |
35 | } | |
36 | ||
37 | static inline SCM | |
38 | scm_from_string_array (const char **args, unsigned int count) | |
39 | { | |
40 | SCM result = SCM_EOL; | |
41 | for (unsigned int index = 0; index != count; ++index) | |
42 | { | |
43 | SCM current_parameter = scm_from_locale_string (args[index]); | |
44 | SCM current_parameter_list = scm_list_1 (current_parameter); | |
45 | ||
46 | result = scm_append (scm_list_2 (current_parameter_list, result)); | |
47 | } | |
48 | return scm_reverse(result); | |
49 | } | |
50 | ||
51 | static void | |
52 | generic_event_handler (irc_session_t * sesion, const char *event, | |
53 | const char *origin, const char **params, | |
54 | unsigned int count) | |
55 | { | |
56 | struct scm_t_irc_session *scm_irc_session = irc_get_ctx (sesion); | |
57 | SCM scm_params = scm_from_string_array (params, count); | |
58 | ||
59 | scm_call_4 (scm_irc_session->event_dispatcher, scm_irc_session->closure, | |
60 | scm_from_locale_string (event), scm_from_locale_string (origin), | |
61 | scm_params); | |
62 | } | |
63 | ||
64 | SCM_DEFINE (scm_create_irc_session, | |
65 | "irc-create-session", 3, 0, 0, | |
66 | (SCM closure, SCM event_dispatcher, SCM numeric_dispatcher), | |
67 | "Create irc session with callback functions specified by alist. This is" | |
68 | "low-level api you should not use directly in user-level scheme code.") | |
69 | { | |
70 | struct scm_t_irc_session *scm_irc_session; | |
71 | irc_session_t *irc_session = irc_create_session (&irc_callbacks); | |
72 | scm_irc_session = | |
73 | scm_gc_malloc (sizeof (struct scm_t_irc_session), "irc-session"); | |
74 | irc_set_ctx (irc_session, scm_irc_session); | |
75 | ||
76 | scm_irc_session->closure = closure; | |
77 | scm_irc_session->event_dispatcher = event_dispatcher; | |
78 | scm_irc_session->numeric_dispatcher = numeric_dispatcher; | |
79 | scm_irc_session->session = irc_session; | |
80 | ||
81 | return scm_new_smob (scm_t_irc_session_tag, (scm_t_bits) scm_irc_session); | |
82 | } | |
83 | ||
84 | SCM_DEFINE (scm_irc_connect, "irc-connect", 8, 0, 0, | |
85 | (SCM scm_session, SCM scm_server, SCM scm_port, | |
86 | SCM scm_nick, SCM scm_server_pass, SCM scm_username, | |
87 | SCM scm_realname, SCM scm_use_ipv6_p), | |
88 | "This function prepares and initiates a connection to the IRC" | |
89 | "server. The connection is done asynchronously (see" | |
90 | "event_connect), so the success return value means that" | |
91 | "connection was initiated successfully.") | |
92 | { | |
93 | irc_session_t *session = scm_to_irc_session(scm_session); | |
94 | scm_dynwind_begin (0); | |
95 | char *server = guarded_scm_to_ascii_string (scm_server); | |
96 | char *nick = guarded_scm_to_ascii_string (scm_nick); | |
97 | char *server_pass = guarded_scm_to_ascii_string (scm_server_pass); | |
98 | char *username = guarded_scm_to_ascii_string (scm_username); | |
99 | char *realname = guarded_scm_to_ascii_string (scm_realname); | |
100 | unsigned short int port = scm_to_uint16 (scm_port); | |
101 | int (*connect_fn) (irc_session_t *, const char *, unsigned short, | |
102 | const char *, const char *, const char *, const char *) | |
103 | = scm_to_bool (scm_use_ipv6_p) ? irc_connect6 : irc_connect; | |
104 | int error = | |
105 | (*connect_fn) (session, server, port, server_pass, | |
106 | nick, username, realname); | |
107 | if (error) | |
108 | scm_throw_from_irc_session (session); | |
109 | ||
110 | scm_dynwind_end (); | |
111 | scm_remember_upto_here_1 (scm_session); | |
112 | return SCM_UNSPECIFIED; | |
113 | } | |
114 | ||
115 | SCM_DEFINE (scm_irc_run, "irc-run", 1, 0, 0, | |
116 | (SCM scm_session), | |
117 | "This function goes into the loop, processing the IRC events, and" | |
118 | "calling appropriate callbacks. This function will not return until" | |
119 | "the server connection is terminated – either by server, or by calling" | |
120 | "irc_cmd_quit. This function should be used, if you don’t need" | |
121 | "asynchronous request processing (i.e. your bot just reacts on the" | |
122 | "events, and doesn’t generate it asynchronously). Even in last case," | |
123 | "you still can call irc_run, and start the asynchronous thread in" | |
124 | "event_connect handler.") | |
125 | { | |
126 | scm_assert_smob_type (scm_t_irc_session_tag, scm_session); | |
127 | struct scm_t_irc_session *c_scm_session = SCM_SMOB_DATA (scm_session); | |
128 | irc_run (c_scm_session->session); | |
129 | /* | |
130 | * Error is not checked due bug in underlying library. | |
131 | */ | |
132 | scm_remember_upto_here_1 (scm_session); | |
133 | return SCM_UNSPECIFIED; | |
134 | } | |
135 | ||
136 | static SCM | |
137 | scm_mark_irc_session (SCM s) | |
138 | { | |
139 | struct scm_t_irc_session *scm_session = SCM_SMOB_DATA(s); | |
140 | ||
141 | scm_gc_mark (scm_session->event_dispatcher); | |
142 | scm_gc_mark (scm_session->numeric_dispatcher); | |
143 | return scm_session->closure; | |
144 | } | |
145 | ||
146 | static size_t | |
147 | scm_free_irc_session (SCM s) | |
148 | { | |
149 | struct scm_t_irc_session *scm_session = SCM_SMOB_DATA(s); | |
150 | if (scm_session->session) | |
151 | { | |
152 | irc_disconnect(scm_session->session); | |
153 | irc_destroy_session (scm_session->session); | |
154 | } | |
155 | scm_session->session = NULL; | |
156 | return 0; | |
157 | } | |
158 | ||
159 | SCM_DEFINE (scm_irc_disconnect, "irc-disconnect", 1, 0, 0, | |
160 | (SCM s), "Rude disconnect.") | |
161 | { | |
162 | irc_session_t *session = scm_to_irc_session(s); | |
163 | irc_disconnect(session); | |
164 | return SCM_UNSPECIFIED; | |
165 | } | |
166 | ||
167 | ||
168 | static inline void | |
169 | setup_generic_event_handler (irc_callbacks_t * cb) | |
170 | { | |
171 | cb->event_connect | |
172 | = cb->event_nick | |
173 | = cb->event_quit | |
174 | = cb->event_join | |
175 | = cb->event_part | |
176 | = cb->event_mode | |
177 | = cb->event_umode | |
178 | = cb->event_topic | |
179 | = cb->event_kick | |
180 | = cb->event_channel | |
181 | = cb->event_privmsg | |
182 | = cb->event_notice | |
183 | = cb->event_channel_notice | |
184 | = cb->event_invite = generic_event_handler; | |
185 | } | |
186 | ||
187 | #include "cmd.c" | |
188 | #include "misc.c" | |
189 | void | |
190 | scm_init_im_irc () | |
191 | { | |
192 | irc_error_symbol = scm_from_locale_symbol ("irc-error"); | |
193 | setup_generic_event_handler (&irc_callbacks); | |
194 | scm_t_irc_session_tag = | |
195 | scm_make_smob_type ("irc-session", sizeof (struct scm_t_irc_session)); | |
196 | scm_set_smob_mark (scm_t_irc_session_tag, scm_mark_irc_session); | |
197 | scm_set_smob_free (scm_t_irc_session_tag, scm_free_irc_session); | |
198 | ||
199 | #ifndef SCM_MAGIC_SNARFER | |
200 | #include "init.x" | |
201 | #endif | |
202 | } |