Mercurial > pidgin.yaz
comparison src/protocols/msn/switchboard.c @ 5309:e2e53316a21d
[gaim-migrate @ 5681]
Announcing the new MSN prpl! It probably has some bugs, and for the time
being, there is no file transfer. That's good though, because the current
MSN file transfer is a little broken. I've had many corrupted files. I'll
commit new file transfer code when it's written.
I want this heavily tested before 0.63! If you use MSN, please talk to
people on it. Let me know of any oddities, crashes, bugs, whatever. I'll
fix things as I find them.
committer: Tailor Script <tailor@pidgin.im>
author | Christian Hammond <chipx86@chipx86.com> |
---|---|
date | Tue, 06 May 2003 02:06:56 +0000 |
parents | abe4d103e300 |
children | d5690ed70085 |
comparison
equal
deleted
inserted
replaced
5308:6aa785e55d0f | 5309:e2e53316a21d |
---|---|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 * GNU General Public License for more details. | 16 * GNU General Public License for more details. |
17 * | 17 * |
18 * You should have received a copy of the GNU General Public License | 18 * You should have received a copy of the GNU General Public License |
19 * along with this program; if not, write to the Free Software | 19 * along with this program; if not, write to the Free Software |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 * | |
22 */ | 21 */ |
23 #include "msn.h" | 22 #include "msn.h" |
24 | 23 #include "switchboard.h" |
25 #ifdef _WIN32 | 24 #include "utils.h" |
26 #include "win32dep.h" | 25 |
27 #endif | 26 static GHashTable *switchboard_commands = NULL; |
28 | 27 static GHashTable *switchboard_msg_types = NULL; |
29 G_MODULE_IMPORT GSList *connections; | 28 |
30 | 29 |
31 static char * | 30 /************************************************************************** |
32 msn_parse_format(char *mime) | 31 * Catch-all commands |
33 { | 32 **************************************************************************/ |
34 char *cur; | 33 static gboolean |
35 GString *ret = g_string_new(NULL); | 34 __blank_cmd(MsnServConn *servconn, const char *command, const char **params, |
36 guint colorbuf; | 35 size_t param_count) |
37 char *colors = (char *)(&colorbuf); | 36 { |
38 | 37 return TRUE; |
39 | 38 } |
40 cur = strstr(mime, "FN="); | 39 |
41 if (cur && (*(cur = cur + 3) != ';')) { | 40 static gboolean |
42 ret = g_string_append(ret, "<FONT FACE=\""); | 41 __unknown_cmd(MsnServConn *servconn, const char *command, const char **params, |
43 while (*cur && *cur != ';') { | 42 size_t param_count) |
44 ret = g_string_append_c(ret, *cur); | 43 { |
45 cur++; | 44 gaim_debug(GAIM_DEBUG_ERROR, "msg", |
45 "Handled switchboard message: %s\n", command); | |
46 | |
47 return FALSE; | |
48 } | |
49 | |
50 /************************************************************************** | |
51 * Switchboard Commands | |
52 **************************************************************************/ | |
53 static gboolean | |
54 __ans_cmd(MsnServConn *servconn, const char *command, const char **params, | |
55 size_t param_count) | |
56 { | |
57 struct gaim_connection *gc = servconn->session->account->gc; | |
58 MsnSwitchBoard *swboard = servconn->data; | |
59 | |
60 if (swboard->chat != NULL) | |
61 gaim_chat_add_user(GAIM_CHAT(swboard->chat), gc->username, NULL); | |
62 | |
63 return TRUE; | |
64 } | |
65 | |
66 static gboolean | |
67 __bye_cmd(MsnServConn *servconn, const char *command, const char **params, | |
68 size_t param_count) | |
69 { | |
70 struct gaim_connection *gc = servconn->session->account->gc; | |
71 MsnSwitchBoard *swboard = servconn->data; | |
72 const char *user = params[0]; | |
73 | |
74 if (swboard->chat != NULL) | |
75 gaim_chat_remove_user(GAIM_CHAT(swboard->chat), user, NULL); | |
76 else { | |
77 const char *username; | |
78 struct gaim_conversation *conv; | |
79 struct buddy *b; | |
80 char buf[MSN_BUF_LEN]; | |
81 | |
82 if ((b = gaim_find_buddy(gc->account, user)) != NULL) | |
83 username = gaim_get_buddy_alias(b); | |
84 else | |
85 username = user; | |
86 | |
87 g_snprintf(buf, sizeof(buf), | |
88 _("%s has closed the conversation window."), username); | |
89 | |
90 if ((conv = gaim_find_conversation(user)) != NULL) | |
91 gaim_conversation_write(conv, NULL, buf, -1, WFLAG_SYSTEM, | |
92 time(NULL)); | |
93 | |
94 msn_switchboard_destroy(swboard); | |
95 | |
96 return FALSE; | |
97 } | |
98 | |
99 return TRUE; | |
100 } | |
101 | |
102 static gboolean | |
103 __iro_cmd(MsnServConn *servconn, const char *command, const char **params, | |
104 size_t param_count) | |
105 { | |
106 struct gaim_connection *gc = servconn->session->account->gc; | |
107 MsnSwitchBoard *swboard = servconn->data; | |
108 | |
109 swboard->total_users = atoi(params[2]); | |
110 | |
111 if (swboard->total_users > 1) { | |
112 if (swboard->chat == NULL) | |
113 swboard->chat = serv_got_joined_chat(gc, ++swboard->chat_id, | |
114 "MSN Chat"); | |
115 | |
116 gaim_chat_add_user(GAIM_CHAT(swboard->chat), params[3], NULL); | |
117 } | |
118 | |
119 if (swboard->chat != NULL) | |
120 gaim_chat_add_user(GAIM_CHAT(swboard->chat), gc->username, NULL); | |
121 | |
122 return TRUE; | |
123 } | |
124 | |
125 static gboolean | |
126 __joi_cmd(MsnServConn *servconn, const char *command, const char **params, | |
127 size_t param_count) | |
128 { | |
129 struct gaim_connection *gc = servconn->session->account->gc; | |
130 MsnSwitchBoard *swboard = servconn->data; | |
131 const char *passport; | |
132 | |
133 passport = params[0]; | |
134 | |
135 if (swboard->total_users == 1) { | |
136 swboard->chat = serv_got_joined_chat(gc, ++swboard->chat_id, | |
137 "MSN Chat"); | |
138 gaim_chat_add_user(GAIM_CHAT(swboard->chat), | |
139 msn_user_get_passport(swboard->user), NULL); | |
140 gaim_chat_add_user(GAIM_CHAT(swboard->chat), gc->username, NULL); | |
141 | |
142 msn_user_unref(swboard->user); | |
143 } | |
144 | |
145 if (swboard->chat != NULL) | |
146 gaim_chat_add_user(GAIM_CHAT(swboard->chat), passport, NULL); | |
147 | |
148 swboard->total_users++; | |
149 | |
150 while (servconn->txqueue) { | |
151 char *buf = servconn->txqueue->data; | |
152 | |
153 servconn->txqueue = g_slist_remove(servconn->txqueue, buf); | |
154 | |
155 if (msn_servconn_write(swboard->servconn, buf, strlen(buf)) < 0) { | |
156 msn_switchboard_destroy(swboard); | |
157 | |
158 return FALSE; | |
46 } | 159 } |
47 ret = g_string_append(ret, "\">"); | 160 } |
48 } | 161 |
49 | 162 return TRUE; |
50 cur = strstr(mime, "EF="); | 163 } |
51 if (cur && (*(cur = cur + 3) != ';')) { | 164 |
52 while (*cur && *cur != ';') { | 165 static gboolean |
53 ret = g_string_append_c(ret, '<'); | 166 __msg_cmd(MsnServConn *servconn, const char *command, const char **params, |
54 ret = g_string_append_c(ret, *cur); | 167 size_t param_count) |
55 ret = g_string_append_c(ret, '>'); | 168 { |
56 cur++; | 169 gaim_debug(GAIM_DEBUG_INFO, "msn", "Found message. Parsing.\n"); |
170 | |
171 servconn->parsing_msg = TRUE; | |
172 servconn->msg_passport = g_strdup(params[0]); | |
173 servconn->msg_friendly = g_strdup(params[1]); | |
174 servconn->msg_len = atoi(params[2]); | |
175 | |
176 return TRUE; | |
177 } | |
178 | |
179 static gboolean | |
180 __nak_cmd(MsnServConn *servconn, const char *command, const char **params, | |
181 size_t param_count) | |
182 { | |
183 /* | |
184 * TODO: Investigate this, as it seems to occur frequently with | |
185 * the old prpl. | |
186 */ | |
187 do_error_dialog(_("An MSN message may not have been received."), | |
188 NULL, GAIM_ERROR); | |
189 | |
190 return TRUE; | |
191 } | |
192 | |
193 static gboolean | |
194 __out_cmd(MsnServConn *servconn, const char *command, const char **params, | |
195 size_t param_count) | |
196 { | |
197 struct gaim_connection *gc = servconn->session->account->gc; | |
198 MsnSwitchBoard *swboard = servconn->data; | |
199 | |
200 if (swboard->chat != NULL) | |
201 serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(swboard->chat))); | |
202 | |
203 msn_switchboard_destroy(swboard); | |
204 | |
205 return FALSE; | |
206 } | |
207 | |
208 static gboolean | |
209 __usr_cmd(MsnServConn *servconn, const char *command, const char **params, | |
210 size_t param_count) | |
211 { | |
212 MsnSwitchBoard *swboard = servconn->data; | |
213 | |
214 if (!msn_switchboard_send_command(swboard, "CAL", | |
215 msn_user_get_passport(swboard->user))) { | |
216 msn_switchboard_destroy(swboard); | |
217 | |
218 return FALSE; | |
219 } | |
220 | |
221 return TRUE; | |
222 } | |
223 | |
224 /************************************************************************** | |
225 * Message Types | |
226 **************************************************************************/ | |
227 static gboolean | |
228 __plain_msg(MsnServConn *servconn, const MsnMessage *msg) | |
229 { | |
230 struct gaim_connection *gc = servconn->session->account->gc; | |
231 MsnSwitchBoard *swboard = servconn->data; | |
232 char *body; | |
233 const char *value; | |
234 char *format; | |
235 int flags = 0; | |
236 | |
237 body = g_strdup(msn_message_get_body(msg)); | |
238 | |
239 if ((value = msn_message_get_attr(msg, "User-Agent")) != NULL) { | |
240 if (!g_ascii_strncasecmp(value, "Gaim", 4)) | |
241 flags |= IM_FLAG_GAIMUSER; | |
242 } | |
243 | |
244 if ((value = msn_message_get_attr(msg, "X-MMS-IM-Format")) != NULL) { | |
245 format = msn_parse_format(value); | |
246 | |
247 body = g_strdup_printf("%s%s", format, body); | |
248 | |
249 g_free(format); | |
250 } | |
251 | |
252 if (swboard->chat != NULL) | |
253 serv_got_chat_in(gc, gaim_chat_get_id(GAIM_CHAT(swboard->chat)), | |
254 servconn->msg_passport, flags, body, time(NULL)); | |
255 else | |
256 serv_got_im(gc, servconn->msg_passport, body, flags, time(NULL), -1); | |
257 | |
258 g_free(body); | |
259 | |
260 return TRUE; | |
261 } | |
262 | |
263 static gboolean | |
264 __control_msg(MsnServConn *servconn, const MsnMessage *msg) | |
265 { | |
266 struct gaim_connection *gc = servconn->session->account->gc; | |
267 MsnSwitchBoard *swboard = servconn->data; | |
268 const char *value; | |
269 | |
270 if (swboard->chat == NULL && | |
271 (value = msn_message_get_attr(msg, "TypingUser")) != NULL) { | |
272 | |
273 serv_got_typing(gc, servconn->msg_passport, MSN_TYPING_RECV_TIMEOUT, | |
274 TYPING); | |
275 } | |
276 | |
277 return TRUE; | |
278 } | |
279 | |
280 /************************************************************************** | |
281 * Connect stuff | |
282 **************************************************************************/ | |
283 static gboolean | |
284 __connect_cb(gpointer data, gint source, GaimInputCondition cond) | |
285 { | |
286 MsnServConn *servconn = data; | |
287 MsnSwitchBoard *swboard = servconn->data; | |
288 char outparams[MSN_BUF_LEN]; | |
289 | |
290 if (servconn->fd != source) | |
291 servconn->fd = source; | |
292 | |
293 swboard->in_use = TRUE; | |
294 | |
295 gaim_debug(GAIM_DEBUG_INFO, "msn", "Connecting to switchboard...\n"); | |
296 | |
297 if (msn_switchboard_is_invited(swboard)) { | |
298 g_snprintf(outparams, sizeof(outparams), "%s %s %s", | |
299 servconn->session->account->gc->username, | |
300 swboard->auth_key, swboard->session_id); | |
301 | |
302 if (!msn_switchboard_send_command(swboard, "ANS", outparams)) { | |
303 msn_switchboard_destroy(swboard); | |
304 | |
305 return FALSE; | |
57 } | 306 } |
58 } | 307 } |
59 | 308 else { |
60 cur = strstr(mime, "CO="); | 309 g_snprintf(outparams, sizeof(outparams), "%s %s", |
61 if (cur && (*(cur = cur + 3) != ';')) { | 310 servconn->session->account->gc->username, swboard->auth_key); |
62 if (sscanf (cur, "%x;", &colorbuf) == 1) { | 311 |
63 char tag[64]; | 312 if (!msn_switchboard_send_command(swboard, "USR", outparams)) { |
64 g_snprintf(tag, sizeof(tag), "<FONT COLOR=\"#%02hhx%02hhx%02hhx\">", colors[0], colors[1], colors[2]); | 313 msn_switchboard_destroy(swboard); |
65 ret = g_string_append(ret, tag); | 314 |
315 return FALSE; | |
66 } | 316 } |
67 } | 317 } |
68 | 318 |
69 cur = url_decode(ret->str); | 319 return TRUE; |
70 g_string_free(ret, TRUE); | |
71 return cur; | |
72 } | |
73 | |
74 static int | |
75 msn_process_switch(struct msn_switchboard *ms, char *buf) | |
76 { | |
77 struct gaim_connection *gc = ms->gc; | |
78 char sendbuf[MSN_BUF_LEN]; | |
79 static int id = 0; | |
80 | |
81 if (!g_ascii_strncasecmp(buf, "ACK", 3)) { | |
82 } else if (!g_ascii_strncasecmp(buf, "ANS", 3)) { | |
83 if (ms->chat) | |
84 gaim_chat_add_user(GAIM_CHAT(ms->chat), gc->username, NULL); | |
85 } else if (!g_ascii_strncasecmp(buf, "BYE", 3)) { | |
86 char *user, *tmp = buf; | |
87 GET_NEXT(tmp); | |
88 user = tmp; | |
89 | |
90 if (ms->chat) { | |
91 gaim_chat_remove_user(GAIM_CHAT(ms->chat), user, NULL); | |
92 } else { | |
93 char msgbuf[256]; | |
94 const char *username; | |
95 struct gaim_conversation *cnv; | |
96 struct buddy *b; | |
97 | |
98 if ((b = gaim_find_buddy(gc->account, user)) != NULL) | |
99 username = gaim_get_buddy_alias(b); | |
100 else | |
101 username = user; | |
102 | |
103 g_snprintf(msgbuf, sizeof(msgbuf), | |
104 _("%s has closed the conversation window"), username); | |
105 | |
106 if ((cnv = gaim_find_conversation(user))) | |
107 gaim_conversation_write(cnv, NULL, msgbuf, -1, | |
108 WFLAG_SYSTEM, time(NULL)); | |
109 | |
110 msn_kill_switch(ms); | |
111 return 0; | |
112 } | |
113 } else if (!g_ascii_strncasecmp(buf, "CAL", 3)) { | |
114 } else if (!g_ascii_strncasecmp(buf, "IRO", 3)) { | |
115 char *tot, *user, *tmp = buf; | |
116 | |
117 GET_NEXT(tmp); | |
118 GET_NEXT(tmp); | |
119 GET_NEXT(tmp); | |
120 tot = tmp; | |
121 GET_NEXT(tmp); | |
122 ms->total = atoi(tot); | |
123 user = tmp; | |
124 GET_NEXT(tmp); | |
125 | |
126 if (ms->total > 1) { | |
127 if (!ms->chat) | |
128 ms->chat = serv_got_joined_chat(gc, ++id, "MSN Chat"); | |
129 | |
130 gaim_chat_add_user(GAIM_CHAT(ms->chat), user, NULL); | |
131 } | |
132 } else if (!g_ascii_strncasecmp(buf, "JOI", 3)) { | |
133 char *user, *tmp = buf; | |
134 GET_NEXT(tmp); | |
135 user = tmp; | |
136 GET_NEXT(tmp); | |
137 | |
138 if (ms->total == 1) { | |
139 ms->chat = serv_got_joined_chat(gc, ++id, "MSN Chat"); | |
140 gaim_chat_add_user(GAIM_CHAT(ms->chat), ms->user, NULL); | |
141 gaim_chat_add_user(GAIM_CHAT(ms->chat), gc->username, NULL); | |
142 g_free(ms->user); | |
143 ms->user = NULL; | |
144 } | |
145 if (ms->chat) | |
146 gaim_chat_add_user(GAIM_CHAT(ms->chat), user, NULL); | |
147 ms->total++; | |
148 while (ms->txqueue) { | |
149 char *send = add_cr(ms->txqueue->data); | |
150 g_snprintf(sendbuf, sizeof(sendbuf), | |
151 "MSG %u N %d\r\n%s%s", ++ms->trId, | |
152 strlen(MIME_HEADER) + strlen(send), | |
153 MIME_HEADER, send); | |
154 | |
155 g_free(ms->txqueue->data); | |
156 ms->txqueue = g_slist_remove(ms->txqueue, ms->txqueue->data); | |
157 | |
158 if (msn_write(ms->fd, sendbuf, strlen(sendbuf)) < 0) { | |
159 msn_kill_switch(ms); | |
160 return 0; | |
161 } | |
162 } | |
163 } else if (!g_ascii_strncasecmp(buf, "MSG", 3)) { | |
164 char *user, *tmp = buf; | |
165 int length; | |
166 | |
167 GET_NEXT(tmp); | |
168 user = tmp; | |
169 | |
170 GET_NEXT(tmp); | |
171 | |
172 GET_NEXT(tmp); | |
173 length = atoi(tmp); | |
174 | |
175 ms->msg = TRUE; | |
176 ms->msguser = g_strdup(user); | |
177 ms->msglen = length; | |
178 } else if (!g_ascii_strncasecmp(buf, "NAK", 3)) { | |
179 do_error_dialog(_("An MSN message may not have been received."), NULL, GAIM_ERROR); | |
180 } else if (!g_ascii_strncasecmp(buf, "NLN", 3)) { | |
181 } else if (!g_ascii_strncasecmp(buf, "OUT", 3)) { | |
182 if (ms->chat) | |
183 serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(ms->chat))); | |
184 msn_kill_switch(ms); | |
185 return 0; | |
186 } else if (!g_ascii_strncasecmp(buf, "USR", 3)) { | |
187 /* good, we got USR, now we need to find out who we want to talk to */ | |
188 struct msn_switchboard *ms = msn_find_writable_switch(gc); | |
189 | |
190 if (!ms) | |
191 return 0; | |
192 | |
193 g_snprintf(sendbuf, sizeof(sendbuf), "CAL %u %s\r\n", | |
194 ++ms->trId, ms->user); | |
195 | |
196 if (msn_write(ms->fd, sendbuf, strlen(sendbuf)) < 0) { | |
197 msn_kill_switch(ms); | |
198 return 0; | |
199 } | |
200 } else if (isdigit(*buf)) { | |
201 handle_errcode(buf, TRUE); | |
202 | |
203 if (atoi(buf) == 217) | |
204 msn_kill_switch(ms); | |
205 | |
206 } else { | |
207 gaim_debug(GAIM_DEBUG_WARNING, "msn", "Unhandled message!\n"); | |
208 } | |
209 | |
210 return 1; | |
211 } | 320 } |
212 | 321 |
213 static void | 322 static void |
214 msn_process_switch_msg(struct msn_switchboard *ms, char *msg) | 323 __failed_read_cb(gpointer data, gint source, GaimInputCondition cond) |
215 { | 324 { |
216 char *content, *agent, *format; | 325 MsnServConn *servconn = data; |
217 char *message = NULL; | 326 |
218 int flags = 0; | 327 msn_switchboard_destroy(servconn->data); |
219 | 328 } |
220 agent = strstr(msg, "User-Agent: "); | 329 |
221 if (agent) { | 330 MsnSwitchBoard * |
222 if (!g_ascii_strncasecmp(agent, "User-Agent: Gaim", | 331 msn_switchboard_new(MsnSession *session) |
223 strlen("User-Agent: Gaim"))) | 332 { |
224 flags |= IM_FLAG_GAIMUSER; | 333 MsnSwitchBoard *swboard; |
225 } | 334 MsnServConn *servconn; |
226 | 335 |
227 format = strstr(msg, "X-MMS-IM-Format: "); | 336 g_return_val_if_fail(session != NULL, NULL); |
228 if (format) { | 337 |
229 format = msn_parse_format(format); | 338 swboard = g_new0(MsnSwitchBoard, 1); |
230 } else { | 339 |
231 format = NULL; | 340 swboard->servconn = servconn = msn_servconn_new(session); |
232 } | 341 msn_servconn_set_connect_cb(servconn, __connect_cb); |
233 | 342 msn_servconn_set_failed_read_cb(servconn, __failed_read_cb); |
234 content = strstr(msg, "Content-Type: "); | 343 |
235 if (!content) | 344 servconn->data = swboard; |
236 return; | 345 |
237 if (!g_ascii_strncasecmp(content, "Content-Type: text/x-msmsgscontrol\r\n", | 346 session->switches = g_list_append(session->switches, swboard); |
238 strlen( "Content-Type: text/x-msmsgscontrol\r\n"))) { | 347 |
239 if (strstr(content,"TypingUser: ") && !ms->chat) { | 348 if (switchboard_commands == NULL) { |
240 serv_got_typing(ms->gc, ms->msguser, | 349 /* Register the command callbacks. */ |
241 MSN_TYPING_RECV_TIMEOUT, TYPING); | 350 msn_servconn_register_command(servconn, "ACK", __blank_cmd); |
242 return; | 351 msn_servconn_register_command(servconn, "ANS", __ans_cmd); |
243 } | 352 msn_servconn_register_command(servconn, "BYE", __bye_cmd); |
244 | 353 msn_servconn_register_command(servconn, "CAL", __blank_cmd); |
245 } else if (!g_ascii_strncasecmp(content, "Content-Type: text/x-msmsgsinvite;", | 354 msn_servconn_register_command(servconn, "IRO", __iro_cmd); |
246 strlen("Content-Type: text/x-msmsgsinvite;"))) { | 355 msn_servconn_register_command(servconn, "JOI", __joi_cmd); |
247 | 356 msn_servconn_register_command(servconn, "MSG", __msg_cmd); |
248 /* | 357 msn_servconn_register_command(servconn, "NAK", __nak_cmd); |
249 * NOTE: Other things, such as voice communication, would go in | 358 msn_servconn_register_command(servconn, "NLN", __blank_cmd); |
250 * here too (since they send the same Content-Type). However, | 359 msn_servconn_register_command(servconn, "OUT", __out_cmd); |
251 * this is the best check for file transfer messages, so I'm | 360 msn_servconn_register_command(servconn, "USR", __usr_cmd); |
252 * calling msn_process_ft_invite_msg(). If anybody adds support | 361 msn_servconn_register_command(servconn, "_unknown_", __unknown_cmd); |
253 * for anything else that sends a text/x-msmsgsinvite, perhaps | 362 |
254 * this should be changed. For now, it stays. | 363 /* Register the message type callbacks. */ |
255 */ | 364 msn_servconn_register_msg_type(servconn, "text/plain", __plain_msg); |
256 msn_process_ft_msg(ms, content); | 365 msn_servconn_register_msg_type(servconn, "text/x-msmsgscontrol", |
257 | 366 __control_msg); |
258 } else if (!g_ascii_strncasecmp(content, "Content-Type: text/plain", | 367 |
259 strlen("Content-Type: text/plain"))) { | 368 /* Save these for future use. */ |
260 | 369 switchboard_commands = servconn->commands; |
261 char *skiphead = strstr(msg, "\r\n\r\n"); | 370 switchboard_msg_types = servconn->msg_types; |
262 | 371 } |
263 if (!skiphead || !skiphead[4]) { | 372 else { |
264 return; | 373 g_hash_table_destroy(servconn->commands); |
265 } | 374 g_hash_table_destroy(servconn->msg_types); |
266 | 375 |
267 skiphead += 4; | 376 servconn->commands = switchboard_commands; |
268 strip_linefeed(skiphead); | 377 servconn->msg_types = switchboard_msg_types; |
269 | 378 } |
270 if (format) { | 379 |
271 message = g_strdup_printf("%s%s", format, skiphead); | 380 return swboard; |
272 } else { | 381 } |
273 message = g_strdup(skiphead); | 382 |
274 } | 383 void |
275 | 384 msn_switchboard_destroy(MsnSwitchBoard *swboard) |
276 if (ms->chat) | 385 { |
277 serv_got_chat_in(ms->gc, gaim_chat_get_id(GAIM_CHAT(ms->chat)), | 386 MsnSession *session; |
278 ms->msguser, flags, message, time(NULL)); | 387 |
279 else | 388 g_return_if_fail(swboard != NULL); |
280 serv_got_im(ms->gc, ms->msguser, message, flags, time(NULL), -1); | 389 |
281 | 390 session = swboard->servconn->session; |
282 g_free(message); | 391 |
283 } | 392 if (swboard->servconn->connected) |
284 } | 393 msn_switchboard_disconnect(swboard); |
285 | 394 |
286 static void | 395 if (swboard->user != NULL) |
287 msn_switchboard_callback(gpointer data, gint source, GaimInputCondition cond) | 396 msn_user_unref(swboard->user); |
288 { | 397 |
289 struct msn_switchboard *ms = data; | 398 if (swboard->auth_key != NULL) |
399 g_free(swboard->auth_key); | |
400 | |
401 if (swboard->session_id != NULL) | |
402 g_free(swboard->session_id); | |
403 | |
404 session->switches = g_list_remove(session->switches, swboard); | |
405 | |
406 msn_servconn_destroy(swboard->servconn); | |
407 | |
408 g_free(swboard); | |
409 } | |
410 | |
411 void | |
412 msn_switchboard_set_user(MsnSwitchBoard *swboard, MsnUser *user) | |
413 { | |
414 g_return_if_fail(swboard != NULL); | |
415 | |
416 swboard->user = user; | |
417 | |
418 msn_user_ref(user); | |
419 } | |
420 | |
421 MsnUser * | |
422 msn_switchboard_get_user(const MsnSwitchBoard *swboard) | |
423 { | |
424 g_return_val_if_fail(swboard != NULL, NULL); | |
425 | |
426 return swboard->user; | |
427 } | |
428 | |
429 void | |
430 msn_switchboard_set_auth_key(MsnSwitchBoard *swboard, const char *key) | |
431 { | |
432 g_return_if_fail(swboard != NULL); | |
433 g_return_if_fail(key != NULL); | |
434 | |
435 swboard->auth_key = g_strdup(key); | |
436 } | |
437 | |
438 const char * | |
439 msn_switchboard_get_auth_key(const MsnSwitchBoard *swboard) | |
440 { | |
441 g_return_val_if_fail(swboard != NULL, NULL); | |
442 | |
443 return swboard->auth_key; | |
444 } | |
445 | |
446 void | |
447 msn_switchboard_set_session_id(MsnSwitchBoard *swboard, const char *id) | |
448 { | |
449 g_return_if_fail(swboard != NULL); | |
450 g_return_if_fail(id != NULL); | |
451 | |
452 if (swboard->session_id != NULL) | |
453 g_free(swboard->session_id); | |
454 | |
455 swboard->session_id = g_strdup(id); | |
456 } | |
457 | |
458 const char * | |
459 msn_switchboard_get_session_id(const MsnSwitchBoard *swboard) | |
460 { | |
461 g_return_val_if_fail(swboard != NULL, NULL); | |
462 | |
463 return swboard->session_id; | |
464 } | |
465 | |
466 void | |
467 msn_switchboard_set_invited(MsnSwitchBoard *swboard, gboolean invited) | |
468 { | |
469 g_return_if_fail(swboard != NULL); | |
470 | |
471 swboard->invited = invited; | |
472 } | |
473 | |
474 gboolean | |
475 msn_switchboard_is_invited(const MsnSwitchBoard *swboard) | |
476 { | |
477 g_return_val_if_fail(swboard != NULL, FALSE); | |
478 | |
479 return swboard->invited; | |
480 } | |
481 | |
482 gboolean | |
483 msn_switchboard_connect(MsnSwitchBoard *swboard, const char *server, int port) | |
484 { | |
485 g_return_val_if_fail(swboard != NULL, FALSE); | |
486 | |
487 msn_servconn_set_server(swboard->servconn, server, port); | |
488 | |
489 if (msn_servconn_connect(swboard->servconn)) | |
490 swboard->in_use = TRUE; | |
491 | |
492 return swboard->in_use; | |
493 } | |
494 | |
495 void | |
496 msn_switchboard_disconnect(MsnSwitchBoard *swboard) | |
497 { | |
498 g_return_if_fail(swboard != NULL); | |
499 g_return_if_fail(swboard->servconn->connected); | |
500 | |
501 msn_servconn_disconnect(swboard->servconn); | |
502 | |
503 swboard->in_use = FALSE; | |
504 } | |
505 | |
506 gboolean | |
507 msn_switchboard_send_msg(MsnSwitchBoard *swboard, MsnMessage *msg) | |
508 { | |
509 char *buf; | |
510 int ret; | |
511 | |
512 g_return_val_if_fail(swboard != NULL, FALSE); | |
513 g_return_val_if_fail(msg != NULL, FALSE); | |
514 | |
515 msn_message_set_transaction_id(msg, ++swboard->trId); | |
516 buf = msn_message_build_string(msg); | |
517 | |
518 if (swboard->servconn->txqueue != NULL || !swboard->in_use) { | |
519 gaim_debug(GAIM_DEBUG_INFO, "msn", "Appending message to queue.\n"); | |
520 | |
521 swboard->servconn->txqueue = | |
522 g_slist_append(swboard->servconn->txqueue, buf); | |
523 | |
524 return TRUE; | |
525 } | |
526 | |
527 ret = msn_servconn_write(swboard->servconn, buf, strlen(buf)); | |
528 | |
529 g_free(buf); | |
530 | |
531 return (ret > 0); | |
532 } | |
533 | |
534 gboolean | |
535 msn_switchboard_send_command(MsnSwitchBoard *swboard, const char *command, | |
536 const char *params) | |
537 { | |
290 char buf[MSN_BUF_LEN]; | 538 char buf[MSN_BUF_LEN]; |
291 int cont = 1; | 539 |
292 int len; | 540 g_return_val_if_fail(swboard != NULL, FALSE); |
293 | 541 g_return_val_if_fail(command != NULL, FALSE); |
294 ms->fd = source; | 542 |
295 len = read(ms->fd, buf, sizeof(buf)); | 543 if (params == NULL) |
296 if (len <= 0) { | 544 g_snprintf(buf, sizeof(buf), "%s %u\r\n", command, |
297 msn_kill_switch(ms); | 545 ++swboard->trId); |
298 return; | 546 else |
299 } | 547 g_snprintf(buf, sizeof(buf), "%s %u %s\r\n", |
300 | 548 command, ++swboard->trId, params); |
301 ms->rxqueue = g_realloc(ms->rxqueue, len + ms->rxlen); | 549 |
302 memcpy(ms->rxqueue + ms->rxlen, buf, len); | 550 return (msn_servconn_write(swboard->servconn, buf, strlen(buf)) > 0); |
303 ms->rxlen += len; | 551 } |
304 | |
305 while (cont) { | |
306 if (!ms->rxlen) | |
307 return; | |
308 | |
309 if (ms->msg) { | |
310 char *msg; | |
311 if (ms->msglen > ms->rxlen) | |
312 return; | |
313 msg = ms->rxqueue; | |
314 ms->rxlen -= ms->msglen; | |
315 if (ms->rxlen) { | |
316 ms->rxqueue = g_memdup(msg + ms->msglen, ms->rxlen); | |
317 } else { | |
318 ms->rxqueue = NULL; | |
319 msg = g_realloc(msg, ms->msglen + 1); | |
320 } | |
321 msg[ms->msglen] = 0; | |
322 ms->msglen = 0; | |
323 ms->msg = FALSE; | |
324 | |
325 msn_process_switch_msg(ms, msg); | |
326 | |
327 g_free(ms->msguser); | |
328 g_free(msg); | |
329 } else { | |
330 char *end = ms->rxqueue; | |
331 int cmdlen; | |
332 char *cmd; | |
333 int i = 0; | |
334 | |
335 while (i + 1 < ms->rxlen) { | |
336 if (*end == '\r' && end[1] == '\n') | |
337 break; | |
338 end++; i++; | |
339 } | |
340 if (i + 1 == ms->rxlen) | |
341 return; | |
342 | |
343 cmdlen = end - ms->rxqueue + 2; | |
344 cmd = ms->rxqueue; | |
345 ms->rxlen -= cmdlen; | |
346 if (ms->rxlen) { | |
347 ms->rxqueue = g_memdup(cmd + cmdlen, ms->rxlen); | |
348 } else { | |
349 ms->rxqueue = NULL; | |
350 cmd = g_realloc(cmd, cmdlen + 1); | |
351 } | |
352 cmd[cmdlen] = 0; | |
353 | |
354 gaim_debug(GAIM_DEBUG_MISC, "msn", "S: %s", cmd); | |
355 g_strchomp(cmd); | |
356 cont = msn_process_switch(ms, cmd); | |
357 | |
358 g_free(cmd); | |
359 } | |
360 } | |
361 } | |
362 | |
363 void | |
364 msn_rng_connect(gpointer data, gint source, GaimInputCondition cond) | |
365 { | |
366 struct msn_switchboard *ms = data; | |
367 struct gaim_connection *gc = ms->gc; | |
368 struct msn_data *md; | |
369 char buf[MSN_BUF_LEN]; | |
370 | |
371 if (source == -1 || !g_slist_find(connections, gc)) { | |
372 close(source); | |
373 g_free(ms->sessid); | |
374 g_free(ms->auth); | |
375 g_free(ms); | |
376 return; | |
377 } | |
378 | |
379 md = gc->proto_data; | |
380 | |
381 if (ms->fd != source) | |
382 ms->fd = source; | |
383 | |
384 g_snprintf(buf, sizeof(buf), "ANS %u %s %s %s\r\n", ++ms->trId, gc->username, ms->auth, ms->sessid); | |
385 if (msn_write(ms->fd, buf, strlen(buf)) < 0) { | |
386 close(ms->fd); | |
387 g_free(ms->sessid); | |
388 g_free(ms->auth); | |
389 g_free(ms); | |
390 return; | |
391 } | |
392 | |
393 md->switches = g_slist_append(md->switches, ms); | |
394 ms->inpa = gaim_input_add(ms->fd, GAIM_INPUT_READ, | |
395 msn_switchboard_callback, ms); | |
396 } | |
397 | |
398 static void | |
399 msn_ss_xfr_connect(gpointer data, gint source, GaimInputCondition cond) | |
400 { | |
401 struct msn_switchboard *ms = data; | |
402 struct gaim_connection *gc = ms->gc; | |
403 char buf[MSN_BUF_LEN]; | |
404 | |
405 if (source == -1 || !g_slist_find(connections, gc)) { | |
406 close(source); | |
407 if (g_slist_find(connections, gc)) { | |
408 msn_kill_switch(ms); | |
409 do_error_dialog(_("Gaim was unable to send an MSN message"), | |
410 _("Gaim encountered an error communicating with the " | |
411 "MSN switchboard server. Please try again later."), | |
412 GAIM_ERROR); | |
413 } | |
414 | |
415 return; | |
416 } | |
417 | |
418 if (ms->fd != source) | |
419 ms->fd = source; | |
420 | |
421 g_snprintf(buf, sizeof(buf), "USR %u %s %s\r\n", | |
422 ++ms->trId, gc->username, ms->auth); | |
423 | |
424 if (msn_write(ms->fd, buf, strlen(buf)) < 0) { | |
425 g_free(ms->auth); | |
426 g_free(ms); | |
427 return; | |
428 } | |
429 | |
430 ms->inpa = gaim_input_add(ms->fd, GAIM_INPUT_READ, | |
431 msn_switchboard_callback, ms); | |
432 } | |
433 | |
434 struct msn_switchboard * | |
435 msn_find_switch(struct gaim_connection *gc, const char *username) | |
436 { | |
437 struct msn_data *md = (struct msn_data *)gc->proto_data; | |
438 GSList *m = md->switches; | |
439 | |
440 for (m = md->switches; m != NULL; m = m->next) { | |
441 struct msn_switchboard *ms = (struct msn_switchboard *)m->data; | |
442 | |
443 if (ms->total <= 1 && !gaim_utf8_strcasecmp(ms->user, username)) | |
444 return ms; | |
445 } | |
446 | |
447 return NULL; | |
448 } | |
449 | |
450 struct msn_switchboard * | |
451 msn_find_switch_by_id(struct gaim_connection *gc, int chat_id) | |
452 { | |
453 struct msn_data *md = (struct msn_data *)gc->proto_data; | |
454 GSList *m; | |
455 | |
456 for (m = md->switches; m != NULL; m = m->next) { | |
457 struct msn_switchboard *ms = (struct msn_switchboard *)m->data; | |
458 | |
459 if (ms->chat && gaim_chat_get_id(GAIM_CHAT(ms->chat)) == chat_id) | |
460 return ms; | |
461 } | |
462 | |
463 return NULL; | |
464 } | |
465 | |
466 struct msn_switchboard * | |
467 msn_find_writable_switch(struct gaim_connection *gc) | |
468 { | |
469 struct msn_data *md = (struct msn_data *)gc->proto_data; | |
470 GSList *m; | |
471 | |
472 for (m = md->switches; m != NULL; m = m->next) { | |
473 struct msn_switchboard *ms = (struct msn_switchboard *)m->data; | |
474 | |
475 if (ms->txqueue != NULL) | |
476 return ms; | |
477 } | |
478 | |
479 return NULL; | |
480 } | |
481 | |
482 void | |
483 msn_kill_switch(struct msn_switchboard *ms) | |
484 { | |
485 struct gaim_connection *gc = ms->gc; | |
486 struct msn_data *md = gc->proto_data; | |
487 | |
488 if (ms->inpa) | |
489 gaim_input_remove(ms->inpa); | |
490 | |
491 close(ms->fd); | |
492 g_free(ms->rxqueue); | |
493 | |
494 if (ms->msg) g_free(ms->msguser); | |
495 if (ms->user) g_free(ms->user); | |
496 if (ms->sessid) g_free(ms->sessid); | |
497 | |
498 g_free(ms->auth); | |
499 | |
500 while (ms->txqueue) { | |
501 g_free(ms->txqueue->data); | |
502 ms->txqueue = g_slist_remove(ms->txqueue, ms->txqueue->data); | |
503 } | |
504 | |
505 if (ms->chat) | |
506 serv_got_chat_left(gc, gaim_chat_get_id(GAIM_CHAT(ms->chat))); | |
507 | |
508 md->switches = g_slist_remove(md->switches, ms); | |
509 | |
510 g_free(ms); | |
511 } | |
512 | |
513 struct msn_switchboard * | |
514 msn_switchboard_connect(struct gaim_connection *gc, const char *host, int port) | |
515 { | |
516 struct msn_switchboard *ms; | |
517 | |
518 if (host == NULL || port == 0) | |
519 return NULL; | |
520 | |
521 ms = msn_find_writable_switch(gc); | |
522 | |
523 if (ms == NULL) | |
524 return NULL; | |
525 | |
526 if (proxy_connect(gc->account, (char *)host, port, msn_ss_xfr_connect, | |
527 ms) != 0) { | |
528 msn_kill_switch(ms); | |
529 | |
530 return NULL; | |
531 } | |
532 | |
533 return ms; | |
534 } |