2 * Copyright (C) 2007, 2008 OpenedHand Ltd.
4 * Author: Jorn Baayen <jorn@openedhand.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
23 * SECTION:gupnp-root-device
24 * @short_description: Class for root device implementations.
26 * #GUPnPRootDevice allows for implementing root devices.
31 #include <libgssdp/gssdp-resource-group.h>
33 #include "gupnp-root-device.h"
34 #include "gupnp-context-private.h"
35 #include "http-headers.h"
38 G_DEFINE_TYPE (GUPnPRootDevice,
42 struct _GUPnPRootDevicePrivate {
43 GUPnPXMLDoc *description_doc;
45 GSSDPResourceGroup *group;
47 char *description_path;
48 char *description_dir;
49 char *relative_location;
55 PROP_DESCRIPTION_PATH,
61 gupnp_root_device_finalize (GObject *object)
63 GUPnPRootDevice *device;
64 GObjectClass *object_class;
66 device = GUPNP_ROOT_DEVICE (object);
68 g_free (device->priv->description_path);
69 g_free (device->priv->description_dir);
70 g_free (device->priv->relative_location);
73 object_class = G_OBJECT_CLASS (gupnp_root_device_parent_class);
74 object_class->finalize (object);
78 gupnp_root_device_dispose (GObject *object)
80 GUPnPRootDevice *device;
81 GObjectClass *object_class;
83 device = GUPNP_ROOT_DEVICE (object);
85 if (device->priv->group) {
86 g_object_unref (device->priv->group);
87 device->priv->group = NULL;
90 if (device->priv->description_doc) {
91 g_object_unref (device->priv->description_doc);
92 device->priv->description_doc = NULL;
96 object_class = G_OBJECT_CLASS (gupnp_root_device_parent_class);
97 object_class->dispose (object);
101 gupnp_root_device_init (GUPnPRootDevice *device)
103 device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device,
104 GUPNP_TYPE_ROOT_DEVICE,
105 GUPnPRootDevicePrivate);
109 gupnp_root_device_set_property (GObject *object,
114 GUPnPRootDevice *device;
116 device = GUPNP_ROOT_DEVICE (object);
118 switch (property_id) {
119 case PROP_DESCRIPTION_DOC:
120 device->priv->description_doc = g_value_dup_object (value);
122 case PROP_DESCRIPTION_PATH:
123 device->priv->description_path = g_value_dup_string (value);
125 case PROP_DESCRIPTION_DIR:
126 device->priv->description_dir = g_value_dup_string (value);
129 gupnp_root_device_set_available
130 (device, g_value_get_boolean (value));
133 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
139 gupnp_root_device_get_property (GObject *object,
144 GUPnPRootDevice *device;
146 device = GUPNP_ROOT_DEVICE (object);
148 switch (property_id) {
149 case PROP_DESCRIPTION_PATH:
150 g_value_set_string (value,
151 device->priv->description_path);
153 case PROP_DESCRIPTION_DIR:
154 g_value_set_string (value,
155 device->priv->description_dir);
158 g_value_set_boolean (value,
159 gupnp_root_device_get_available (device));
162 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
168 fill_resource_group (xmlNode *element,
169 const char *location,
170 GSSDPResourceGroup *group)
173 xmlChar *udn, *device_type;
177 udn = xml_util_get_child_element_content (element, "UDN");
179 g_warning ("No UDN specified.");
184 device_type = xml_util_get_child_element_content (element,
187 g_warning ("No deviceType specified.");
192 gssdp_resource_group_add_resource_simple (group,
197 usn = g_strdup_printf ("%s::%s", (char *) udn, (char *) device_type);
198 gssdp_resource_group_add_resource_simple (group,
199 (const char *) device_type,
204 xmlFree (device_type);
206 /* Add embedded services */
207 child = xml_util_get_element (element,
211 for (child = child->children; child; child = child->next) {
212 xmlChar *service_type;
214 if (strcmp ("service", (char *) child->name))
217 service_type = xml_util_get_child_element_content
218 (child, "serviceType");
222 usn = g_strdup_printf ("%s::%s",
224 (char *) service_type);
225 gssdp_resource_group_add_resource_simple
227 (const char *) service_type,
232 xmlFree (service_type);
239 /* Add embedded devices */
240 child = xml_util_get_element (element,
244 for (child = child->children; child; child = child->next)
245 if (!strcmp ("device", (char *) child->name))
246 fill_resource_group (child, location, group);
250 /* Load and parse @description_path as an XML document, synchronously. */
252 load_and_parse (const char *description_path)
254 GUPnPXMLDoc *description_doc;
255 GError *error = NULL;
257 /* We don't, so load and parse it */
258 description_doc = gupnp_xml_doc_new_from_path (description_path,
260 if (description_doc == NULL) {
261 g_critical ("Error loading description: %s\n", error->message);
263 g_error_free (error);
266 return description_doc;
270 gupnp_root_device_constructor (GType type,
271 guint n_construct_params,
272 GObjectConstructParam *construct_params)
274 GObjectClass *object_class;
276 GUPnPRootDevice *device;
277 GUPnPContext *context;
278 const char *description_path, *description_dir, *udn;
279 char *desc_path, *location, *usn, *relative_location;
281 GUPnPXMLDoc *description_doc;
282 xmlNode *root_element, *element;
288 /* Get 'description-doc', 'context', 'description-dir' and
289 * 'description-path' property values */
290 description_doc = NULL;
292 description_path = NULL;
293 description_dir = NULL;
295 for (i = 0; i < n_construct_params; i++) {
296 const char *par_name;
298 par_name = construct_params[i].pspec->name;
300 if (strcmp (par_name, "description-doc") == 0) {
302 g_value_get_object (construct_params[i].value);
307 if (strcmp (par_name, "context") == 0) {
309 g_value_get_object (construct_params[i].value);
314 if (strcmp (par_name, "description-path") == 0) {
316 g_value_get_string (construct_params[i].value);
321 if (strcmp (par_name, "description-dir") == 0) {
323 g_value_get_string (construct_params[i].value);
330 g_warning ("No context specified.");
335 if (!description_path) {
336 g_warning ("Path to description document not specified.");
341 if (!description_dir) {
342 g_warning ("Path to description directory not specified.");
347 if (g_path_is_absolute (description_path))
348 desc_path = g_strdup (description_path);
350 desc_path = g_build_filename (description_dir,
354 /* Check whether we have a parsed description document */
355 if (!description_doc) {
356 /* We don't, so load and parse it */
357 description_doc = load_and_parse (desc_path);
358 if (description_doc == NULL)
362 /* Find correct element */
363 root_element = xml_util_get_element ((xmlNode *) description_doc->doc,
367 g_warning ("\"/root\" element not found.");
372 element = xml_util_get_element (root_element,
376 g_warning ("\"/root/device\" element not found.");
381 /* Set 'element' and 'description-doc' properties */
382 for (i = 0; i < n_construct_params; i++) {
383 const char *par_name;
385 par_name = construct_params[i].pspec->name;
387 if (strcmp (par_name, "element") == 0) {
388 g_value_set_pointer (construct_params[i].value,
394 if (strcmp (par_name, "description-doc") == 0) {
395 g_value_set_object (construct_params[i].value,
403 object_class = G_OBJECT_CLASS (gupnp_root_device_parent_class);
405 object = object_class->constructor (type,
408 device = GUPNP_ROOT_DEVICE (object);
410 /* Generate location relative to HTTP root */
411 device->priv->relative_location = g_strdup_printf ("RootDevice%p.xml", object);
413 relative_location = g_strjoin (NULL,
415 device->priv->relative_location,
418 /* Host the description file and dir */
419 gupnp_context_host_path (context, desc_path, relative_location);
420 gupnp_context_host_path (context, device->priv->description_dir, "");
422 /* Generate full location */
423 location = g_strjoin (NULL,
424 _gupnp_context_get_server_url (context),
427 g_free (relative_location);
429 /* Save the URL base, if any */
430 url_base = xml_util_get_child_element_content_uri (root_element,
434 url_base = soup_uri_new (location);
436 /* Set additional properties */
437 g_object_set (object,
438 "location", location,
439 "url-base", url_base,
442 soup_uri_free (url_base);
444 /* Create resource group */
445 device->priv->group = gssdp_resource_group_new (GSSDP_CLIENT (context));
447 /* Add services and devices to resource group */
448 udn = gupnp_device_info_get_udn (GUPNP_DEVICE_INFO (device));
449 usn = g_strdup_printf ("%s::upnp:rootdevice", (const char *) udn);
450 gssdp_resource_group_add_resource_simple (device->priv->group,
456 fill_resource_group (element, location, device->priv->group);
466 gupnp_root_device_class_init (GUPnPRootDeviceClass *klass)
468 GObjectClass *object_class;
470 object_class = G_OBJECT_CLASS (klass);
472 object_class->set_property = gupnp_root_device_set_property;
473 object_class->get_property = gupnp_root_device_get_property;
474 object_class->constructor = gupnp_root_device_constructor;
475 object_class->dispose = gupnp_root_device_dispose;
476 object_class->finalize = gupnp_root_device_finalize;
478 g_type_class_add_private (klass, sizeof (GUPnPRootDevicePrivate));
481 * GUPnPRootDevice:description-doc:
483 * Device description document. Constructor property.
485 g_object_class_install_property
487 PROP_DESCRIPTION_DOC,
488 g_param_spec_object ("description-doc",
489 "Description document",
490 "Device description document",
493 G_PARAM_CONSTRUCT_ONLY |
494 G_PARAM_STATIC_NAME |
495 G_PARAM_STATIC_NICK |
496 G_PARAM_STATIC_BLURB));
499 * GUPnPRootDevice:description-path:
501 * The path to device description document. This could either be an
502 * absolute path or path relative to GUPnPRootDevice:description-dir.
504 g_object_class_install_property
506 PROP_DESCRIPTION_PATH,
507 g_param_spec_string ("description-path",
509 "The path to device descrition document",
512 G_PARAM_CONSTRUCT_ONLY |
513 G_PARAM_STATIC_NAME |
514 G_PARAM_STATIC_NICK |
515 G_PARAM_STATIC_BLURB));
518 * GUPnPRootDevice:description-dir:
520 * The path to directory where description documents are provided.
522 g_object_class_install_property
524 PROP_DESCRIPTION_DIR,
525 g_param_spec_string ("description-dir",
526 "Description Directory",
527 "The path to directory where "
528 "description documents are provided",
531 G_PARAM_CONSTRUCT_ONLY |
532 G_PARAM_STATIC_NAME |
533 G_PARAM_STATIC_NICK |
534 G_PARAM_STATIC_BLURB));
537 * GUPnPRootDevice:available:
539 * TRUE if this device is available.
541 g_object_class_install_property
544 g_param_spec_boolean ("available",
546 "Whether this device is available",
549 G_PARAM_STATIC_NAME |
550 G_PARAM_STATIC_NICK |
551 G_PARAM_STATIC_BLURB));
555 * gupnp_root_device_new
556 * @context: The #GUPnPContext
557 * @description_path: Path to device description document. This could either
558 * be an absolute path or path relative to @description_dir.
559 * @description_dir: Path to directory where description documents are provided.
561 * Create a new #GUPnPRootDevice object, automatically loading and parsing
562 * device description document from @description_path.
564 * Return value: A new @GUPnPRootDevice object.
567 gupnp_root_device_new (GUPnPContext *context,
568 const char *description_path,
569 const char *description_dir)
571 GUPnPResourceFactory *factory;
573 factory = gupnp_resource_factory_get_default ();
575 return gupnp_root_device_new_full (context,
583 * gupnp_root_device_new_full:
584 * @context: A #GUPnPContext
585 * @factory: A #GUPnPResourceFactory
586 * @description_doc: Device description document, or %NULL
587 * @description_path: Path to device description document. This could either
588 * be an absolute path or path relative to @description_dir.
589 * @description_dir: Path to directory where description documents are provided.
591 * Create a new #GUPnPRootDevice, automatically loading and parsing
592 * device description document from @description_path if @description_doc is
595 * Return value: A new #GUPnPRootDevice object.
598 gupnp_root_device_new_full (GUPnPContext *context,
599 GUPnPResourceFactory *factory,
600 GUPnPXMLDoc *description_doc,
601 const char *description_path,
602 const char *description_dir)
604 g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL);
605 g_return_val_if_fail (GUPNP_IS_RESOURCE_FACTORY (factory), NULL);
607 return g_object_new (GUPNP_TYPE_ROOT_DEVICE,
609 "resource-factory", factory,
611 "description-doc", description_doc,
612 "description-path", description_path,
613 "description-dir", description_dir,
618 * gupnp_root_device_set_available:
619 * @root_device: A #GUPnPRootDevice
620 * @available: %TRUE if @root_device should be available
622 * Controls whether or not @root_device is available (announcing
626 gupnp_root_device_set_available (GUPnPRootDevice *root_device,
629 g_return_if_fail (GUPNP_IS_ROOT_DEVICE (root_device));
631 gssdp_resource_group_set_available (root_device->priv->group,
634 g_object_notify (G_OBJECT (root_device), "available");
638 * gupnp_root_device_get_available:
639 * @root_device: A #GUPnPRootDevice
641 * Get whether or not @root_device is available (announcing its presence).
643 * Return value: %TRUE if @root_device is available, %FALSE otherwise.
646 gupnp_root_device_get_available (GUPnPRootDevice *root_device)
648 g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), FALSE);
650 return gssdp_resource_group_get_available (root_device->priv->group);
654 * gupnp_root_device_get_relative_location:
655 * @root_device: A #GUPnPRootDevice
657 * Get the relative location of @root_device.
659 * Return value: The relative location of @root_device.
662 gupnp_root_device_get_relative_location (GUPnPRootDevice *root_device)
664 g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
666 return root_device->priv->relative_location;
670 * gupnp_root_device_get_description_path:
671 * @root_device: A #GUPnPRootDevice
673 * Get the path to the device description document of @root_device.
675 * Return value: The path to device description document of @root_device.
678 gupnp_root_device_get_description_path (GUPnPRootDevice *root_device)
680 g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
682 return root_device->priv->description_path;
686 * gupnp_root_device_get_description_dir:
687 * @root_device: A #GUPnPRootDevice
689 * Get the path to the directory containing description documents related to
692 * Return value: The path to description document directory of @root_device.
695 gupnp_root_device_get_description_dir (GUPnPRootDevice *root_device)
697 g_return_val_if_fail (GUPNP_IS_ROOT_DEVICE (root_device), NULL);
699 return root_device->priv->description_dir;