Mercurial > pidgin
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 } |