comparison libpurple/protocols/bonjour/jabber.c @ 17542:496d007a8912

Some more Bonjour cleanup and leak fixing.
author Daniel Atallah <daniel.atallah@gmail.com>
date Wed, 06 Jun 2007 04:22:15 +0000
parents a62a695ccfb5
children 61005dea822b
comparison
equal deleted inserted replaced
17541:a62a695ccfb5 17542:496d007a8912
121 return "2"; 121 return "2";
122 } 122 }
123 123
124 return "1"; 124 return "1";
125 } 125 }
126
126 static void 127 static void
127 _jabber_parse_and_write_message_to_ui(char *message, PurpleConnection *connection, PurpleBuddy *gb) 128 _jabber_parse_and_write_message_to_ui(char *message, PurpleConnection *connection, PurpleBuddy *gb)
128 { 129 {
129 xmlnode *body_node = NULL; 130 xmlnode *message_node, *body_node, *html_node, *events_node;
130 char *body = NULL; 131 char *body, *html_body = NULL;
131 xmlnode *html_node = NULL;
132 gboolean isHTML = FALSE;
133 xmlnode *html_body_node = NULL;
134 const char *ichat_balloon_color = NULL; 132 const char *ichat_balloon_color = NULL;
135 const char *ichat_text_color = NULL; 133 const char *ichat_text_color = NULL;
136 xmlnode *html_body_font_node = NULL;
137 const char *font_face = NULL; 134 const char *font_face = NULL;
138 const char *font_size = NULL; 135 const char *font_size = NULL;
139 const char *font_color = NULL; 136 const char *font_color = NULL;
140 char *html_body = NULL;
141 xmlnode *events_node = NULL;
142 gboolean composing_event = FALSE; 137 gboolean composing_event = FALSE;
143 gint garbage = -1;
144 xmlnode *message_node = NULL;
145 138
146 /* Parsing of the message */ 139 /* Parsing of the message */
147 message_node = xmlnode_from_str(message, strlen(message)); 140 message_node = xmlnode_from_str(message, strlen(message));
148 if (message_node == NULL) { 141 if (message_node == NULL)
149 return; 142 return;
150 }
151 143
152 body_node = xmlnode_get_child(message_node, "body"); 144 body_node = xmlnode_get_child(message_node, "body");
153 if (body_node != NULL) { 145 if (body_node == NULL) {
154 body = xmlnode_get_data(body_node); 146 xmlnode_free(message_node);
155 } else {
156 return; 147 return;
157 } 148 }
149 body = xmlnode_get_data(body_node);
158 150
159 html_node = xmlnode_get_child(message_node, "html"); 151 html_node = xmlnode_get_child(message_node, "html");
160 if (html_node != NULL) 152 if (html_node != NULL)
161 { 153 {
162 isHTML = TRUE; 154 xmlnode *html_body_node;
155
163 html_body_node = xmlnode_get_child(html_node, "body"); 156 html_body_node = xmlnode_get_child(html_node, "body");
164 if (html_body_node != NULL) 157 if (html_body_node != NULL)
165 { 158 {
159 xmlnode *html_body_font_node;
160
166 ichat_balloon_color = xmlnode_get_attrib(html_body_node, "ichatballooncolor"); 161 ichat_balloon_color = xmlnode_get_attrib(html_body_node, "ichatballooncolor");
167 ichat_text_color = xmlnode_get_attrib(html_body_node, "ichattextcolor"); 162 ichat_text_color = xmlnode_get_attrib(html_body_node, "ichattextcolor");
168 html_body_font_node = xmlnode_get_child(html_body_node, "font"); 163 html_body_font_node = xmlnode_get_child(html_body_node, "font");
169 if (html_body_font_node != NULL) 164 if (html_body_font_node != NULL)
170 { /* Types of messages sent by iChat */ 165 { /* Types of messages sent by iChat */
171 font_face = xmlnode_get_attrib(html_body_font_node, "face"); 166 font_face = xmlnode_get_attrib(html_body_font_node, "face");
172 /* The absolute iChat font sizes should be converted to 1..7 range */ 167 /* The absolute iChat font sizes should be converted to 1..7 range */
173 font_size = xmlnode_get_attrib(html_body_font_node, "ABSZ"); 168 font_size = xmlnode_get_attrib(html_body_font_node, "ABSZ");
174 if (font_size != NULL) 169 if (font_size != NULL)
175 {
176 font_size = _font_size_ichat_to_purple(atoi(font_size)); 170 font_size = _font_size_ichat_to_purple(atoi(font_size));
177 }
178 font_color = xmlnode_get_attrib(html_body_font_node, "color"); 171 font_color = xmlnode_get_attrib(html_body_font_node, "color");
179 html_body = xmlnode_get_data(html_body_font_node); 172 html_body = xmlnode_get_data(html_body_font_node);
180 if (html_body == NULL) 173 if (html_body == NULL)
181 { 174 {
175 gint garbage = -1;
182 /* This is the kind of formated messages that Purple creates */ 176 /* This is the kind of formated messages that Purple creates */
183 html_body = xmlnode_to_str(html_body_font_node, &garbage); 177 html_body = xmlnode_to_str(html_body_font_node, &garbage);
184 } 178 }
185 } else {
186 isHTML = FALSE;
187 } 179 }
188 } else { 180 }
189 isHTML = FALSE;
190 }
191
192 } 181 }
193 182
194 events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event"); 183 events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event");
195 if (events_node != NULL) 184 if (events_node != NULL)
196 { 185 {
199 composing_event = TRUE; 188 composing_event = TRUE;
200 } 189 }
201 if (xmlnode_get_child(events_node, "id") != NULL) 190 if (xmlnode_get_child(events_node, "id") != NULL)
202 { 191 {
203 /* The user is just typing */ 192 /* The user is just typing */
193 /* TODO: Deal with typing notification */
204 xmlnode_free(message_node); 194 xmlnode_free(message_node);
205 g_free(body); 195 g_free(body);
206 g_free(html_body); 196 g_free(html_body);
207 return; 197 return;
208 } 198 }
209 } 199 }
210 200
211 /* Compose the message */ 201 /* Compose the message */
212 if (isHTML) 202 if (html_body != NULL)
213 { 203 {
204 g_free(body);
205
214 if (font_face == NULL) font_face = "Helvetica"; 206 if (font_face == NULL) font_face = "Helvetica";
215 if (font_size == NULL) font_size = "3"; 207 if (font_size == NULL) font_size = "3";
216 if (ichat_text_color == NULL) ichat_text_color = "#000000"; 208 if (ichat_text_color == NULL) ichat_text_color = "#000000";
217 if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF"; 209 if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF";
218 body = g_strconcat("<font face='", font_face, "' size='", font_size, "' color='", ichat_text_color, 210 body = g_strconcat("<font face='", font_face, "' size='", font_size, "' color='", ichat_text_color,
219 "' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL); 211 "' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL);
220 } 212 }
221 213
214 /* TODO: Should we do something with "composing_event" here? */
215
222 /* Send the message to the UI */ 216 /* Send the message to the UI */
223 serv_got_im(connection, gb->name, body, 0, time(NULL)); 217 serv_got_im(connection, gb->name, body, 0, time(NULL));
224 218
225 /* Free all the strings and nodes (the attributes are freed with their nodes) */ 219 /* Free all the strings and nodes (the attributes are freed with their nodes) */
226 xmlnode_free(message_node); 220 xmlnode_free(message_node);
227 g_free(body); 221 g_free(body);
228 g_free(html_body); 222 g_free(html_body);
229 } 223 }
230 224
231 struct _check_buddy_by_address_t { 225 struct _check_buddy_by_address_t {
232 char *address; 226 const char *address;
233 PurpleBuddy **gb; 227 PurpleBuddy **gb;
234 BonjourJabber *bj; 228 BonjourJabber *bj;
235 }; 229 };
236 230
237 static void 231 static void
238 _check_buddy_by_address(gpointer key, gpointer value, gpointer data) 232 _check_buddy_by_address(gpointer key, gpointer value, gpointer data)
239 { 233 {
240 PurpleBuddy *gb = (PurpleBuddy*)value; 234 PurpleBuddy *gb = value;
241 BonjourBuddy *bb; 235 BonjourBuddy *bb;
242 struct _check_buddy_by_address_t *cbba; 236 struct _check_buddy_by_address_t *cbba = data;
243
244 gb = value;
245 cbba = data;
246 237
247 /* 238 /*
248 * If the current PurpleBuddy's data is not null and the PurpleBuddy's account 239 * If the current PurpleBuddy's data is not null and the PurpleBuddy's account
249 * is the same as the account requesting the check then continue to determine 240 * is the same as the account requesting the check then continue to determine
250 * whether the buddies IP matches the target IP. 241 * whether the buddies IP matches the target IP.
272 total_message_length += partial_message_length; 263 total_message_length += partial_message_length;
273 } 264 }
274 265
275 if (partial_message_length == -1) 266 if (partial_message_length == -1)
276 { 267 {
277 purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); 268 if (errno != EAGAIN)
269 purple_debug_warning("bonjour", "receive error: %s\n", strerror(errno));
278 if (total_message_length == 0) { 270 if (total_message_length == 0) {
279 return -1; 271 return -1;
280 } 272 }
281 } 273 }
282 274
283 *message = data->str; 275 *message = g_string_free(data, FALSE);
284 g_string_free(data, FALSE);
285 if (total_message_length != 0) 276 if (total_message_length != 0)
286 purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", *message, total_message_length); 277 purple_debug_info("bonjour", "Receive: -%s- %d bytes\n", *message, total_message_length);
287 278
288 return total_message_length; 279 return total_message_length;
289 } 280 }
311 static void 302 static void
312 _client_socket_handler(gpointer data, gint socket, PurpleInputCondition condition) 303 _client_socket_handler(gpointer data, gint socket, PurpleInputCondition condition)
313 { 304 {
314 char *message = NULL; 305 char *message = NULL;
315 gint message_length; 306 gint message_length;
316 PurpleBuddy *gb = (PurpleBuddy*)data; 307 PurpleBuddy *gb = data;
317 PurpleAccount *account = gb->account; 308 PurpleAccount *account = gb->account;
318 PurpleConversation *conversation; 309 PurpleConversation *conversation;
319 char *closed_conv_message; 310 BonjourBuddy *bb = gb->proto_data;
320 BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data;
321 gboolean closed_conversation = FALSE; 311 gboolean closed_conversation = FALSE;
322 xmlnode *message_node = NULL; 312 xmlnode *message_node;
323 313
324 /* Read the data from the socket */ 314 /* Read the data from the socket */
325 if ((message_length = _read_data(socket, &message)) == -1) { 315 if ((message_length = _read_data(socket, &message)) == -1) {
326 /* There have been an error reading from the socket */ 316 /* There have been an error reading from the socket */
317 /* TODO: Shouldn't we handle the error if it isn't EAGAIN? */
327 return; 318 return;
328 } else if (message_length == 0) { /* The other end has closed the socket */ 319 } else if (message_length == 0) { /* The other end has closed the socket */
329 closed_conversation = TRUE; 320 closed_conversation = TRUE;
330 } else { 321 } else {
331 message[message_length] = '\0'; 322 message[message_length] = '\0';
343 /* data is the start of the stream */ 334 /* data is the start of the stream */
344 if (!(bb->conversation->stream_started)) 335 if (!(bb->conversation->stream_started))
345 { 336 {
346 /* Check if this is the start of the stream */ 337 /* Check if this is the start of the stream */
347 if ((message_node != NULL) && 338 if ((message_node != NULL) &&
348 g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") && 339 g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") &&
349 (xmlnode_get_attrib(message_node,"xmlns:stream") != NULL)) 340 (xmlnode_get_attrib(message_node,"xmlns:stream") != NULL))
350 { 341 {
351 bb->conversation->stream_started = TRUE; 342 bb->conversation->stream_started = TRUE;
352 } 343 }
353 else 344 else
354 { 345 {
355 /* TODO: This needs to be nonblocking! */ 346 /* TODO: This needs to be nonblocking! */
356 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) 347 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1)
357 {
358 purple_debug_error("bonjour", "Unable to start a conversation with %s\n", bb->name); 348 purple_debug_error("bonjour", "Unable to start a conversation with %s\n", bb->name);
359 }
360 else 349 else
361 {
362 bb->conversation->stream_started = TRUE; 350 bb->conversation->stream_started = TRUE;
363 }
364 } 351 }
365 } 352 }
366 353
367 /* 354 /*
368 * Check that this is not the end of the conversation. This is 355 * Check that this is not the end of the conversation. This is
369 * using a magic string, but xmlnode won't play nice when just 356 * using a magic string, but xmlnode won't play nice when just
370 * parsing an end tag 357 * parsing an end tag
371 */ 358 */
372 if (purple_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) { 359 if (purple_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) {
360 char *closed_conv_message;
361
373 /* Close the socket, clear the watcher and free memory */ 362 /* Close the socket, clear the watcher and free memory */
374 if (bb->conversation != NULL) { 363 if (bb->conversation != NULL) {
375 close(bb->conversation->socket); 364 close(bb->conversation->socket);
376 purple_input_remove(bb->conversation->watcher_id); 365 purple_input_remove(bb->conversation->watcher_id);
377 g_free(bb->conversation->buddy_name); 366 g_free(bb->conversation->buddy_name);
398 { 387 {
399 PurpleBuddy *gb = NULL; 388 PurpleBuddy *gb = NULL;
400 struct sockaddr_in their_addr; /* connector's address information */ 389 struct sockaddr_in their_addr; /* connector's address information */
401 socklen_t sin_size = sizeof(struct sockaddr); 390 socklen_t sin_size = sizeof(struct sockaddr);
402 int client_socket; 391 int client_socket;
403 BonjourBuddy *bb = NULL; 392 BonjourBuddy *bb;
404 BonjourJabber *bj = data;
405 char *address_text = NULL; 393 char *address_text = NULL;
406 PurpleBuddyList *bl = purple_get_blist(); 394 PurpleBuddyList *bl = purple_get_blist();
407 struct _check_buddy_by_address_t *cbba; 395 struct _check_buddy_by_address_t *cbba;
408 396
409 /* Check that it is a read condition */ 397 /* Check that it is a read condition */
410 if (condition != PURPLE_INPUT_READ) { 398 if (condition != PURPLE_INPUT_READ)
411 return; 399 return;
412 }
413 400
414 if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1) 401 if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1)
415 {
416 return; 402 return;
417 } 403
418 fcntl(client_socket, F_SETFL, O_NONBLOCK); 404 fcntl(client_socket, F_SETFL, O_NONBLOCK);
419 405
420 /* Look for the buddy that has opened the conversation and fill information */ 406 /* Look for the buddy that has opened the conversation and fill information */
421 address_text = inet_ntoa(their_addr.sin_addr); 407 address_text = inet_ntoa(their_addr.sin_addr);
422 cbba = g_new0(struct _check_buddy_by_address_t, 1); 408 cbba = g_new0(struct _check_buddy_by_address_t, 1);
423 cbba->address = address_text; 409 cbba->address = address_text;
424 cbba->gb = &gb; 410 cbba->gb = &gb;
425 cbba->bj = bj; 411 cbba->bj = data;
426 g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba); 412 g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba);
427 g_free(cbba); 413 g_free(cbba);
428 if (gb == NULL) 414 if (gb == NULL)
429 { 415 {
430 purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n"); 416 purple_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n");
431 close(client_socket); 417 close(client_socket);
432 return; 418 return;
433 } 419 }
434 bb = (BonjourBuddy*)gb->proto_data; 420 bb = gb->proto_data;
435 421
436 /* Check if the conversation has been previously started */ 422 /* Check if the conversation has been previously started */
437 if (bb->conversation == NULL) 423 if (bb->conversation == NULL)
438 { 424 {
439 bb->conversation = g_new(BonjourJabberConversation, 1); 425 bb->conversation = g_new(BonjourJabberConversation, 1);
606 if (bb->conversation->stream_started == FALSE) 592 if (bb->conversation->stream_started == FALSE)
607 { 593 {
608 /* Start the stream */ 594 /* Start the stream */
609 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) 595 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1)
610 { 596 {
611 purple_debug_error("bonjour", "Unable to start a conversation\n"); 597 purple_debug_error("bonjour", "Unable to start a conversation\n");
612 purple_debug_warning("bonjour", "send error: %s\n", strerror(errno)); 598 purple_debug_warning("bonjour", "send error: %s\n", strerror(errno));
613 conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account); 599 conversation = purple_find_conversation_with_account(PURPLE_CONV_TYPE_IM, bb->name, data->account);
614 purple_conversation_write(conversation, NULL, 600 purple_conversation_write(conversation, NULL,
615 _("Unable to send the message, the conversation couldn't be started."), 601 _("Unable to send the message, the conversation couldn't be started."),
616 PURPLE_MESSAGE_SYSTEM, time(NULL)); 602 PURPLE_MESSAGE_SYSTEM, time(NULL));
617 close(bb->conversation->socket); 603 close(bb->conversation->socket);
618 purple_input_remove(bb->conversation->watcher_id); 604 purple_input_remove(bb->conversation->watcher_id);
619 605
620 /* Free all the data related to the conversation */ 606 /* Free all the data related to the conversation */
621 g_free(bb->conversation->buddy_name); 607 g_free(bb->conversation->buddy_name);
622 g_free(bb->conversation); 608 g_free(bb->conversation);
623 bb->conversation = NULL; 609 bb->conversation = NULL;
624 g_free(message); 610 g_free(message);
625 return 0; 611 return 0;
626 } 612 }
627 613
628 bb->conversation->stream_started = TRUE; 614 bb->conversation->stream_started = TRUE;
629 } 615 }
630 616
631 /* Send the message */ 617 /* Send the message */
632 ret = _send_data(bb->conversation->socket, message) == -1; 618 ret = (_send_data(bb->conversation->socket, message) == -1);
633 g_free(message); 619 g_free(message);
634 620
635 if (ret == -1) 621 if (ret == -1)
636 return -10000; 622 return -10000;
637 623
660 } 646 }
661 647
662 void 648 void
663 bonjour_jabber_stop(BonjourJabber *data) 649 bonjour_jabber_stop(BonjourJabber *data)
664 { 650 {
665 PurpleBuddy *gb = NULL; 651 /* Close the server socket and remove the watcher */
666 BonjourBuddy *bb = NULL;
667 GSList *buddies;
668 GSList *l;
669
670 /* Close the server socket and remove all the watcher */
671 if (data->socket >= 0) 652 if (data->socket >= 0)
672 close(data->socket); 653 close(data->socket);
673 if (data->watcher_id > 0) 654 if (data->watcher_id > 0)
674 purple_input_remove(data->watcher_id); 655 purple_input_remove(data->watcher_id);
675 656
676 /* Close all the sockets and remove all the watchers after sending end streams */ 657 /* Close all the conversation sockets and remove all the watchers after sending end streams */
677 if (data->account->gc != NULL) 658 if (data->account->gc != NULL)
678 { 659 {
660 GSList *buddies;
661 GSList *l;
662
679 buddies = purple_find_buddies(data->account, data->account->username); 663 buddies = purple_find_buddies(data->account, data->account->username);
680 for (l = buddies; l; l = l->next) 664 for (l = buddies; l; l = l->next)
681 { 665 bonjour_jabber_close_conversation(data, l->data);
682 gb = (PurpleBuddy*)l->data;
683 bb = (BonjourBuddy*)gb->proto_data;
684 if (bb->conversation != NULL)
685 {
686 send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0);
687 close(bb->conversation->socket);
688 purple_input_remove(bb->conversation->watcher_id);
689 }
690 }
691 g_slist_free(buddies); 666 g_slist_free(buddies);
692 } 667 }
693 } 668 }