diff options
Diffstat (limited to 'camlibs/directory/directory.c')
-rw-r--r-- | camlibs/directory/directory.c | 696 |
1 files changed, 696 insertions, 0 deletions
diff --git a/camlibs/directory/directory.c b/camlibs/directory/directory.c new file mode 100644 index 000000000..5a289173e --- /dev/null +++ b/camlibs/directory/directory.c @@ -0,0 +1,696 @@ +/* directory.c + * + * Copyright © 2001 Lutz Müller <lutz@users.sf.net> + * Copyright © 2005 Marcus Meissner <marcus@jet.franken.de> + * + * 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 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "config.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <utime.h> +#include <unistd.h> + +#ifdef HAVE_LIBEXIF +#include <libexif/exif-data.h> +#endif + +#include <gphoto2/gphoto2-setting.h> +#include <gphoto2/gphoto2-library.h> +#include <gphoto2/gphoto2-port.h> +#include <gphoto2/gphoto2-port-log.h> + +#ifdef ENABLE_NLS +# include <libintl.h> +# undef _ +# define _(String) dgettext (GETTEXT_PACKAGE, String) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# define textdomain(String) (String) +# define gettext(String) (String) +# define dgettext(Domain,Message) (Message) +# define dcgettext(Domain,Message,Type) (Message) +# define bindtextdomain(Domain,Directory) (Domain) +# define _(String) (String) +# define N_(String) (String) +#endif + +static const struct { + const char *extension; + const char *mime_type; +} mime_table[] = { + {"jpeg", GP_MIME_JPEG}, + {"jpg", GP_MIME_JPEG}, + {"tif", GP_MIME_TIFF}, + {"ppm", GP_MIME_PPM}, + {"pgm", GP_MIME_PGM}, + {"avi", GP_MIME_AVI}, + {"mov", GP_MIME_QUICKTIME}, + {"mpg", GP_MIME_MPEG}, + {"pbm", "image/x-portable-bitmap"}, + {"crw", GP_MIME_CRW}, + {"cr2", GP_MIME_RAW}, + {"nef", GP_MIME_RAW}, + {"mrw", GP_MIME_RAW}, + {"dng", GP_MIME_RAW}, + {"sr2", GP_MIME_RAW}, + {"png", GP_MIME_PNG}, + {"wav", GP_MIME_WAV}, + {NULL, NULL} +}; + +/* #define DEBUG */ +/* #define FOLLOW_LINKS */ + +#define GP_MODULE "directory" + +static const char * +get_mime_type (const char *filename) +{ + + char *dot; + int x=0; + + dot = strrchr(filename, '.'); + if (dot) { + for (x = 0; mime_table[x].extension; x++) { +#ifdef OS2 + if (!stricmp(mime_table[x].extension, dot+1)) +#else + if (!strcasecmp (mime_table[x].extension, dot+1)) +#endif + return (mime_table[x].mime_type); + } + } + + return (NULL); +} + +int camera_id (CameraText *id) +{ + strcpy(id->text, "directory"); + + return (GP_OK); +} + + +int camera_abilities (CameraAbilitiesList *list) +{ + CameraAbilities a; + + memset(&a, 0, sizeof(a)); + strcpy(a.model, "Directory Browse"); + a.status = GP_DRIVER_STATUS_PRODUCTION; + a.port = GP_PORT_DISK; + a.speed[0] = 0; + + a.operations = GP_OPERATION_NONE; + +#ifdef DEBUG + a.file_operations = GP_FILE_OPERATION_PREVIEW | + GP_FILE_OPERATION_DELETE | + GP_FILE_OPERATION_EXIF; +#else + a.file_operations = GP_FILE_OPERATION_DELETE | + GP_FILE_OPERATION_EXIF; +#endif + a.folder_operations = GP_FOLDER_OPERATION_MAKE_DIR | + GP_FOLDER_OPERATION_REMOVE_DIR | + GP_FOLDER_OPERATION_PUT_FILE; + + gp_abilities_list_append(list, a); + + /* Since "Directory Browse" is hardcoded in clients, + * better also add a new name here. + */ + strcpy(a.model, "Mass Storage Camera"); + gp_abilities_list_append(list, a); + return (GP_OK); +} + +static int +file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, + void *data, GPContext *context) +{ + gp_system_dir dir; + gp_system_dirent de; + char buf[1024], f[1024]; + unsigned int id, n; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (f, sizeof(f), "%s/%s/", + settings.disk.mountpoint, + folder + ); + /* UNIX / is empty, or we recurse through the whole fs */ + if ( (!strcmp(settings.disk.mountpoint, "") || + !strcmp(settings.disk.mountpoint, "/")) && + !strcmp(folder,"/") + ) + return GP_OK; + } else { + /* old style access */ + if (folder[strlen(folder)-1] != '/') + sprintf (f, "%s%c", folder, '/'); + else + strcpy (f, folder); + } + dir = gp_system_opendir ((char*) f); + if (!dir) + return (GP_ERROR); + + /* Make sure we have 1 delimiter */ + + /* Count the files */ + n = 0; + while (gp_system_readdir (dir)) + n++; + + gp_system_closedir (dir); + dir = gp_system_opendir (f); + if (!dir) + return (GP_ERROR); + id = gp_context_progress_start (context, n, _("Listing files in " + "'%s'..."), f); + n = 0; + while ((de = gp_system_readdir(dir))) { + + /* Give some feedback */ + gp_context_progress_update (context, id, n + 1); + gp_context_idle (context); + if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { + gp_system_closedir (dir); + return (GP_ERROR_CANCEL); + } + + if (strcmp(gp_system_filename(de), "." ) && + strcmp(gp_system_filename(de), "..")) { + sprintf (buf, "%s%s", f, gp_system_filename (de)); + if (gp_system_is_file (buf) && (get_mime_type (buf))) + gp_list_append (list, gp_system_filename (de), + NULL); + } + n++; + } + gp_system_closedir (dir); + gp_context_progress_stop (context, id); + + return (GP_OK); +} + +static int +folder_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, + void *data, GPContext *context) +{ + gp_system_dir dir; + gp_system_dirent de; + char buf[1024], f[1024]; + unsigned int id, n; + struct stat st; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (f, sizeof(f), "%s/%s/", + settings.disk.mountpoint, + folder + ); + /* UNIX / is empty, or we recurse through the whole fs */ + if ( (!strcmp(settings.disk.mountpoint, "") || + !strcmp(settings.disk.mountpoint, "/")) && + !strcmp(folder,"/") + ) + return GP_OK; + } else { + /* old style access */ + /* Make sure we have 1 delimiter */ + if (folder[strlen(folder)-1] != '/') + sprintf (f, "%s%c", folder, '/'); + else + strcpy (f, folder); + } + dir = gp_system_opendir ((char*) f); + if (!dir) + return (GP_ERROR); + /* Count the files */ + n = 0; + while (gp_system_readdir (dir)) + n++; + gp_system_closedir (dir); + + dir = gp_system_opendir (f); + if (!dir) + return (GP_ERROR); + id = gp_context_progress_start (context, n, _("Listing folders in " + "'%s'..."), folder); + n = 0; + while ((de = gp_system_readdir (dir))) { + /* Give some feedback */ + gp_context_progress_update (context, id, n + 1); + gp_context_idle (context); + if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { + gp_system_closedir (dir); + return (GP_ERROR_CANCEL); + } + if ((strcmp (gp_system_filename (de), "." ) != 0) && + (strcmp (gp_system_filename (de), "..") != 0)) { + sprintf (buf, "%s%s", f, gp_system_filename (de)); + + /* lstat ... do not follow symlinks */ + if (lstat (buf, &st) != 0) { + gp_context_error (context, _("Could not get information " + "about '%s' (%m)."), buf); + return (GP_ERROR); + } + if (S_ISDIR (st.st_mode)) + gp_list_append (list, + gp_system_filename (de), + NULL); + } + n++; + } + gp_system_closedir (dir); + gp_context_progress_stop (context, id); + return (GP_OK); +} + +static int +get_info_func (CameraFilesystem *fs, const char *folder, const char *file, + CameraFileInfo *info, void *data, GPContext *context) +{ + char path[1024]; + const char *mime_type; + struct stat st; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + file + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, file); + } + + if (lstat (path, &st) != 0) { + gp_context_error (context, _("Could not get information " + "about '%s' in '%s' (%m)."), file, folder); + return (GP_ERROR); + } + + info->preview.fields = GP_FILE_INFO_NONE; + info->file.fields = GP_FILE_INFO_SIZE | GP_FILE_INFO_NAME | + GP_FILE_INFO_TYPE | GP_FILE_INFO_PERMISSIONS | + GP_FILE_INFO_MTIME; + + info->file.mtime = st.st_mtime; + info->file.permissions = GP_FILE_PERM_NONE; + if (st.st_mode & S_IRUSR) + info->file.permissions |= GP_FILE_PERM_READ; + if (st.st_mode & S_IWUSR) + info->file.permissions |= GP_FILE_PERM_DELETE; + strcpy (info->file.name, file); + info->file.size = st.st_size; + mime_type = get_mime_type (file); + if (!mime_type) + mime_type = "application/octet-stream"; + strcpy (info->file.type, mime_type); + + return (GP_OK); +} + +static int +set_info_func (CameraFilesystem *fs, const char *folder, const char *file, + CameraFileInfo info, void *data, GPContext *context) +{ + int retval; + char path_old[1024], path_new[1024], path[1024]; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + file + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, file); + } + + /* We don't support updating permissions (yet) */ + if (info.file.fields & GP_FILE_INFO_PERMISSIONS) + return (GP_ERROR_NOT_SUPPORTED); + + if (info.file.fields & GP_FILE_INFO_MTIME) { + struct utimbuf utimbuf; + + utimbuf.actime = info.file.mtime; + utimbuf.modtime = info.file.mtime; + if (utime (path, &utimbuf) != 0) { + gp_context_error (context, _("Could not change " + "time of file '%s' in '%s' (%m)."), + file, folder); + return (GP_ERROR); + } + } + + if (info.file.fields & GP_FILE_INFO_NAME) { + if (!strcmp (info.file.name, file)) + return (GP_OK); + + /* We really have to rename the poor file... */ + if (strlen (folder) == 1) { + snprintf (path_old, sizeof (path_old), "/%s", + file); + snprintf (path_new, sizeof (path_new), "/%s", + info.file.name); + } else { + snprintf (path_old, sizeof (path_old), "%s/%s", + folder, file); + snprintf (path_new, sizeof (path_new), "%s/%s", + folder, info.file.name); + } + retval = rename (path_old, path_new); + if (retval != 0) { + switch (errno) { + case EISDIR: + return (GP_ERROR_DIRECTORY_EXISTS); + case EEXIST: + return (GP_ERROR_FILE_EXISTS); + case EINVAL: + return (GP_ERROR_BAD_PARAMETERS); + case EIO: + return (GP_ERROR_IO); + case ENOMEM: + return (GP_ERROR_NO_MEMORY); + case ENOENT: + return (GP_ERROR_FILE_NOT_FOUND); + default: + return (GP_ERROR); + } + } + } + + return (GP_OK); +} + +static int +get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, + CameraFileType type, CameraFile *file, void *user_data, + GPContext *context) +{ + char path[1024]; + int result = GP_OK; +#ifdef DEBUG + unsigned int i, id; +#endif +#ifdef HAVE_LIBEXIF + ExifData *data; + unsigned char *buf; + unsigned int buf_len; +#endif /* HAVE_LIBEXIF */ + Camera *camera = (Camera*)user_data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + filename + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, filename); + } + + switch (type) { + case GP_FILE_TYPE_NORMAL: + result = gp_file_open (file, path); + break; +#ifdef DEBUG + case GP_FILE_TYPE_PREVIEW: + result = gp_file_open (file, path); + break; +#endif +#ifdef HAVE_LIBEXIF + case GP_FILE_TYPE_EXIF: + data = exif_data_new_from_file (path); + if (!data) { + gp_context_error (context, _("Could not open '%s'."), + path); + return (GP_ERROR); + } + exif_data_save_data (data, &buf, &buf_len); + exif_data_unref (data); + gp_file_set_data_and_size (file, buf, buf_len); + return (GP_OK); +#endif /* HAVE_LIBEXIF */ + default: + return (GP_ERROR_NOT_SUPPORTED); + } + if (result < 0) + return (result); + +#ifdef DEBUG + id = gp_context_progress_start (context, 500., "Getting file..."); + GP_DEBUG ("Progress id: %i", id); + for (i = 0; i < 500; i++) { + gp_context_progress_update (context, id, i + 1); + gp_context_idle (context); + if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) + return (GP_ERROR_CANCEL); + usleep (10); + } + gp_context_progress_stop (context, id); +#endif + + return (GP_OK); +} + +static int +camera_manual (Camera *camera, CameraText *manual, GPContext *context) +{ + strcpy (manual->text, _("The Directory Browse \"camera\" lets " + "you index photos on your hard drive.")); + + return (GP_OK); +} + +static int +camera_about (Camera *camera, CameraText *about, GPContext *context) +{ + strcpy (about->text, _("Directory Browse Mode - written " + "by Scott Fritzinger <scottf@unr.edu>.")); + + return (GP_OK); +} + +static int +make_dir_func (CameraFilesystem *fs, const char *folder, const char *name, + void *data, GPContext *context) +{ + char path[2048]; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + name + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, name); + } + return (gp_system_mkdir (path)); +} + +static int +remove_dir_func (CameraFilesystem *fs, const char *folder, const char *name, + void *data, GPContext *context) +{ + char path[2048]; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + name + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, name); + } + return (gp_system_rmdir (path)); +} + +static int +delete_file_func (CameraFilesystem *fs, const char *folder, + const char *file, void *data, GPContext *context) +{ + char path[2048]; + int result; + Camera *camera = (Camera*)data; + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + file + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, file); + } + result = unlink (path); + if (result) { + gp_context_error (context, _("Could not delete file '%s' " + "in folder '%s' (error code %i: %m)."), + file, folder, result); + return (GP_ERROR); + } + + return (GP_OK); +} + +static int +put_file_func (CameraFilesystem *fs, const char *folder, + CameraFile *file, void *data, GPContext *context) +{ + char path[2048]; + const char *name; + int result; +#ifdef DEBUG + unsigned int i, id; +#endif + Camera *camera = (Camera*)data; + + gp_file_get_name (file, &name); + + if (camera->port->type == GP_PORT_DISK) { + GPPortSettings settings; + + gp_port_get_settings (camera->port, &settings); + snprintf (path, sizeof(path), "%s/%s/%s", + settings.disk.mountpoint, + folder, + name + ); + } else { + /* old style access */ + snprintf (path, sizeof (path), "%s/%s", folder, name); + } + + result = gp_file_save (file, path); + if (result < 0) + return (result); + +#ifdef DEBUG + id = gp_context_progress_start (context, 500., "Uploading file..."); + for (i = 0; i < 500; i++) { + gp_context_progress_update (context, id, i + 1); + gp_context_idle (context); + if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) + return (result); + usleep (10); + } + gp_context_progress_stop (context, id); +#endif + + return (GP_OK); +} + +#ifdef DEBUG +static int +camera_capture_preview (Camera *camera, CameraFile *file, GPContext *context) +{ + int r; + + r = gp_file_open (file, "/usr/share/pixmaps/gnome-logo-large.png"); + if (r < 0) + return (r); + + return (GP_OK); +} + +static int +camera_capture (Camera *camera, CameraCaptureType type, CameraFilePath *path, + GPContext *context) +{ + if (path) { + strcpy (path->folder, "/usr/share/pixmaps"); + strcpy (path->name, "gnome-logo-large.png"); + } + + return (GP_OK); +} +#endif + +static CameraFilesystemFuncs fsfuncs = { + .file_list_func = file_list_func, + .folder_list_func = folder_list_func, + .set_info_func = set_info_func, + .get_info_func = get_info_func, + .get_file_func = get_file_func, + .put_file_func = put_file_func, + .del_file_func = delete_file_func, + .make_dir_func = make_dir_func, + .remove_dir_func = remove_dir_func, +}; + +int +camera_init (Camera *camera, GPContext *context) +{ + /* First, set up all the function pointers */ + camera->functions->manual = camera_manual; + camera->functions->about = camera_about; + return gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera); +} |