/* * @author Hallyson Melo * * This program 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 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define GST_MYTHTV_ID_NUM 1 #define MYTHTV_VERSION_DEFAULT 30 #define MYTHTV_TRANSFER_MAX_WAITS 100 /* internal GnomeVFS plug-in buffer size ( 120 Kbytes ) */ #define MYTHTV_BUFFER_SIZE 80*1024 /* internally sized GnomeVFS plug-in buffer ( 4 Kbytes ) */ #define MYTHTV_MAX_VFS_BUFFER_SIZE 4096 /* maximum number of bytes to be requested to the MythTV backend ( 64 Kbytes ) */ #define MYTHTV_MAX_REQUEST_SIZE 64*1024 typedef struct { GMythFile *file; GMythLiveTV *livetv; GMythBackendInfo *backend_info; GMythURI *gmyth_uri; GMythRecorder *live_recorder; gboolean started; gint64 offset; gboolean is_livetv; /* it is, or not a Live TV content transfer */ gboolean is_local_file; /* tell if the file is local to the current content transfer */ gchar *channel_name; gint mythtv_version; gboolean configured; } MythtvHandle; static GnomeVFSResult do_read (GnomeVFSMethod * method, GnomeVFSMethodHandle * method_handle, gpointer buffer, GnomeVFSFileSize num_bytes, GnomeVFSFileSize * bytes_read, GnomeVFSContext * context); static GnomeVFSResult myth_connection_start (MythtvHandle * method_handle); static void myth_destroy_handle (MythtvHandle * method_handle); static GnomeVFSResult myth_handle_new (GnomeVFSURI * uri, MythtvHandle ** method_handle); static GnomeVFSResult myth_get_file_info (MythtvHandle * myth_handle, GnomeVFSURI * uri, GnomeVFSFileInfo * info); static GnomeVFSResult myth_handle_new (GnomeVFSURI * uri, MythtvHandle ** method_handle) { gchar *tmp_str1; gchar *tmp_str2; _GNOME_VFS_METHOD_PARAM_CHECK (*method_handle == NULL); if (gnome_vfs_uri_get_host_name (uri) == NULL) { return GNOME_VFS_ERROR_INVALID_HOST_NAME; } *method_handle = g_new0 (MythtvHandle, 1); (*method_handle)->mythtv_version = MYTHTV_VERSION_DEFAULT; (*method_handle)->is_livetv = FALSE; (*method_handle)->is_local_file = FALSE; tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); tmp_str2 = gnome_vfs_unescape_string (tmp_str1, ""); gchar *tmp_str3 = strstr (tmp_str2, ".nuv.avi"); if (tmp_str3 != NULL) { tmp_str3[4] = '\0'; } (*method_handle)->backend_info = gmyth_backend_info_new_with_uri (tmp_str2); (*method_handle)->gmyth_uri = gmyth_uri_new_with_value (tmp_str2); g_free (tmp_str1); g_free (tmp_str2); return GNOME_VFS_OK; } static void myth_destroy_handle (MythtvHandle * method_handle) { //TODO: abort if in tranfer state if (method_handle->backend_info != NULL) { g_object_unref (method_handle->backend_info); method_handle->backend_info = NULL; } if (method_handle->channel_name != NULL) { g_free (method_handle->channel_name); method_handle->channel_name = NULL; } if (method_handle->livetv != NULL) { g_object_unref (method_handle->livetv); method_handle->livetv = NULL; } if (method_handle->file != NULL) { g_object_unref (method_handle->file); method_handle->file = NULL; } if (method_handle->gmyth_uri != NULL) { g_object_unref (method_handle->gmyth_uri); method_handle->gmyth_uri = NULL; } g_free (method_handle); } static GnomeVFSResult myth_get_file_info (MythtvHandle * myth_handle, GnomeVFSURI * uri, GnomeVFSFileInfo * info) { GMythURI *gmyth_uri; GMythBackendInfo *backend_info; gboolean is_livetv; gboolean is_local; _GNOME_VFS_METHOD_PARAM_CHECK (info != NULL); g_debug ("%s - %d", __FUNCTION__, __LINE__); if (myth_handle == NULL) { gchar *tmp_str1; gchar *tmp_str2; tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); tmp_str2 = gnome_vfs_unescape_string (tmp_str1, ""); backend_info = gmyth_backend_info_new_with_uri (tmp_str2); gmyth_uri = gmyth_uri_new_with_value (tmp_str2); g_free (tmp_str1); g_free (tmp_str2); } else { backend_info = g_object_ref (myth_handle->backend_info); gmyth_uri = g_object_ref (myth_handle->gmyth_uri); } info->valid_fields = 0; info->valid_fields = GNOME_VFS_FILE_INFO_FIELDS_TYPE | GNOME_VFS_FILE_INFO_FIELDS_MIME_TYPE | GNOME_VFS_FILE_INFO_FIELDS_PERMISSIONS; info->type = GNOME_VFS_FILE_TYPE_REGULAR; /* fixme: get from file extension? */ info->mime_type = g_strdup ("video/x-nuv"); info->permissions = GNOME_VFS_PERM_USER_READ | GNOME_VFS_PERM_OTHER_READ | GNOME_VFS_PERM_GROUP_READ; info->name = g_strdup (gmyth_uri_get_path (gmyth_uri)); /* file size for remote files */ is_livetv = gmyth_uri_is_livetv (gmyth_uri); if (is_livetv == FALSE) { GMythFile *file = NULL; gboolean ret = FALSE; /* Verifies if the file exists */ if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) { g_object_unref (file); g_object_unref (backend_info); g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__); return GNOME_VFS_ERROR_NOT_FOUND; } is_local = gmyth_uri_is_local_file (gmyth_uri); if (is_local == TRUE ) { file = GMYTH_FILE (gmyth_file_local_new(backend_info)); ret = gmyth_file_local_open (GMYTH_FILE_LOCAL (file)); } else { file = GMYTH_FILE (gmyth_file_transfer_new(backend_info)); ret = gmyth_file_transfer_open (GMYTH_FILE_TRANSFER(file), gmyth_uri_get_path (gmyth_uri)); } if (!ret) { g_object_unref (file); g_object_unref (backend_info); g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__); return GNOME_VFS_ERROR_NOT_FOUND; } info->size = gmyth_file_get_filesize (file); info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE; g_object_unref (file); } g_object_unref (backend_info); g_object_unref (gmyth_uri); return GNOME_VFS_OK; } static GnomeVFSResult myth_connection_start (MythtvHandle * method_handle) { GnomeVFSResult result = GNOME_VFS_OK; _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); _GNOME_VFS_METHOD_PARAM_CHECK (method_handle->backend_info != NULL); /* Connect to the backend */ if ( ( method_handle->is_livetv = gmyth_uri_is_livetv (method_handle->gmyth_uri) ) == TRUE) { method_handle->livetv = gmyth_livetv_new (method_handle->backend_info); method_handle->channel_name = gmyth_uri_get_channel_name (method_handle->gmyth_uri); if (method_handle->channel_name != NULL) { if (gmyth_livetv_channel_name_setup (method_handle->livetv, method_handle->channel_name) == FALSE) { result = GNOME_VFS_ERROR_INVALID_URI; goto error; } } else if (gmyth_livetv_setup (method_handle->livetv) == FALSE) { result = GNOME_VFS_ERROR_INVALID_URI; goto error; } method_handle->file = GMYTH_FILE( gmyth_livetv_create_file_transfer (method_handle->livetv) ); if (method_handle->file == NULL) { result = GNOME_VFS_ERROR_INVALID_URI; g_debug ("MythTV FileTransfer is NULL!\n"); goto error; } if (!gmyth_file_transfer_open ( GMYTH_FILE_TRANSFER(method_handle->file), method_handle->livetv->uri != NULL ? gmyth_uri_get_path (method_handle->livetv->uri) : method_handle->livetv->proginfo->pathname->str)) { g_debug ("Couldn't open MythTV FileTransfer is NULL!\n"); result = GNOME_VFS_ERROR_NOT_OPEN; goto error; } } else { gboolean ret = TRUE; /* Verifies if the file exists */ if (!gmyth_util_file_exists (method_handle->backend_info, gmyth_uri_get_path (method_handle->gmyth_uri))) { g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__); goto error; } if ( ( method_handle->is_local_file = gmyth_uri_is_local_file(method_handle->gmyth_uri) ) == TRUE ) { method_handle->file = GMYTH_FILE( gmyth_file_local_new(method_handle->backend_info) ); ret = gmyth_file_local_open ( GMYTH_FILE_LOCAL( method_handle->file ) ); } else { method_handle->file = GMYTH_FILE( gmyth_file_transfer_new(method_handle->backend_info) ); ret = gmyth_file_transfer_open ( GMYTH_FILE_TRANSFER(method_handle->file), gmyth_uri_get_path (method_handle->gmyth_uri)); } /* sets the Playback monitor connection */ if (!ret) { g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__); result = GNOME_VFS_ERROR_NOT_FOUND; goto error; } } /* if - LiveTV or not? */ method_handle->configured = TRUE; if (method_handle->file == NULL) { result = GNOME_VFS_ERROR_NOT_OPEN; } error: return result; } static GnomeVFSResult do_open (GnomeVFSMethod * method, GnomeVFSMethodHandle ** method_handle, GnomeVFSURI * uri, GnomeVFSOpenMode mode, GnomeVFSContext * context) { MythtvHandle *myth_handle = NULL; GnomeVFSResult result = GNOME_VFS_OK; _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); _GNOME_VFS_METHOD_PARAM_CHECK (uri != NULL); if (mode & GNOME_VFS_OPEN_WRITE) { return GNOME_VFS_ERROR_INVALID_OPEN_MODE; } result = myth_handle_new (uri, &myth_handle); if (result != GNOME_VFS_OK) return result; result = myth_connection_start (myth_handle); if (result != GNOME_VFS_OK) { myth_destroy_handle (myth_handle); myth_handle = NULL; return result; } *method_handle = (GnomeVFSMethodHandle *) myth_handle; return result; } static GnomeVFSResult do_create (GnomeVFSMethod *method, GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri, GnomeVFSOpenMode mode, gboolean exclusive, guint perm, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_close (GnomeVFSMethod * method, GnomeVFSMethodHandle * method_handle, GnomeVFSContext * context) { MythtvHandle *myth_handle = (MythtvHandle *) method_handle; myth_destroy_handle (myth_handle); return GNOME_VFS_OK; } static GnomeVFSResult do_read (GnomeVFSMethod * method, GnomeVFSMethodHandle * method_handle, gpointer buffer, GnomeVFSFileSize num_bytes, GnomeVFSFileSize * bytes_read, GnomeVFSContext * context) { GnomeVFSResult retval = GNOME_VFS_OK; MythtvHandle *myth_handle; GMythFileReadResult result; GByteArray *myth_buffer = g_byte_array_new (); _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); myth_handle = (MythtvHandle *) method_handle; if ( myth_handle->is_local_file ) result = gmyth_file_local_read ( GMYTH_FILE_LOCAL(myth_handle->file), myth_buffer, num_bytes, myth_handle->is_livetv ); else result = gmyth_file_transfer_read ( GMYTH_FILE_TRANSFER(myth_handle->file), myth_buffer, num_bytes, myth_handle->is_livetv ); if (result == GMYTH_FILE_READ_ERROR) { retval = GNOME_VFS_ERROR_IO; } if (result == GMYTH_FILE_READ_EOF) { retval = GNOME_VFS_ERROR_EOF; } if (myth_buffer->len > 0) { g_memmove (buffer, myth_buffer->data, myth_buffer->len); *bytes_read = (GnomeVFSFileSize) myth_buffer->len; myth_handle->offset += myth_buffer->len; g_byte_array_free (myth_buffer, TRUE); } return retval; } static GnomeVFSResult do_write (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, gconstpointer buffer, GnomeVFSFileSize num_bytes, GnomeVFSFileSize *bytes_written, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_seek (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSSeekPosition whence, GnomeVFSFileOffset offset, GnomeVFSContext *context) { MythtvHandle *myth_handle; guint64 whence_p = 0; gint64 new_offset = 0; _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); myth_handle = (MythtvHandle *) method_handle; g_debug ("seek offset %"G_GINT64_FORMAT" whence %d", offset, whence); if (gmyth_uri_is_livetv (myth_handle->gmyth_uri)) return GNOME_VFS_ERROR_NOT_SUPPORTED; switch (whence) { case GNOME_VFS_SEEK_START: whence_p = 0; break; case GNOME_VFS_SEEK_CURRENT: whence_p = myth_handle->offset; break; case GNOME_VFS_SEEK_END: return GNOME_VFS_ERROR_NOT_SUPPORTED; } new_offset = gmyth_file_transfer_seek (myth_handle->file, offset, whence_p); if (new_offset != 0) { myth_handle->offset = new_offset; return GNOME_VFS_OK; } return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_tell (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSFileSize *offset_return) { MythtvHandle *myth_handle = NULL; _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); myth_handle = (MythtvHandle *) method_handle; *offset_return = myth_handle->offset; return GNOME_VFS_OK; } static GnomeVFSResult do_truncate_handle (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSFileSize where, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_open_directory (GnomeVFSMethod *method, GnomeVFSMethodHandle **method_handle, GnomeVFSURI *uri, GnomeVFSFileInfoOptions options, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_close_directory (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_read_directory (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSFileInfo *file_info, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_get_file_info (GnomeVFSMethod * method, GnomeVFSURI * uri, GnomeVFSFileInfo * file_info, GnomeVFSFileInfoOptions options, GnomeVFSContext * context) { return myth_get_file_info (NULL, uri, file_info); } static GnomeVFSResult do_get_file_info_from_handle (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, GnomeVFSFileInfo *file_info, GnomeVFSFileInfoOptions options, GnomeVFSContext *context) { MythtvHandle *myth_handle = (MythtvHandle *) method_handle; return myth_get_file_info (myth_handle, NULL, file_info); } static gboolean do_is_local (GnomeVFSMethod * method, const GnomeVFSURI * uri) { return FALSE; } static GnomeVFSResult do_make_directory (GnomeVFSMethod *method, GnomeVFSURI *uri, guint perm, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_remove_directory (GnomeVFSMethod *method, GnomeVFSURI *uri, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_move (GnomeVFSMethod *method, GnomeVFSURI *old_uri, GnomeVFSURI *new_uri, gboolean force_replace, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_unlink (GnomeVFSMethod *method, GnomeVFSURI *uri, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_check_same_fs (GnomeVFSMethod *method, GnomeVFSURI *a, GnomeVFSURI *b, gboolean *same_fs_return, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_set_file_info (GnomeVFSMethod *method, GnomeVFSURI *uri, const GnomeVFSFileInfo *info, GnomeVFSSetFileInfoMask mask, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_truncate (GnomeVFSMethod *method, GnomeVFSURI *uri, GnomeVFSFileSize where, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_find_directory (GnomeVFSMethod *method, GnomeVFSURI *near_uri, GnomeVFSFindDirectoryKind kind, GnomeVFSURI **result_uri, gboolean create_if_needed, gboolean find_if_needed, guint permissions, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_create_symbolic_link (GnomeVFSMethod *method, GnomeVFSURI *uri, const char *target_reference, GnomeVFSContext *context) { return GNOME_VFS_ERROR_READ_ONLY; } static GnomeVFSResult do_monitor_add (GnomeVFSMethod *method, GnomeVFSMethodHandle **method_handle_return, GnomeVFSURI *uri, GnomeVFSMonitorType monitor_type) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_monitor_cancel (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSResult do_file_control (GnomeVFSMethod *method, GnomeVFSMethodHandle *method_handle, const char *operation, gpointer operation_data, GnomeVFSContext *context) { return GNOME_VFS_ERROR_NOT_SUPPORTED; } static GnomeVFSMethod method = { sizeof (GnomeVFSMethod), do_open, do_create, do_close, do_read, do_write, do_seek, do_tell, do_truncate_handle, do_open_directory, do_close_directory, do_read_directory, do_get_file_info, do_get_file_info_from_handle, do_is_local, do_make_directory, do_remove_directory, do_move, do_unlink, do_check_same_fs, do_set_file_info, do_truncate, do_find_directory, do_create_symbolic_link, do_monitor_add, do_monitor_cancel, do_file_control }; GnomeVFSMethod * vfs_module_init (const char *method_name, const char *args) { return &method; } void vfs_module_shutdown (GnomeVFSMethod * method) { }