Changes in protocols/msn/ns.c [5ebff60:2fe8297]
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
protocols/msn/ns.c
r5ebff60 r2fe8297 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);39 37 40 38 static void msn_ns_send_adl_start(struct im_connection *ic); 41 39 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); 42 43 43 44 int msn_ns_write(struct im_connection *ic, int fd, const char *fmt, ...) … … 54 55 55 56 if (fd < 0) { 56 fd = md-> ns->fd;57 fd = md->fd; 57 58 } 58 59 59 60 if (getenv("BITLBEE_DEBUG")) { 60 fprintf(stderr, " ->NS%d:%s\n", fd, out);61 fprintf(stderr, "\x1b[91m>>>[NS%d] %s\n\x1b[97m", fd, out); 61 62 } 62 63 63 64 len = strlen(out); 64 st = write(fd, out, len); 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 65 73 g_free(out); 66 74 if (st != len) { … … 73 81 } 74 82 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) { 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) { 86 113 imcb_error(ic, "Could not connect to server"); 87 114 imc_logout(ic, TRUE); … … 89 116 } 90 117 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); 118 g_free(md->rxq); 119 md->rxlen = 0; 120 md->rxq = g_new0(char, 1); 115 121 116 122 if (md->uuid == NULL) { … … 130 136 131 137 if (msn_ns_write(ic, source, "VER %d %s CVR0\r\n", ++md->trId, MSNP_VER)) { 132 handler->inpa = b_input_add(handler->fd, B_EV_IO_READ, msn_ns_callback, handler); 138 if (!md->is_http) { 139 md->inpa = b_input_add(md->fd, B_EV_IO_READ, msn_ns_callback, md); 140 } 133 141 imcb_log(ic, "Connected to server, waiting for reply"); 134 142 } … … 137 145 } 138 146 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; 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; 153 164 } 154 165 155 166 static gboolean msn_ns_callback(gpointer data, gint source, b_input_condition cond) 156 167 { 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. */ 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) { 161 181 imcb_error(ic, "Error while reading from server"); 162 182 imc_logout(ic, TRUE); 163 164 183 return FALSE; 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; 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; 174 200 175 201 if (num_parts == 0) { … … 185 211 } 186 212 187 return(msn_ns_write(ic, handler->fd, "CVR %d 0x0409 mac 10.2.0 ppc macmsgs 3.5.1 macmsgs %s\r\n",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", 188 214 ++md->trId, ic->acc->user)); 189 215 } else if (strcmp(cmd[0], "CVR") == 0) { 190 216 /* We don't give a damn about the information we just received */ 191 return msn_ns_write(ic, handler->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user);217 return msn_ns_write(ic, md->fd, "USR %d SSO I %s\r\n", ++md->trId, ic->acc->user); 192 218 } else if (strcmp(cmd[0], "XFR") == 0) { 193 219 char *server; … … 195 221 196 222 if (num_parts >= 6 && strcmp(cmd[2], "NS") == 0) { 197 b_event_remove( handler->inpa);198 handler->inpa = -1;223 b_event_remove(md->inpa); 224 md->inpa = -1; 199 225 200 226 server = strchr(cmd[3], ':'); … … 209 235 210 236 imcb_log(ic, "Transferring to other server"); 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 } 237 return msn_ns_connect(ic, server, port); 259 238 } else { 260 239 imcb_error(ic, "Syntax error"); … … 290 269 } 291 270 292 handler->msglen = atoi(cmd[3]);293 294 if ( handler->msglen <= 0) {271 md->msglen = atoi(cmd[3]); 272 273 if (md->msglen <= 0) { 295 274 imcb_error(ic, "Syntax error"); 296 275 imc_logout(ic, TRUE); 297 276 return(0); 298 277 } 299 } else if (strcmp(cmd[0], "BLP") == 0) {300 msn_ns_send_adl_start(ic);301 return msn_ns_finish_login(ic);302 278 } else if (strcmp(cmd[0], "ADL") == 0) { 303 279 if (num_parts >= 3 && strcmp(cmd[2], "OK") == 0) { … … 305 281 return msn_ns_finish_login(ic); 306 282 } else if (num_parts >= 3) { 307 handler->msglen = atoi(cmd[2]); 308 } 309 } else if (strcmp(cmd[0], "PRP") == 0) { 310 imcb_connected(ic); 283 md->msglen = atoi(cmd[2]); 284 } 311 285 } else if (strcmp(cmd[0], "CHL") == 0) { 312 286 char *resp; … … 326 300 g_free(resp); 327 301 return st; 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 } 302 } else if (strcmp(cmd[0], "QRY") == 0) { 303 /* CONGRATULATIONS */ 417 304 } else if (strcmp(cmd[0], "OUT") == 0) { 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); 305 imcb_error(ic, "Session terminated by remote server (%s)", cmd[1] ? cmd[1] : "reason unknown"); 306 imc_logout(ic, TRUE); 431 307 return(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) { 308 } else if (strcmp(cmd[0], "GCF") == 0) { 485 309 /* Coming up is cmd[2] bytes of stuff we're supposed to 486 310 censore. Meh. */ 487 handler->msglen = atoi(cmd[2]); 488 } else if (strcmp(cmd[0], "UBX") == 0) { 489 /* Status message. */ 311 md->msglen = atoi(cmd[2]); 312 } else if ((strcmp(cmd[0], "NFY") == 0) || (strcmp(cmd[0], "SDG") == 0)) { 490 313 if (num_parts >= 3) { 491 handler->msglen = atoi(cmd[2]); 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]); 492 319 } 493 320 } else if (strcmp(cmd[0], "NOT") == 0) { 494 /* Some kind of notification, poorly documented but495 apparently used to announce address book changes. */496 321 if (num_parts >= 2) { 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]); 322 md->msglen = atoi(cmd[1]); 502 323 } 503 324 } else if (strcmp(cmd[0], "QNG") == 0) { … … 516 337 /* Oh yes, errors can have payloads too now. Discard them for now. */ 517 338 if (num_parts >= 3) { 518 handler->msglen = atoi(cmd[2]);339 md->msglen = atoi(cmd[2]); 519 340 } 520 341 } else { 521 /* debug( "Received unknown command from main server: %s", cmd[0] ); */342 imcb_error(ic, "Received unknown command from main server: %s", cmd[0]); 522 343 } 523 344 … … 525 346 } 526 347 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;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; 530 351 char *body; 531 352 int blen = 0; … … 598 419 } 599 420 } else if (g_strncasecmp(ct, "text/x-msmsgsactivemailnotification", 35) == 0) { 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); 421 /* Notification that a message has been read... Ignore it */ 652 422 } else { 653 423 debug("Can't handle %s packet from notification server", ct); … … 656 426 g_free(ct); 657 427 } 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);670 428 } else if (strcmp(cmd[0], "ADL") == 0) { 671 429 struct xt_node *adl, *d, *c; … … 716 474 } 717 475 } 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); 476 } else if ((strcmp(cmd[0], "SDG") == 0) || (strcmp(cmd[0], "NFY") == 0)) { 477 msn_ns_structured_message(md, msg, msglen, cmd); 744 478 } 745 479 746 480 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); 747 586 } 748 587 … … 768 607 void msn_auth_got_contact_list(struct im_connection *ic) 769 608 { 770 struct msn_data *md;771 772 609 /* Dead connection? */ 773 610 if (g_slist_find(msn_connections, ic) == NULL) { … … 775 612 } 776 613 777 m d = ic->proto_data;778 msn_ns_ write(ic, -1, "BLP %d %s\r\n", ++md->trId, "BL");614 msn_ns_send_adl_start(ic); 615 msn_ns_finish_login(ic); 779 616 } 780 617 781 618 static gboolean msn_ns_send_adl_1(gpointer key, gpointer value, gpointer data) 782 619 { 783 struct xt_node *adl = data, *d, *c ;620 struct xt_node *adl = data, *d, *c, *s; 784 621 struct bee_user *bu = value; 785 622 struct msn_buddy_data *bd = bu->data; … … 810 647 c = xt_new_node("c", NULL, NULL); 811 648 xt_add_attr(c, "n", handle); 812 xt_add_attr(c, "l", l);813 649 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); 814 654 xt_insert_child(d, c); 815 655 … … 881 721 882 722 if ((md->flags & MSN_DONE_ADL) && (md->flags & MSN_GOT_PROFILE)) { 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 } 723 imcb_connected(ic); 888 724 } 889 725 … … 891 727 } 892 728 729 // TODO: typing notifications, nudges lol, etc 893 730 int msn_ns_sendmessage(struct im_connection *ic, bee_user_t *bu, const char *text) 894 731 { 895 732 struct msn_data *md = ic->proto_data; 896 int type= 0;897 char *buf , *handle;733 int retval = 0; 734 char *buf; 898 735 899 736 if (strncmp(text, "\r\r\r", 3) == 0) { … … 903 740 } 904 741 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 } 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 }
Note: See TracChangeset
for help on using the changeset viewer.