Logo Search packages:      
Sourcecode: uget version File versions  Download package

ug_plugin.c

/*
 *
 *   Copyright (C) 2005-2009 by Raymond Huang
 *   plushuang at users.sourceforge.net
 *
 *  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; either
 *  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
 *
 *  ---
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU Lesser General Public License in all respects
 *  for all of the code used other than OpenSSL.  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so.  If you
 *  do not wish to do so, delete this exception statement from your
 *  version.  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 *
 */

#include <string.h>

#include <ug_plugin.h>
#include <ug_class.h>
#include <ug_data_download.h>
#include <ug_utils.h>
#include <ug_stdio.h>
#include <ug_url.h>

// ---------------------------------------------------------------------------
// UgPluginClass
//
void  ug_plugin_class_register (const UgPluginClass* plugin_class)
{
      const gchar**     string;

      plugin_class->global_init ();

      ug_class_register (plugin_class->name, UG_CLASS_PLUGIN, (gpointer) plugin_class);

      if (plugin_class->schemes) {
            for (string = plugin_class->schemes;  *string;  string++)
                  ug_class_register (*string, UG_CLASS_PLUGIN_SCHEME, (gpointer) plugin_class);
      }

      if (plugin_class->file_types) {
            for (string = plugin_class->file_types;  *string;  string++)
                  ug_class_register (*string, UG_CLASS_PLUGIN_FILE_TYPE, (gpointer) plugin_class);
      }
}

void  ug_plugin_class_unregister (const UgPluginClass* plugin_class)
{
      const gchar**     string;

      ug_class_unregister (plugin_class->name, UG_CLASS_PLUGIN);

      if (plugin_class->schemes) {
            for (string = plugin_class->schemes;  *string;  string++)
                  ug_class_unregister (*string, UG_CLASS_PLUGIN_SCHEME);
      }

      if (plugin_class->file_types) {
            for (string = plugin_class->file_types;  *string;  string++)
                  ug_class_unregister (*string, UG_CLASS_PLUGIN_FILE_TYPE);
      }

      plugin_class->global_finalize ();
}

const UgPluginClass*    ug_plugin_class_find (const gchar* name, const gchar* type)
{
      if (type == NULL)
            type = UG_CLASS_PLUGIN;

      return (const UgPluginClass*) ug_class_find (name, type);
}


// ---------------------------------------------------------------------------
// UgPlugin : UgPlugin is a base structure for downloading.
//
UgPlugin*   ug_plugin_new     (const UgPluginClass* plugin_class, UgDataset* dataset)
{
      UgPlugin*   plugin;
      UgInitFunc  init;

      plugin = g_malloc0 (plugin_class->instance_size);

      // initialize base data
      plugin->plugin_class = plugin_class;
      plugin->lock = g_mutex_new ();
      plugin->dataset = ug_data_copy (dataset);
//    plugin->queue = NULL;
//    plugin->state = UG_STATE_STOP;
      plugin->ref_count = 1;

      init = plugin_class->init;
      if (init)
            init (plugin);

      return plugin;
}

UgPlugin*   ug_plugin_new_by_name   (const gchar* name, UgDataset* dataset)
{
      const UgPluginClass*    plugin_class;

      plugin_class = ug_plugin_class_find (name, NULL);
      if (plugin_class == NULL)
            return NULL;
      return ug_plugin_new (plugin_class, dataset);
}

UgPlugin*   ug_plugin_new_by_data   (UgDataset* dataset)
{
      const UgPluginClass*    plugin_class;
      UgDataCommon*     common;
      UgUrlPart*        urlpart;
      UgPathPart*       pathpart;
      gchar*                  string;

      plugin_class = NULL;
      common = ug_dataset_get (dataset, UgDataCommonClass, 0);
      if (common == NULL)
            return NULL;

      if (common->url) {
            urlpart = ug_url_part_new (common->url, -1);
            if (urlpart->url_scheme_len) {
                  string = g_strndup (urlpart->url, urlpart->url_scheme_len);
                  plugin_class = ug_plugin_class_find (string, UG_CLASS_PLUGIN_SCHEME);
                  g_free (string);
            }
            ug_url_part_free (urlpart);
      }
      else if (common->file) {
            pathpart = ug_path_part_new (common->file, -1);
            if (pathpart->file_ext_len) {
                  string = g_strndup (pathpart->file_ext, pathpart->file_ext_len);
                  plugin_class = ug_plugin_class_find (string, UG_CLASS_PLUGIN_FILE_TYPE);
                  g_free (string);
            }
            ug_path_part_free (pathpart);
      }

      if (plugin_class == NULL)
            return NULL;
      return ug_plugin_new (plugin_class, dataset);
}

void  ug_plugin_ref     (UgPlugin* plugin)
{
      plugin->ref_count++;
}

void  ug_plugin_unref   (UgPlugin* plugin)
{
      UgFinalizeFunc    finalize;

      plugin->ref_count--;
      if (plugin->ref_count == 0) {
            finalize = plugin->plugin_class->finalize;
            if (finalize)
                  finalize (plugin);

            // finalize base data
            g_mutex_free (plugin->lock);
            ug_data_free (plugin->dataset);
            ug_data_list_free (plugin->queue);
            g_free (plugin);
      }
}

void  ug_plugin_lock          (UgPlugin* plugin)
{
      g_mutex_lock (plugin->lock);
}

void  ug_plugin_unlock  (UgPlugin* plugin)
{
      g_mutex_unlock (plugin->lock);
}

void ug_plugin_delay (UgPlugin* plugin, guint millisecond)
{
      gulong u_second = millisecond * 1000;

      while (plugin->state == UG_STATE_RUNNING) {
            if (u_second < 250000) {
                  g_usleep (u_second);
                  return;
            }
            g_usleep (250000);
            u_second -= 250000;
      }
}

gboolean    ug_plugin_dispatch (UgPlugin* plugin, UgCallback callback, gpointer callback_data)
{
      UgMessage*  message;
      UgMessage*  prev;
      UgMessage*  tail;

      g_mutex_lock (plugin->lock);
      message = plugin->queue;
      plugin->queue = NULL;
      g_mutex_unlock (plugin->lock);

      if (callback) {
            for (tail = ug_data_list_last (message);  tail;  tail = tail->prev) {
                  // if progress repeat, skip current message.
                  if (tail->type == UG_MESSAGE_PROGRESS) {
                        prev = tail->prev;
                        if (prev && prev->type == UG_MESSAGE_PROGRESS)
                              continue;
                  }
                  callback (plugin, tail, callback_data);
            }
      }

      ug_data_list_free (message);

      return (plugin->state == UG_STATE_RUNNING);
}

void  ug_plugin_post (UgPlugin* plugin, UgMessage* message)
{
      g_mutex_lock (plugin->lock);
      plugin->queue = ug_data_list_prepend (plugin->queue, message);
      g_mutex_unlock (plugin->lock);
}

// concatenate folder and file to new path and try create folder and empty file.
// If folder create failed, post UG_MESSAGE_ERROR_FOLDER_CREATE_FAILED.
// If file exist, it will change filename and post UG_MESSAGE_DATA_FILE_CHANGED.
// if function succeeded, return new path and it's folder length.
gchar*            ug_plugin_create_file (UgPlugin* plugin, const gchar* folder, const gchar* file, guint* folder_len)
{
      UgPathPart*       pathpart;
      GString*          gstr;
      guint             location_len;
      // for file creation
      const gchar*      tail_str;   // string of '.' + filename extension
      guint             head_len;   // length of folder + primary filename
      guint             retry_count;
      int                     fd;

      gstr = g_string_sized_new (80);
      // concatenate full path
      if (folder) {
            g_string_append (gstr, folder);
            if (gstr->len  &&  gstr->str [gstr->len -1] != G_DIR_SEPARATOR)
                  g_string_append_c (gstr, G_DIR_SEPARATOR);
      }
      if (file)
            g_string_append (gstr, file);
      // use UgPathPart to get head_len, tail_str, location_len
      pathpart = ug_path_part_new (gstr->str, gstr->len);
      head_len = gstr->len - pathpart->file_ext_len;
      tail_str = file  + strlen (file) - pathpart->file_ext_len;
      if (pathpart->file_ext) {
            head_len--;
            tail_str--;
      }
      location_len = UG_PATH_PART_LOCATION_LEN (pathpart);
      ug_path_part_free (pathpart);
      // create folder
      if (location_len && ug_create_dir_all (gstr->str, location_len) == -1) {
            ug_plugin_post (plugin, ug_message_new_error (UG_MESSAGE_ERROR_FOLDER_CREATE_FAILED, NULL));
            g_string_free (gstr, TRUE);
            return NULL;
      }

      // create file
      for (retry_count=0;  retry_count < 100;  retry_count++) {
//          fd = open (gstr->str, O_CREAT | O_EXCL | O_RDWR, S_IREAD | S_IWRITE | S_IRGRP | S_IROTH);
            fd = ug_fd_open (gstr->str, UG_FD_O_CREATE | UG_FD_O_EXCL | UG_FD_O_RDWR, UG_FD_S_IREAD | UG_FD_S_IWRITE | UG_FD_S_IRGRP | UG_FD_S_IROTH);
            if (fd != -1) {
//                close (fd);
                  ug_fd_close (fd);
                  break;
            }
            g_string_truncate (gstr, head_len);
            g_string_append_printf (gstr, "(%d)", retry_count);
            g_string_append (gstr, tail_str);
      }
      if (retry_count == 100) {
            ug_plugin_post (plugin, ug_message_new_error (UG_MESSAGE_ERROR_FILE_CREATE_FAILED, NULL));
            g_string_free (gstr, TRUE);
            return NULL;
      }
      if (retry_count > 0)
            ug_plugin_post (plugin, ug_message_new_data (UG_MESSAGE_DATA_FILE_CHANGED, gstr->str + location_len));

      if (folder_len)
            *folder_len = location_len;
      return g_string_free (gstr, FALSE);
}

// rename file from old_utf8 to new_utf8.
// If file rename fail, it will post UG_MESSAGE_WARNING_FILE_RENAME_FAILED and return FALSE.
gboolean    ug_plugin_rename_file (UgPlugin* plugin, const gchar* old_utf8, const gchar* new_utf8)
{
      if (ug_rename_file (old_utf8, new_utf8) == 0)
            return TRUE;

      // file rename failed.
      ug_plugin_post (plugin, ug_message_new_warning (UG_MESSAGE_WARNING_FILE_RENAME_FAILED, NULL));
      return FALSE;
}

// --- virtual functions ---
UgResult ug_plugin_set_state (UgPlugin* plugin, UgState  state)
{
      UgSetStateFunc  set_state = plugin->plugin_class->set_state;

      if (set_state)
            return set_state (plugin, state);
      return UG_RESULT_UNSUPPORT;
}

UgResult ug_plugin_get_state (UgPlugin* plugin, UgState* state)
{
      UgGetStateFunc  get_state = plugin->plugin_class->get_state;

      if (get_state)
            return get_state (plugin, state);
      return UG_RESULT_UNSUPPORT;
}

UgResult ug_plugin_get (UgPlugin* plugin, guint parameter, gpointer data)
{
      UgGetFunc  get = plugin->plugin_class->get;

      if (get)
            return get (plugin, parameter, data);
      return UG_RESULT_UNSUPPORT;
}


Generated by  Doxygen 1.6.0   Back to index