Mercurial > pidgin
annotate src/protocols/bonjour/jabber.c @ 13909:8264f52a1142
[gaim-migrate @ 16406]
More of sf patch #1490646, from Jonty Wareing & Jono Cole
"The screen name + hostname of the sending user is sent
in the outgoing jabber message, fixing a sporadic
problem with iChat.
The port in use has been fixed to the one described in
the Bonjour specification and can no longer be changed
in the prpl preferences - modifiying this just stops
the client from being able to start a chat.
The option for a buddy icon has been removed for now as
no code actually uses it yet - we plan to change this
in the future.
This update also introduces automatic local port retry
for up to ten attempts if the port is in
use (e.g. if multiple instances of gaim are running)."
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Mon, 03 Jul 2006 00:37:41 +0000 |
parents | 425e0f861e88 |
children | 6c907830a45f |
rev | line source |
---|---|
11477 | 1 /* |
2 * gaim - Bonjour Protocol Plugin | |
3 * | |
4 * Gaim is the legal property of its developers, whose names are too numerous | |
5 * to list here. Please refer to the COPYRIGHT file distributed with this | |
6 * source distribution. | |
7 * | |
8 * This program is free software; you can redistribute it and/or modify | |
9 * it under the terms of the GNU General Public License as published by | |
10 * the Free Software Foundation; either version 2 of the License, or | |
11 * (at your option) any later version. | |
12 * | |
13 * This program is distributed in the hope that it will be useful, | |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 * GNU General Public License for more details. | |
17 * | |
18 * You should have received a copy of the GNU General Public License | |
19 * along with this program; if not, write to the Free Software | |
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
21 */ | |
11688
1fd2a974379f
[gaim-migrate @ 13974]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11539
diff
changeset
|
22 #ifndef _WIN32 |
11477 | 23 #include <sys/socket.h> |
24 #include <netinet/in.h> | |
25 #include <arpa/inet.h> | |
11688
1fd2a974379f
[gaim-migrate @ 13974]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11539
diff
changeset
|
26 #else |
1fd2a974379f
[gaim-migrate @ 13974]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11539
diff
changeset
|
27 #include "libc_interface.h" |
1fd2a974379f
[gaim-migrate @ 13974]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11539
diff
changeset
|
28 #endif |
1fd2a974379f
[gaim-migrate @ 13974]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11539
diff
changeset
|
29 #include <sys/types.h> |
11477 | 30 #include <glib.h> |
31 #include <glib/gprintf.h> | |
32 #include <unistd.h> | |
33 #include <fcntl.h> | |
34 | |
35 #include "network.h" | |
36 #include "eventloop.h" | |
37 #include "connection.h" | |
38 #include "blist.h" | |
39 #include "xmlnode.h" | |
40 #include "debug.h" | |
41 #include "notify.h" | |
42 #include "util.h" | |
43 | |
44 #include "jabber.h" | |
45 #include "bonjour.h" | |
46 #include "buddy.h" | |
47 | |
12443 | 48 static gint |
11539 | 49 _connect_to_buddy(GaimBuddy *gb) |
11477 | 50 { |
51 gint socket_fd; | |
52 gint retorno = 0; | |
53 struct sockaddr_in buddy_address; | |
11539 | 54 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
55 /* Create a socket and make it non-blocking */ |
11477 | 56 socket_fd = socket(PF_INET, SOCK_STREAM, 0); |
11539 | 57 |
11477 | 58 buddy_address.sin_family = PF_INET; |
59 buddy_address.sin_port = htons(((BonjourBuddy*)(gb->proto_data))->port_p2pj); | |
60 inet_aton(((BonjourBuddy*)(gb->proto_data))->ip, &(buddy_address.sin_addr)); | |
61 memset(&(buddy_address.sin_zero), '\0', 8); | |
11539 | 62 |
11477 | 63 retorno = connect(socket_fd, (struct sockaddr*)&buddy_address, sizeof(struct sockaddr)); |
64 if (retorno == -1) { | |
11823 | 65 gaim_debug_warning("bonjour", "connect error: %s\n", strerror(errno)); |
11477 | 66 } |
67 fcntl(socket_fd, F_SETFL, O_NONBLOCK); | |
68 | |
69 return socket_fd; | |
70 } | |
71 | |
12443 | 72 #if 0 /* this isn't used anywhere... */ |
73 static const char * | |
11539 | 74 _font_size_gaim_to_ichat(int size) |
11477 | 75 { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
76 switch (size) { |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
77 case 1: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
78 return "8"; |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
79 case 2: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
80 return "10"; |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
81 case 3: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
82 return "12"; |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
83 case 4: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
84 return "14"; |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
85 case 5: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
86 return "17"; |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
87 case 6: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
88 return "21"; |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
89 case 7: |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
90 return "24"; |
11477 | 91 } |
11539 | 92 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
93 return "12"; |
11477 | 94 } |
12443 | 95 #endif |
11477 | 96 |
12443 | 97 static const char * |
11539 | 98 _font_size_ichat_to_gaim(int size) |
11477 | 99 { |
100 if (size > 24) { | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
101 return "7"; |
11539 | 102 } else if (size >= 21) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
103 return "6"; |
11539 | 104 } else if (size >= 17) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
105 return "5"; |
11539 | 106 } else if (size >= 14) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
107 return "4"; |
11539 | 108 } else if (size >= 12) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
109 return "3"; |
11539 | 110 } else if (size >= 10) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
111 return "2"; |
11477 | 112 } |
113 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
114 return "1"; |
11477 | 115 } |
12443 | 116 static void |
11539 | 117 _jabber_parse_and_write_message_to_ui(char *message, GaimConnection *connection, GaimBuddy *gb) |
11477 | 118 { |
11539 | 119 xmlnode *body_node = NULL; |
120 char *body = NULL; | |
121 xmlnode *html_node = NULL; | |
11477 | 122 gboolean isHTML = FALSE; |
11539 | 123 xmlnode *html_body_node = NULL; |
124 const char *ichat_balloon_color = NULL; | |
125 const char *ichat_text_color = NULL; | |
126 xmlnode *html_body_font_node = NULL; | |
127 const char *font_face = NULL; | |
128 const char *font_size = NULL; | |
129 const char *font_color = NULL; | |
130 char *html_body = NULL; | |
131 xmlnode *events_node = NULL; | |
11477 | 132 gboolean composing_event = FALSE; |
133 gint garbage = -1; | |
11539 | 134 xmlnode *message_node = NULL; |
11477 | 135 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
136 /* Parsing of the message */ |
11477 | 137 message_node = xmlnode_from_str(message, strlen(message)); |
138 if (message_node == NULL) { | |
139 return; | |
140 } | |
11539 | 141 |
11477 | 142 body_node = xmlnode_get_child(message_node, "body"); |
143 if (body_node != NULL) { | |
144 body = xmlnode_get_data(body_node); | |
145 } else { | |
146 return; | |
147 } | |
11539 | 148 |
11477 | 149 html_node = xmlnode_get_child(message_node, "html"); |
11539 | 150 if (html_node != NULL) |
151 { | |
11477 | 152 isHTML = TRUE; |
153 html_body_node = xmlnode_get_child(html_node, "body"); | |
11539 | 154 if (html_body_node != NULL) |
155 { | |
11477 | 156 ichat_balloon_color = xmlnode_get_attrib(html_body_node, "ichatballooncolor"); |
157 ichat_text_color = xmlnode_get_attrib(html_body_node, "ichattextcolor"); | |
158 html_body_font_node = xmlnode_get_child(html_body_node, "font"); | |
11539 | 159 if (html_body_font_node != NULL) |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
160 { /* Types of messages sent by iChat */ |
11477 | 161 font_face = xmlnode_get_attrib(html_body_font_node, "face"); |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
162 /* The absolute iChat font sizes should be converted to 1..7 range */ |
11477 | 163 font_size = xmlnode_get_attrib(html_body_font_node, "ABSZ"); |
11539 | 164 if (font_size != NULL) |
165 { | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
166 font_size = _font_size_ichat_to_gaim(atoi(font_size)); |
11477 | 167 } |
168 font_color = xmlnode_get_attrib(html_body_font_node, "color"); | |
169 html_body = xmlnode_get_data(html_body_font_node); | |
11539 | 170 if (html_body == NULL) |
171 { | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
172 /* This is the kind of formated messages that Gaim creates */ |
11477 | 173 html_body = xmlnode_to_str(html_body_font_node, &garbage); |
174 } | |
175 } else { | |
176 isHTML = FALSE; | |
177 } | |
178 } else { | |
179 isHTML = FALSE; | |
180 } | |
11539 | 181 |
11477 | 182 } |
11539 | 183 |
11477 | 184 events_node = xmlnode_get_child_with_namespace(message_node, "x", "jabber:x:event"); |
11539 | 185 if (events_node != NULL) |
186 { | |
187 if (xmlnode_get_child(events_node, "composing") != NULL) | |
188 { | |
11477 | 189 composing_event = TRUE; |
190 } | |
11539 | 191 if (xmlnode_get_child(events_node, "id") != NULL) |
192 { | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
193 /* The user is just typing */ |
11477 | 194 xmlnode_free(message_node); |
195 g_free(body); | |
196 g_free(html_body); | |
197 return; | |
198 } | |
199 } | |
11539 | 200 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
201 /* Compose the message */ |
11539 | 202 if (isHTML) |
203 { | |
11477 | 204 if (font_face == NULL) font_face = "Helvetica"; |
205 if (font_size == NULL) font_size = "3"; | |
206 if (ichat_text_color == NULL) ichat_text_color = "#000000"; | |
207 if (ichat_balloon_color == NULL) ichat_balloon_color = "#FFFFFF"; | |
11539 | 208 body = g_strconcat("<font face='", font_face, "' size='", font_size, "' color='", ichat_text_color, |
11477 | 209 "' back='", ichat_balloon_color, "'>", html_body, "</font>", NULL); |
210 } | |
11539 | 211 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
212 /* Send the message to the UI */ |
11477 | 213 serv_got_im(connection, gb->name, body, 0, time(NULL)); |
11539 | 214 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
215 /* Free all the strings and nodes (the attributes are freed with their nodes) */ |
11477 | 216 xmlnode_free(message_node); |
217 g_free(body); | |
218 g_free(html_body); | |
219 } | |
220 | |
12708 | 221 struct _check_buddy_by_address_t { |
222 char *address; | |
223 GaimBuddy **gb; | |
13900 | 224 BonjourJabber *bj; |
12708 | 225 }; |
226 | |
227 static void | |
228 _check_buddy_by_address(gpointer key, gpointer value, gpointer data) | |
11477 | 229 { |
11539 | 230 GaimBuddy *gb = (GaimBuddy*)value; |
13900 | 231 BonjourBuddy *bb; |
232 struct _check_buddy_by_address_t *cbba; | |
233 | |
234 gb = value; | |
235 cbba = data; | |
11539 | 236 |
13900 | 237 /* |
238 * If the current GaimBuddy's data is not null and the GaimBuddy's account | |
239 * is the same as the account requesting the check then continue to determine | |
240 * whether the buddies IP matches the target IP. | |
241 */ | |
242 if (cbba->bj->account == gb->account) | |
243 { | |
244 bb = gb->proto_data; | |
245 if ((bb != NULL) && (g_strcasecmp(bb->ip, cbba->address) == 0)) | |
246 *(cbba->gb) = gb; | |
11477 | 247 } |
248 } | |
249 | |
12443 | 250 static gint |
11539 | 251 _read_data(gint socket, char **message) |
11477 | 252 { |
11539 | 253 GString *data = g_string_new(""); |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
254 char partial_data[512]; |
11477 | 255 gint total_message_length = 0; |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
256 gint partial_message_length = 0; |
11477 | 257 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
258 /* Read chunks of 512 bytes till the end of the data */ |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
259 while ((partial_message_length = recv(socket, partial_data, 512, 0)) > 0) |
11539 | 260 { |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
261 g_string_append_len(data, partial_data, partial_message_length); |
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
262 total_message_length += partial_message_length; |
11477 | 263 } |
11539 | 264 |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
265 if (partial_message_length == -1) |
11539 | 266 { |
11823 | 267 gaim_debug_warning("bonjour", "receive error: %s\n", strerror(errno)); |
11477 | 268 if (total_message_length == 0) { |
269 return -1; | |
270 } | |
271 } | |
272 | |
273 *message = data->str; | |
274 g_string_free(data, FALSE); | |
11539 | 275 if (total_message_length != 0) |
276 gaim_debug_info("bonjour", "Receive: -%s- %d bytes\n", *message, total_message_length); | |
277 | |
11477 | 278 return total_message_length; |
279 } | |
280 | |
12443 | 281 static gint |
11539 | 282 _send_data(gint socket, char *message) |
11477 | 283 { |
284 gint message_len = strlen(message); | |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
285 gint partial_sent = 0; |
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
286 gchar *partial_message = message; |
11539 | 287 |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
288 while ((partial_sent = send(socket, partial_message, message_len, 0)) < message_len) |
11539 | 289 { |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
290 if (partial_sent != -1) { |
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
291 partial_message += partial_sent; |
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
292 message_len -= partial_sent; |
11477 | 293 } else { |
294 return -1; | |
295 } | |
296 } | |
11539 | 297 |
11477 | 298 return strlen(message); |
299 } | |
300 | |
12443 | 301 static void |
11539 | 302 _client_socket_handler(gpointer data, gint socket, GaimInputCondition condition) |
11477 | 303 { |
11539 | 304 char *message = NULL; |
11477 | 305 gint message_length; |
11539 | 306 GaimBuddy *gb = (GaimBuddy*)data; |
307 GaimAccount *account = gb->account; | |
308 GaimConversation *conversation; | |
309 char *closed_conv_message; | |
310 BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data; | |
11477 | 311 gboolean closed_conversation = FALSE; |
13902 | 312 xmlnode *message_node = NULL; |
11477 | 313 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
314 /* Read the data from the socket */ |
11477 | 315 if ((message_length = _read_data(socket, &message)) == -1) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
316 /* There have been an error reading from the socket */ |
11477 | 317 return; |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
318 } else if (message_length == 0) { /* The other end has closed the socket */ |
11477 | 319 closed_conversation = TRUE; |
320 } else { | |
321 message[message_length] = '\0'; | |
11539 | 322 |
11477 | 323 while (g_ascii_iscntrl(message[message_length - 1])) { |
324 message[message_length - 1] = '\0'; | |
325 message_length--; | |
326 } | |
327 } | |
11539 | 328 |
13902 | 329 /* Parse the message into an XMLnode for analysis */ |
330 message_node = xmlnode_from_str(message, strlen(message)); | |
11539 | 331 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
332 /* Check if the start of the stream has been received, if not check that the current */ |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
333 /* data is the start of the stream */ |
13902 | 334 if (!(bb->conversation->stream_started)) |
11539 | 335 { |
13902 | 336 /* Check if this is the start of the stream */ |
337 if ((message_node != NULL) && | |
338 g_ascii_strcasecmp(xmlnode_get_attrib(message_node, "xmlns"), "jabber:client") && | |
339 (xmlnode_get_attrib(message_node,"xmlns:stream") != NULL)) | |
340 { | |
341 bb->conversation->stream_started = TRUE; | |
342 } | |
343 else | |
344 { | |
345 /* TODO: This needs to be nonblocking! */ | |
346 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) | |
347 { | |
348 gaim_debug_error("bonjour", "Unable to start a conversation with %s\n", bb->name); | |
349 } | |
350 else | |
351 { | |
352 bb->conversation->stream_started = TRUE; | |
11477 | 353 } |
354 } | |
355 } | |
11539 | 356 |
13902 | 357 /* |
358 * Check that this is not the end of the conversation. This is | |
359 * using a magic string, but xmlnode won't play nice when just | |
360 * parsing an end tag | |
361 */ | |
11477 | 362 if (g_str_has_prefix(message, STREAM_END) || (closed_conversation == TRUE)) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
363 /* Close the socket, clear the watcher and free memory */ |
11477 | 364 if (bb->conversation != NULL) { |
365 close(bb->conversation->socket); | |
366 gaim_input_remove(bb->conversation->watcher_id); | |
367 g_free(bb->conversation->buddy_name); | |
368 g_free(bb->conversation); | |
369 bb->conversation = NULL; | |
370 } | |
11539 | 371 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
372 /* Inform the user that the conversation has been closed */ |
11498 | 373 conversation = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, gb->name, account); |
13266 | 374 closed_conv_message = g_strdup_printf(_("%s has closed the conversation."), gb->name); |
11477 | 375 gaim_conversation_write(conversation, NULL, closed_conv_message, GAIM_MESSAGE_SYSTEM, time(NULL)); |
13266 | 376 g_free(closed_conv_message); |
11477 | 377 } else { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
378 /* Parse the message to get the data and send to the ui */ |
11477 | 379 _jabber_parse_and_write_message_to_ui(message, account->gc, gb); |
380 } | |
13902 | 381 |
382 xmlnode_free(message_node); | |
11477 | 383 } |
384 | |
12443 | 385 static void |
11539 | 386 _server_socket_handler(gpointer data, int server_socket, GaimInputCondition condition) |
11477 | 387 { |
11539 | 388 GaimBuddy *gb = NULL; |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
389 struct sockaddr_in their_addr; /* connector's address information */ |
11515 | 390 socklen_t sin_size = sizeof(struct sockaddr); |
11477 | 391 int client_socket; |
11539 | 392 BonjourBuddy *bb = NULL; |
13900 | 393 BonjourJabber *bj = data; |
11539 | 394 char *address_text = NULL; |
395 GaimBuddyList *bl = gaim_get_blist(); | |
12733 | 396 struct _check_buddy_by_address_t *cbba; |
11477 | 397 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
398 /* Check that it is a read condition */ |
11477 | 399 if (condition != GAIM_INPUT_READ) { |
400 return; | |
401 } | |
402 | |
11539 | 403 if ((client_socket = accept(server_socket, (struct sockaddr *)&their_addr, &sin_size)) == -1) |
404 { | |
11477 | 405 return; |
406 } | |
407 fcntl(client_socket, F_SETFL, O_NONBLOCK); | |
408 | |
13900 | 409 /* Look for the buddy that has opened the conversation and fill information */ |
11477 | 410 address_text = inet_ntoa(their_addr.sin_addr); |
12733 | 411 cbba = g_new0(struct _check_buddy_by_address_t, 1); |
12708 | 412 cbba->address = address_text; |
413 cbba->gb = &gb; | |
13900 | 414 cbba->bj = bj; |
13249 | 415 g_hash_table_foreach(bl->buddies, _check_buddy_by_address, cbba); |
12708 | 416 g_free(cbba); |
11539 | 417 if (gb == NULL) |
418 { | |
11477 | 419 gaim_debug_info("bonjour", "We don't like invisible buddies, this is not a superheros comic\n"); |
420 close(client_socket); | |
421 return; | |
422 } | |
423 bb = (BonjourBuddy*)gb->proto_data; | |
424 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
425 /* Check if the conversation has been previously started */ |
11539 | 426 if (bb->conversation == NULL) |
427 { | |
11477 | 428 bb->conversation = g_new(BonjourJabberConversation, 1); |
429 bb->conversation->socket = client_socket; | |
430 bb->conversation->stream_started = FALSE; | |
431 bb->conversation->buddy_name = g_strdup(gb->name); | |
432 bb->conversation->message_id = 1; | |
11539 | 433 |
11477 | 434 if (bb->conversation->stream_started == FALSE) { |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
435 /* Start the stream */ |
11477 | 436 send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0); |
437 bb->conversation->stream_started = TRUE; | |
438 } | |
439 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
440 /* Open a watcher for the client socket */ |
11539 | 441 bb->conversation->watcher_id = gaim_input_add(client_socket, GAIM_INPUT_READ, |
11477 | 442 _client_socket_handler, gb); |
443 } else { | |
444 close(client_socket); | |
445 } | |
446 } | |
447 | |
11539 | 448 gint |
449 bonjour_jabber_start(BonjourJabber *data) | |
11477 | 450 { |
451 struct sockaddr_in my_addr; | |
452 int yes = 1; | |
13909 | 453 int i; |
454 gboolean bind_successful; | |
11477 | 455 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
456 /* Open a listening socket for incoming conversations */ |
11539 | 457 if ((data->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) |
458 { | |
13266 | 459 gaim_debug_error("bonjour", "Cannot open socket: %s\n", strerror(errno)); |
460 gaim_connection_error(data->account->gc, _("Cannot open socket")); | |
11477 | 461 return -1; |
462 } | |
11539 | 463 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
464 /* Make the socket reusable */ |
11539 | 465 if (setsockopt(data->socket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) != 0) |
466 { | |
13266 | 467 gaim_debug_error("bonjour", "Error setting socket options: %s\n", strerror(errno)); |
468 gaim_connection_error(data->account->gc, _("Error setting socket options")); | |
11477 | 469 return -1; |
470 } | |
471 | |
472 memset(&my_addr, 0, sizeof(struct sockaddr_in)); | |
473 my_addr.sin_family = PF_INET; | |
11539 | 474 |
13909 | 475 /* Attempt to find a free port */ |
476 bind_successful = FALSE; | |
477 for (i = 0; i < 10; i++) | |
478 { | |
479 my_addr.sin_port = htons(data->port); | |
480 if (bind(data->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == 0) | |
481 { | |
482 bind_successful = TRUE; | |
483 break; | |
484 } | |
485 data->port++; | |
486 } | |
487 | |
488 /* On no! We tried 10 ports and could not bind to ANY of them */ | |
489 if (!bind_successful) | |
11539 | 490 { |
13266 | 491 gaim_debug_error("bonjour", "Cannot bind socket: %s\n", strerror(errno)); |
13909 | 492 gaim_connection_error(data->account->gc, _("Could not bind socket to port")); |
11477 | 493 return -1; |
494 } | |
11539 | 495 |
13909 | 496 /* Attempt to listen on the bound socket */ |
11539 | 497 if (listen(data->socket, 10) != 0) |
498 { | |
13266 | 499 gaim_debug_error("bonjour", "Cannot listen on socket: %s\n", strerror(errno)); |
13909 | 500 gaim_connection_error(data->account->gc, _("Could not listen on socket")); |
11477 | 501 return -1; |
502 } | |
503 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
504 #if 0 |
12730
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12708
diff
changeset
|
505 /* TODO: Why isn't this being used? */ |
d5b8f4dc1622
[gaim-migrate @ 15074]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12708
diff
changeset
|
506 data->socket = gaim_network_listen(data->port, SOCK_STREAM); |
11477 | 507 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
508 if (data->socket == -1) |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
509 { |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
510 gaim_debug_error("bonjour", "No se ha podido crear el socket\n"); |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
511 } |
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
512 #endif |
11477 | 513 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
514 /* Open a watcher in the socket we have just opened */ |
11477 | 515 data->watcher_id = gaim_input_add(data->socket, GAIM_INPUT_READ, _server_socket_handler, data); |
11539 | 516 |
13909 | 517 return data->port; |
11477 | 518 } |
519 | |
11693 | 520 int |
11539 | 521 bonjour_jabber_send_message(BonjourJabber *data, const gchar *to, const gchar *body) |
11477 | 522 { |
11539 | 523 xmlnode *message_node = NULL; |
524 gchar *message = NULL; | |
11477 | 525 gint message_length = -1; |
11539 | 526 xmlnode *message_body_node = NULL; |
527 xmlnode *message_html_node = NULL; | |
528 xmlnode *message_html_body_node = NULL; | |
529 xmlnode *message_html_body_font_node = NULL; | |
530 xmlnode *message_x_node = NULL; | |
11693 | 531 GaimBuddy *gb = NULL; |
532 BonjourBuddy *bb = NULL; | |
11539 | 533 char *conv_message = NULL; |
534 GaimConversation *conversation = NULL; | |
535 char *message_from_ui = NULL; | |
536 char *stripped_message = NULL; | |
537 | |
11693 | 538 gb = gaim_find_buddy(data->account, to); |
539 if (gb == NULL) | |
540 /* You can not send a message to an offline buddy */ | |
541 return -10000; | |
542 | |
543 bb = (BonjourBuddy *)gb->proto_data; | |
544 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
545 /* Enclose the message from the UI within a "font" node */ |
11477 | 546 message_body_node = xmlnode_new("body"); |
547 stripped_message = gaim_markup_strip_html(body); | |
548 xmlnode_insert_data(message_body_node, stripped_message, strlen(stripped_message)); | |
11539 | 549 |
11477 | 550 message_from_ui = g_strconcat("<font>", body, "</font>", NULL); |
551 message_html_body_font_node = xmlnode_from_str(message_from_ui, strlen(message_from_ui)); | |
11539 | 552 |
11477 | 553 message_html_body_node = xmlnode_new("body"); |
554 xmlnode_insert_child(message_html_body_node, message_html_body_font_node); | |
11539 | 555 |
11477 | 556 message_html_node = xmlnode_new("html"); |
557 xmlnode_set_attrib(message_html_node, "xmlns", "http://www.w3.org/1999/xhtml"); | |
558 xmlnode_insert_child(message_html_node, message_html_body_node); | |
559 | |
560 message_x_node = xmlnode_new("x"); | |
561 xmlnode_set_attrib(message_x_node, "xmlns", "jabber:x:event"); | |
562 xmlnode_insert_child(message_x_node, xmlnode_new("composing")); | |
11539 | 563 |
11477 | 564 message_node = xmlnode_new("message"); |
565 xmlnode_set_attrib(message_node, "to", ((BonjourBuddy*)(gb->proto_data))->name); | |
13909 | 566 xmlnode_set_attrib(message_node, "from", data->account->username); |
11477 | 567 xmlnode_set_attrib(message_node, "type", "chat"); |
568 xmlnode_insert_child(message_node, message_body_node); | |
569 xmlnode_insert_child(message_node, message_html_node); | |
570 xmlnode_insert_child(message_node, message_x_node); | |
11539 | 571 |
11477 | 572 message = xmlnode_to_str(message_node, &message_length); |
573 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
574 /* Check if there is a previously open conversation */ |
11539 | 575 if (bb->conversation == NULL) |
576 { | |
11477 | 577 bb->conversation = g_new(BonjourJabberConversation, 1); |
13006
e19c59a6ff11
[gaim-migrate @ 15359]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
12733
diff
changeset
|
578 bb->conversation->socket = _connect_to_buddy(gb); |
11477 | 579 bb->conversation->stream_started = FALSE; |
580 bb->conversation->buddy_name = g_strdup(gb->name); | |
11539 | 581 bb->conversation->watcher_id = gaim_input_add(bb->conversation->socket, |
13902 | 582 GAIM_INPUT_READ, _client_socket_handler, gb); |
11477 | 583 } |
584 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
585 /* Check if the stream for the conversation has been started */ |
11539 | 586 if (bb->conversation->stream_started == FALSE) |
587 { | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
588 /* Start the stream */ |
11539 | 589 if (send(bb->conversation->socket, DOCTYPE, strlen(DOCTYPE), 0) == -1) |
590 { | |
11477 | 591 gaim_debug_error("bonjour", "Unable to start a conversation\n"); |
11823 | 592 gaim_debug_warning("bonjour", "send error: %s\n", strerror(errno)); |
13266 | 593 conv_message = g_strdup(_("Unable to send the message, the conversation couldn't be started.")); |
11498 | 594 conversation = gaim_find_conversation_with_account(GAIM_CONV_TYPE_IM, bb->name, data->account); |
11477 | 595 gaim_conversation_write(conversation, NULL, conv_message, GAIM_MESSAGE_SYSTEM, time(NULL)); |
596 close(bb->conversation->socket); | |
597 gaim_input_remove(bb->conversation->watcher_id); | |
11539 | 598 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
599 /* Free all the data related to the conversation */ |
11477 | 600 g_free(bb->conversation->buddy_name); |
601 g_free(bb->conversation); | |
602 bb->conversation = NULL; | |
11693 | 603 return 0; |
11477 | 604 } |
11539 | 605 |
11477 | 606 bb->conversation->stream_started = TRUE; |
607 } | |
11539 | 608 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
609 /* Send the message */ |
11539 | 610 if (_send_data(bb->conversation->socket, message) == -1) |
11693 | 611 return -10000; |
612 | |
613 return 1; | |
11477 | 614 } |
615 | |
11539 | 616 void |
617 bonjour_jabber_close_conversation(BonjourJabber *data, GaimBuddy *gb) | |
11477 | 618 { |
11539 | 619 BonjourBuddy *bb = (BonjourBuddy*)gb->proto_data; |
620 | |
621 if (bb->conversation != NULL) | |
622 { | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
623 /* Send the end of the stream to the other end of the conversation */ |
11477 | 624 send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0); |
11539 | 625 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
626 /* Close the socket and remove the watcher */ |
11477 | 627 close(bb->conversation->socket); |
628 gaim_input_remove(bb->conversation->watcher_id); | |
11539 | 629 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
630 /* Free all the data related to the conversation */ |
11477 | 631 g_free(bb->conversation->buddy_name); |
632 g_free(bb->conversation); | |
633 bb->conversation = NULL; | |
634 } | |
635 } | |
636 | |
11539 | 637 void |
638 bonjour_jabber_stop(BonjourJabber *data) | |
11477 | 639 { |
11539 | 640 GaimBuddy *gb = NULL; |
641 BonjourBuddy *bb = NULL; | |
642 GSList *buddies; | |
643 GSList *l; | |
644 | |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
645 /* Close the server socket and remove all the watcher */ |
11477 | 646 close(data->socket); |
647 gaim_input_remove(data->watcher_id); | |
11539 | 648 |
11826
e05778d4f12d
[gaim-migrate @ 14117]
Richard Laager <rlaager@wiktel.com>
parents:
11823
diff
changeset
|
649 /* Close all the sockets and remove all the watchers after sending end streams */ |
11539 | 650 if (data->account->gc != NULL) |
651 { | |
11477 | 652 buddies = gaim_find_buddies(data->account, data->account->username); |
11539 | 653 for (l = buddies; l; l = l->next) |
654 { | |
11477 | 655 gb = (GaimBuddy*)l->data; |
656 bb = (BonjourBuddy*)gb->proto_data; | |
11539 | 657 if (bb->conversation != NULL) |
658 { | |
11477 | 659 send(bb->conversation->socket, STREAM_END, strlen(STREAM_END), 0); |
660 close(bb->conversation->socket); | |
661 gaim_input_remove(bb->conversation->watcher_id); | |
662 } | |
663 } | |
664 g_slist_free(buddies); | |
665 } | |
666 } |