diff options
Diffstat (limited to 'camlibs/ricoh/g3.c')
-rw-r--r-- | camlibs/ricoh/g3.c | 908 |
1 files changed, 908 insertions, 0 deletions
diff --git a/camlibs/ricoh/g3.c b/camlibs/ricoh/g3.c new file mode 100644 index 000000000..0997b0273 --- /dev/null +++ b/camlibs/ricoh/g3.c @@ -0,0 +1,908 @@ +/* g3.c + * + * Copyright © 2003 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 <stdio.h> +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <gphoto2/gphoto2-library.h> +#include <gphoto2/gphoto2-result.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 _(String) (String) +# define N_(String) (String) +#endif + +/* channel header: + * + * channel host/client length data checksum padding + * 01 01 00 00 07 00 00 00 <7 byte> <1 byte> <fill to next 4> + * + */ + +static int +g3_channel_read(GPPort *port, int *channel, char **buffer, int *len) +{ + unsigned char xbuf[0x800]; + int tocopy, ret, curlen; + + ret = gp_port_read(port, xbuf, 0x800); + if (ret < GP_OK) { + gp_log(GP_LOG_ERROR, "g3", "read error in g3_channel_read\n"); + return ret; + } + + if ((xbuf[2] != 0xff) && (xbuf[3] != 0xff)) { + gp_log(GP_LOG_ERROR, "g3" ,"first bytes do not match.\n"); + return GP_ERROR_IO; + } + + *channel = xbuf[1]; + *len = xbuf[4] + (xbuf[5]<<8) + (xbuf[6]<<16) + (xbuf[7]<<24); + /* Safety buffer of 0x800 ... we can only read in 0x800 chunks, + * otherwise the communication gets hickups. However *len might be + * less. + */ + if (!*buffer) + *buffer = malloc(*len + 1 + 0x800); + else + *buffer = realloc(*buffer, *len + 1 + 0x800); + tocopy = *len; + if (tocopy > 0x800-8) tocopy = 0x800-8; + memcpy(*buffer, xbuf+8, tocopy); + curlen = tocopy; + while (curlen < *len) { + ret = gp_port_read(port, *buffer + curlen, 0x800); + if (ret < GP_OK) { + gp_log(GP_LOG_ERROR, "g3", "read error in g3_channel_read\n"); + return ret; + } + curlen += ret; + } + (*buffer)[*len] = 0x00; + return GP_OK; +} + +static int +g3_channel_read_bytes( + GPPort *port, int *channel, char **buffer, int expected, GPContext *context, + const char *msg +) { + unsigned char *xbuf; + int id, ret, len, xlen = 0; + + if (!*buffer) + *buffer = malloc (expected); + else + *buffer = realloc (*buffer, expected); + xbuf = malloc(65536 + 12); + + id = gp_context_progress_start (context, expected, "%s", msg); + + /* The camera lets us read in packets of at least max 64kb size. */ + while (expected > 0) { + int rest = expected; + if (rest > 65536) rest = 65536; + + rest = (rest + 9 + 3) & ~3; + if (rest < 0x800) rest = 0x800; + + ret = gp_port_read(port, xbuf, rest); + if (ret < GP_OK) { + gp_log(GP_LOG_ERROR, "g3", "read error in g3_channel_read\n"); + return ret; + } + if (ret != rest) { + gp_log(GP_LOG_ERROR, "g3", "read error in g3_channel_read\n"); + return ret; + } + + if ((xbuf[2] != 0xff) || (xbuf[3] != 0xff)) { + gp_log(GP_LOG_ERROR, "g3", "first bytes do not match.\n"); + free(xbuf); + return GP_ERROR_IO; + } + len = xbuf[4] + (xbuf[5]<<8) + (xbuf[6]<<16) + (xbuf[7]<<24); + *channel = xbuf[1]; + if (len > expected) + gp_log(GP_LOG_ERROR,"g3","len %d is > rest expected %d\n", len, expected); + memcpy(*buffer+xlen, xbuf+8, len); + expected -= len; + xlen += len; + gp_context_progress_update (context, id, xlen); + } + gp_context_progress_stop (context, id); + free(xbuf); + return GP_OK; +} + +static int +g3_channel_write(GPPort *port, int channel, char *buffer, int len) +{ + unsigned char *xbuf; + int ret = GP_OK, nlen, curlen = 0; + + while (len > 0) { + int sendlen = len; + + if (sendlen>65536) sendlen = 65536; + nlen = (4 + 4 + sendlen + 1 + 3) & ~3; + xbuf = calloc(nlen,1); + + xbuf[0] = 1; + xbuf[1] = channel; + xbuf[2] = 0; + xbuf[3] = 0; + xbuf[4] = sendlen & 0xff; + xbuf[5] = (sendlen>>8) & 0xff; + xbuf[6] = (sendlen>>16) & 0xff; + xbuf[7] = (sendlen>>24) & 0xff; + memcpy(xbuf+8, buffer + curlen, sendlen); + curlen += sendlen; + xbuf[8+sendlen] = 0x03; + ret = gp_port_write( port, (char*)xbuf, nlen); + free(xbuf); + if (ret < GP_OK) break; + len -= sendlen; + } + return ret; +} + +static int +g3_ftp_command_and_reply(GPPort *port, char *cmd, char **reply) { + int ret, channel, len; + char *realcmd, *s; + + realcmd = malloc(strlen(cmd)+2+1);strcpy(realcmd, cmd);strcat(realcmd, "\r\n"); + + gp_log(GP_LOG_DEBUG, "g3" , "sending %s", cmd); + ret = g3_channel_write(port, 1, realcmd, strlen(realcmd)); + free(realcmd); + if (ret < GP_OK) { + gp_log (GP_LOG_ERROR, "g3", "ftp command write failed? %d\n", ret); + return ret; + } + ret = g3_channel_read(port, &channel, reply, &len); + if (ret < GP_OK) { + gp_log (GP_LOG_ERROR, "g3", "ftp reply read failed? %d\n", ret); + return ret; + } + s = strchr(*reply, '\r'); + if (s) *s='\0'; + + gp_log(GP_LOG_DEBUG, "g3" , "reply %s", *reply); + return GP_OK; +} + +int +camera_id (CameraText *id) +{ + strcpy(id->text, "ricoh_g3"); + return (GP_OK); +} + +int +camera_abilities (CameraAbilitiesList *list) +{ + CameraAbilities a; + + memset(&a, 0, sizeof(a)); + strcpy(a.model, "Ricoh:Caplio G3"); + a.status = GP_DRIVER_STATUS_PRODUCTION; + a.port = GP_PORT_USB; + a.usb_vendor = 0x5ca; + a.usb_product = 0x2204; + + a.operations = GP_OPERATION_NONE; + a.file_operations = GP_FILE_OPERATION_DELETE | GP_FILE_OPERATION_EXIF; + a.folder_operations = GP_FOLDER_OPERATION_MAKE_DIR | + GP_FOLDER_OPERATION_REMOVE_DIR ; + + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio RR30"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2202; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio 300G"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2203; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Medion:MD 6126"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2205; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio G4"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2208; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Capilo RX"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x220b; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio GX"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x220c; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio R1"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x220d; + gp_abilities_list_append(list, a); + + /* same id as above */ + strcpy(a.model, "Ricoh:Caplio RZ1"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x220d; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Sea & Sea:5000G"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x220e; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Rollei:dr5"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x220f; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio R1v"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2212; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio R2"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2213; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio GX 8"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2214; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio R3"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2216; + gp_abilities_list_append(list, a); + + strcpy(a.model, "Ricoh:Caplio R4"); + a.usb_vendor = 0x5ca; + a.usb_product = 0x2217; + gp_abilities_list_append(list, a); + + return (GP_OK); +} + +static int +g3_cwd_command( GPPort *port, const char *folder) { + char *cmd, *reply = NULL; + int ret; + + cmd = malloc(strlen("CWD ") + strlen(folder) + 2 + 1); + sprintf(cmd,"CWD %s", folder); + ret = g3_ftp_command_and_reply(port, cmd, &reply); + free(cmd); + if (ret < GP_OK) { + if (reply) free(reply); + return ret; + } + if (reply[0]=='5') /* Failed, most likely no such directory */ + ret = GP_ERROR_DIRECTORY_NOT_FOUND; + free(reply); + return ret; +} + +static int +get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, + CameraFileType type, CameraFile *file, void *data, + GPContext *context) +{ + Camera *camera = data; + char *buf = NULL, *reply = NULL, *cmd =NULL, *msg = NULL; + int ret, channel, bytes, seek, len; + + ret = g3_cwd_command (camera->port, folder); + if (ret < GP_OK) goto out; + + switch (type) { + case GP_FILE_TYPE_NORMAL: + msg = _("Downloading..."); + if (strstr(filename,"AVI") || strstr(filename,"avi")) + msg = _("Downloading movie..."); + if (strstr(filename,"jpg") || strstr(filename,"JPG") || + strstr(filename,"tif") || strstr(filename,"TIF") + ) + msg = _("Downloading image..."); + if (strstr(filename,"wav") || strstr(filename,"WAV")) + msg = _("Downloading audio..."); + cmd = malloc(strlen("RETR ") + strlen(filename) + 2 + 1); + sprintf(cmd,"RETR %s", filename); + ret = g3_ftp_command_and_reply(camera->port, cmd, &buf); + free(cmd); + if (ret < GP_OK) goto out; + if (buf[0] != '1') { /* error, most likely file not found */ + ret = GP_ERROR_FILE_NOT_FOUND; + goto out; + } + + bytes = 0; + sscanf(buf, "150 data connection for RETR.(%d)", &bytes); + break; + case GP_FILE_TYPE_EXIF: + msg = _("Downloading EXIF data..."); + if (!strstr(filename,".JPG") && !strstr(filename,".jpg")) { + gp_context_error (context,_("No EXIF data available for %s."), + filename); + ret = GP_ERROR_FILE_NOT_FOUND; + goto out; + } + cmd = malloc(strlen("-SRET ") + strlen(filename) + 2 + 1); + sprintf(cmd,"-SRET %s", filename); + ret = g3_ftp_command_and_reply(camera->port, cmd, &buf); + free(cmd); + if (ret < GP_OK) goto out; + if (buf[0] != '1') { /* error, most likely file not found */ + ret = GP_ERROR_FILE_NOT_FOUND; + goto out; + } + bytes = seek = 0; + sscanf(buf, "150 %d byte Seek=%d", &bytes, &seek); + if (seek == -2) { + /* FIXME: pretty bad, the camera has some time out problems + * if this happens */ + gp_context_error (context,_("No EXIF data available for %s."), + filename); + ret = GP_ERROR_FILE_NOT_FOUND; + g3_channel_read(camera->port, &channel, &reply, &len); /* reply */ + goto out; + } + bytes += seek; + break; + default: + return GP_ERROR_NOT_SUPPORTED; + } + + ret = g3_channel_read_bytes(camera->port, &channel, &buf, bytes, context, msg); + if (ret < GP_OK) goto out; + ret = g3_channel_read(camera->port, &channel, &reply, &len); /* reply */ + if (ret < GP_OK) goto out; + gp_log(GP_LOG_DEBUG, "g3" , "reply %s", reply); + gp_file_set_data_and_size (file, buf, bytes); + buf = NULL; /* now owned by libgphoto2 filesystem */ + +out: + if (buf) free(buf); + if (reply) free(reply); + return (GP_OK); +} + +#if 0 +/* Works to some degree, but the firmware on the camera is not really happy + * with it and sometimes refuses to send data the correct way + */ +static int +put_file_func (CameraFilesystem *fs, const char *folder, CameraFile *file, + void *data, GPContext *context) +{ + Camera *camera = data; + char *buf = NULL, *reply = NULL, *cmd =NULL; + const char *fn = NULL, *imgdata = NULL; + int ret, channel, len; + long size; + + ret = g3_cwd_command (camera->port, folder); + if (ret < GP_OK) goto out; + + ret = gp_file_get_name (file, &fn); + if (ret < GP_OK) goto out; + ret = gp_file_get_data_and_size (file, &imgdata, &size); + if (ret < GP_OK) goto out; + + cmd = malloc(strlen("-STOR ") + 20 + strlen(fn) + 2 + 1); + sprintf(cmd,"-STOR %ld %s", size, fn); + ret = g3_ftp_command_and_reply(camera->port, cmd, &buf); + free(cmd); + if (ret < GP_OK) goto out; + if (buf[0] != '1') { /* error, most likely file not found */ + ret = GP_ERROR; + goto out; + } + ret = g3_channel_write(camera->port, 2, (char*)imgdata, size); /* data */ + if (ret < GP_OK) goto out; + ret = g3_channel_read(camera->port, &channel, &reply, &len); /* reply */ + if (ret < GP_OK) goto out; +out: + if (buf) free(buf); + if (reply) free(reply); + return (GP_OK); +} +#endif + +static int +delete_file_func (CameraFilesystem *fs, const char *folder, + const char *filename, void *data, GPContext *context) +{ + Camera *camera = data; + char *reply = NULL, *cmd = NULL; + int ret; + + ret = g3_cwd_command (camera->port, folder); + if (ret < GP_OK) + return ret; + + cmd = malloc(strlen("DELE ")+strlen(filename)+1); + sprintf(cmd,"DELE %s",filename); + ret = g3_ftp_command_and_reply(camera->port, cmd, &reply); + if (ret < GP_OK) + goto out; + if (reply[0] == '5') { + gp_context_error (context, _("Could not delete file.")); + ret = GP_ERROR; + } +out: + if (cmd) free(cmd); + if (reply) free(reply); + return (GP_OK); +} + +static int +rmdir_func (CameraFilesystem *fs, const char *folder, + const char *name, void *data, GPContext *context) +{ + Camera *camera = data; + char *reply = NULL, *cmd = NULL; + int ret; + + ret = g3_cwd_command (camera->port, folder); + if (ret<GP_OK) + return ret; + + cmd = realloc(cmd,strlen("RMD ")+strlen(name)+1); + sprintf(cmd,"RMD %s",name); + ret = g3_ftp_command_and_reply(camera->port, cmd, &reply); + if (ret < GP_OK) + goto out; + if (reply[0] == '5') { + gp_context_error (context, _("Could not remove directory.")); + ret = GP_ERROR; + } +out: + if (cmd) free(cmd); + if (reply) free(reply); + return (GP_OK); +} + +static int +mkdir_func (CameraFilesystem *fs, const char *folder, + const char *name, void *data, GPContext *context) +{ + Camera *camera = data; + char *reply = NULL, *cmd = NULL; + int ret; + + ret = g3_cwd_command (camera->port, folder); + if (ret<GP_OK) + return ret; + + cmd = realloc(cmd,strlen("MKD ")+strlen(name)+1); + sprintf(cmd,"MKD %s",name); + ret = g3_ftp_command_and_reply(camera->port, cmd, &reply); + if (ret < GP_OK) + goto out; + if (reply[0] == '5') { + gp_context_error (context, _("Could not create directory.")); + ret = GP_ERROR; + } +out: + if (cmd) free(cmd); + if (reply) free(reply); + return (GP_OK); +} + +static int +camera_summary (Camera *camera, CameraText *summary, GPContext *context) +{ + char *t = summary->text; + int ret; + char *buf = NULL; + + t[0]='\0'; + ret = g3_ftp_command_and_reply (camera->port, "-VER", &buf); + if (ret == GP_OK) + sprintf(t+strlen(t), _("Version: %s\n"), buf+4); /* skip "200 " */ + ret = g3_ftp_command_and_reply(camera->port, "-RTST", &buf); /* RTC test */ + if (ret == GP_OK) { + int rtcstat; + if (sscanf(buf, "200 RTC status=%d", &rtcstat)) + sprintf(t+strlen(t), _("RTC Status: %d\n"), rtcstat); + } + ret = g3_ftp_command_and_reply(camera->port, "-TIME", &buf); + if (ret == GP_OK) { + char day[20], time[20]; + if (sscanf(buf, "200 %s %s for -TIME", day, time)) + sprintf(t+strlen(t), _("Camera time: %s %s\n"), day, time); + } + ret = g3_ftp_command_and_reply(camera->port, "-GCID", &buf); + if (ret == GP_OK) { + char camid[40]; + if (sscanf(buf, "200 CameraID=%s for -GCID", camid)) + sprintf(t+strlen(t), _("Camera ID: %s\n"), camid); + } + ret = g3_ftp_command_and_reply(camera->port, "-GSID", &buf); + if (ret == GP_OK) { + char cardid[40]; + if (strstr(buf, "200 SD ID= for -GSID")) { + sprintf(t+strlen(t), _("No SD Card inserted.\n")); + } else { + if (sscanf(buf, "200 SD ID=%s for -GSID", cardid)) { + sprintf(t+strlen(t), _("SD Card ID: %s\n"), cardid); + } + } + } + ret = g3_ftp_command_and_reply(camera->port, "-GTPN", &buf); + if (ret == GP_OK) { + int total; + if (sscanf (buf, "200 TotalPhotoNo=%d for -GTPN", &total)) + sprintf(t+strlen(t), _("Photos on camera: %d\n"), total); + } + ret = g3_ftp_command_and_reply(camera->port, "-DCAP /EXT0", &buf); + if (ret == GP_OK) { + int space, sfree; + if (sscanf (buf, "200 /EXT0 capacity %d byte,free %d byte.", &space, &sfree)) { + sprintf(t+strlen(t), _("SD memory: %d MB total, %d MB free.\n"), space/1024/1024, sfree/1024/1024); + } + } + ret = g3_ftp_command_and_reply(camera->port, "-DCAP /IROM", &buf); + if (ret == GP_OK) { + int space, sfree; + if (sscanf (buf, "200 /IROM capacity %d byte,free %d byte.", &space, &sfree)) { + sprintf(t+strlen(t), _("Internal memory: %d MB total, %d MB free.\n"), space/1024/1024, sfree/1024/1024); + } + } + if (buf) free (buf); + return (GP_OK); +} + +static int +camera_about (Camera *camera, CameraText *about, GPContext *context) +{ + strcpy (about->text, _("Ricoh Caplio G3.\n" + "Marcus Meissner <marcus@jet.franken.de>\n" + "Reverse engineered using USB Snoopy, looking\n" + "at the firmware update image and wild guessing.\n" + )); + + return (GP_OK); +} + +static int +get_info_func (CameraFilesystem *fs, const char *folder, const char *filename, + CameraFileInfo *info, void *data, GPContext *context) +{ + Camera *camera = data; + int ret, bytes, width, height, k; + struct tm xtm; + char *cmd = NULL, *reply = NULL; + + info->file.fields = GP_FILE_INFO_TYPE | GP_FILE_INFO_NAME | + GP_FILE_INFO_SIZE | GP_FILE_INFO_TYPE; + strcpy(info->file.type,GP_MIME_UNKNOWN); + strcpy(info->file.name, filename); + + if (!strcmp(filename+9,"JPG") || !strcmp(filename+9,"jpg")) + strcpy(info->file.type,GP_MIME_JPEG); + + if (!strcmp(filename+9,"AVI") || !strcmp(filename+9,"avi")) + strcpy(info->file.type,GP_MIME_AVI); + + if (!strcmp(filename+9,"WAV") || !strcmp(filename+9,"wav")) + strcpy(info->file.type,GP_MIME_WAV); + + if (!strcmp(filename+9,"MTA") || !strcmp(filename+9,"mta")) + strcpy(info->file.type,"text/plain"); + + cmd = malloc(strlen("-FDAT ")+strlen(folder)+1+strlen(filename)+1); + sprintf(cmd, "-FDAT %s/%s", folder,filename); + ret = g3_ftp_command_and_reply(camera->port, cmd, &reply); + if (ret < GP_OK) goto out; + if (sscanf(reply, "200 date=%d:%d:%d %d:%d:%d", + &xtm.tm_year, + &xtm.tm_mon, + &xtm.tm_mday, + &xtm.tm_hour, + &xtm.tm_min, + &xtm.tm_sec + )) { + xtm.tm_mon--; /* range 0 - 11 */ + xtm.tm_year -= 1900; /* number of years since 1900 */ + info->file.mtime = mktime(&xtm); + info->file.fields |= GP_FILE_INFO_MTIME; + } + + /* -INFO command only sometimes work on non jpeg/avi files */ + if ( !strcmp(info->file.type,GP_MIME_JPEG) || + !strcmp(info->file.type,GP_MIME_AVI) + ) { + sprintf(cmd, "-INFO %s/%s", folder,filename); + g3_ftp_command_and_reply(camera->port, cmd, &reply); + if (ret < GP_OK) goto out; + + /* 200 1330313 byte W=2048 H=1536 K=0 for -INFO */ + if (sscanf(reply, "200 %d byte W=%d H=%d K=%d for -INFO", &bytes, &width, &height , &k)) { + if (width != 0 && height != 0) { + info->file.fields |= GP_FILE_INFO_WIDTH | GP_FILE_INFO_HEIGHT; + info->file.height = height; + info->file.width = width; + } + info->file.fields |= GP_FILE_INFO_SIZE; + info->file.size = bytes; + if (k != 0) + gp_log(GP_LOG_ERROR, "g3", "k is %d for %s/%s\n", k, folder,filename); + } + } +out: + if (reply) free(reply); + if (cmd) free(cmd); + + return (GP_OK); + +} + + +static int +folder_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, + void *data, GPContext *context) +{ + Camera *camera = data; + char *buf = NULL, *reply = NULL; + char *cmd = NULL; + int ret = GP_OK, channel, len, rlen; + + if (!strcmp("/",folder)) { + /* Lets hope they dont invent other names. */ + + /* We check the folder we get, since we should + * not add EXT0 without SD card. + */ + ret = g3_ftp_command_and_reply(camera->port, "-NLST /", &buf); + if (ret < GP_OK) goto out; + if (buf[0] == '4') { + /* seen with R3: 450 Open Error... likely OK. */ + goto out; + } + if (buf[0] != '1') { + ret = GP_ERROR_IO; + goto out; + } + ret = g3_channel_read(camera->port, &channel, &buf, &len); /* data. */ + if (ret < GP_OK) goto out; + g3_channel_read(camera->port, &channel, &reply, &rlen); /* next reply */ + if (ret < GP_OK) goto out; + gp_log(GP_LOG_DEBUG, "g3" , "reply %s", reply); + + if (!strcmp("/EXT0",buf)) + gp_list_append (list, "EXT0", NULL); + + /* always add internal memory */ + gp_list_append (list, "IROM", NULL); + return GP_OK; + } + + cmd = malloc(6 + strlen(folder) + 1); + strcpy(cmd, "-NLST "); + strcat(cmd, folder); + + ret = g3_ftp_command_and_reply(camera->port, cmd, &buf); + free(cmd);cmd = NULL; + if (ret < GP_OK) goto out; + if (buf[0] == '1') { /* 1xx means another reply follows */ + int n = 0; + + ret = g3_channel_read(camera->port, &channel, &buf, &len); /* data. */ + if (ret < GP_OK) goto out; + g3_channel_read(camera->port, &channel, &reply, &rlen); /* next reply */ + if (ret < GP_OK) goto out; + gp_log(GP_LOG_DEBUG, "g3" , "reply %s", reply); + + for (n=0;n<len/32;n++) { + if (buf[n*32+11] == 0x10) { + if (buf[n*32] == '.') /* skip . and .. entries */ + continue; + ret = gp_list_append (list, buf+n*32, NULL); + if (ret != GP_OK) goto out; + } + } + } else { + if (buf[0] == '4') + ret = GP_OK; + else + ret = GP_ERROR_IO; + } +out: + if (buf) free(buf); + if (reply) free(reply); + return ret; +} + +/* for DOS FAT -> UNIX time conversion */ +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + +static int +file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list, + void *data, GPContext *context) +{ + Camera *camera = data; + char *buf = NULL, *reply = NULL, *cmd; + int ret = GP_OK; + unsigned char *ubuf; + + cmd = malloc(6 + strlen(folder) + 1); + strcpy(cmd, "-NLST "); + strcat(cmd, folder); + ret = g3_ftp_command_and_reply(camera->port, cmd, (char**)&buf); + free(cmd); cmd = NULL; + if (ret < GP_OK) goto out; + if (buf[0] == '1') { /* 1xx means another reply follows */ + int n = 0, channel, len, rlen; + ret = g3_channel_read(camera->port, &channel, &buf, &len); /* data. */ + if (ret < GP_OK) goto out; + g3_channel_read(camera->port, &channel, &reply, &rlen); /* next reply */ + if (ret < GP_OK) goto out; + gp_log(GP_LOG_DEBUG, "g3" , "reply %s", reply); + + ubuf = (unsigned char*)buf; + for (n=0;n < len/32;n++) { + if (buf[n*32+11] == 0x20) { + CameraFileInfo info; + char xfn[13]; + int date, time, month, year; + + strncpy (xfn, buf+n*32, 8); + xfn[8] = '.'; + strncpy (xfn+9, buf+n*32+8, 3); + xfn[8+1+3] = '\0'; + + ret = gp_filesystem_append (fs, folder, xfn, context); + if (ret < GP_OK) goto out; + + /* we also get parts of fs info for free, so just set it */ + info.file.fields = + GP_FILE_INFO_NAME | + GP_FILE_INFO_SIZE | + GP_FILE_INFO_MTIME; + info.file.size =(ubuf[n*32+28]<<24)| + (ubuf[n*32+29]<<16)| + (ubuf[n*32+30]<< 8)| + (ubuf[n*32+31] ); + strcpy(info.file.name,xfn); + if (!strcmp(xfn+9,"JPG") || !strcmp(xfn+9,"jpg")) { + strcpy(info.file.type,GP_MIME_JPEG); + info.file.fields |= GP_FILE_INFO_TYPE; + } + + if (!strcmp(xfn+9,"AVI") || !strcmp(xfn+9,"avi")) { + strcpy(info.file.type,GP_MIME_AVI); + info.file.fields |= GP_FILE_INFO_TYPE; + } + + if (!strcmp(xfn+9,"WAV") || !strcmp(xfn+9,"wav")) { + strcpy(info.file.type,GP_MIME_WAV); + info.file.fields |= GP_FILE_INFO_TYPE; + } + + if (!strcmp(xfn+9,"MTA") || !strcmp(xfn+9,"mta")) { + strcpy(info.file.type,"text/plain"); + info.file.fields |= GP_FILE_INFO_TYPE; + } + info.preview.fields = 0; + date = (ubuf[n*32+16]) | (ubuf[n*32+17]<<8); + time = (ubuf[n*32+14]) | (ubuf[n*32+15]<<8); + + /* from kernel fs/fat/, time_dos2unix. */ + month = ((date >> 5) - 1) & 15; + year = date >> 9; + info.file.mtime = + (time & 31)*2+60*((time >> 5) & 63)+ + (time >> 11)*3600+86400*((date & 31)-1+ + day_n[month]+(year/4)+year*365- + ((year & 3) == 0 && month < 2 ? 1 : 0)+ + 3653); + + ret = gp_filesystem_set_info_noop(fs, folder, info, context); + + } + } + } else { + if (buf[0] == '4') /* 450 Open Error ... like dir not there */ + ret = GP_OK; + else + ret = GP_ERROR_IO; + } +out: + if (buf) free(buf); + if (reply) free(reply); + if (cmd) free(cmd); + return (GP_OK); +} + +static CameraFilesystemFuncs fsfuncs = { + .file_list_func = file_list_func, + .get_file_func = get_file_func, + .del_file_func = delete_file_func, + .get_info_func = get_info_func, + .folder_list_func = folder_list_func, + .make_dir_func = mkdir_func, + .remove_dir_func = rmdir_func, +}; + +int +camera_init (Camera *camera, GPContext *context) +{ + /*char *buf;*/ + GPPortSettings settings; + + /* First, set up all the needed function pointers */ + camera->functions->summary = camera_summary; + camera->functions->about = camera_about; + + /* Now, tell the filesystem where to get lists, files and info */ + gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera); + + gp_port_get_settings(camera->port, &settings); + settings.usb.inep = 0x81; + settings.usb.outep = 0x02; + settings.usb.intep = 0x83; + gp_port_set_settings(camera->port, settings); + /* + * The port is already provided with camera->port (and + * already open). You just have to use functions like + * gp_port_timeout_set, gp_port_settings_get, gp_port_settings_set. + */ + + /* + * Once you have configured the port, you should check if a + * connection to the camera can be established. + */ + + /* testing code ... + buf = NULL; + g3_ftp_command_and_reply(camera->port, "-PWOF STDBY", &buf); + */ + return (GP_OK); +} |