Mercurial > pidgin
comparison src/protocols/msn/msg.c @ 8646:1e211dde3cae
[gaim-migrate @ 9398]
Added a patch by shx to clean up the message-handling code and split the
command stuff from it, among a few other things. Also, I fixed a crash in
message parsing, which I think may close a couple bug reports.
committer: Tailor Script <tailor@pidgin.im>
| author | Christian Hammond <chipx86@chipx86.com> |
|---|---|
| date | Tue, 13 Apr 2004 04:08:22 +0000 |
| parents | 06f57183e29f |
| children | d16e1bfaf08a |
comparison
equal
deleted
inserted
replaced
| 8645:47f647dd2ac3 | 8646:1e211dde3cae |
|---|---|
| 128 msg->msnslp_header.ack_length_2 = acked_msg->msnslp_header.total_size_2; | 128 msg->msnslp_header.ack_length_2 = acked_msg->msnslp_header.total_size_2; |
| 129 | 129 |
| 130 return msg; | 130 return msg; |
| 131 } | 131 } |
| 132 | 132 |
| 133 MsnMessage * | 133 void |
| 134 msn_message_new_from_str(MsnSession *session, const char *str) | 134 msn_message_parse_payload(MsnMessage *msg, const char *payload, |
| 135 { | 135 size_t payload_len) |
| 136 MsnMessage *msg; | 136 { |
| 137 char *command_header; | 137 char *tmp_base, *tmp, *c; |
| 138 char *tmp_base, *msg_base, *tmp, *field1, *field2, *c; | |
| 139 const char *content_type; | 138 const char *content_type; |
| 140 const char *c2; | 139 |
| 141 | 140 tmp_base = g_malloc(payload_len + 1); |
| 142 g_return_val_if_fail(str != NULL, NULL); | 141 memcpy(tmp_base, payload, payload_len); |
| 143 g_return_val_if_fail(!g_ascii_strncasecmp(str, "MSG", 3), NULL); | 142 tmp_base[payload_len] = '\0'; |
| 144 | |
| 145 msg = msn_message_new(); | |
| 146 | |
| 147 /* Clear out the old stuff. */ | |
| 148 msn_message_set_attr(msg, "User-Agent", NULL); | |
| 149 msn_message_set_content_type(msg, NULL); | |
| 150 msn_message_set_charset(msg, NULL); | |
| 151 | |
| 152 /* | |
| 153 * We need to grab the header and then the size, since this might have | |
| 154 * binary data. | |
| 155 */ | |
| 156 if ((c2 = strchr(str, '\r')) != NULL) | |
| 157 { | |
| 158 tmp = command_header = g_strndup(str, (c2 - str)); | |
| 159 | |
| 160 GET_NEXT(tmp); /* Skip MSG */ | |
| 161 field1 = tmp; | |
| 162 | |
| 163 GET_NEXT(tmp); /* Skip the passport or TID */ | |
| 164 field2 = tmp; | |
| 165 | |
| 166 GET_NEXT(tmp); /* Skip the username or flag */ | |
| 167 msg->size = atoi(tmp); | |
| 168 } | |
| 169 else | |
| 170 { | |
| 171 /* Kind of screwed :) This won't happen. */ | |
| 172 msn_message_destroy(msg); | |
| 173 | |
| 174 return NULL; | |
| 175 } | |
| 176 | |
| 177 tmp_base = g_malloc(msg->size + 1); | |
| 178 memcpy(tmp_base, c2 + 2, msg->size); | |
| 179 tmp_base[msg->size] = '\0'; | |
| 180 | 143 |
| 181 tmp = tmp_base; | 144 tmp = tmp_base; |
| 182 | 145 |
| 183 /* | |
| 184 * We're going to make sure this is incoming by checking field1. | |
| 185 * If it has any non-numbers in it, it's incoming. Otherwise, outgoing. | |
| 186 */ | |
| 187 msg->incoming = FALSE; | |
| 188 | |
| 189 for (c = field1; *c != '\0'; c++) { | |
| 190 if (*c < '0' || *c > '9') { | |
| 191 msg->incoming = TRUE; | |
| 192 break; | |
| 193 } | |
| 194 } | |
| 195 | |
| 196 if (msg->incoming) { | |
| 197 msg->sender = msn_users_find_with_passport(session->users, field1); | |
| 198 | |
| 199 if (msg->sender == NULL) | |
| 200 msg->sender = msn_user_new(session, field1, field2); | |
| 201 else | |
| 202 msn_user_ref(msg->sender); | |
| 203 } | |
| 204 else { | |
| 205 msg->tid = atoi(field1); | |
| 206 msg->flag = *field2; | |
| 207 } | |
| 208 | |
| 209 msg_base = tmp; | |
| 210 | |
| 211 /* Back to the parsination. */ | 146 /* Back to the parsination. */ |
| 212 while (*tmp != '\r') { | 147 while (*tmp != '\r') |
| 148 { | |
| 213 char *key, *value; | 149 char *key, *value; |
| 214 | 150 |
| 215 key = tmp; | 151 key = tmp; |
| 216 | 152 |
| 217 GET_NEXT(tmp); /* Key */ | 153 GET_NEXT(tmp); /* Key */ |
| 221 GET_NEXT_LINE(tmp); /* Value */ | 157 GET_NEXT_LINE(tmp); /* Value */ |
| 222 | 158 |
| 223 if ((c = strchr(key, ':')) != NULL) | 159 if ((c = strchr(key, ':')) != NULL) |
| 224 *c = '\0'; | 160 *c = '\0'; |
| 225 | 161 |
| 226 if (!g_ascii_strcasecmp(key, "Content-Type")) { | 162 if (!g_ascii_strcasecmp(key, "Content-Type")) |
| 163 { | |
| 227 char *charset; | 164 char *charset; |
| 228 | 165 |
| 229 if ((c = strchr(value, ';')) != NULL) { | 166 if ((c = strchr(value, ';')) != NULL) |
| 230 if ((charset = strchr(c, '=')) != NULL) { | 167 { |
| 168 if ((charset = strchr(c, '=')) != NULL) | |
| 169 { | |
| 231 charset++; | 170 charset++; |
| 232 msn_message_set_charset(msg, charset); | 171 msn_message_set_charset(msg, charset); |
| 233 } | 172 } |
| 234 | 173 |
| 235 *c = '\0'; | 174 *c = '\0'; |
| 259 | 198 |
| 260 memcpy(header, tmp, 48); | 199 memcpy(header, tmp, 48); |
| 261 | 200 |
| 262 tmp += 48; | 201 tmp += 48; |
| 263 | 202 |
| 264 body_len = msg->size - (tmp - tmp_base) - 5; | 203 body_len = payload_len - (tmp - tmp_base) - 5; |
| 265 msg->body = g_malloc(body_len + 1); | |
| 266 | 204 |
| 267 if (body_len > 0) | 205 if (body_len > 0) |
| 206 { | |
| 207 msg->body = g_malloc(body_len + 1); | |
| 268 memcpy(msg->body, tmp, body_len); | 208 memcpy(msg->body, tmp, body_len); |
| 269 | 209 msg->body[body_len] = '\0'; |
| 270 msg->body[body_len] = '\0'; | 210 |
| 271 | 211 tmp++; |
| 272 tmp++; | 212 } |
| 213 else | |
| 214 msg->body = NULL; | |
| 273 | 215 |
| 274 memcpy(footer, tmp, 4); | 216 memcpy(footer, tmp, 4); |
| 275 | 217 |
| 276 tmp += 4; | 218 tmp += 4; |
| 277 | 219 |
| 310 else | 252 else |
| 311 { | 253 { |
| 312 char *tmp2; | 254 char *tmp2; |
| 313 size_t body_len; | 255 size_t body_len; |
| 314 | 256 |
| 315 body_len = msg->size - (tmp - tmp_base); | 257 body_len = payload_len - (tmp - tmp_base); |
| 316 | 258 |
| 317 tmp2 = g_malloc(body_len + 1); | 259 tmp2 = g_malloc(body_len + 1); |
| 318 | 260 |
| 319 if (body_len > 0) | 261 if (body_len > 0) |
| 320 memcpy(tmp2, tmp, body_len); | 262 memcpy(tmp2, tmp, body_len); |
| 324 msn_message_set_body(msg, tmp2); | 266 msn_message_set_body(msg, tmp2); |
| 325 | 267 |
| 326 g_free(tmp2); | 268 g_free(tmp2); |
| 327 } | 269 } |
| 328 | 270 |
| 329 g_free(command_header); | |
| 330 g_free(tmp_base); | 271 g_free(tmp_base); |
| 331 | 272 |
| 332 /* Done! */ | 273 /* Done! */ |
| 333 | |
| 334 return msg; | |
| 335 } | 274 } |
| 336 | 275 |
| 337 void | 276 void |
| 338 msn_message_destroy(MsnMessage *msg) | 277 msn_message_destroy(MsnMessage *msg) |
| 339 { | 278 { |
| 340 g_return_if_fail(msg != NULL); | 279 g_return_if_fail(msg != NULL); |
| 341 | 280 |
| 342 if (msg->ref_count > 0) { | 281 if (msg->ref_count > 0) |
| 282 { | |
| 343 msn_message_unref(msg); | 283 msn_message_unref(msg); |
| 344 | 284 |
| 345 return; | 285 return; |
| 346 } | 286 } |
| 347 | |
| 348 if (msg->sender != NULL) | |
| 349 msn_user_unref(msg->sender); | |
| 350 | |
| 351 if (msg->receiver != NULL) | |
| 352 msn_user_unref(msg->receiver); | |
| 353 | 287 |
| 354 if (msg->body != NULL) | 288 if (msg->body != NULL) |
| 355 g_free(msg->body); | 289 g_free(msg->body); |
| 356 | 290 |
| 357 if (msg->content_type != NULL) | 291 if (msg->content_type != NULL) |
| 398 | 332 |
| 399 return msg; | 333 return msg; |
| 400 } | 334 } |
| 401 | 335 |
| 402 char * | 336 char * |
| 403 msn_message_to_string(const MsnMessage *msg, size_t *ret_size) | 337 msn_message_gen_payload(const MsnMessage *msg, size_t *ret_size) |
| 404 { | 338 { |
| 405 GList *l; | 339 GList *l; |
| 406 char *msg_start; | |
| 407 char *str; | 340 char *str; |
| 408 char buf[MSN_BUF_LEN]; | 341 char buf[MSN_BUF_LEN]; |
| 409 int len; | 342 int len; |
| 410 | 343 |
| 411 /* | 344 /* |
| 417 * | 350 * |
| 418 * -- ChipX86 | 351 * -- ChipX86 |
| 419 */ | 352 */ |
| 420 g_return_val_if_fail(msg != NULL, NULL); | 353 g_return_val_if_fail(msg != NULL, NULL); |
| 421 | 354 |
| 422 if (msn_message_is_incoming(msg)) { | 355 len = msg->size + 1; |
| 423 MsnUser *sender = msn_message_get_sender(msg); | |
| 424 | |
| 425 g_snprintf(buf, sizeof(buf), "MSG %s %s %d\r\n", | |
| 426 msn_user_get_passport(sender), msn_user_get_name(sender), | |
| 427 (int)msg->size); | |
| 428 } | |
| 429 else { | |
| 430 g_snprintf(buf, sizeof(buf), "MSG %d %c %d\r\n", | |
| 431 msn_message_get_transaction_id(msg), | |
| 432 msn_message_get_flag(msg), (int)msg->size); | |
| 433 } | |
| 434 | |
| 435 len = strlen(buf) + msg->size + 1; | |
| 436 | 356 |
| 437 str = g_new0(char, len + 1); | 357 str = g_new0(char, len + 1); |
| 438 | 358 |
| 439 g_strlcpy(str, buf, len); | |
| 440 | |
| 441 msg_start = str + strlen(str); | |
| 442 | |
| 443 /* Standard header. */ | 359 /* Standard header. */ |
| 444 if (msg->charset == NULL) { | 360 if (msg->charset == NULL) |
| 361 { | |
| 445 g_snprintf(buf, sizeof(buf), | 362 g_snprintf(buf, sizeof(buf), |
| 446 "MIME-Version: 1.0\r\n" | 363 "MIME-Version: 1.0\r\n" |
| 447 "Content-Type: %s\r\n", | 364 "Content-Type: %s\r\n", |
| 448 msg->content_type); | 365 msg->content_type); |
| 449 } | 366 } |
| 450 else { | 367 else |
| 368 { | |
| 451 g_snprintf(buf, sizeof(buf), | 369 g_snprintf(buf, sizeof(buf), |
| 452 "MIME-Version: 1.0\r\n" | 370 "MIME-Version: 1.0\r\n" |
| 453 "Content-Type: %s; charset=%s\r\n", | 371 "Content-Type: %s; charset=%s\r\n", |
| 454 msg->content_type, msg->charset); | 372 msg->content_type, msg->charset); |
| 455 } | 373 } |
| 456 | 374 |
| 457 g_strlcat(str, buf, len); | 375 g_strlcat(str, buf, len); |
| 458 | 376 |
| 459 for (l = msg->attr_list; l != NULL; l = l->next) { | 377 for (l = msg->attr_list; l != NULL; l = l->next) |
| 378 { | |
| 460 const char *key = (char *)l->data; | 379 const char *key = (char *)l->data; |
| 461 const char *value; | 380 const char *value; |
| 462 | 381 |
| 463 value = msn_message_get_attr(msg, key); | 382 value = msn_message_get_attr(msg, key); |
| 464 | 383 |
| 520 { | 439 { |
| 521 const char *body = msn_message_get_body(msg); | 440 const char *body = msn_message_get_body(msg); |
| 522 | 441 |
| 523 if (body != NULL) | 442 if (body != NULL) |
| 524 { | 443 { |
| 525 g_strlcpy(c, body, msg->size - (c - msg_start)); | 444 g_strlcpy(c, body, msg->size - (c - str)); |
| 526 | 445 |
| 527 c += strlen(body); | 446 c += strlen(body); |
| 528 | 447 |
| 529 if (strlen(body) > 0) | 448 if (strlen(body) > 0) |
| 530 *c++ = '\0'; | 449 *c++ = '\0'; |
| 531 } | 450 } |
| 532 } | 451 } |
| 533 | 452 |
| 534 c += msn_put32(c, msg->msnslp_footer.app_id); | 453 c += msn_put32(c, msg->msnslp_footer.app_id); |
| 535 | 454 |
| 536 if (msg->size != (c - msg_start)) | 455 if (msg->size != (c - str)) |
| 537 { | 456 { |
| 538 gaim_debug(GAIM_DEBUG_ERROR, "msn", | 457 gaim_debug(GAIM_DEBUG_ERROR, "msn", |
| 539 "Outgoing message size (%d) and data length (%d) " | 458 "Outgoing message size (%d) and data length (%d) " |
| 540 "do not match!\n", msg->size, (c - msg_start)); | 459 "do not match!\n", msg->size, (c - str)); |
| 541 } | 460 } |
| 542 } | 461 } |
| 543 else | 462 else |
| 544 { | 463 { |
| 545 const char *body = msn_message_get_body(msg); | 464 const char *body = msn_message_get_body(msg); |
| 546 | 465 |
| 547 g_strlcat(str, body, len); | 466 g_strlcat(str, body, len); |
| 548 | 467 |
| 549 if (msg->size != strlen(msg_start)) { | 468 if (msg->size != strlen(str)) |
| 469 { | |
| 550 gaim_debug(GAIM_DEBUG_ERROR, "msn", | 470 gaim_debug(GAIM_DEBUG_ERROR, "msn", |
| 551 "Outgoing message size (%d) and string length (%d) " | 471 "Outgoing message size (%d) and string length (%d) " |
| 552 "do not match!\n", msg->size, strlen(msg_start)); | 472 "do not match!\n", msg->size, strlen(str)); |
| 553 } | 473 } |
| 554 } | 474 } |
| 555 | 475 |
| 556 if (ret_size != NULL) | 476 if (ret_size != NULL) |
| 557 *ret_size = len - 1; | 477 *ret_size = len - 1; |
| 558 | 478 |
| 559 return str; | 479 return str; |
| 560 } | |
| 561 | |
| 562 gboolean | |
| 563 msn_message_is_outgoing(const MsnMessage *msg) | |
| 564 { | |
| 565 g_return_val_if_fail(msg != NULL, FALSE); | |
| 566 | |
| 567 return !msg->incoming; | |
| 568 } | |
| 569 | |
| 570 gboolean | |
| 571 msn_message_is_incoming(const MsnMessage *msg) | |
| 572 { | |
| 573 g_return_val_if_fail(msg != NULL, FALSE); | |
| 574 | |
| 575 return msg->incoming; | |
| 576 } | |
| 577 | |
| 578 void | |
| 579 msn_message_set_sender(MsnMessage *msg, MsnUser *user) | |
| 580 { | |
| 581 g_return_if_fail(msg != NULL); | |
| 582 g_return_if_fail(user != NULL); | |
| 583 | |
| 584 msg->sender = user; | |
| 585 | |
| 586 msn_user_ref(msg->sender); | |
| 587 } | |
| 588 | |
| 589 MsnUser * | |
| 590 msn_message_get_sender(const MsnMessage *msg) | |
| 591 { | |
| 592 g_return_val_if_fail(msg != NULL, NULL); | |
| 593 | |
| 594 return msg->sender; | |
| 595 } | |
| 596 | |
| 597 void | |
| 598 msn_message_set_receiver(MsnMessage *msg, MsnUser *user) | |
| 599 { | |
| 600 g_return_if_fail(msg != NULL); | |
| 601 g_return_if_fail(user != NULL); | |
| 602 | |
| 603 msg->receiver = user; | |
| 604 | |
| 605 if (msg->msnslp_message) | |
| 606 msn_message_set_attr(msg, "P2P-Dest", msn_user_get_passport(user)); | |
| 607 | |
| 608 msn_user_ref(msg->receiver); | |
| 609 } | |
| 610 | |
| 611 MsnUser * | |
| 612 msn_message_get_receiver(const MsnMessage *msg) | |
| 613 { | |
| 614 g_return_val_if_fail(msg != NULL, NULL); | |
| 615 | |
| 616 return msg->receiver; | |
| 617 } | |
| 618 | |
| 619 void | |
| 620 msn_message_set_transaction_id(MsnMessage *msg, unsigned int tid) | |
| 621 { | |
| 622 g_return_if_fail(msg != NULL); | |
| 623 g_return_if_fail(tid > 0); | |
| 624 | |
| 625 msg->tid = tid; | |
| 626 } | |
| 627 | |
| 628 unsigned int | |
| 629 msn_message_get_transaction_id(const MsnMessage *msg) | |
| 630 { | |
| 631 g_return_val_if_fail(msg != NULL, 0); | |
| 632 | |
| 633 return msg->tid; | |
| 634 } | 480 } |
| 635 | 481 |
| 636 void | 482 void |
| 637 msn_message_set_flag(MsnMessage *msg, char flag) | 483 msn_message_set_flag(MsnMessage *msg, char flag) |
| 638 { | 484 { |
