Mercurial > pidgin.yaz
annotate plugins/msn/msn.c @ 1443:336fc98b7f90
[gaim-migrate @ 1453]
ha! take that, foul knave
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Mon, 29 Jan 2001 02:53:40 +0000 |
parents | 113a3d16f1ce |
children | de0b946e86a4 |
rev | line source |
---|---|
1259 | 1 /* |
2 * gaim - MSN Protocol Plugin | |
3 * | |
4 * Copyright (C) 2000, Rob Flynn <rob@tgflinux.com> | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify | |
7 * it under the terms of the GNU General Public License as published by | |
8 * the Free Software Foundation; either version 2 of the License, or | |
9 * (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 * | |
20 */ | |
21 | |
22 #include "../config.h" | |
23 | |
24 #include <netdb.h> | |
25 #include <gtk/gtk.h> | |
26 #include <unistd.h> | |
27 #include <errno.h> | |
28 #include <netinet/in.h> | |
29 #include <arpa/inet.h> | |
30 #include <string.h> | |
31 #include <stdlib.h> | |
32 #include <stdio.h> | |
33 #include <time.h> | |
34 #include <sys/socket.h> | |
35 #include <sys/stat.h> | |
36 #include "multi.h" | |
37 #include "prpl.h" | |
38 #include "gaim.h" | |
39 #include "md5.h" | |
40 | |
1284 | 41 #include "pixmaps/msn_online.xpm" |
1285 | 42 #include "pixmaps/msn_away.xpm" |
1284 | 43 |
1259 | 44 #define MSN_BUF_LEN 4096 |
45 | |
1277 | 46 #define MSN_OPT_SERVER 0 |
47 #define MSN_OPT_PORT 1 | |
48 | |
1259 | 49 #define MIME_HEADER "MIME-Version: 1.0\r\nContent-Type: text/plain; charset=UTF-8\r\nX-MMS-IM-Format: FN=MS%20Sans%20Serif; EF=; CO=0; CS=0; PF=0\r\n\r\n" |
50 | |
51 #define MSN_ONLINE 1 | |
52 #define MSN_BUSY 2 | |
53 #define MSN_IDLE 3 | |
54 #define MSN_BRB 4 | |
55 #define MSN_AWAY 5 | |
56 #define MSN_PHONE 6 | |
57 #define MSN_LUNCH 7 | |
58 #define MSN_OFFLINE 8 | |
59 #define MSN_HIDDEN 9 | |
60 | |
61 | |
62 struct msn_ask_add_permit { | |
63 struct gaim_connection *gc; | |
64 char *user; | |
65 char *friendly; | |
66 }; | |
67 | |
68 struct msn_data { | |
69 int fd; | |
70 | |
71 char protocol[6]; | |
72 char *friendly; | |
73 gchar *policy; | |
74 }; | |
75 | |
76 struct msn_conn { | |
77 gchar *user; | |
78 int inpa; | |
79 int fd; | |
80 }; | |
81 | |
1283 | 82 void msn_callback(gpointer data, gint fd, GdkInputCondition condition); |
1259 | 83 |
1282 | 84 GSList *msn_connections = NULL; |
1259 | 85 |
1282 | 86 static char *msn_name() |
87 { | |
1259 | 88 return "MSN"; |
89 } | |
90 | |
1282 | 91 char *name() |
92 { | |
1259 | 93 return "MSN"; |
94 } | |
95 | |
1282 | 96 char *description() |
97 { | |
1259 | 98 return "Allows gaim to use the MSN protocol. For some reason, this frightens me."; |
99 } | |
100 | |
1282 | 101 struct msn_conn *find_msn_conn_by_user(gchar * user) |
102 { | |
1259 | 103 struct msn_conn *mc; |
104 GSList *conns = msn_connections; | |
105 | |
106 while (conns) { | |
107 mc = (struct msn_conn *)conns->data; | |
108 | |
109 if (mc != NULL) { | |
110 if (strcasecmp(mc->user, user) == 0) { | |
111 return mc; | |
112 } | |
113 } | |
114 | |
115 conns = g_slist_next(conns); | |
116 } | |
117 | |
118 return NULL; | |
119 } | |
120 | |
1282 | 121 void msn_read_line(char *buf, int fd) |
122 { | |
1259 | 123 |
124 int status; | |
125 char c; | |
126 int i = 0; | |
1282 | 127 |
1307 | 128 printf("%s (%d)\n", strerror(errno), errno); |
129 | |
1259 | 130 do { |
131 status = recv(fd, &c, 1, 0); | |
132 | |
133 if (!status) | |
134 return; | |
135 | |
136 buf[i] = c; | |
137 i++; | |
138 } while (c != '\n'); | |
139 | |
140 buf[i] = '\0'; | |
141 g_strchomp(buf); | |
142 | |
143 /* I'm a bastard again :-) */ | |
144 printf("MSN: %s\n", buf); | |
1307 | 145 printf("%s (%d)\n", strerror(errno), errno); |
1259 | 146 } |
147 | |
1282 | 148 int msn_connect(char *server, int port) |
149 { | |
1259 | 150 int fd; |
151 struct hostent *host; | |
152 struct sockaddr_in site; | |
153 | |
154 printf("Connecting to '%s' on '%d'\n", server, port); | |
155 host = gethostbyname(server); | |
156 if (!host) { | |
157 return -1; | |
158 } | |
159 | |
160 site.sin_family = AF_INET; | |
161 site.sin_addr.s_addr = *(long *)(host->h_addr); | |
162 site.sin_port = htons(port); | |
163 | |
164 fd = socket(AF_INET, SOCK_STREAM, 0); | |
165 if (fd < 0) { | |
166 return -1; | |
167 } | |
168 | |
169 if (connect(fd, (struct sockaddr *)&site, sizeof(site)) < 0) { | |
170 return -1; | |
171 } | |
172 | |
173 return fd; | |
174 } | |
175 | |
1282 | 176 static void msn_add_buddy(struct gaim_connection *gc, char *who) |
177 { | |
1259 | 178 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 179 time_t trId = time((time_t *) NULL); |
1259 | 180 gchar buf[4096]; |
181 | |
182 g_snprintf(buf, 4096, "ADD %d FL %s %s\n", trId, who, who); | |
183 write(mdata->fd, buf, strlen(buf)); | |
184 } | |
185 | |
1282 | 186 static void msn_rem_permit(struct gaim_connection *gc, char *who) |
187 { | |
1259 | 188 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 189 time_t trId = time((time_t *) NULL); |
1259 | 190 gchar buf[4096]; |
191 | |
192 g_snprintf(buf, 4096, "REM %d AL %s %s\n", trId, who, who); | |
193 write(mdata->fd, buf, strlen(buf)); | |
194 } | |
195 | |
1282 | 196 static void msn_add_permit(struct gaim_connection *gc, char *who) |
197 { | |
1259 | 198 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 199 time_t trId = time((time_t *) NULL); |
1259 | 200 gchar buf[4096]; |
201 | |
202 g_snprintf(buf, 4096, "ADD %d AL %s %s\n", trId, who, who); | |
203 write(mdata->fd, buf, strlen(buf)); | |
204 } | |
205 | |
1282 | 206 static void msn_rem_deny(struct gaim_connection *gc, char *who) |
207 { | |
1277 | 208 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 209 time_t trId = time((time_t *) NULL); |
1277 | 210 gchar buf[4096]; |
211 | |
212 g_snprintf(buf, 4096, "REM %d BL %s %s\n", trId, who, who); | |
213 write(mdata->fd, buf, strlen(buf)); | |
214 } | |
215 | |
1282 | 216 static void msn_add_deny(struct gaim_connection *gc, char *who) |
217 { | |
1277 | 218 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 219 time_t trId = time((time_t *) NULL); |
1277 | 220 gchar buf[4096]; |
221 | |
222 g_snprintf(buf, 4096, "ADD %d BL %s %s\n", trId, who, who); | |
223 write(mdata->fd, buf, strlen(buf)); | |
224 } | |
225 | |
1282 | 226 static void msn_remove_buddy(struct gaim_connection *gc, char *who) |
227 { | |
1259 | 228 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 229 time_t trId = time((time_t *) NULL); |
1259 | 230 gchar buf[4096]; |
231 | |
232 g_snprintf(buf, 4096, "REM %d FL %s\n", trId, who); | |
233 write(mdata->fd, buf, strlen(buf)); | |
234 } | |
235 | |
1282 | 236 void msn_accept_add_permit(gpointer w, struct msn_ask_add_permit *ap) |
237 { | |
1259 | 238 gchar buf[4096]; |
239 | |
240 msn_add_permit(ap->gc, ap->user); | |
241 } | |
242 | |
1282 | 243 void msn_cancel_add_permit(gpointer w, struct msn_ask_add_permit *ap) |
244 { | |
245 | |
1259 | 246 g_free(ap->user); |
247 g_free(ap->friendly); | |
248 g_free(ap); | |
249 } | |
250 | |
1283 | 251 void msn_callback(gpointer data, gint fd, GdkInputCondition condition) |
1282 | 252 { |
1283 | 253 struct gaim_connection *gc = data; |
1259 | 254 struct msn_data *mdata; |
255 char c; | |
256 int i = 0; | |
257 int status; | |
258 gchar buf[4096]; | |
259 gchar **resps; | |
1282 | 260 |
1259 | 261 mdata = (struct msn_data *)gc->proto_data; |
262 | |
263 do { | |
264 /* Read data from whatever connection our inpa | |
265 * refered us from */ | |
1282 | 266 status = recv(fd, &c, 1, 0); |
1259 | 267 |
268 if (!status) | |
269 return; | |
270 | |
271 buf[i] = c; | |
1282 | 272 i++; |
1259 | 273 } while (c != '\n'); |
274 | |
275 buf[i] = '\0'; | |
276 | |
277 g_strchomp(buf); | |
278 | |
279 printf("MSN: %s\n", buf); | |
280 | |
1282 | 281 if (strlen(buf) == 0) { |
282 return; | |
283 } | |
284 | |
1259 | 285 resps = g_strsplit(buf, " ", 0); |
286 | |
287 /* See if someone is bumping us */ | |
288 if (strcasecmp(resps[0], "BYE") == 0) { | |
289 struct msn_conn *mc; | |
1282 | 290 GSList *conns = msn_connections; |
291 | |
1259 | 292 /* Yup. Let's find their convo and kill it */ |
293 | |
294 mc = find_msn_conn_by_user(resps[1]); | |
295 | |
296 /* If we have the convo, remove it */ | |
297 if (mc != NULL) { | |
298 /* and remove it */ | |
299 conns = g_slist_remove(conns, mc); | |
300 | |
301 g_free(mc->user); | |
302 gdk_input_remove(mc->inpa); | |
303 close(mc->fd); | |
304 | |
305 | |
306 g_free(mc); | |
307 } | |
308 | |
309 g_strfreev(resps); | |
310 return; | |
311 } | |
312 | |
313 if (strcasecmp(resps[0], "ADD") == 0) { | |
1282 | 314 |
1259 | 315 if (strcasecmp(resps[2], "RL") == 0) { |
316 gchar buf[4096]; | |
317 struct msn_ask_add_permit *ap = g_new0(struct msn_ask_add_permit, 1); | |
1282 | 318 |
319 g_snprintf(buf, 4096, "The user %s (%s) wants to add you to their buddylist.", | |
320 resps[4], resps[5]); | |
1259 | 321 |
322 ap->user = g_strdup(resps[4]); | |
323 ap->friendly = g_strdup(resps[5]); | |
324 ap->gc = gc; | |
325 | |
1282 | 326 do_ask_dialog(buf, ap, (GtkFunction) msn_accept_add_permit, |
327 (GtkFunction) msn_cancel_add_permit); | |
1259 | 328 } |
329 | |
330 g_strfreev(resps); | |
331 return; | |
332 } | |
333 | |
334 if (strcasecmp(resps[0], "REM") == 0) { | |
1282 | 335 |
1259 | 336 if (strcasecmp(resps[2], "RL") == 0) { |
337 msn_rem_permit(gc, resps[4]); | |
338 } | |
339 | |
340 g_strfreev(resps); | |
341 return; | |
342 } | |
1282 | 343 |
1259 | 344 if (strcasecmp(resps[0], "FLN") == 0) { |
1285 | 345 serv_got_update(gc, resps[1], 0, 0, 0, 0, 0, 0); |
1259 | 346 } |
347 | |
1285 | 348 /* Check buddy update status */ |
349 if ( (strcasecmp(resps[0], "NLN") == 0) || (strcasecmp(resps[0], "ILN") == 0)) { | |
1259 | 350 int status; |
1285 | 351 int query; |
1259 | 352 |
1285 | 353 if (strcasecmp(resps[0], "NLN") == 0) |
354 query = 1; | |
1259 | 355 else |
1285 | 356 query = 2; |
357 | |
358 if (!strcasecmp(resps[query], "NLN")) | |
359 status = UC_NORMAL; | |
360 else if (!strcasecmp(resps[query], "BSY")) | |
361 status = UC_NORMAL | (MSN_BUSY << 5); | |
362 else if (!strcasecmp(resps[query], "IDL")) | |
363 status = UC_NORMAL | (MSN_IDLE << 5); | |
364 else if (!strcasecmp(resps[query], "BRB")) | |
365 status = UC_NORMAL | (MSN_BRB << 5); | |
366 else if (!strcasecmp(resps[query], "AWY")) | |
367 status = UC_UNAVAILABLE; | |
368 else if (!strcasecmp(resps[query], "PHN")) | |
369 status = UC_NORMAL | (MSN_PHONE << 5); | |
370 else if (!strcasecmp(resps[query], "LUN")) | |
371 status = UC_NORMAL | (MSN_LUNCH << 5); | |
372 else | |
373 status = UC_NORMAL; | |
1259 | 374 |
1285 | 375 serv_got_update(gc, resps[query+1], 1, 0, 0, 0, status, 0); |
1259 | 376 |
377 g_strfreev(resps); | |
378 return; | |
379 } | |
1282 | 380 |
1259 | 381 /* Check to see if we have an incoming buddylist */ |
1282 | 382 if (strcasecmp(resps[0], "LST") == 0) { |
1259 | 383 /* Check to see if there are any buddies in the list */ |
384 if (atoi(resps[5]) == 0) { | |
385 /* No buddies */ | |
386 g_strfreev(resps); | |
387 return; | |
388 } | |
389 | |
390 /* FIXME: We should support the permit and deny | |
391 * lists as well */ | |
392 | |
393 if (strcasecmp(resps[2], "FL") == 0) { | |
394 struct buddy *b; | |
395 | |
396 b = find_buddy(gc, resps[6]); | |
397 | |
398 if (!b) | |
399 add_buddy(gc, "Buddies", resps[6], resps[6]); | |
400 } | |
1282 | 401 |
1259 | 402 g_strfreev(resps); |
403 return; | |
404 } | |
1282 | 405 |
1259 | 406 /* Check to see if we got a message request */ |
407 if (strcasecmp(resps[0], "MSG") == 0) { | |
408 gchar *message; | |
409 gchar *buf2; | |
410 int size; | |
411 int status; | |
1282 | 412 |
1259 | 413 /* Determine our message size */ |
414 size = atoi(resps[3]); | |
415 | |
1282 | 416 buf2 = (gchar *) g_malloc(sizeof(gchar) * (size + 1)); |
1259 | 417 status = recv(fd, buf2, size, 0); |
418 buf2[size] = 0; | |
419 | |
1308 | 420 if (strcasecmp("hotmail", resps[1]) == 0) { |
421 | |
1327 | 422 /* FIXME: Eventually remove the following printf() */ |
423 printf("---READ---\n%s\n---END---\n", buf2); | |
1308 | 424 if (strstr(buf2, "Content-Type: text/x-msmsgsemailnotification")) { |
425 g_snprintf(buf, sizeof(buf), "%s has new hotmail", gc->username); | |
426 do_error_dialog(buf, "Gaim: MSN New Mail"); | |
427 } | |
428 | |
429 g_strfreev(resps); | |
430 return; | |
431 } | |
432 | |
1259 | 433 /* Looks like we got the message. If it's blank, let's bail */ |
1282 | 434 if (strcasecmp(strstr(buf2, "\r\n\r\n") + 4, "\r\n") == 0) { |
1259 | 435 g_free(buf2); |
436 g_strfreev(resps); | |
437 return; | |
438 } | |
439 | |
1282 | 440 serv_got_im(gc, resps[1], strstr(buf2, "\r\n\r\n") + 4, 0); |
1259 | 441 |
442 g_free(buf2); | |
443 g_strfreev(resps); | |
444 return; | |
445 } | |
1282 | 446 |
1259 | 447 |
448 /* Check to see if we got a ring request */ | |
449 if (strcasecmp(resps[0], "RNG") == 0) { | |
450 gchar **address; | |
451 struct msn_conn *mc = g_new0(struct msn_conn, 1); | |
452 | |
453 address = g_strsplit(resps[2], ":", 0); | |
454 | |
455 if (!(mc->fd = msn_connect(address[0], atoi(address[1])))) { | |
456 do_error_dialog(resps[5], "Msg Err from"); | |
457 g_strfreev(address); | |
458 g_strfreev(resps); | |
459 g_free(mc); | |
460 return; | |
461 } | |
462 | |
463 mc->user = g_strdup(resps[5]); | |
464 | |
1283 | 465 mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_callback, gc); |
1282 | 466 |
1259 | 467 g_snprintf(buf, 4096, "ANS 1 %s %s %s\n", gc->username, resps[4], resps[1]); |
468 write(mc->fd, buf, strlen(buf)); | |
469 | |
470 msn_connections = g_slist_append(msn_connections, mc); | |
471 | |
472 g_strfreev(address); | |
473 g_strfreev(resps); | |
474 return; | |
475 } | |
476 | |
477 g_strfreev(resps); | |
478 | |
479 } | |
480 | |
1282 | 481 void msn_login(struct aim_user *user) |
482 { | |
483 time_t trId = time((time_t *) NULL); | |
1259 | 484 char buf[4096]; |
485 char buf2[4096]; | |
1282 | 486 |
1259 | 487 struct gaim_connection *gc = new_gaim_conn(user); |
488 struct msn_data *mdata = gc->proto_data = g_new0(struct msn_data, 1); | |
489 char c; | |
490 int i; | |
491 int status; | |
492 | |
493 md5_state_t st; | |
494 md5_byte_t di[16]; | |
495 int x; | |
496 | |
497 gchar **results; | |
498 | |
1282 | 499 g_snprintf(mdata->protocol, strlen("MSNP2") + 1, "MSNP2"); |
500 | |
501 set_login_progress(gc, 1, "Connecting"); | |
1259 | 502 |
503 while (gtk_events_pending()) | |
504 gtk_main_iteration(); | |
505 if (!g_slist_find(connections, gc)) | |
506 return; | |
507 | |
508 if (!(mdata->fd = msn_connect("messenger.hotmail.com", 1863))) { | |
509 hide_login_progress(gc, "Error connection to server"); | |
510 signoff(gc); | |
1282 | 511 return; |
1259 | 512 } |
1282 | 513 |
1308 | 514 printf("AAA: %s (%d)\n", strerror(errno), errno); |
515 | |
1259 | 516 g_snprintf(buf, sizeof(buf), "Signon: %s", gc->username); |
517 set_login_progress(gc, 2, buf); | |
1282 | 518 |
1279 | 519 while (gtk_events_pending()) |
520 gtk_main_iteration(); | |
1259 | 521 |
1308 | 522 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 523 /* This is where we will attempt to sign on */ |
524 g_snprintf(buf, 4096, "VER %d %s\n", trId, mdata->protocol); | |
525 write(mdata->fd, buf, strlen(buf)); | |
526 | |
1308 | 527 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 528 msn_read_line(&buf2, mdata->fd); |
529 | |
1308 | 530 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1282 | 531 buf[strlen(buf) - 1] = '\0'; |
1259 | 532 if (strcmp(buf, buf2) != 0) { |
533 hide_login_progress(gc, buf2); | |
534 signoff(gc); | |
535 return; | |
536 } | |
537 | |
538 /* Looks like our versions matched up. Let's find out | |
539 * which policy we should use */ | |
540 | |
1308 | 541 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 542 g_snprintf(buf, 4096, "INF %d\n", trId); |
543 write(mdata->fd, buf, strlen(buf)); | |
544 | |
1308 | 545 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 546 msn_read_line(&buf2, mdata->fd); |
547 results = g_strsplit(buf2, " ", 0); | |
548 mdata->policy = g_strdup(results[2]); | |
549 g_strfreev(results); | |
550 | |
1308 | 551 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 552 /* We've set our policy. Now, lets attempt a sign on */ |
1282 | 553 g_snprintf(buf, 4096, "USR %d %s I %s\n", trId, mdata->policy, gc->username); |
1259 | 554 write(mdata->fd, buf, strlen(buf)); |
555 | |
1308 | 556 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 557 msn_read_line(&buf2, mdata->fd); |
558 | |
1308 | 559 printf("AAA: %s (%d)\n", strerror(errno), errno); |
1259 | 560 /* This is where things get kinky */ |
561 results = g_strsplit(buf2, " ", 0); | |
562 | |
563 /* Are we being transfered to another server ? */ | |
564 if (strcasecmp(results[0], "XFR") == 0) { | |
565 /* Yup. We should connect to the _new_ server */ | |
566 strcpy(buf, results[3]); | |
567 g_strfreev(results); | |
568 | |
569 results = g_strsplit(buf, ":", 0); | |
570 | |
571 /* Connect to the new server */ | |
572 if (!(mdata->fd = msn_connect(results[0], atoi(results[1])))) { | |
573 hide_login_progress(gc, "Error connecting to server"); | |
574 signoff(gc); | |
575 g_strfreev(results); | |
1282 | 576 return; |
1259 | 577 } |
578 | |
579 | |
580 g_strfreev(results); | |
581 | |
582 /* We're now connected to the new server. Send signon | |
583 * information again */ | |
1282 | 584 g_snprintf(buf, 4096, "USR %d %s I %s\n", trId, mdata->policy, gc->username); |
1259 | 585 write(mdata->fd, buf, strlen(buf)); |
586 | |
587 msn_read_line(&buf, mdata->fd); | |
588 results = g_strsplit(buf, " ", 0); | |
589 | |
590 } | |
1282 | 591 |
1259 | 592 /* Otherwise, if we have a USR response, let's handle it */ |
593 if (strcasecmp("USR", results[0]) == 0) { | |
594 /* Looks like we got a response. Let's get our challenge | |
595 * string */ | |
596 strcpy(buf, results[4]); | |
597 | |
1282 | 598 } else { |
1259 | 599 g_strfreev(results); |
600 hide_login_progress(gc, "Error signing on"); | |
601 signoff(gc); | |
602 return; | |
603 } | |
604 g_strfreev(results); | |
605 | |
606 /* Build our response string */ | |
607 snprintf(buf2, 4096, "%s%s", buf, gc->password); | |
608 | |
609 /* Use the MD5 Hashing */ | |
610 md5_init(&st); | |
611 md5_append(&st, (const md5_byte_t *)buf2, strlen(buf2)); | |
612 md5_finish(&st, di); | |
613 | |
614 /* And now encode it in hex */ | |
615 sprintf(buf, "%02x", di[0]); | |
616 for (x = 1; x < 16; x++) { | |
617 sprintf(buf, "%s%02x", buf, di[x]); | |
618 } | |
619 | |
620 /* And now we should fire back a response */ | |
621 g_snprintf(buf2, 4096, "USR %d %s S %s\n", trId, mdata->policy, buf); | |
622 write(mdata->fd, buf2, strlen(buf2)); | |
623 | |
624 | |
625 msn_read_line(&buf, mdata->fd); | |
626 | |
627 results = g_strsplit(buf, " ", 0); | |
628 | |
629 if ((strcasecmp("USR", results[0]) == 0) && (strcasecmp("OK", results[2]) == 0)) { | |
630 mdata->friendly = g_strdup(results[4]); | |
631 g_strfreev(results); | |
1282 | 632 } else { |
1259 | 633 g_strfreev(results); |
634 hide_login_progress(gc, "Error signing on!"); | |
635 signoff(gc); | |
636 return; | |
637 | |
638 } | |
639 set_login_progress(gc, 3, "Getting Config"); | |
1279 | 640 while (gtk_events_pending()) |
641 gtk_main_iteration(); | |
642 | |
1259 | 643 g_snprintf(buf, 4096, "SYN %d 0\n", trId); |
644 write(mdata->fd, buf, strlen(buf)); | |
645 | |
646 /* Go online */ | |
647 g_snprintf(buf, 4096, "CHG %d NLN\n", trId); | |
648 write(mdata->fd, buf, strlen(buf)); | |
649 | |
650 account_online(gc); | |
651 serv_finish_login(gc); | |
652 | |
653 if (bud_list_cache_exists(gc)) | |
654 do_import(NULL, gc); | |
655 | |
656 /* We want to do this so that we can read what's going on */ | |
1283 | 657 gc->inpa = gdk_input_add(mdata->fd, GDK_INPUT_READ, msn_callback, gc); |
1259 | 658 } |
659 | |
1282 | 660 void msn_send_im(struct gaim_connection *gc, char *who, char *message, int away) |
661 { | |
1259 | 662 struct msn_conn *mc; |
663 struct msn_data *mdata; | |
1282 | 664 time_t trId = time((time_t *) NULL); |
1259 | 665 char *buf; |
666 | |
667 mdata = (struct msn_data *)gc->proto_data; | |
668 mc = find_msn_conn_by_user(who); | |
669 | |
1307 | 670 /* Are we trying to send a message to ourselves? Naughty us! */ |
671 if (!g_strcasecmp(who, gc->username)) { | |
672 do_error_dialog("You cannot send a message to yourself!!", "GAIM: Msn Error"); | |
673 return; | |
674 } | |
675 | |
1282 | 676 if (mc == NULL) { |
1259 | 677 gchar buf2[4096]; |
678 gchar *address; | |
679 gchar *auth; | |
680 gchar **resps; | |
681 | |
682 /* Request a new switchboard connection */ | |
683 g_snprintf(buf2, 4096, "XFR %d SB\n", trId); | |
684 write(mdata->fd, buf2, strlen(buf2)); | |
1282 | 685 |
1259 | 686 /* Read the results */ |
687 msn_read_line(&buf2, mdata->fd); | |
688 | |
689 resps = g_strsplit(buf2, " ", 0); | |
690 | |
691 address = g_strdup(resps[3]); | |
692 auth = g_strdup(resps[5]); | |
693 g_strfreev(resps); | |
694 | |
695 resps = g_strsplit(address, ":", 0); | |
696 | |
697 mc = g_new0(struct msn_conn, 1); | |
698 | |
699 if (!(mc->fd = msn_connect(resps[0], atoi(resps[1])))) { | |
700 g_strfreev(resps); | |
701 g_free(address); | |
702 g_free(auth); | |
703 g_free(mc); | |
704 return; | |
705 } | |
706 | |
707 /* Looks like we got connected ok. Now, let's verify */ | |
708 g_snprintf(buf2, 4096, "USR %d %s %s\n", trId, gc->username, auth); | |
709 write(mc->fd, buf2, strlen(buf2)); | |
710 | |
711 /* Read the results */ | |
712 msn_read_line(&buf2, mc->fd); | |
713 g_strfreev(resps); | |
1282 | 714 |
1259 | 715 resps = g_strsplit(buf2, " ", 0); |
1282 | 716 |
1259 | 717 if (!(strcasecmp("OK", resps[2]) == 0)) { |
718 g_free(auth); | |
719 g_free(address); | |
720 g_strfreev(resps); | |
721 g_free(mc); | |
722 return; | |
723 } | |
724 | |
725 mc->user = g_strdup(who); | |
1283 | 726 mc->inpa = gdk_input_add(mc->fd, GDK_INPUT_READ, msn_callback, gc); |
1259 | 727 |
728 msn_connections = g_slist_append(msn_connections, mc); | |
729 | |
730 /* Now we must invite our new user to the switchboard session */ | |
731 g_snprintf(buf2, 4096, "CAL %d %s\n", trId, who); | |
732 write(mc->fd, buf2, strlen(buf2)); | |
733 | |
734 /* FIXME: This causes a delay. I will make some sort of queing feature to prevent | |
735 * this from being needed */ | |
736 | |
1307 | 737 while ((!strstr(buf2, "JOI")) && (!g_strncasecmp(buf2, "215", 3))) { |
1259 | 738 msn_read_line(&buf2, mc->fd); |
739 } | |
1282 | 740 |
1259 | 741 g_free(auth); |
742 g_free(address); | |
743 g_strfreev(resps); | |
744 | |
745 } | |
746 | |
1282 | 747 /* Always practice safe sets :-) */ |
748 buf = (gchar *) g_malloc(sizeof(gchar) * (strlen(message) + strlen(MIME_HEADER) + 64)); | |
1259 | 749 |
1282 | 750 g_snprintf(buf, strlen(message) + strlen(MIME_HEADER) + 64, "MSG %d N %d\r\n%s%s", trId, |
751 strlen(message) + strlen(MIME_HEADER), MIME_HEADER, message); | |
1259 | 752 |
753 write(mc->fd, buf, strlen(buf)); | |
754 | |
755 g_free(buf); | |
756 } | |
757 | |
1282 | 758 static void msn_close(struct gaim_connection *gc) |
759 { | |
1275 | 760 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
761 GSList *conns = msn_connections; | |
762 struct msn_conn *mc = NULL; | |
763 char buf[4096]; | |
764 | |
765 while (conns) { | |
766 mc = (struct msn_conn *)conns->data; | |
767 | |
768 if (mc->inpa > 0) | |
769 gdk_input_remove(mc->inpa); | |
770 | |
771 if (mc->fd > 0) | |
772 close(mc->fd); | |
773 | |
774 if (mc->user != NULL) | |
775 g_free(mc->user); | |
1282 | 776 |
1275 | 777 conns = g_slist_remove(conns, mc); |
778 g_free(mc); | |
779 } | |
780 | |
781 | |
782 g_snprintf(buf, 4096, "OUT\n"); | |
783 write(mdata->fd, buf, strlen(buf)); | |
1282 | 784 |
1275 | 785 if (gc->inpa > 0) |
786 gdk_input_remove(gc->inpa); | |
787 | |
788 close(mdata->fd); | |
789 | |
790 if (mdata->friendly != NULL) | |
791 g_free(mdata->friendly); | |
792 | |
793 g_free(gc->proto_data); | |
794 | |
795 debug_printf(_("Signed off.\n")); | |
1282 | 796 |
1275 | 797 } |
798 | |
1282 | 799 static void msn_set_away(struct gaim_connection *gc, char *msg) |
800 { | |
1278 | 801 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 802 time_t trId = time((time_t *) NULL); |
1278 | 803 gchar buf[4096]; |
804 | |
805 if (msg) { | |
806 g_snprintf(buf, 4096, "CHG %d AWY\n", trId); | |
807 } else if (gc->is_idle) { | |
808 g_snprintf(buf, 4096, "CHG %d IDL\n", trId); | |
809 } else { | |
810 g_snprintf(buf, 4096, "CHG %d NLN\n", trId); | |
811 } | |
812 | |
813 write(mdata->fd, buf, strlen(buf)); | |
1282 | 814 |
1278 | 815 } |
816 | |
1282 | 817 static void msn_set_idle(struct gaim_connection *gc, int idle) |
818 { | |
1278 | 819 struct msn_data *mdata = (struct msn_data *)gc->proto_data; |
1282 | 820 time_t trId = time((time_t *) NULL); |
1278 | 821 gchar buf[4096]; |
822 | |
823 if (idle) { | |
824 g_snprintf(buf, 4096, "CHG %d IDL\n", trId); | |
825 } else { | |
826 g_snprintf(buf, 4096, "CHG %d NLN\n", trId); | |
827 } | |
828 | |
829 write(mdata->fd, buf, strlen(buf)); | |
1282 | 830 |
1278 | 831 } |
832 | |
1285 | 833 static char **msn_list_icon(int uc) |
1284 | 834 { |
1285 | 835 if (uc == UC_UNAVAILABLE) |
836 return msn_away_xpm; | |
837 else if (uc == UC_NORMAL) | |
838 return msn_online_xpm; | |
839 | |
840 /* Our default online icon */ | |
1284 | 841 return msn_online_xpm; |
842 } | |
843 | |
1259 | 844 static struct prpl *my_protocol = NULL; |
845 | |
1282 | 846 void msn_init(struct prpl *ret) |
847 { | |
1259 | 848 ret->protocol = PROTO_MSN; |
849 ret->name = msn_name; | |
1284 | 850 ret->list_icon = msn_list_icon; |
1259 | 851 ret->action_menu = NULL; |
852 ret->user_opts = NULL; | |
853 ret->login = msn_login; | |
1275 | 854 ret->close = msn_close; |
1259 | 855 ret->send_im = msn_send_im; |
856 ret->set_info = NULL; | |
857 ret->get_info = NULL; | |
1278 | 858 ret->set_away = msn_set_away; |
1259 | 859 ret->get_away_msg = NULL; |
860 ret->set_dir = NULL; | |
861 ret->get_dir = NULL; | |
862 ret->dir_search = NULL; | |
1278 | 863 ret->set_idle = msn_set_idle; |
1259 | 864 ret->change_passwd = NULL; |
865 ret->add_buddy = msn_add_buddy; | |
866 ret->add_buddies = NULL; | |
867 ret->remove_buddy = msn_remove_buddy; | |
868 ret->add_permit = msn_add_permit; | |
869 ret->rem_permit = msn_rem_permit; | |
1277 | 870 ret->add_deny = msn_add_deny; |
871 ret->rem_deny = msn_rem_deny; | |
1259 | 872 ret->warn = NULL; |
873 ret->accept_chat = NULL; | |
874 ret->join_chat = NULL; | |
875 ret->chat_invite = NULL; | |
876 ret->chat_leave = NULL; | |
877 ret->chat_whisper = NULL; | |
878 ret->chat_send = NULL; | |
879 ret->keepalive = NULL; | |
880 | |
881 my_protocol = ret; | |
882 } | |
883 | |
1282 | 884 char *gaim_plugin_init(GModule * handle) |
885 { | |
1443
336fc98b7f90
[gaim-migrate @ 1453]
Eric Warmenhoven <eric@warmenhoven.org>
parents:
1327
diff
changeset
|
886 load_protocol(msn_init, sizeof(struct prpl)); |
1259 | 887 return NULL; |
888 } | |
889 | |
1282 | 890 void gaim_plugin_remove() |
891 { | |
1259 | 892 struct prpl *p = find_prpl(PROTO_MSN); |
893 if (p == my_protocol) | |
894 unload_protocol(p); | |
895 } |