6 * Purple is the legal property of its developers, whose names are too numerous
7 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #include "glibcompat.h"
28 #include "google_p2p.h"
29 #include "jingle/jingle.h"
34 struct _JingleGoogleP2P
36 JingleTransport parent
;
41 GList
*local_candidates
;
42 GList
*remote_candidates
;
43 } JingleGoogleP2PPrivate
;
47 PROP_LOCAL_CANDIDATES
,
48 PROP_REMOTE_CANDIDATES
,
52 static GParamSpec
*properties
[PROP_LAST
];
54 G_DEFINE_DYNAMIC_TYPE_EXTENDED(
57 JINGLE_TYPE_TRANSPORT
,
59 G_ADD_PRIVATE_DYNAMIC(JingleGoogleP2P
)
62 /******************************************************************************
63 * JingleGoogleP2P Transport Implementation
64 *****************************************************************************/
66 jingle_google_p2p_add_local_candidate(JingleTransport
*transport
, const gchar
*id
,
67 guint generation
, PurpleMediaCandidate
*candidate
)
69 JingleGoogleP2P
*google_p2p
= JINGLE_GOOGLE_P2P(transport
);
70 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(google_p2p
);
71 JingleGoogleP2PCandidate
*google_p2p_candidate
;
75 PurpleMediaCandidateType type
;
76 PurpleMediaNetworkProtocol protocol
;
79 ip
= purple_media_candidate_get_ip(candidate
);
80 username
= purple_media_candidate_get_username(candidate
);
81 password
= purple_media_candidate_get_password(candidate
);
82 type
= purple_media_candidate_get_candidate_type(candidate
);
83 protocol
= purple_media_candidate_get_protocol(candidate
);
85 google_p2p_candidate
= jingle_google_p2p_candidate_new(id
, generation
,
86 ip
, purple_media_candidate_get_port(candidate
),
87 purple_media_candidate_get_priority(candidate
),
88 type
== PURPLE_MEDIA_CANDIDATE_TYPE_HOST
? "host" :
89 type
== PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX
? "srflx" :
90 type
== PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX
? "prflx" :
91 type
== PURPLE_MEDIA_CANDIDATE_TYPE_RELAY
? "relay" :
93 protocol
== PURPLE_MEDIA_NETWORK_PROTOCOL_UDP
? "udp" : "tcp",
100 for (iter
= priv
->local_candidates
; iter
; iter
= g_list_next(iter
)) {
101 JingleGoogleP2PCandidate
*c
= iter
->data
;
102 if (!strcmp(c
->id
, id
)) {
103 generation
= c
->generation
+ 1;
105 g_boxed_free(JINGLE_TYPE_GOOGLE_P2P_CANDIDATE
, c
);
106 priv
->local_candidates
= g_list_delete_link(
107 priv
->local_candidates
, iter
);
109 google_p2p_candidate
->generation
= generation
;
111 priv
->local_candidates
= g_list_append(
112 priv
->local_candidates
, candidate
);
114 g_object_notify_by_pspec(G_OBJECT(google_p2p
), properties
[PROP_LOCAL_CANDIDATES
]);
120 priv
->local_candidates
= g_list_append(
121 priv
->local_candidates
, google_p2p_candidate
);
123 g_object_notify_by_pspec(G_OBJECT(google_p2p
), properties
[PROP_LOCAL_CANDIDATES
]);
126 static JingleGoogleP2PCandidate
*
127 jingle_google_p2p_get_remote_candidate_by_id(JingleGoogleP2P
*google_p2p
,
130 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(google_p2p
);
131 GList
*iter
= priv
->remote_candidates
;
132 for (; iter
; iter
= g_list_next(iter
)) {
133 JingleGoogleP2PCandidate
*candidate
= iter
->data
;
134 if (!strcmp(candidate
->id
, id
)) {
142 jingle_google_p2p_add_remote_candidate(JingleGoogleP2P
*google_p2p
, JingleGoogleP2PCandidate
*candidate
)
144 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(google_p2p
);
145 JingleGoogleP2PCandidate
*google_p2p_candidate
=
146 jingle_google_p2p_get_remote_candidate_by_id(google_p2p
,
148 if (google_p2p_candidate
!= NULL
) {
149 priv
->remote_candidates
= g_list_remove(priv
->remote_candidates
,
150 google_p2p_candidate
);
151 g_boxed_free(JINGLE_TYPE_GOOGLE_P2P_CANDIDATE
, google_p2p_candidate
);
153 priv
->remote_candidates
= g_list_append(priv
->remote_candidates
, candidate
);
155 g_object_notify_by_pspec(G_OBJECT(google_p2p
), properties
[PROP_REMOTE_CANDIDATES
]);
159 jingle_google_p2p_get_remote_candidates(JingleTransport
*transport
)
161 JingleGoogleP2P
*google_p2p
= JINGLE_GOOGLE_P2P(transport
);
162 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(google_p2p
);
163 GList
*candidates
= priv
->remote_candidates
;
166 for (; candidates
; candidates
= g_list_next(candidates
)) {
167 JingleGoogleP2PCandidate
*candidate
= candidates
->data
;
168 PurpleMediaCandidate
*new_candidate
= purple_media_candidate_new("", 0,
169 !strcmp(candidate
->type
, "host") ?
170 PURPLE_MEDIA_CANDIDATE_TYPE_HOST
:
171 !strcmp(candidate
->type
, "srflx") ?
172 PURPLE_MEDIA_CANDIDATE_TYPE_SRFLX
:
173 !strcmp(candidate
->type
, "prflx") ?
174 PURPLE_MEDIA_CANDIDATE_TYPE_PRFLX
:
175 !strcmp(candidate
->type
, "relay") ?
176 PURPLE_MEDIA_CANDIDATE_TYPE_RELAY
: 0,
177 !strcmp(candidate
->protocol
, "udp") ?
178 PURPLE_MEDIA_NETWORK_PROTOCOL_UDP
:
179 PURPLE_MEDIA_NETWORK_PROTOCOL_TCP_PASSIVE
,
180 candidate
->address
, candidate
->port
);
181 g_object_set(new_candidate
,
182 "username", candidate
->username
,
183 "password", candidate
->password
,
184 "priority", candidate
->preference
,
186 ret
= g_list_append(ret
, new_candidate
);
192 static PurpleXmlNode
*
193 jingle_google_p2p_to_xml_internal(JingleTransport
*transport
, PurpleXmlNode
*content
, JingleActionType action
)
195 PurpleXmlNode
*node
= JINGLE_TRANSPORT_CLASS(jingle_google_p2p_parent_class
)->to_xml(transport
, content
, action
);
197 if (action
== JINGLE_SESSION_INITIATE
||
198 action
== JINGLE_SESSION_ACCEPT
||
199 action
== JINGLE_TRANSPORT_INFO
||
200 action
== JINGLE_CONTENT_ADD
||
201 action
== JINGLE_TRANSPORT_REPLACE
) {
202 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(JINGLE_GOOGLE_P2P(transport
));
203 GList
*iter
= priv
->local_candidates
;
205 for (; iter
; iter
= g_list_next(iter
)) {
206 JingleGoogleP2PCandidate
*candidate
= iter
->data
;
207 PurpleXmlNode
*xmltransport
;
208 gchar
*generation
, *network
, *port
, *preference
;
210 if (candidate
->rem_known
== TRUE
)
213 candidate
->rem_known
= TRUE
;
215 xmltransport
= purple_xmlnode_new_child(node
, "candidate");
216 generation
= g_strdup_printf("%d", candidate
->generation
);
217 network
= g_strdup_printf("%d", candidate
->network
);
218 port
= g_strdup_printf("%d", candidate
->port
);
219 preference
= g_strdup_printf("%d", candidate
->preference
);
221 purple_xmlnode_set_attrib(xmltransport
, "generation", generation
);
222 purple_xmlnode_set_attrib(xmltransport
, "name", candidate
->id
);
223 purple_xmlnode_set_attrib(xmltransport
, "address", candidate
->address
);
224 purple_xmlnode_set_attrib(xmltransport
, "network", network
);
225 purple_xmlnode_set_attrib(xmltransport
, "port", port
);
226 purple_xmlnode_set_attrib(xmltransport
, "preference", preference
);
227 purple_xmlnode_set_attrib(xmltransport
, "protocol", candidate
->protocol
);
228 purple_xmlnode_set_attrib(xmltransport
, "type", candidate
->type
);
229 purple_xmlnode_set_attrib(xmltransport
, "username", candidate
->username
);
230 purple_xmlnode_set_attrib(xmltransport
, "password", candidate
->password
);
242 static JingleTransport
*
243 jingle_google_p2p_parse_internal(PurpleXmlNode
*google_p2p
)
245 JingleTransport
*transport
= JINGLE_TRANSPORT_CLASS(jingle_google_p2p_parent_class
)->parse(google_p2p
);
246 PurpleXmlNode
*candidate
= purple_xmlnode_get_child(google_p2p
, "candidate");
247 JingleGoogleP2PCandidate
*google_p2p_candidate
= NULL
;
249 for (; candidate
; candidate
= purple_xmlnode_get_next_twin(candidate
)) {
250 const gchar
*generation
= purple_xmlnode_get_attrib(candidate
, "generation");
251 const gchar
*id
= purple_xmlnode_get_attrib(candidate
, "name");
252 const gchar
*address
= purple_xmlnode_get_attrib(candidate
, "address");
253 const gchar
*port
= purple_xmlnode_get_attrib(candidate
, "port");
254 const gchar
*preference
= purple_xmlnode_get_attrib(candidate
, "preference");
255 const gchar
*type
= purple_xmlnode_get_attrib(candidate
, "type");
256 const gchar
*protocol
= purple_xmlnode_get_attrib(candidate
, "protocol");
257 const gchar
*username
= purple_xmlnode_get_attrib(candidate
, "username");
258 const gchar
*password
= purple_xmlnode_get_attrib(candidate
, "password");
260 if (!generation
|| !id
|| !address
|| !port
|| !preference
||
261 !type
|| !protocol
|| !username
|| !password
)
264 google_p2p_candidate
= jingle_google_p2p_candidate_new(id
,
272 google_p2p_candidate
->rem_known
= TRUE
;
273 jingle_google_p2p_add_remote_candidate(JINGLE_GOOGLE_P2P(transport
), google_p2p_candidate
);
279 /******************************************************************************
280 * JingleGoogleP2P GObject stuff
281 *****************************************************************************/
283 jingle_google_p2p_init(JingleGoogleP2P
*google_p2p
)
288 jingle_google_p2p_finalize(GObject
*google_p2p
)
290 /* JingleGoogleP2PPrivate *priv = JINGLE_GOOGLE_P2P_GET_PRIVATE(google_p2p); */
291 purple_debug_info("jingle","jingle_google_p2p_finalize\n");
293 G_OBJECT_CLASS(jingle_google_p2p_parent_class
)->finalize(google_p2p
);
297 jingle_google_p2p_set_property(GObject
*object
, guint prop_id
, const GValue
*value
, GParamSpec
*pspec
)
299 JingleGoogleP2P
*google_p2p
= JINGLE_GOOGLE_P2P(object
);
300 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(google_p2p
);
303 case PROP_LOCAL_CANDIDATES
:
304 priv
->local_candidates
= g_value_get_pointer(value
);
306 case PROP_REMOTE_CANDIDATES
:
307 priv
->remote_candidates
= g_value_get_pointer(value
);
310 G_OBJECT_WARN_INVALID_PROPERTY_ID(object
, prop_id
, pspec
);
316 jingle_google_p2p_get_property(GObject
*object
, guint prop_id
, GValue
*value
, GParamSpec
*pspec
)
318 JingleGoogleP2P
*google_p2p
= JINGLE_GOOGLE_P2P(object
);
319 JingleGoogleP2PPrivate
*priv
= jingle_google_p2p_get_instance_private(google_p2p
);
322 case PROP_LOCAL_CANDIDATES
:
323 g_value_set_pointer(value
, priv
->local_candidates
);
325 case PROP_REMOTE_CANDIDATES
:
326 g_value_set_pointer(value
, priv
->remote_candidates
);
329 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
335 jingle_google_p2p_class_finalize(JingleGoogleP2PClass
*klass
) {
339 jingle_google_p2p_class_init(JingleGoogleP2PClass
*klass
)
341 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
342 JingleTransportClass
*transport_class
= JINGLE_TRANSPORT_CLASS(klass
);
344 obj_class
->finalize
= jingle_google_p2p_finalize
;
345 obj_class
->set_property
= jingle_google_p2p_set_property
;
346 obj_class
->get_property
= jingle_google_p2p_get_property
;
348 transport_class
->to_xml
= jingle_google_p2p_to_xml_internal
;
349 transport_class
->parse
= jingle_google_p2p_parse_internal
;
350 transport_class
->transport_type
= NS_GOOGLE_TRANSPORT_P2P
;
351 transport_class
->add_local_candidate
= jingle_google_p2p_add_local_candidate
;
352 transport_class
->get_remote_candidates
= jingle_google_p2p_get_remote_candidates
;
354 properties
[PROP_LOCAL_CANDIDATES
] = g_param_spec_pointer("local-candidates",
356 "The local candidates for this transport.",
357 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
359 properties
[PROP_REMOTE_CANDIDATES
] = g_param_spec_pointer("remote-candidates",
361 "The remote candidates for this transport.",
362 G_PARAM_READABLE
| G_PARAM_STATIC_STRINGS
);
364 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
367 /******************************************************************************
368 * JingleGoogleP2PCandidate Boxed Implementation
369 *****************************************************************************/
370 static JingleGoogleP2PCandidate
*
371 jingle_google_p2p_candidate_copy(JingleGoogleP2PCandidate
*candidate
)
373 JingleGoogleP2PCandidate
*new_candidate
= g_new0(JingleGoogleP2PCandidate
, 1);
374 new_candidate
->id
= g_strdup(candidate
->id
);
375 new_candidate
->address
= g_strdup(candidate
->address
);
376 new_candidate
->port
= candidate
->port
;
377 new_candidate
->preference
= candidate
->preference
;
378 new_candidate
->type
= g_strdup(candidate
->type
);
379 new_candidate
->protocol
= g_strdup(candidate
->protocol
);
380 new_candidate
->username
= g_strdup(candidate
->username
);
381 new_candidate
->password
= g_strdup(candidate
->password
);
382 new_candidate
->generation
= candidate
->generation
;
384 new_candidate
->rem_known
= candidate
->rem_known
;
386 return new_candidate
;
390 jingle_google_p2p_candidate_free(JingleGoogleP2PCandidate
*candidate
)
392 g_free(candidate
->id
);
393 g_free(candidate
->address
);
394 g_free(candidate
->type
);
395 g_free(candidate
->protocol
);
396 g_free(candidate
->username
);
397 g_free(candidate
->password
);
400 G_DEFINE_BOXED_TYPE(JingleGoogleP2PCandidate
, jingle_google_p2p_candidate
,
401 jingle_google_p2p_candidate_copy
, jingle_google_p2p_candidate_free
)
404 /******************************************************************************
406 *****************************************************************************/
408 jingle_google_p2p_register(PurplePlugin
*plugin
) {
409 jingle_google_p2p_register_type(G_TYPE_MODULE(plugin
));
412 JingleGoogleP2PCandidate
*
413 jingle_google_p2p_candidate_new(const gchar
*id
, guint generation
,
414 const gchar
*address
, guint port
, guint preference
,
415 const gchar
*type
, const gchar
*protocol
,
416 const gchar
*username
, const gchar
*password
)
418 JingleGoogleP2PCandidate
*candidate
= g_new0(JingleGoogleP2PCandidate
, 1);
419 candidate
->id
= g_strdup(id
);
420 candidate
->address
= g_strdup(address
);
421 candidate
->port
= port
;
422 candidate
->preference
= preference
;
423 candidate
->type
= g_strdup(type
);
424 candidate
->protocol
= g_strdup(protocol
);
425 candidate
->username
= g_strdup(username
);
426 candidate
->password
= g_strdup(password
);
427 candidate
->generation
= generation
;
429 candidate
->rem_known
= FALSE
;