Mercurial > pidgin.yaz
comparison libpurple/protocols/bonjour/jabber.c @ 17791:61005dea822b
Cleanup, fix a leak and prevent the inbound xml from being parsed twice for every message.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Fri, 08 Jun 2007 06:04:06 +0000 |
parents | 496d007a8912 |
children | a1d05bc43d95 |
comparison
equal
deleted
inserted
replaced
17790:a8aa651f341f | 17791:61005dea822b |
---|---|
26 #else | 26 #else |
27 #include "libc_interface.h" | 27 #include "libc_interface.h" |
28 #endif | 28 #endif |
29 #include <sys/types.h> | 29 #include <sys/types.h> |
30 #include <glib.h> | 30 #include <glib.h> |
31 #include <glib/gprintf.h> | |
32 #include <unistd.h> | 31 #include <unistd.h> |
33 #include <fcntl.h> | 32 #include <fcntl.h> |
34 | 33 |
35 #include "network.h" | 34 #include "network.h" |
36 #include "eventloop.h" | 35 #include "eventloop.h" |
123 | 122 |
124 return "1"; | 123 return "1"; |
125 } | 124 } |
126 | 125 |
127 static void | 126 static void |
128 _jabber_parse_and_write_message_to_ui(char *message, PurpleConnection *connection, PurpleBuddy *gb) | 127 _jabber_parse_and_write_message_to_ui(xmlnode *message_node, PurpleConnection *connection, PurpleBuddy *gb) |
129 { | 128 { |
130 xmlnode *message_node, *body_node, *html_node, *events_node; | 129 xmlnode *body_node, *html_node, *events_node; |
131 char *body, *html_body = NULL; | 130 char *body, *html_body = NULL; |
132 const char *ichat_balloon_color = NULL; | 131 const char *ichat_balloon_color = NULL; |
133 const char *ichat_text_color = NULL; | 132 const char *ichat_text_color = NULL; |
134 const char *font_face = NULL; | 133 const char *font_face = NULL; |
135 const char *font_size = NULL; | 134 const char *font_size = NULL; |
136 const char *font_color = NULL; | 135 const char *font_color = NULL; |
137 gboolean composing_event = FALSE; | 136 gboolean composing_event = FALSE; |
138 | 137 |
139 /* Parsing of the message */ | 138 body_node = xmlnode_get_child(message_node, "body"); |
140 message_node = xmlnode_from_str(message, strlen(message)); | 139 if (body_node == NULL) |
141 if (message_node == NULL) | |
142 return; | 140 return; |
143 | |
144 body_node = xmlnode_get_child(message_node, "body"); | |
145 if (body_node == NULL) { | |
146 xmlnode_free(message_node); | |
147 return; | |
148 } | |
149 body = xmlnode_get_data(body_node); | 141 body = xmlnode_get_data(body_node); |
150 | 142 |
151 html_node = xmlnode_get_child(message_node, "html"); | 143 html_node = xmlnode_get_child(message_node, "html"); |
152 if (html_node != NULL) | 144 if (html_node != NULL) |
153 { | 145 { |
169 if (font_size != NULL) | 161 if (font_size != NULL) |
170 font_size = _font_size_ichat_to_purple(atoi(font_size)); | 162 font_size = _font_size_ichat_to_purple(atoi(font_size)); |
171 font_color = xmlnode_get_attrib(html_body_font_node, "color"); | 163 font_color = xmlnode_get_attrib(html_body_font_node, "color"); |
172 html_body = xmlnode_get_data(html_body_font_node); | 164 html_body = xmlnode_get_data(html_body_font_node); |
173 if (html_body == NULL) | 165 if (html_body == NULL) |
174 { | |
175 gint garbage = -1; | |
176 /* This is the kind of formated messages that Purple creates */ | 166 /* This is the kind of formated messages that Purple creates */ |
177 html_body = xmlnode_to_str(html_body_font_node, &garbage); | 167 html_body = xmlnode_to_str(html_body_font_node, NULL); |
178 } | |
179 } | 168 } |
180 } | 169 } |
181 } | 170 } |
182 | 171 |
183 events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event"); | 172 events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event"); |
189 } | 178 } |
190 if (xmlnode_get_child(events_node, "id") != NULL) | 179 if (xmlnode_get_child(events_node, "id") != NULL) |
191 { | 180 { |
192 /* The user is just typing */ | 181 /* The user is just typing */ |
193 /* TODO: Deal with typing notification */ | 182 /* TODO: Deal with typing notification */ |
194 xmlnode_free(message_node); | |
195 g_free(body); | 183 g_free(body); |
196 g_free(html_body); | 184 g_free(html_body); |
197 return; | 185 return; |
198 } | 186 } |
199 } | 187 } |
205 | 193 |
206 if (font_face == NULL) font_face = "Helvetica"; | 194 if (font_face == NULL) font_face = "Helvetica"; |
207 if (font_size == NULL) font_size = "3"; | 195 if (font_size == NULL) font_size = "3"; |
208 if (ichat_text_color == NULL) ichat_text_color = "#000000"; | 196 if (ichat_text_color == NULL) ichat_text_color = "#000000"; |
209 if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF"; | 197 if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF"; |
210 body = g_strconcat("<font face='", font_face, "' size='", font_size, "' color='", ichat_text_color, | 198 body = g_strdup_printf("<font face='%s' size='%s' color='%s' back='%s'>%s</font>", |
211 "' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL); | 199 font_face, font_size, ichat_text_color, ichat_balloon_color, |
200 html_body); | |
212 } | 201 } |
213 | 202 |
214 /* TODO: Should we do something with "composing_event" here? */ | 203 /* TODO: Should we do something with "composing_event" here? */ |
215 | 204 |
216 /* Send the message to the UI */ | 205 /* Send the message to the UI */ |
217 serv_got_im(connection, gb->name, body, 0, time(NULL)); | 206 serv_got_im(connection, gb->name, body, 0, time(NULL)); |
218 | 207 |
219 /* Free all the strings and nodes (the attributes are freed with their nodes) */ | |
220 xmlnode_free(message_node); | |
221 g_free(body); | 208 g_free(body); |
222 g_free(html_body); | 209 g_free(html_body); |
223 } | 210 } |
224 | 211 |
225 struct _check_buddy_by_address_t { | 212 struct _check_buddy_by_address_t { |
354 /* | 341 /* |
355 * Check that this is not the end of the conversation. This is | 342 * Check that this is not the end of the conversation. This is |
356 * using a magic string, but xmlnode won't play nice when just | 343 * using a magic string, but xmlnode won't play nice when just |
357 * parsing an end tag | 344 * parsing an end tag |
358 */ | 345 */ |
359 if (purple_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) { | 346 if (closed_conversation || purple_str_has_prefix(message, STREAM_END)) { |
360 char *closed_conv_message; | 347 char *closed_conv_message; |
361 | 348 |
362 /* Close the socket, clear the watcher and free memory */ | 349 /* Close the socket, clear the watcher and free memory */ |
363 if (bb->conversation != NULL) { | 350 if (bb->conversation != NULL) { |
364 close(bb->conversation->socket); | 351 close(bb->conversation->socket); |
371 /* Inform the user that the conversation has been closed */ | 358 /* Inform the user that the conversation has been closed */ |
372 conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, gb->name, account); | 359 conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, gb->name, account); |
373 closed_conv_message = g_strdup_printf(_("%s has closed the conversation."), gb->name); | 360 closed_conv_message = g_strdup_printf(_("%s has closed the conversation."), gb->name); |
374 purple_conversation_write(conversation, NULL, closed_conv_message, PURPLE_MESSAGE_SYSTEM, time(NULL)); | 361 purple_conversation_write(conversation, NULL, closed_conv_message, PURPLE_MESSAGE_SYSTEM, time(NULL)); |
375 g_free(closed_conv_message); | 362 g_free(closed_conv_message); |
363 } else if (message_node != NULL) { | |
364 /* Parse the message to get the data and send to the ui */ | |
365 _jabber_parse_and_write_message_to_ui(message_node, account->gc, gb); | |
376 } else { | 366 } else { |
377 /* Parse the message to get the data and send to the ui */ | 367 /* TODO: Deal with receiving only a partial message */ |
378 _jabber_parse_and_write_message_to_ui(message, account->gc, gb); | 368 } |
379 } | 369 |
380 | 370 g_free(message); |
381 if (message_node != NULL) | 371 if (message_node != NULL) |
382 xmlnode_free(message_node); | 372 xmlnode_free(message_node); |
383 } | 373 } |
384 | 374 |
385 static void | 375 static void |
424 { | 414 { |
425 bb->conversation = g_new(BonjourJabberConversation, 1); | 415 bb->conversation = g_new(BonjourJabberConversation, 1); |
426 bb->conversation->socket = client_socket; | 416 bb->conversation->socket = client_socket; |
427 bb->conversation->stream_started = FALSE; | 417 bb->conversation->stream_started = FALSE; |
428 bb->conversation->buddy_name = g_strdup(gb->name); | 418 bb->conversation->buddy_name = g_strdup(gb->name); |
429 bb->conversation->message_id = 1; | |
430 | 419 |
431 if (bb->conversation->stream_started == FALSE) { | 420 if (bb->conversation->stream_started == FALSE) { |
432 /* Start the stream */ | 421 /* Start the stream */ |
433 send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0); | 422 send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0); |
434 bb->conversation->stream_started = TRUE; | 423 bb->conversation->stream_started = TRUE; |
515 } | 504 } |
516 | 505 |
517 int | 506 int |
518 bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body) | 507 bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body) |
519 { | 508 { |
520 xmlnode *message_node = NULL; | 509 xmlnode *message_node, *node, *node2; |
521 gchar *message = NULL; | 510 gchar *message; |
522 gint message_length = -1; | 511 PurpleBuddy *pb; |
523 xmlnode *message_body_node = NULL; | 512 BonjourBuddy *bb; |
524 xmlnode *message_html_node = NULL; | 513 int ret; |
525 xmlnode *message_html_body_node = NULL; | 514 |
526 xmlnode *message_html_body_font_node = NULL; | 515 pb = purple_find_buddy(data->account, to); |
527 xmlnode *message_x_node = NULL; | 516 if (pb == NULL) { |
528 PurpleBuddy *gb = NULL; | |
529 BonjourBuddy *bb = NULL; | |
530 PurpleConversation *conversation = NULL; | |
531 char *message_from_ui = NULL; | |
532 char *stripped_message = NULL; | |
533 gint ret; | |
534 | |
535 gb = purple_find_buddy(data->account, to); | |
536 if (gb == NULL) { | |
537 purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to); | 517 purple_debug_info("bonjour", "Can't send a message to an offline buddy (%s).\n", to); |
538 /* You can not send a message to an offline buddy */ | 518 /* You can not send a message to an offline buddy */ |
539 return -10000; | 519 return -10000; |
540 } | 520 } |
541 | 521 |
542 bb = (BonjourBuddy *)gb->proto_data; | 522 bb = pb->proto_data; |
543 | 523 |
544 /* Check if there is a previously open conversation */ | 524 /* Check if there is a previously open conversation */ |
545 if (bb->conversation == NULL) | 525 if (bb->conversation == NULL) |
546 { | 526 { |
547 int socket = _connect_to_buddy(gb); | 527 int socket = _connect_to_buddy(pb); |
548 if (socket < 0) | 528 if (socket < 0) |
549 return -10001; | 529 return -10001; |
550 | 530 |
551 bb->conversation = g_new(BonjourJabberConversation, 1); | 531 bb->conversation = g_new(BonjourJabberConversation, 1); |
552 bb->conversation->socket = socket; | 532 bb->conversation->socket = socket; |
553 bb->conversation->stream_started = FALSE; | 533 bb->conversation->stream_started = FALSE; |
554 bb->conversation->buddy_name = g_strdup(gb->name); | 534 bb->conversation->buddy_name = g_strdup(pb->name); |
555 bb->conversation->watcher_id = purple_input_add(bb->conversation->socket, | 535 bb->conversation->watcher_id = purple_input_add(bb->conversation->socket, |
556 PURPLE_INPUT_READ, _client_socket_handler, gb); | 536 PURPLE_INPUT_READ, _client_socket_handler, pb); |
557 } | 537 } |
538 | |
539 message_node = xmlnode_new("message"); | |
540 xmlnode_set_attrib(message_node, "to", bb->name); | |
541 xmlnode_set_attrib(message_node, "from", purple_account_get_username(data->account)); | |
542 xmlnode_set_attrib(message_node, "type", "chat"); | |
558 | 543 |
559 /* Enclose the message from the UI within a "font" node */ | 544 /* Enclose the message from the UI within a "font" node */ |
560 message_body_node = xmlnode_new("body"); | 545 node = xmlnode_new_child(message_node, "body"); |
561 stripped_message = purple_markup_strip_html(body); | 546 message = purple_markup_strip_html(body); |
562 xmlnode_insert_data(message_body_node, stripped_message, strlen(stripped_message)); | 547 xmlnode_insert_data(node, message, strlen(message)); |
563 g_free(stripped_message); | 548 g_free(message); |
564 | 549 |
565 message_from_ui = g_strconcat("<font>", body, "</font>", NULL); | 550 node = xmlnode_new_child(message_node, "html"); |
566 message_html_body_font_node = xmlnode_from_str(message_from_ui, strlen(message_from_ui)); | 551 xmlnode_set_namespace(node, "http://www.w3.org/1999/xhtml"); |
567 g_free(message_from_ui); | 552 |
568 | 553 node = xmlnode_new_child(node, "body"); |
569 message_html_body_node = xmlnode_new("body"); | 554 message = g_strdup_printf("<font>%s</font>", body); |
570 xmlnode_insert_child(message_html_body_node, message_html_body_font_node); | 555 node2 = xmlnode_from_str(message, strlen(message)); |
571 | 556 g_free(message); |
572 message_html_node = xmlnode_new("html"); | 557 xmlnode_insert_child(node, node2); |
573 xmlnode_set_attrib(message_html_node, "xmlns", "http://www.w3.org/1999/xhtml"); | 558 |
574 xmlnode_insert_child(message_html_node, message_html_body_node); | 559 node = xmlnode_new_child(message_node, "x"); |
575 | 560 xmlnode_set_namespace(node, "jabber:x:event"); |
576 message_x_node = xmlnode_new("x"); | 561 xmlnode_insert_child(node, xmlnode_new("composing")); |
577 xmlnode_set_attrib(message_x_node, "xmlns", "jabber:x:event"); | 562 |
578 xmlnode_insert_child(message_x_node, xmlnode_new("composing")); | 563 |
579 | 564 message = xmlnode_to_str(message_node, NULL); |
580 message_node = xmlnode_new("message"); | |
581 xmlnode_set_attrib(message_node, "to", ((BonjourBuddy*)(gb->proto_data))->name); | |
582 xmlnode_set_attrib(message_node, "from", data->account->username); | |
583 xmlnode_set_attrib(message_node, "type", "chat"); | |
584 xmlnode_insert_child(message_node, message_body_node); | |
585 xmlnode_insert_child(message_node, message_html_node); | |
586 xmlnode_insert_child(message_node, message_x_node); | |
587 | |
588 message = xmlnode_to_str(message_node, &message_length); | |
589 xmlnode_free(message_node); | 565 xmlnode_free(message_node); |
590 | 566 |
591 /* Check if the stream for the conversation has been started */ | 567 /* Check if the stream for the conversation has been started */ |
592 if (bb->conversation->stream_started == FALSE) | 568 if (bb->conversation->stream_started == FALSE) |
593 { | 569 { |
594 /* Start the stream */ | 570 /* Start the stream */ |
595 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) | 571 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) |
596 { | 572 { |
573 PurpleConversation *conv; | |
574 | |
597 purple_debug_error("bonjour", "Unable to start a conversation\n"); | 575 purple_debug_error("bonjour", "Unable to start a conversation\n"); |
598 purple_debug_warning("bonjour", "send error: %s\n", strerror(errno)); | 576 purple_debug_warning("bonjour", "send error: %s\n", strerror(errno)); |
599 conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account); | 577 conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account); |
600 purple_conversation_write(conversation, NULL, | 578 purple_conversation_write(conv, NULL, |
601 _("Unable to send the message, the conversation couldn't be started."), | 579 _("Unable to send the message, the conversation couldn't be started."), |
602 PURPLE_MESSAGE_SYSTEM, time(NULL)); | 580 PURPLE_MESSAGE_SYSTEM, time(NULL)); |
603 close(bb->conversation->socket); | 581 close(bb->conversation->socket); |
604 purple_input_remove(bb->conversation->watcher_id); | 582 purple_input_remove(bb->conversation->watcher_id); |
605 | 583 |
623 | 601 |
624 return 1; | 602 return 1; |
625 } | 603 } |
626 | 604 |
627 void | 605 void |
628 bonjour_jabber_close_conversation(BonjourJabber *data, PurpleBuddy *gb) | 606 bonjour_jabber_close_conversation(PurpleBuddy *pb) |
629 { | 607 { |
630 BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data; | 608 BonjourBuddy *bb = pb->proto_data; |
631 | 609 BonjourJabberConversation *bconv = bb->conversation; |
632 if (bb->conversation != NULL) | 610 |
633 { | 611 if (bconv != NULL) |
634 /* Send the end of the stream to the other end of the conversation */ | 612 { |
635 send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0); | |
636 | |
637 /* Close the socket and remove the watcher */ | 613 /* Close the socket and remove the watcher */ |
638 close(bb->conversation->socket); | 614 if (bconv->socket >= 0) { |
639 purple_input_remove(bb->conversation->watcher_id); | 615 /* Send the end of the stream to the other end of the conversation */ |
616 if (bconv->stream_started) | |
617 send(bconv->socket, STREAM_END, strlen(STREAM_END), 0); | |
618 /* TODO: We're really supposed to wait for "</stream:stream>" before closing the socket */ | |
619 close(bconv->socket); | |
620 } | |
621 purple_input_remove(bconv->watcher_id); | |
640 | 622 |
641 /* Free all the data related to the conversation */ | 623 /* Free all the data related to the conversation */ |
642 g_free(bb->conversation->buddy_name); | 624 g_free(bconv->buddy_name); |
643 g_free(bb->conversation); | 625 g_free(bconv); |
644 bb->conversation = NULL; | 626 bb->conversation = NULL; |
645 } | 627 } |
646 } | 628 } |
647 | 629 |
648 void | 630 void |
655 purple_input_remove(data->watcher_id); | 637 purple_input_remove(data->watcher_id); |
656 | 638 |
657 /* Close all the conversation sockets and remove all the watchers after sending end streams */ | 639 /* Close all the conversation sockets and remove all the watchers after sending end streams */ |
658 if (data->account->gc != NULL) | 640 if (data->account->gc != NULL) |
659 { | 641 { |
660 GSList *buddies; | 642 GSList *buddies, *l; |
661 GSList *l; | 643 |
662 | 644 buddies = purple_find_buddies(data->account, purple_account_get_username(data->account)); |
663 buddies = purple_find_buddies(data->account, data->account->username); | |
664 for (l = buddies; l; l = l->next) | 645 for (l = buddies; l; l = l->next) |
665 bonjour_jabber_close_conversation(data, l->data); | 646 bonjour_jabber_close_conversation(l->data); |
666 g_slist_free(buddies); | 647 g_slist_free(buddies); |
667 } | 648 } |
668 } | 649 } |