Changes in protocols/msn/ns.c [2fe8297:5ebff60]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/ns.c
r2fe8297 r5ebff60 35 35 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond); 36 36 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond); 37 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts); 38 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts); 37 39 38 40 static void msn_ns_send_adl_start(struct im_connection *ic); 39 41 static void msn_ns_send_adl(struct im_connection *ic); 40 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd);41 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action);42 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put);43 42 44 43 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 55 54 56 55 if (fd < 0) { 57 fd = md-> fd;56 fd = md->ns->fd; 58 57 } 59 58 60 59 if (getenv("BITLBEE_DEBUG")) { 61 fprintf(stderr, " \x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out);60 fprintf(stderr, "->NS%d:%s\n", fd, out); 62 61 } 63 62 64 63 len = strlen(out); 65 66 if (md->is_http) { 67 st = len; 68 msn_gw_write(md->gw, out, len); 69 } else { 70 st = write(fd, out, len); 71 } 72 64 st = write(fd, out, len); 73 65 g_free(out); 74 66 if (st != len) { … … 81 73 } 82 74 83 gboolean msn_ns_connect(struct im_connection *ic, const char *host, int port) 84 { 85 struct msn_data *md = ic->proto_data; 86 87 if (md->fd >= 0) { 88 closesocket(md->fd); 89 } 90 91 if (md->is_http) { 92 md->gw = msn_gw_new(ic); 93 md->gw->callback = msn_ns_callback; 94 msn_ns_connected(md, -1, B_EV_IO_READ); 95 } else { 96 md->fd = proxy_connect(host, port, msn_ns_connected, md); 97 if (md->fd < 0) { 98 imcb_error(ic, "Could not connect to server"); 99 imc_logout(ic, TRUE); 100 return FALSE; 101 } 102 } 103 104 return TRUE; 105 } 106 107 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 108 { 109 struct msn_data *md = data; 110 struct im_connection *ic = md->ic; 111 112 if (source == -1 && !md->is_http) { 75 gboolean msn_ns_connect(struct im_connection *ic, struct msn_handler_data *handler, const char *host, int port) 76 { 77 if (handler->fd >= 0) { 78 closesocket(handler->fd); 79 } 80 81 handler->exec_command = msn_ns_command; 82 handler->exec_message = msn_ns_message; 83 handler->data = ic; 84 handler->fd = proxy_connect(host, port, msn_ns_connected, handler); 85 if (handler->fd < 0) { 113 86 imcb_error(ic, "Could not connect to server"); 114 87 imc_logout(ic, TRUE); … … 116 89 } 117 90 118 g_free(md->rxq); 119 md->rxlen = 0; 120 md->rxq = g_new0(char, 1); 91 return TRUE; 92 } 93 94 static gboolean msn_ns_connected(gpointer data, gint source, b_input_condition cond) 95 { 96 struct msn_handler_data *handler = data; 97 struct im_connection *ic = handler->data; 98 struct msn_data *md; 99 100 if (!g_slist_find(msn_connections, ic)) { 101 return FALSE; 102 } 103 104 md = ic->proto_data; 105 106 if (source == -1) { 107 imcb_error(ic, "Could not connect to server"); 108 imc_logout(ic, TRUE); 109 return FALSE; 110 } 111 112 g_free(handler->rxq); 113 handler->rxlen = 0; 114 handler->rxq = g_new0(char, 1); 121 115 122 116 if (md->uuid == NULL) { … … 136 130 137 131 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 138 if (!md->is_http) { 139 md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); 140 } 132 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler); 141 133 imcb_log(ic, "Connected to server, waiting for reply"); 142 134 } … … 145 137 } 146 138 147 void msn_ns_close(struct msn_data *md) 148 { 149 if (md->gw) { 150 msn_gw_free(md->gw); 151 } 152 if (md->fd >= 0) { 153 closesocket(md->fd); 154 b_event_remove(md->inpa); 155 } 156 157 md->fd = md->inpa = -1; 158 g_free(md->rxq); 159 g_free(md->cmd_text); 160 161 md->rxlen = 0; 162 md->rxq = NULL; 163 md->cmd_text = NULL; 139 void msn_ns_close(struct msn_handler_data *handler) 140 { 141 if (handler->fd >= 0) { 142 closesocket(handler->fd); 143 b_event_remove(handler->inpa); 144 } 145 146 handler->fd = handler->inpa = -1; 147 g_free(handler->rxq); 148 g_free(handler->cmd_text); 149 150 handler->rxlen = 0; 151 handler->rxq = NULL; 152 handler->cmd_text = NULL; 164 153 } 165 154 166 155 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 167 156 { 168 struct msn_data *md = data; 169 struct im_connection *ic = md->ic; 170 char *bytes; 171 int st; 172 173 if (md->is_http) { 174 st = msn_gw_read(md->gw, &bytes); 175 } else { 176 bytes = g_malloc(1024); 177 st = read(md->fd, bytes, 1024); 178 } 179 180 if (st <= 0) { 157 struct msn_handler_data *handler = data; 158 struct im_connection *ic = handler->data; 159 160 if (msn_handler(handler) == -1) { /* Don't do this on ret == 0, it's already done then. */ 181 161 imcb_error(ic, "Error while reading from server"); 182 162 imc_logout(ic, TRUE); 163 183 164 return FALSE; 184 } 185 186 msn_queue_feed(md, bytes, st); 187 188 g_free(bytes); 189 190 /* Ignore ret == 0, it's already disconnected then. */ 191 msn_handler(md); 192 193 return TRUE; 194 195 } 196 197 int msn_ns_command(struct msn_data *md, char **cmd, int num_parts) 198 { 199 struct im_connection *ic = md->ic; 165 } else { 166 return TRUE; 167 } 168 } 169 170 static int msn_ns_command(struct msn_handler_data *handler, char **cmd, int num_parts) 171 { 172 struct im_connection *ic = handler->data; 173 struct msn_data *md = ic->proto_data; 200 174 201 175 if (num_parts == 0) { … … 211 185 } 212 186 213 return(msn_ns_write(ic, md->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s VmVyc2lvbjogMQ0KWGZyQ291bnQ6IDINClhmclNlbnRVVENUaW1lOiA2MzU2MTQ3OTU5NzgzOTAwMDANCklzR2VvWGZyOiB0cnVlDQo=\r\n",187 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n", 214 188 ++md->trId, ic->acc->user)); 215 189 } else if (strcmp(cmd[0], "CVR") == 0) { 216 190 /* We don't give a damn about the information we just received */ 217 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);191 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user); 218 192 } else if (strcmp(cmd[0], "XFR") == 0) { 219 193 char *server; … … 221 195 222 196 if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { 223 b_event_remove( md->inpa);224 md->inpa = -1;197 b_event_remove(handler->inpa); 198 handler->inpa = -1; 225 199 226 200 server = strchr(cmd[3], ':'); … … 235 209 236 210 imcb_log(ic, "Transferring to other server"); 237 return msn_ns_connect(ic, server, port); 211 return msn_ns_connect(ic, handler, server, port); 212 } else if (num_parts >= 6 && strcmp(cmd[2], "SB") == 0) { 213 struct msn_switchboard *sb; 214 215 server = strchr(cmd[3], ':'); 216 if (!server) { 217 imcb_error(ic, "Syntax error"); 218 imc_logout(ic, TRUE); 219 return(0); 220 } 221 *server = 0; 222 port = atoi(server + 1); 223 server = cmd[3]; 224 225 if (strcmp(cmd[4], "CKI") != 0) { 226 imcb_error(ic, "Unknown authentication method for switchboard"); 227 imc_logout(ic, TRUE); 228 return(0); 229 } 230 231 debug("Connecting to a new switchboard with key %s", cmd[5]); 232 233 if ((sb = msn_sb_create(ic, server, port, cmd[5], MSN_SB_NEW)) == NULL) { 234 /* Although this isn't strictly fatal for the NS connection, it's 235 definitely something serious (we ran out of file descriptors?). */ 236 imcb_error(ic, "Could not create new switchboard"); 237 imc_logout(ic, TRUE); 238 return(0); 239 } 240 241 if (md->msgq) { 242 struct msn_message *m = md->msgq->data; 243 GSList *l; 244 245 sb->who = g_strdup(m->who); 246 247 /* Move all the messages to the first user in the message 248 queue to the switchboard message queue. */ 249 l = md->msgq; 250 while (l) { 251 m = l->data; 252 l = l->next; 253 if (strcmp(m->who, sb->who) == 0) { 254 sb->msgq = g_slist_append(sb->msgq, m); 255 md->msgq = g_slist_remove(md->msgq, m); 256 } 257 } 258 } 238 259 } else { 239 260 imcb_error(ic, "Syntax error"); … … 269 290 } 270 291 271 md->msglen = atoi(cmd[3]);272 273 if ( md->msglen <= 0) {292 handler->msglen = atoi(cmd[3]); 293 294 if (handler->msglen <= 0) { 274 295 imcb_error(ic, "Syntax error"); 275 296 imc_logout(ic, TRUE); 276 297 return(0); 277 298 } 299 } else if (strcmp(cmd[0], "BLP") == 0) { 300 msn_ns_send_adl_start(ic); 301 return msn_ns_finish_login(ic); 278 302 } else if (strcmp(cmd[0], "ADL") == 0) { 279 303 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 281 305 return msn_ns_finish_login(ic); 282 306 } else if (num_parts >= 3) { 283 md->msglen = atoi(cmd[2]); 284 } 307 handler->msglen = atoi(cmd[2]); 308 } 309 } else if (strcmp(cmd[0], "PRP") == 0) { 310 imcb_connected(ic); 285 311 } else if (strcmp(cmd[0], "CHL") == 0) { 286 312 char *resp; … … 300 326 g_free(resp); 301 327 return st; 302 } else if (strcmp(cmd[0], "QRY") == 0) { 303 /* CONGRATULATIONS */ 328 } else if (strcmp(cmd[0], "ILN") == 0 || strcmp(cmd[0], "NLN") == 0) { 329 const struct msn_away_state *st; 330 const char *handle; 331 int cap = 0; 332 333 if (num_parts < 6) { 334 imcb_error(ic, "Syntax error"); 335 imc_logout(ic, TRUE); 336 return(0); 337 } 338 /* ILN and NLN are more or less the same, except ILN has a trId 339 at the start, and NLN has a capability field at the end. 340 Does ILN still exist BTW? */ 341 if (cmd[0][1] == 'I') { 342 cmd++; 343 } else { 344 cap = atoi(cmd[4]); 345 } 346 347 handle = msn_normalize_handle(cmd[2]); 348 if (strcmp(handle, ic->acc->user) == 0) { 349 return 1; /* That's me! */ 350 351 } 352 http_decode(cmd[3]); 353 imcb_rename_buddy(ic, handle, cmd[3]); 354 355 st = msn_away_state_by_code(cmd[1]); 356 if (!st) { 357 /* FIXME: Warn/Bomb about unknown away state? */ 358 st = msn_away_state_list + 1; 359 } 360 361 imcb_buddy_status(ic, handle, OPT_LOGGED_IN | 362 (st != msn_away_state_list ? OPT_AWAY : 0) | 363 (cap & 1 ? OPT_MOBILE : 0), 364 st->name, NULL); 365 366 msn_sb_stop_keepalives(msn_sb_by_handle(ic, handle)); 367 } else if (strcmp(cmd[0], "FLN") == 0) { 368 const char *handle; 369 370 if (cmd[1] == NULL) { 371 return 1; 372 } 373 374 handle = msn_normalize_handle(cmd[1]); 375 imcb_buddy_status(ic, handle, 0, NULL, NULL); 376 msn_sb_start_keepalives(msn_sb_by_handle(ic, handle), TRUE); 377 } else if (strcmp(cmd[0], "RNG") == 0) { 378 struct msn_switchboard *sb; 379 char *server; 380 int session, port; 381 382 if (num_parts < 7) { 383 imcb_error(ic, "Syntax error"); 384 imc_logout(ic, TRUE); 385 return(0); 386 } 387 388 session = atoi(cmd[1]); 389 390 server = strchr(cmd[2], ':'); 391 if (!server) { 392 imcb_error(ic, "Syntax error"); 393 imc_logout(ic, TRUE); 394 return(0); 395 } 396 *server = 0; 397 port = atoi(server + 1); 398 server = cmd[2]; 399 400 if (strcmp(cmd[3], "CKI") != 0) { 401 imcb_error(ic, "Unknown authentication method for switchboard"); 402 imc_logout(ic, TRUE); 403 return(0); 404 } 405 406 debug("Got a call from %s (session %d). Key = %s", cmd[5], session, cmd[4]); 407 408 if ((sb = msn_sb_create(ic, server, port, cmd[4], session)) == NULL) { 409 /* Although this isn't strictly fatal for the NS connection, it's 410 definitely something serious (we ran out of file descriptors?). */ 411 imcb_error(ic, "Could not create new switchboard"); 412 imc_logout(ic, TRUE); 413 return(0); 414 } else { 415 sb->who = g_strdup(msn_normalize_handle(cmd[5])); 416 } 304 417 } else if (strcmp(cmd[0], "OUT") == 0) { 305 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown"); 306 imc_logout(ic, TRUE); 418 int allow_reconnect = TRUE; 419 420 if (cmd[1] && strcmp(cmd[1], "OTH") == 0) { 421 imcb_error(ic, "Someone else logged in with your account"); 422 allow_reconnect = FALSE; 423 } else if (cmd[1] && strcmp(cmd[1], "SSD") == 0) { 424 imcb_error(ic, "Terminating session because of server shutdown"); 425 } else { 426 imcb_error(ic, "Session terminated by remote server (%s)", 427 cmd[1] ? cmd[1] : "reason unknown)"); 428 } 429 430 imc_logout(ic, allow_reconnect); 307 431 return(0); 308 } else if (strcmp(cmd[0], "GCF") == 0) { 432 } else if (strcmp(cmd[0], "IPG") == 0) { 433 imcb_error(ic, "Received IPG command, we don't handle them yet."); 434 435 handler->msglen = atoi(cmd[1]); 436 437 if (handler->msglen <= 0) { 438 imcb_error(ic, "Syntax error"); 439 imc_logout(ic, TRUE); 440 return(0); 441 } 442 } 443 #if 0 444 else if (strcmp(cmd[0], "ADG") == 0) { 445 char *group = g_strdup(cmd[3]); 446 int groupnum, i; 447 GSList *l, *next; 448 449 http_decode(group); 450 if (sscanf(cmd[4], "%d", &groupnum) == 1) { 451 if (groupnum >= md->groupcount) { 452 md->grouplist = g_renew(char *, md->grouplist, groupnum + 1); 453 for (i = md->groupcount; i <= groupnum; i++) { 454 md->grouplist[i] = NULL; 455 } 456 md->groupcount = groupnum + 1; 457 } 458 g_free(md->grouplist[groupnum]); 459 md->grouplist[groupnum] = group; 460 } else { 461 /* Shouldn't happen, but if it does, give up on the group. */ 462 g_free(group); 463 imcb_error(ic, "Syntax error"); 464 imc_logout(ic, TRUE); 465 return 0; 466 } 467 468 for (l = md->grpq; l; l = next) { 469 struct msn_groupadd *ga = l->data; 470 next = l->next; 471 if (g_strcasecmp(ga->group, group) == 0) { 472 if (!msn_buddy_list_add(ic, "FL", ga->who, ga->who, group)) { 473 return 0; 474 } 475 476 g_free(ga->group); 477 g_free(ga->who); 478 g_free(ga); 479 md->grpq = g_slist_remove(md->grpq, ga); 480 } 481 } 482 } 483 #endif 484 else if (strcmp(cmd[0], "GCF") == 0) { 309 485 /* Coming up is cmd[2] bytes of stuff we're supposed to 310 486 censore. Meh. */ 311 md->msglen = atoi(cmd[2]); 312 } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) { 487 handler->msglen = atoi(cmd[2]); 488 } else if (strcmp(cmd[0], "UBX") == 0) { 489 /* Status message. */ 313 490 if (num_parts >= 3) { 314 md->msglen = atoi(cmd[2]); 315 } 316 } else if (strcmp(cmd[0], "PUT") == 0) { 317 if (num_parts >= 4) { 318 md->msglen = atoi(cmd[3]); 491 handler->msglen = atoi(cmd[2]); 319 492 } 320 493 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but 495 apparently used to announce address book changes. */ 321 496 if (num_parts >= 2) { 322 md->msglen = atoi(cmd[1]); 497 handler->msglen = atoi(cmd[1]); 498 } 499 } else if (strcmp(cmd[0], "UBM") == 0) { 500 if (num_parts >= 7) { 501 handler->msglen = atoi(cmd[6]); 323 502 } 324 503 } else if (strcmp(cmd[0], "QNG") == 0) { … … 337 516 /* Oh yes, errors can have payloads too now. Discard them for now. */ 338 517 if (num_parts >= 3) { 339 md->msglen = atoi(cmd[2]);518 handler->msglen = atoi(cmd[2]); 340 519 } 341 520 } else { 342 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]);521 /* debug( "Received unknown command from main server: %s", cmd[0] ); */ 343 522 } 344 523 … … 346 525 } 347 526 348 int msn_ns_message(struct msn_data *md, char *msg, int msglen, char **cmd, int num_parts)349 { 350 struct im_connection *ic = md->ic;527 static int msn_ns_message(struct msn_handler_data *handler, char *msg, int msglen, char **cmd, int num_parts) 528 { 529 struct im_connection *ic = handler->data; 351 530 char *body; 352 531 int blen = 0; … … 419 598 } 420 599 } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { 421 /* Notification that a message has been read... Ignore it */ 600 } else if (g_strncasecmp(ct, "text/x-msmsgsinitialmdatanotification", 37) == 0 || 601 g_strncasecmp(ct, "text/x-msmsgsoimnotification", 28) == 0) { 602 /* We received an offline message. Or at least notification 603 that there is one waiting for us. Fetching the message(s) 604 and purging them from the server is a lot of SOAPy work 605 not worth doing IMHO. Also I thought it was possible to 606 have the notification server send them directly, I was 607 pretty sure I saw Pidgin do it.. 608 609 At least give a notification for now, seems like a 610 reasonable thing to do. Only problem is, they'll keep 611 coming back at login time until you read them using a 612 different client. :-( */ 613 614 char *xml = get_rfc822_header(body, "Mail-Data:", blen); 615 struct xt_node *md, *m; 616 617 if (!xml) { 618 return 1; 619 } 620 md = xt_from_string(xml, 0); 621 if (!md) { 622 return 1; 623 } 624 625 for (m = md->children; (m = xt_find_node(m, "M")); m = m->next) { 626 struct xt_node *e = xt_find_node(m->children, "E"); 627 struct xt_node *rt = xt_find_node(m->children, "RT"); 628 struct tm tp; 629 time_t msgtime = 0; 630 631 if (!e || !e->text) { 632 continue; 633 } 634 635 memset(&tp, 0, sizeof(tp)); 636 if (rt && rt->text && 637 sscanf(rt->text, "%4d-%2d-%2dT%2d:%2d:%2d.", 638 &tp.tm_year, &tp.tm_mon, &tp.tm_mday, 639 &tp.tm_hour, &tp.tm_min, &tp.tm_sec) == 6) { 640 tp.tm_year -= 1900; 641 tp.tm_mon--; 642 msgtime = mktime_utc(&tp); 643 644 } 645 imcb_buddy_msg(ic, e->text, 646 "<< \002BitlBee\002 - Received offline message. BitlBee can't show these. >>", 0, 647 msgtime); 648 } 649 650 g_free(xml); 651 xt_free_node(md); 422 652 } else { 423 653 debug("Can't handle %s packet from notification server", ct); … … 426 656 g_free(ct); 427 657 } 658 } else if (strcmp(cmd[0], "UBX") == 0) { 659 struct xt_node *ubx, *psm; 660 char *psm_text = NULL; 661 662 ubx = xt_from_string(msg, msglen); 663 if (ubx && strcmp(ubx->name, "Data") == 0 && 664 (psm = xt_find_node(ubx->children, "PSM"))) { 665 psm_text = psm->text; 666 } 667 668 imcb_buddy_status_msg(ic, msn_normalize_handle(cmd[1]), psm_text); 669 xt_free_node(ubx); 428 670 } else if (strcmp(cmd[0], "ADL") == 0) { 429 671 struct xt_node *adl, *d, *c; … … 474 716 } 475 717 } 476 } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) { 477 msn_ns_structured_message(md, msg, msglen, cmd); 718 } else if (strcmp(cmd[0], "UBM") == 0) { 719 /* This one will give us msgs from federated networks. Technically 720 it should also get us offline messages, but I don't know how 721 I can signal MSN servers to use it. */ 722 char *ct, *handle; 723 724 if (strcmp(cmd[1], ic->acc->user) == 0) { 725 /* With MPOP, you'll get copies of your own msgs from other 726 sessions. Discard those at least for now. */ 727 return 1; 728 } 729 730 ct = get_rfc822_header(msg, "Content-Type", msglen); 731 if (strncmp(ct, "text/plain", 10) != 0) { 732 /* Typing notification or something? */ 733 g_free(ct); 734 return 1; 735 } 736 if (strcmp(cmd[2], "1") != 0) { 737 handle = g_strdup_printf("%s:%s", cmd[2], cmd[1]); 738 } else { 739 handle = g_strdup(cmd[1]); 740 } 741 742 imcb_buddy_msg(ic, handle, body, 0, 0); 743 g_free(handle); 478 744 } 479 745 480 746 return 1; 481 }482 483 static void msn_ns_structured_message(struct msn_data *md, char *msg, int msglen, char **cmd)484 {485 char **parts = NULL;486 char *semicolon = NULL;487 char *action = NULL;488 char *from = NULL;489 char *who = NULL;490 491 parts = g_strsplit(msg, "\r\n\r\n", 4);492 493 if (!(from = get_rfc822_header(parts[0], "From", 0))) {494 goto cleanup;495 }496 497 /* either the semicolon or the end of the string */498 semicolon = strchr(from, ';') ? : (from + strlen(from));499 500 who = g_strndup(from + 2, semicolon - from - 2);501 502 if ((strcmp(cmd[0], "SDG") == 0) && (action = get_rfc822_header(parts[2], "Message-Type", 0))) {503 msn_ns_sdg(md, who, parts, action);504 505 } else if ((strcmp(cmd[0], "NFY") == 0) && (action = get_rfc822_header(parts[2], "Uri", 0))) {506 gboolean is_put = (strcmp(cmd[1], "PUT") == 0);507 msn_ns_nfy(md, who, parts, action, is_put);508 }509 510 cleanup:511 g_strfreev(parts);512 g_free(action);513 g_free(from);514 g_free(who);515 }516 517 static void msn_ns_sdg(struct msn_data *md, char *who, char **parts, char *action)518 {519 struct im_connection *ic = md->ic;520 521 if (strcmp(action, "Control/Typing") == 0) {522 imcb_buddy_typing(ic, who, OPT_TYPING);523 } else if (strcmp(action, "Text") == 0) {524 imcb_buddy_msg(ic, who, parts[3], 0, 0);525 }526 }527 528 static void msn_ns_nfy(struct msn_data *md, char *who, char **parts, char *action, gboolean is_put)529 {530 struct im_connection *ic = md->ic;531 struct xt_node *body = NULL;532 struct xt_node *s = NULL;533 const char *state = NULL;534 char *nick = NULL;535 char *psm = NULL;536 int flags = OPT_LOGGED_IN;537 538 if (strcmp(action, "/user") != 0) {539 return;540 }541 542 if (!(body = xt_from_string(parts[3], 0))) {543 goto cleanup;544 }545 546 s = body->children;547 while ((s = xt_find_node(s, "s"))) {548 struct xt_node *s2;549 char *n = xt_find_attr(s, "n"); /* service name: IM, PE, etc */550 551 if (strcmp(n, "IM") == 0) {552 /* IM has basic presence information */553 if (!is_put) {554 /* NFY DEL with a <s> usually means log out from the last endpoint */555 flags &= ~OPT_LOGGED_IN;556 break;557 }558 559 s2 = xt_find_node(s->children, "Status");560 if (s2 && s2->text_len) {561 const struct msn_away_state *msn_state = msn_away_state_by_code(s2->text);562 state = msn_state->name;563 if (msn_state != msn_away_state_list) {564 flags |= OPT_AWAY;565 }566 }567 } else if (strcmp(n, "PE") == 0) {568 if ((s2 = xt_find_node(s->children, "PSM")) && s2->text_len) {569 psm = s2->text;570 }571 if ((s2 = xt_find_node(s->children, "FriendlyName")) && s2->text_len) {572 nick = s2->text;573 }574 }575 s = s->next;576 }577 578 imcb_buddy_status(ic, who, flags, state, psm);579 580 if (nick) {581 imcb_rename_buddy(ic, who, nick);582 }583 584 cleanup:585 xt_free_node(body);586 747 } 587 748 … … 607 768 void msn_auth_got_contact_list(struct im_connection *ic) 608 769 { 770 struct msn_data *md; 771 609 772 /* Dead connection? */ 610 773 if (g_slist_find(msn_connections, ic) == NULL) { … … 612 775 } 613 776 614 m sn_ns_send_adl_start(ic);615 msn_ns_ finish_login(ic);777 md = ic->proto_data; 778 msn_ns_write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL"); 616 779 } 617 780 618 781 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 619 782 { 620 struct xt_node *adl = data, *d, *c , *s;783 struct xt_node *adl = data, *d, *c; 621 784 struct bee_user *bu = value; 622 785 struct msn_buddy_data *bd = bu->data; … … 647 810 c = xt_new_node("c", NULL, NULL); 648 811 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l); 649 813 xt_add_attr(c, "t", "1"); /* FIXME: Network type, i.e. 32 for Y!MSG */ 650 s = xt_new_node("s", NULL, NULL);651 xt_add_attr(s, "n", "IM");652 xt_add_attr(s, "l", l);653 xt_insert_child(c, s);654 814 xt_insert_child(d, c); 655 815 … … 721 881 722 882 if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { 723 imcb_connected(ic); 883 if (md->flags & MSN_EMAIL_UNVERIFIED) { 884 imcb_connected(ic); 885 } else { 886 return msn_ns_set_display_name(ic, set_getstr(&ic->acc->set, "display_name")); 887 } 724 888 } 725 889 … … 727 891 } 728 892 729 // TODO: typing notifications, nudges lol, etc730 893 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 731 894 { 732 895 struct msn_data *md = ic->proto_data; 733 int retval= 0;734 char *buf ;896 int type = 0; 897 char *buf, *handle; 735 898 736 899 if (strncmp(text, "\r\r\r", 3) == 0) { … … 740 903 } 741 904 742 buf = g_strdup_printf(MSN_MESSAGE_HEADERS, bu->handle, ic->acc->user, md->uuid, strlen(text), text); 743 retval = msn_ns_write(ic, -1, "SDG %d %zd\r\n%s", ++md->trId, strlen(buf), buf); 744 g_free(buf); 745 return retval; 746 } 905 /* This might be a federated contact. Get its network number, 906 prefixed to bu->handle with a colon. Default is 1. */ 907 for (handle = bu->handle; g_ascii_isdigit(*handle); handle++) { 908 type = type * 10 + *handle - '0'; 909 } 910 if (*handle == ':') { 911 handle++; 912 } else { 913 type = 1; 914 } 915 916 buf = g_strdup_printf("%s%s", MSN_MESSAGE_HEADERS, text); 917 918 if (msn_ns_write(ic, -1, "UUM %d %s %d %d %zd\r\n%s", 919 ++md->trId, handle, type, 920 1, /* type == IM (not nudge/typing) */ 921 strlen(buf), buf)) { 922 return 1; 923 } else { 924 return 0; 925 } 926 } 927 928 void msn_ns_oim_send_queue(struct im_connection *ic, GSList **msgq) 929 { 930 GSList *l; 931 932 for (l = *msgq; l; l = l->next) { 933 struct msn_message *m = l->data; 934 bee_user_t *bu = bee_user_by_handle(ic->bee, ic, m->who); 935 936 if (bu) { 937 if (!msn_ns_sendmessage(ic, bu, m->text)) { 938 return; 939 } 940 } 941 } 942 943 while (*msgq != NULL) { 944 struct msn_message *m = (*msgq)->data; 945 946 g_free(m->who); 947 g_free(m->text); 948 g_free(m); 949 950 *msgq = g_slist_remove(*msgq, m); 951 } 952 }
Note: See TracChangeset
for help on using the changeset viewer.