<commit_before>/*
 * Copyright (C) 2010 Igalia S.L.
 *
 * This component is based on Maemo's mafw-upnp-source source code.
 *
 * Contact: <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <grilo.h>
#include <libgupnp/gupnp.h>
#include <libgupnp-av/gupnp-av.h>
#include <string.h>
#include <stdlib.h>

#ifndef GUPNPAV_OLD_VERSION
#include <libxml/tree.h>
#endif

#include "grl-upnp.h"

#define GRL_UPNP_GET_PRIVATE(object)                                    \
  (G_TYPE_INSTANCE_GET_PRIVATE((object), GRL_UPNP_SOURCE_TYPE, GrlUpnpPrivate))

/* --------- Logging  -------- */

#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "grl-upnp"

/* --- Plugin information --- */

#define PLUGIN_ID   "grl-upnp"
#define PLUGIN_NAME "UPnP"
#define PLUGIN_DESC "A plugin for browsing UPnP servers"

#define SOURCE_ID_TEMPLATE    "grl-upnp-%s"
#define SOURCE_NAME_TEMPLATE  "UPnP - %s"
#define SOURCE_DESC_TEMPLATE  "A source for browsing the UPnP server '%s'"

#define AUTHOR      "<NAME>."
#define LICENSE     "LGPL"
#define SITE        "http://www.igalia.com"

/* --- Other --- */

#ifndef CONTENT_DIR_SERVICE
#define CONTENT_DIR_SERVICE "urn:schemas-upnp-org:service:ContentDirectory"
#endif

#define UPNP_SEARCH_SPEC				\
  "dc:title contains \"%s\" or "			\
  "upnp:album contains \"%s\" or "			\
  "upnp:artist contains \"%s\""

struct _GrlUpnpPrivate {
  GUPnPDeviceProxy* device;
  GUPnPServiceProxy* service;
  gboolean search_enabled;
  gchar *upnp_name;
};

struct OperationSpec {
  GrlMediaSource *source;
  guint operation_id;
  GList *keys;
  guint skip;
  guint count;
  GrlMediaSourceResultCb callback;
  gpointer user_data;
};

struct SourceInfo {
  gchar *source_id;
  gchar *source_name;
  GUPnPDeviceProxy* device;
  GUPnPServiceProxy* service;
  GrlPluginInfo *plugin;
};

static void setup_key_mappings (void);

static gchar *build_source_id (const gchar *udn);

static GrlUpnpSource *grl_upnp_source_new (const gchar *id, const gchar *name);

gboolean grl_upnp_plugin_init (GrlPluginRegistry *registry,
                               const GrlPluginInfo *plugin,
                               GList *configs);

static void grl_upnp_source_finalize (GObject *plugin);

static const GList *grl_upnp_source_supported_keys (GrlMetadataSource *source);

static void grl_upnp_source_browse (GrlMediaSource *source,
                                    GrlMediaSourceBrowseSpec *bs);

static void grl_upnp_source_search (GrlMediaSource *source,
                                    GrlMediaSourceSearchSpec *ss);

static void grl_upnp_source_metadata (GrlMediaSource *source,
                                      GrlMediaSourceMetadataSpec *ms);

static GrlSupportedOps grl_upnp_source_supported_operations (GrlMetadataSource *source);

static void device_available_cb (GUPnPControlPoint *cp,
				 GUPnPDeviceProxy *device,
				 gpointer user_data);
static void device_unavailable_cb (GUPnPControlPoint *cp,
				   GUPnPDeviceProxy *device,
				   gpointer user_data);

/* ===================== Globals  ================= */

static GHashTable *key_mapping = NULL;
static GHashTable *filter_key_mapping = NULL;

/* =================== UPnP Plugin  =============== */

gboolean
grl_upnp_plugin_init (GrlPluginRegistry *registry,
                      const GrlPluginInfo *plugin,
                      GList *configs)
{
  GError *error = NULL;
  GUPnPContext *context;
  GUPnPControlPoint *cp;

  g_debug ("grl_upnp_plugin_init\n");

  /* libsoup needs this */
  if (!g_thread_supported()) {
    g_thread_init (NULL);
  }

  context = gupnp_context_new (NULL, NULL, 0, &error);
  if (error) {
    g_critical ("Failed to create GUPnP context: %s", error->message);
    g_error_free (error);
    return FALSE;
  }

  cp = gupnp_control_point_new (context, "ssdp:all");
  if (!cp) {
    g_critical ("Failed to create control point");
    return FALSE;
  }
  g_signal_connect (cp,
		    "device-proxy-available",
		    G_CALLBACK (device_available_cb),
		    (gpointer) plugin);
  g_signal_connect (cp,
		    "device-proxy-unavailable",
		    G_CALLBACK (device_unavailable_cb),
		    NULL);

  gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);

  return TRUE;
}

GRL_PLUGIN_REGISTER (grl_upnp_plugin_init,
                     NULL,
                     PLUGIN_ID,
                     PLUGIN_NAME,
                     PLUGIN_DESC,
                     PACKAGE_VERSION,
                     AUTHOR,
                     LICENSE,
                     SITE);

/* ================== UPnP GObject ================ */

G_DEFINE_TYPE (GrlUpnpSource, grl_upnp_source, GRL_TYPE_MEDIA_SOURCE);

static GrlUpnpSource *
grl_upnp_source_new (const gchar *source_id, const gchar *name)
{<commit_msg>[upnp] Use the new way to register the plugin<commit_after>/*
 * Copyright (C) 2010 Igalia S.L.
 *
 * This component is based on Maemo's mafw-upnp-source source code.
 *
 * Contact: <NAME> <<EMAIL>>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 *
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <grilo.h>
#include <libgupnp/gupnp.h>
#include <libgupnp-av/gupnp-av.h>
#include <string.h>
#include <stdlib.h>

#ifndef GUPNPAV_OLD_VERSION
#include <libxml/tree.h>
#endif

#include "grl-upnp.h"

#define GRL_UPNP_GET_PRIVATE(object)                                    \
  (G_TYPE_INSTANCE_GET_PRIVATE((object), GRL_UPNP_SOURCE_TYPE, GrlUpnpPrivate))

/* --------- Logging  -------- */

#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "grl-upnp"

/* --- Plugin information --- */

#define PLUGIN_ID   "grl-upnp"

#define SOURCE_ID_TEMPLATE    "grl-upnp-%s"
#define SOURCE_NAME_TEMPLATE  "UPnP - %s"
#define SOURCE_DESC_TEMPLATE  "A source for browsing the UPnP server '%s'"

#define AUTHOR      "<NAME>."
#define LICENSE     "LGPL"
#define SITE        "http://www.igalia.com"

/* --- Other --- */

#ifndef CONTENT_DIR_SERVICE
#define CONTENT_DIR_SERVICE "urn:schemas-upnp-org:service:ContentDirectory"
#endif

#define UPNP_SEARCH_SPEC				\
  "dc:title contains \"%s\" or "			\
  "upnp:album contains \"%s\" or "			\
  "upnp:artist contains \"%s\""

struct _GrlUpnpPrivate {
  GUPnPDeviceProxy* device;
  GUPnPServiceProxy* service;
  gboolean search_enabled;
  gchar *upnp_name;
};

struct OperationSpec {
  GrlMediaSource *source;
  guint operation_id;
  GList *keys;
  guint skip;
  guint count;
  GrlMediaSourceResultCb callback;
  gpointer user_data;
};

struct SourceInfo {
  gchar *source_id;
  gchar *source_name;
  GUPnPDeviceProxy* device;
  GUPnPServiceProxy* service;
  GrlPluginInfo *plugin;
};

static void setup_key_mappings (void);

static gchar *build_source_id (const gchar *udn);

static GrlUpnpSource *grl_upnp_source_new (const gchar *id, const gchar *name);

gboolean grl_upnp_plugin_init (GrlPluginRegistry *registry,
                               const GrlPluginInfo *plugin,
                               GList *configs);

static void grl_upnp_source_finalize (GObject *plugin);

static const GList *grl_upnp_source_supported_keys (GrlMetadataSource *source);

static void grl_upnp_source_browse (GrlMediaSource *source,
                                    GrlMediaSourceBrowseSpec *bs);

static void grl_upnp_source_search (GrlMediaSource *source,
                                    GrlMediaSourceSearchSpec *ss);

static void grl_upnp_source_metadata (GrlMediaSource *source,
                                      GrlMediaSourceMetadataSpec *ms);

static GrlSupportedOps grl_upnp_source_supported_operations (GrlMetadataSource *source);

static void device_available_cb (GUPnPControlPoint *cp,
				 GUPnPDeviceProxy *device,
				 gpointer user_data);
static void device_unavailable_cb (GUPnPControlPoint *cp,
				   GUPnPDeviceProxy *device,
				   gpointer user_data);

/* ===================== Globals  ================= */

static GHashTable *key_mapping = NULL;
static GHashTable *filter_key_mapping = NULL;

/* =================== UPnP Plugin  =============== */

gboolean
grl_upnp_plugin_init (GrlPluginRegistry *registry,
                      const GrlPluginInfo *plugin,
                      GList *configs)
{
  GError *error = NULL;
  GUPnPContext *context;
  GUPnPControlPoint *cp;

  g_debug ("grl_upnp_plugin_init\n");

  /* libsoup needs this */
  if (!g_thread_supported()) {
    g_thread_init (NULL);
  }

  context = gupnp_context_new (NULL, NULL, 0, &error);
  if (error) {
    g_critical ("Failed to create GUPnP context: %s", error->message);
    g_error_free (error);
    return FALSE;
  }

  cp = gupnp_control_point_new (context, "ssdp:all");
  if (!cp) {
    g_critical ("Failed to create control point");
    return FALSE;
  }
  g_signal_connect (cp,
		    "device-proxy-available",
		    G_CALLBACK (device_available_cb),
		    (gpointer) plugin);
  g_signal_connect (cp,
		    "device-proxy-unavailable",
		    G_CALLBACK (device_unavailable_cb),
		    NULL);

  gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE);

  return TRUE;
}

GRL_PLUGIN_REGISTER (grl_upnp_plugin_init,
                     NULL,
                     PLUGIN_ID);

/* ================== UPnP GObject ================ */

G_DEFINE_TYPE (GrlUpnpSource, grl_upnp_source, GRL_TYPE_MEDIA_SOURCE);

static GrlUpnpSource *
grl_upnp_source_new (const gchar *source_id, const gchar *name)
{
{'fraction_non_alphanumeric': 0.11323226651693805, 'fraction_numerical': 0.003368893879842785, 'mean_word_length': 3.295418006430868, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1833484', 'n_tokens_mistral': 3688, 'n_tokens_neox': 3520, 'n_words': 917}