Mercurial > pidgin
comparison libpurple/protocols/myspace/message.c @ 17973:acff371d7908
Fix crash when deleting buddies on Windows. This was done by
correctly printing null strings in MsimMessage debug messages, since _uid_before
had a NULL value when being sent to postprocessing.
Closes #2400.
author | Jeffrey Connelly <jaconnel@calpoly.edu> |
---|---|
date | Sat, 04 Aug 2007 17:43:37 +0000 |
parents | a2298513db8b |
children | b2d81d13f015 |
comparison
equal
deleted
inserted
replaced
17972:8f49acac9d1c | 17973:acff371d7908 |
---|---|
116 static MsimMessage * | 116 static MsimMessage * |
117 msim_msg_new_v(va_list argp) | 117 msim_msg_new_v(va_list argp) |
118 { | 118 { |
119 gchar *key, *value; | 119 gchar *key, *value; |
120 MsimMessageType type; | 120 MsimMessageType type; |
121 GString *gs; | |
122 GList *gl; | |
123 MsimMessage *msg; | 121 MsimMessage *msg; |
124 | 122 |
125 /* Begin with an empty message. */ | 123 /* Begin with an empty message. */ |
126 msg = NULL; | 124 msg = NULL; |
127 | 125 |
151 | 149 |
152 msg = msim_msg_append(msg, key, type, value); | 150 msg = msim_msg_append(msg, key, type, value); |
153 break; | 151 break; |
154 | 152 |
155 case MSIM_TYPE_BINARY: | 153 case MSIM_TYPE_BINARY: |
156 gs = va_arg(argp, GString *); | 154 { |
157 | 155 GString *gs; |
158 g_return_val_if_fail(gs != NULL, FALSE); | 156 |
159 | 157 gs = va_arg(argp, GString *); |
160 /* msim_msg_free() will free this GString the caller created. */ | 158 |
161 msg = msim_msg_append(msg, key, type, gs); | 159 g_return_val_if_fail(gs != NULL, FALSE); |
162 break; | 160 |
161 /* msim_msg_free() will free this GString the caller created. */ | |
162 msg = msim_msg_append(msg, key, type, gs); | |
163 break; | |
164 } | |
163 | 165 |
164 case MSIM_TYPE_LIST: | 166 case MSIM_TYPE_LIST: |
165 gl = va_arg(argp, GList *); | 167 { |
166 | 168 GList *gl; |
167 g_return_val_if_fail(gl != NULL, FALSE); | 169 |
168 | 170 gl = va_arg(argp, GList *); |
169 msg = msim_msg_append(msg, key, type, gl); | 171 |
172 g_return_val_if_fail(gl != NULL, FALSE); | |
173 | |
174 msg = msim_msg_append(msg, key, type, gl); | |
175 break; | |
176 } | |
177 | |
178 case MSIM_TYPE_DICTIONARY: | |
179 { | |
180 MsimMessage *dict; | |
181 | |
182 dict = va_arg(argp, MsimMessage *); | |
183 | |
184 g_return_val_if_fail(dict != NULL, FALSE); | |
185 | |
186 msg = msim_msg_append(msg, key, type, dict); | |
187 break; | |
188 } | |
170 | 189 |
171 default: | 190 default: |
172 purple_debug_info("msim", "msim_send: unknown type %d\n", type); | 191 purple_debug_info("msim", "msim_send: unknown type %d\n", type); |
173 break; | 192 break; |
174 } | 193 } |
266 gs = (GString *)elem->data; | 285 gs = (GString *)elem->data; |
267 | 286 |
268 new_data = g_string_new_len(gs->str, gs->len); | 287 new_data = g_string_new_len(gs->str, gs->len); |
269 } | 288 } |
270 break; | 289 break; |
271 /* TODO: other types */ | 290 case MSIM_TYPE_DICTIONARY: |
291 { | |
292 MsimMessage *dict; | |
293 | |
294 dict = (MsimMessage *)elem->data; | |
295 | |
296 new_data = msim_msg_clone(dict); | |
297 } | |
298 break; | |
299 | |
272 default: | 300 default: |
273 purple_debug_info("msim", "msim_msg_clone_element: unknown type %d\n", elem->type); | 301 purple_debug_info("msim", "msim_msg_clone_element: unknown type %d\n", elem->type); |
274 g_return_if_fail(NULL); | 302 g_return_if_fail(NULL); |
275 } | 303 } |
276 | 304 |
328 /* Free the GString itself and the binary data. */ | 356 /* Free the GString itself and the binary data. */ |
329 g_string_free((GString *)elem->data, TRUE); | 357 g_string_free((GString *)elem->data, TRUE); |
330 break; | 358 break; |
331 | 359 |
332 case MSIM_TYPE_DICTIONARY: | 360 case MSIM_TYPE_DICTIONARY: |
333 /* TODO: free dictionary */ | 361 msim_msg_free((MsimMessage *)elem->data); |
334 break; | 362 break; |
335 | 363 |
336 case MSIM_TYPE_LIST: | 364 case MSIM_TYPE_LIST: |
337 g_list_free((GList *)elem->data); | 365 g_list_free((GList *)elem->data); |
338 break; | 366 break; |
450 * | 478 * |
451 * * MSIM_TYPE_RAW: gchar *. The data WILL BE FREED - use g_strdup() if needed. | 479 * * MSIM_TYPE_RAW: gchar *. The data WILL BE FREED - use g_strdup() if needed. |
452 * | 480 * |
453 * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed. | 481 * * MSIM_TYPE_BINARY: g_string_new_len(data, length). The data AND GString will be freed. |
454 * | 482 * |
455 * * MSIM_TYPE_DICTIONARY: TODO | 483 * * MSIM_TYPE_DICTIONARY: An MsimMessage *. Freed when message is destroyed. |
456 * | 484 * |
457 * * MSIM_TYPE_LIST: GList * of gchar *. Again, everything will be freed. | 485 * * MSIM_TYPE_LIST: GList * of gchar *. Again, everything will be freed. |
458 * | 486 * |
459 * */ | 487 * */ |
460 MsimMessage * | 488 MsimMessage * |
538 items = user_data; | 566 items = user_data; |
539 | 567 |
540 switch (elem->type) | 568 switch (elem->type) |
541 { | 569 { |
542 case MSIM_TYPE_INTEGER: | 570 case MSIM_TYPE_INTEGER: |
543 string = g_strdup_printf("%s(integer): %d", elem->name, GPOINTER_TO_UINT(elem->data)); | 571 string = g_strdup_printf("%s(integer): %d", elem->name, |
572 GPOINTER_TO_UINT(elem->data)); | |
544 break; | 573 break; |
545 | 574 |
546 case MSIM_TYPE_RAW: | 575 case MSIM_TYPE_RAW: |
547 string = g_strdup_printf("%s(raw): %s", elem->name, (gchar *)elem->data); | 576 string = g_strdup_printf("%s(raw): %s", elem->name, |
577 elem->data ? (gchar *)elem->data : "(NULL)"); | |
548 break; | 578 break; |
549 | 579 |
550 case MSIM_TYPE_STRING: | 580 case MSIM_TYPE_STRING: |
551 string = g_strdup_printf("%s(string): %s", elem->name, (gchar *)elem->data); | 581 string = g_strdup_printf("%s(string): %s", elem->name, |
582 elem->data ? (gchar *)elem->data : "(NULL)"); | |
552 break; | 583 break; |
553 | 584 |
554 case MSIM_TYPE_BINARY: | 585 case MSIM_TYPE_BINARY: |
555 gs = (GString *)elem->data; | 586 gs = (GString *)elem->data; |
556 binary = purple_base64_encode((guchar*)gs->str, gs->len); | 587 binary = purple_base64_encode((guchar*)gs->str, gs->len); |
558 g_free(binary); | 589 g_free(binary); |
559 break; | 590 break; |
560 | 591 |
561 case MSIM_TYPE_BOOLEAN: | 592 case MSIM_TYPE_BOOLEAN: |
562 string = g_strdup_printf("%s(boolean): %s", elem->name, | 593 string = g_strdup_printf("%s(boolean): %s", elem->name, |
563 GPOINTER_TO_UINT(elem->data) ? "TRUE" : "FALSE"); | 594 elem->data ? "TRUE" : "FALSE"); |
564 break; | 595 break; |
565 | 596 |
566 case MSIM_TYPE_DICTIONARY: | 597 case MSIM_TYPE_DICTIONARY: |
567 /* TODO: provide human-readable output of dictionary. */ | 598 { |
568 string = g_strdup_printf("%s(dict): TODO", elem->name); | 599 gchar *s; |
600 | |
601 if (!elem->data) | |
602 s = g_strdup("(NULL)"); | |
603 else | |
604 s = msim_msg_dump_to_str((MsimMessage *)elem->data); | |
605 | |
606 if (!s) | |
607 s = g_strdup("(NULL, couldn't msim_msg_dump_to_str)"); | |
608 | |
609 string = g_strdup_printf("%s(dict): %s", elem->name, s); | |
610 | |
611 g_free(s); | |
612 } | |
569 break; | 613 break; |
570 | 614 |
571 case MSIM_TYPE_LIST: | 615 case MSIM_TYPE_LIST: |
572 { | 616 { |
573 GString *gs; | 617 GString *gs; |
587 string = gs->str; | 631 string = gs->str; |
588 } | 632 } |
589 break; | 633 break; |
590 | 634 |
591 default: | 635 default: |
592 string = g_strdup_printf("%s(unknown type %d", elem->name, elem->type); | 636 string = g_strdup_printf("%s(unknown type %d", |
637 elem->name ? elem->name : "(NULL)", elem->type); | |
593 break; | 638 break; |
594 } | 639 } |
595 | 640 |
596 **items = string; | 641 **items = string; |
597 ++(*items); | 642 ++(*items); |
601 * | 646 * |
602 * @param fmt_string A static string, in which '%s' will be replaced. | 647 * @param fmt_string A static string, in which '%s' will be replaced. |
603 */ | 648 */ |
604 void | 649 void |
605 msim_msg_dump(const gchar *fmt_string, MsimMessage *msg) | 650 msim_msg_dump(const gchar *fmt_string, MsimMessage *msg) |
651 { | |
652 gchar *debug_str; | |
653 | |
654 g_return_if_fail(fmt_string != NULL); | |
655 | |
656 debug_str = msim_msg_dump_to_str(msg); | |
657 | |
658 g_return_if_fail(debug_str != NULL); | |
659 | |
660 purple_debug_info("msim_msg_dump", "debug_str=%s\n", debug_str); | |
661 | |
662 | |
663 purple_debug_info("msim", fmt_string, debug_str); | |
664 | |
665 g_free(debug_str); | |
666 } | |
667 | |
668 /** Return a human-readable string of the message. | |
669 * | |
670 * @return A new gchar *, must be g_free()'d. | |
671 */ | |
672 gchar * | |
673 msim_msg_dump_to_str(MsimMessage *msg) | |
606 { | 674 { |
607 gchar *debug_str; | 675 gchar *debug_str; |
608 | 676 |
609 if (!msg) | 677 if (!msg) |
610 { | 678 { |
612 } else { | 680 } else { |
613 debug_str = msim_msg_pack_using(msg, msim_msg_debug_string_element, | 681 debug_str = msim_msg_pack_using(msg, msim_msg_debug_string_element, |
614 "\n", "<MsimMessage: \n", "\n/MsimMessage>"); | 682 "\n", "<MsimMessage: \n", "\n/MsimMessage>"); |
615 } | 683 } |
616 | 684 |
617 g_return_if_fail(debug_str != NULL); | 685 return debug_str; |
618 | |
619 purple_debug_info("msim", fmt_string, debug_str); | |
620 | |
621 g_free(debug_str); | |
622 } | 686 } |
623 | 687 |
624 /** Return a message element data as a new string for a raw protocol message, converting from other types (integer, etc.) if necessary. | 688 /** Return a message element data as a new string for a raw protocol message, converting from other types (integer, etc.) if necessary. |
625 * | 689 * |
626 * @return const gchar * The data as a string, or NULL. Caller must g_free(). | 690 * @return const gchar * The data as a string, or NULL. Caller must g_free(). |
641 /* Not un-escaped - this is a raw element, already escaped if necessary. */ | 705 /* Not un-escaped - this is a raw element, already escaped if necessary. */ |
642 return (gchar *)g_strdup((gchar *)elem->data); | 706 return (gchar *)g_strdup((gchar *)elem->data); |
643 | 707 |
644 case MSIM_TYPE_STRING: | 708 case MSIM_TYPE_STRING: |
645 /* Strings get escaped. msim_escape() creates a new string. */ | 709 /* Strings get escaped. msim_escape() creates a new string. */ |
646 return msim_escape((gchar *)elem->data); | 710 g_return_val_if_fail(elem->data != NULL, NULL); |
711 return elem->data ? msim_escape((gchar *)elem->data) : | |
712 g_strdup("(NULL)"); | |
647 | 713 |
648 case MSIM_TYPE_BINARY: | 714 case MSIM_TYPE_BINARY: |
649 { | 715 { |
650 GString *gs; | 716 GString *gs; |
651 | 717 |
653 /* Do not escape! */ | 719 /* Do not escape! */ |
654 return purple_base64_encode((guchar *)gs->str, gs->len); | 720 return purple_base64_encode((guchar *)gs->str, gs->len); |
655 } | 721 } |
656 | 722 |
657 case MSIM_TYPE_BOOLEAN: | 723 case MSIM_TYPE_BOOLEAN: |
658 /* Not used by the wire protocol * -- see msim_msg_pack_element. */ | 724 /* Not used by messages in the wire protocol * -- see msim_msg_pack_element. |
659 return NULL; | 725 * Only used by dictionaries, see msim_msg_pack_element_dict. */ |
726 return elem->data ? g_strdup("On") : g_strdup("Off"); | |
660 | 727 |
661 case MSIM_TYPE_DICTIONARY: | 728 case MSIM_TYPE_DICTIONARY: |
662 /* TODO: pack using k=v\034k2=v2\034... */ | 729 /* TODO: pack using k=v\034k2=v2\034... */ |
663 return NULL; | 730 return msim_msg_pack_dict((MsimMessage *)elem->data); |
664 | 731 |
665 case MSIM_TYPE_LIST: | 732 case MSIM_TYPE_LIST: |
666 /* Pack using a|b|c|d|... */ | 733 /* Pack using a|b|c|d|... */ |
667 { | 734 { |
668 GString *gs; | 735 GString *gs; |
682 purple_debug_info("msim", "field %s, unknown type %d\n", elem->name, elem->type); | 749 purple_debug_info("msim", "field %s, unknown type %d\n", elem->name, elem->type); |
683 return NULL; | 750 return NULL; |
684 } | 751 } |
685 } | 752 } |
686 | 753 |
754 /** Pack an element into its protcol representation inside a dictionary. | |
755 * | |
756 * See msim_msg_pack_element(). | |
757 */ | |
758 static void | |
759 msim_msg_pack_element_dict(gpointer data, gpointer user_data) | |
760 { | |
761 MsimMessageElement *elem; | |
762 gchar *string, *data_string, ***items; | |
763 | |
764 elem = (MsimMessageElement *)data; | |
765 items = (gchar ***)user_data; | |
766 | |
767 /* Exclude elements beginning with '_' from packed protocol messages. */ | |
768 if (elem->name[0] == '_') | |
769 { | |
770 return; | |
771 } | |
772 | |
773 data_string = msim_msg_pack_element_data(elem); | |
774 | |
775 g_return_if_fail(data_string != NULL); | |
776 | |
777 switch (elem->type) | |
778 { | |
779 /* These types are represented by key name/value pairs (converted above). */ | |
780 case MSIM_TYPE_INTEGER: | |
781 case MSIM_TYPE_RAW: | |
782 case MSIM_TYPE_STRING: | |
783 case MSIM_TYPE_BINARY: | |
784 case MSIM_TYPE_DICTIONARY: | |
785 case MSIM_TYPE_LIST: | |
786 case MSIM_TYPE_BOOLEAN: /* Boolean is On or Off */ | |
787 string = g_strconcat(elem->name, "\\", data_string, NULL); | |
788 break; | |
789 | |
790 default: | |
791 g_free(data_string); | |
792 g_return_if_fail(FALSE); | |
793 break; | |
794 } | |
795 | |
796 g_free(data_string); | |
797 | |
798 **items = string; | |
799 ++(*items); | |
800 } | |
801 | |
687 /** Pack an element into its protocol representation. | 802 /** Pack an element into its protocol representation. |
688 * | 803 * |
689 * @param data Pointer to an MsimMessageElement. | 804 * @param data Pointer to an MsimMessageElement. |
690 * @param user_data Pointer to a gchar ** array of string items. | 805 * @param user_data Pointer to a gchar ** array of string items. |
691 * | 806 * |
700 MsimMessageElement *elem; | 815 MsimMessageElement *elem; |
701 gchar *string, *data_string; | 816 gchar *string, *data_string; |
702 gchar ***items; | 817 gchar ***items; |
703 | 818 |
704 elem = (MsimMessageElement *)data; | 819 elem = (MsimMessageElement *)data; |
705 items = user_data; | 820 items = (gchar ***)user_data; |
706 | 821 |
707 /* Exclude elements beginning with '_' from packed protocol messages. */ | 822 /* Exclude elements beginning with '_' from packed protocol messages. */ |
708 if (elem->name[0] == '_') | 823 if (elem->name[0] == '_') |
709 { | 824 { |
710 return; | 825 return; |
747 **items = string; | 862 **items = string; |
748 ++(*items); | 863 ++(*items); |
749 } | 864 } |
750 | 865 |
751 | 866 |
752 /** Return a packed string suitable for sending over the wire. | 867 /** Return a packed string of a message suitable for sending over the wire. |
753 * | 868 * |
754 * @return A string. Caller must g_free(). | 869 * @return A string. Caller must g_free(). |
755 */ | 870 */ |
756 gchar * | 871 gchar * |
757 msim_msg_pack(MsimMessage *msg) | 872 msim_msg_pack(MsimMessage *msg) |
758 { | 873 { |
759 g_return_val_if_fail(msg != NULL, NULL); | 874 g_return_val_if_fail(msg != NULL, NULL); |
760 | 875 |
761 return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\"); | 876 return msim_msg_pack_using(msg, msim_msg_pack_element, "\\", "\\", "\\final\\"); |
877 } | |
878 | |
879 /** Return a packed string of a dictionary, suitable for embedding in MSIM_TYPE_DICTIONARY. | |
880 * | |
881 * @return A string; caller must g_free(). | |
882 */ | |
883 gchar * | |
884 msim_msg_pack_dict(MsimMessage *msg) | |
885 { | |
886 g_return_val_if_fail(msg != NULL, NULL); | |
887 | |
888 return msim_msg_pack_using(msg, msim_msg_pack_element_dict, "\034", "", ""); | |
762 } | 889 } |
763 | 890 |
764 /** | 891 /** |
765 * Parse a raw protocol message string into a MsimMessage *. | 892 * Parse a raw protocol message string into a MsimMessage *. |
766 * | 893 * |
1003 return NULL; | 1130 return NULL; |
1004 | 1131 |
1005 switch (elem->type) | 1132 switch (elem->type) |
1006 { | 1133 { |
1007 case MSIM_TYPE_LIST: | 1134 case MSIM_TYPE_LIST: |
1008 return msim_msg_list_copy((GList *)(elem->data)); | 1135 return msim_msg_list_copy((GList *)elem->data); |
1009 | 1136 |
1010 case MSIM_TYPE_RAW: | 1137 case MSIM_TYPE_RAW: |
1011 return msim_msg_list_parse((gchar *)(elem->data)); | 1138 return msim_msg_list_parse((gchar *)elem->data); |
1012 | 1139 |
1013 default: | 1140 default: |
1014 purple_debug_info("msim_msg_get_list", "type %d unknown, name %s\n", | 1141 purple_debug_info("msim_msg_get_list", "type %d unknown, name %s\n", |
1142 elem->type, name); | |
1143 return NULL; | |
1144 } | |
1145 } | |
1146 | |
1147 /** Parse a \034-deliminated and =-separated string into a dictionary. TODO */ | |
1148 MsimMessage * | |
1149 msim_msg_dictionary_parse(gchar *raw) | |
1150 { | |
1151 /* TODO - get code from msim_parse_body, but parse into MsimMessage */ | |
1152 return NULL; | |
1153 } | |
1154 | |
1155 /** Return an element as a new dictionary. Caller frees with msim_msg_free(). */ | |
1156 MsimMessage * | |
1157 msim_msg_get_dictionary(MsimMessage *msg, const gchar *name) | |
1158 { | |
1159 MsimMessageElement *elem; | |
1160 | |
1161 elem = msim_msg_get(msg, name); | |
1162 if (!elem) | |
1163 return NULL; | |
1164 | |
1165 switch (elem->type) | |
1166 { | |
1167 case MSIM_TYPE_DICTIONARY: | |
1168 return msim_msg_clone((MsimMessage *)elem->data); | |
1169 | |
1170 case MSIM_TYPE_RAW: | |
1171 return msim_msg_dictionary_parse((gchar *)elem->data); | |
1172 | |
1173 default: | |
1174 purple_debug_info("msim_msg_get_dictionary", "type %d unknown, name %s\n", | |
1015 elem->type, name); | 1175 elem->type, name); |
1016 return NULL; | 1176 return NULL; |
1017 } | 1177 } |
1018 } | 1178 } |
1019 | 1179 |