/* * @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 #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 { GMythFileTransfer *file_transfer; GMythLiveTV *livetv; GMythBackendInfo *backend_info; GMythURI *gmyth_uri; GMythRecorder *live_recorder; gint64 offset; 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; tmp_str1 = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); tmp_str2 = gnome_vfs_unescape_string (tmp_str1, ""); (*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_transfer != NULL) { g_object_unref (method_handle->file_transfer); method_handle->file_transfer = 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; _GNOME_VFS_METHOD_PARAM_CHECK (info != NULL); 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 */ if (gmyth_uri_is_livetv (gmyth_uri) == FALSE) { GMythFileTransfer *file_transfer = gmyth_file_transfer_new (backend_info); /* Verifies if the file exists */ if (!gmyth_util_file_exists (backend_info, gmyth_uri_get_path (gmyth_uri))) { g_object_unref (backend_info); g_debug ("NOT FOUND %s/%d", __FUNCTION__, __LINE__); return GNOME_VFS_ERROR_NOT_FOUND; } info->size = gmyth_file_transfer_get_filesize (file_transfer); info->valid_fields |= GNOME_VFS_FILE_INFO_FIELDS_SIZE; g_object_unref (file_transfer); } 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 (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); g_debug ("[%s] Channel name = %s\n", __FUNCTION__, method_handle->channel_name); 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_transfer = gmyth_livetv_create_file_transfer (method_handle->livetv); if (method_handle->file_transfer == NULL) { result = GNOME_VFS_ERROR_INVALID_URI; g_debug ("MythTV FileTransfer is NULL!\n"); goto error; } if (!gmyth_file_transfer_open (method_handle->file_transfer, 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 { method_handle->file_transfer = gmyth_file_transfer_new (method_handle->backend_info); /* 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__); result = GNOME_VFS_ERROR_NOT_FOUND; goto error; } /* sets the Playback monitor connection */ result = gmyth_file_transfer_open (method_handle->file_transfer, gmyth_uri_get_path (method_handle->gmyth_uri)); } /* if - LiveTV or not? */ method_handle->configured = TRUE; if (method_handle->file_transfer == NULL) { result = GNOME_VFS_ERROR_NOT_OPEN; goto error; } g_return_val_if_fail (method_handle->file_transfer != NULL, 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 result; MythtvHandle *myth_handle; gint64 total_read = 0; GByteArray *myth_buffer = g_byte_array_new (); _GNOME_VFS_METHOD_PARAM_CHECK (method_handle != NULL); myth_handle = (MythtvHandle *) method_handle; result = GNOME_VFS_OK; total_read = gmyth_file_transfer_read (myth_handle->file_transfer, myth_buffer, num_bytes, gmyth_uri_is_livetv (myth_handle->gmyth_uri)); if (total_read == -1) { result = GNOME_VFS_ERROR_IO; total_read = 0; } if (total_read < num_bytes) { result = GNOME_VFS_ERROR_EOF; } if (total_read > 0) { g_memmove (buffer, myth_buffer->data, total_read); g_byte_array_free (myth_buffer, TRUE); myth_handle->offset += total_read; } *bytes_read = (GnomeVFSFileSize) total_read; return result; } 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); return GNOME_VFS_ERROR_NOT_SUPPORTED; /* if (gmyth_uri_is_livetv (myth_handle->gmyth_uri)) 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_transfer, 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) { }