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 }