diff --git a/include/ssh.h b/include/ssh.h index d5fdb5d..07da28e 100644 --- a/include/ssh.h +++ b/include/ssh.h @@ -30,9 +30,11 @@ #include "common.h" +struct SFTPS; struct SSHS; +typedef void (*SFTPCallback)(struct SFTPS*); typedef void (*SSHCallback)(struct SSHS*); @@ -48,11 +50,35 @@ typedef struct SSHS { } SSHT; -SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password); -void sshDisconnect(SSHT **sshData); -int sshExecute(SSHT *sshData, char *command, char **output); -void sshShutdown(void); -void sshStartup(void); +typedef struct SFTPS { + SSHT *sshData; + FILE *local; + LIBSSH2_SFTP *session; + LIBSSH2_SFTP_HANDLE *handle; + char buffer[102400]; + char *ptr; + uint64_t fileSize; + uint64_t fileSent; + size_t nread; + char *source; + char *target; + char *title; + gboolean uploading; + gboolean readMore; + gboolean finished; + gboolean success; + GtkWidget *status; + SFTPCallback callback; +} SFTPT; + + +SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password); +void sshDisconnect(SSHT **sshData); +//int sshExecute(SSHT *sshData, char *command, char **output); +gboolean sshSFTPFileExists(SSHT *sshData, char *target); +SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPCallback callback); +void sshShutdown(void); +void sshStartup(void); #endif // SSH_H diff --git a/include/utils.h b/include/utils.h index d10e257..8b86228 100644 --- a/include/utils.h +++ b/include/utils.h @@ -47,9 +47,11 @@ char *utilFileBasename(char *path); gboolean utilFileCopy(char *from, char *to); gboolean utilFileExists(char *filename); gboolean utilFileOpen(WindowDataT *self, char *extension, char *what); +char *utilFilePath(char *filename); char *utilFileRemoveExtension(char *filename); gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what); gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, char **filename); +size_t utilFileSize(char *filename); GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name); char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock); WindowDataT *utilGetWindowData(GtkWidget *window); diff --git a/src/project.c b/src/project.c index 1434aed..37f82f0 100644 --- a/src/project.c +++ b/src/project.c @@ -937,6 +937,7 @@ EVENT void menuProjectBuildCookRecipes(GtkWidget *object, gpointer userData) { EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) { + //***TODO*** } diff --git a/src/ssh.c b/src/ssh.c index efe782f..41a9dcb 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -28,6 +28,7 @@ #include "ssh.h" #include "utils.h" #include "array.h" +#include "messages.h" #ifdef _WIN32 @@ -38,14 +39,16 @@ closesocket(data->sock); #endif -static SSHT **_activeSSHs = NULL; -static char *_output = NULL; -static int _outputLen = 0; -static char *_buffer = NULL; -static int _bufferLen = 0; +static SFTPT **_activeSFTPs = NULL; +static SSHT **_activeSSHs = NULL; +static char *_output = NULL; +static int _outputLen = 0; +static char *_buffer = NULL; +static int _bufferLen = 0; gboolean sshUpdate(gpointer userData); // Not static +gboolean sshSFTPUpdate(gpointer userData); // Not static static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session); @@ -58,13 +61,13 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) { hostent = gethostbyname(hostname); if (hostent == NULL) { - debug("gethostbyname() failed.\n"); + message(MSG_SEVERE, "gethostbyname() failed.\n"); return NULL; } hostaddr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list))); if (hostaddr == (in_addr_t)-1) { - debug("inet_addr() failed.\n"); + message(MSG_SEVERE, "inet_addr() failed.\n"); return NULL; } @@ -77,7 +80,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) { sin.sin_port = htons(port); sin.sin_addr.s_addr = hostaddr; if (connect(data->sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) != 0) { - debug("connect() failed: %d\n", errno); + message(MSG_ERROR, "connect() failed: %d\n", errno); DEL(data); return NULL; } @@ -94,7 +97,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) { while ((rc = libssh2_session_handshake(data->session, data->sock)) == LIBSSH2_ERROR_EAGAIN) ; if (rc) { - debug("Failure establishing SSH session: %d\n", rc); + message(MSG_ERROR, "Failure establishing SSH session: %d\n", rc); libssh2_session_free(data->session); socketclose(data->sock); DEL(data); @@ -104,7 +107,7 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) { while ((rc = libssh2_userauth_password(data->session, user, password)) == LIBSSH2_ERROR_EAGAIN) ; if (rc) { - debug("Failure authenticating SSH session: %d\n", rc); + message(MSG_ERROR, "Failure authenticating SSH session: %d\n", rc); while (libssh2_session_disconnect(data->session, "Error") == LIBSSH2_ERROR_EAGAIN) ; libssh2_session_free(data->session); @@ -129,6 +132,7 @@ void sshDisconnect(SSHT **sshData) { } +/* int sshExecute(SSHT *sshData, char *command, char **output) { int rc; int exitcode = 127; @@ -201,18 +205,207 @@ SSHT *sshExecuteVerbose(SSHT *sshData, char *title, char *command, SSHCallback c return NULL; } - //***TODO*** SSH Progress Dialog Here + // ***TODO*** SSH Progress Dialog Here //sshData->status = new SSHStatus(sshData); arrpush(_activeSSHs, sshData); return sshData; } +*/ + + +gboolean sshSFTPFileExists(SSHT *sshData, char *target) { + LIBSSH2_SFTP *session; + LIBSSH2_SFTP_HANDLE *handle; + LIBSSH2_SFTP_ATTRIBUTES attrs; + char *path; + char *file; + char buffer[512]; + int rc; + gboolean result = FALSE; + + do { + session = libssh2_sftp_init(sshData->session); + if (!session) { + if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) { + return FALSE; + } + } + } while (!session); + + path = utilFilePath(target); + file = utilFileBasename(target); + + do { + handle = libssh2_sftp_opendir(session, path); + if ((!handle) && (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN)) { + libssh2_sftp_shutdown(session); + free(file); + free(path); + return FALSE; + } + } while (!handle); + + do { + while ((rc = libssh2_sftp_readdir(handle, buffer, sizeof(buffer), &attrs)) == LIBSSH2_ERROR_EAGAIN) { + ; + } + // rc is the size of the content in buffer + if (rc > 0) { + if (strcmp(buffer, file) == 0) { + result = TRUE; + break; + } + } else { + if (rc == LIBSSH2_ERROR_EAGAIN) { + // Blocking - do nothing + } else { + // Finished. + break; + } + } + } while(1); + + free(file); + free(path); + + libssh2_sftp_closedir(handle); + libssh2_sftp_shutdown(session); + + return result; +} + + +SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPCallback callback) { + SFTPT *sftp = NULL; + int i; + + // Do not allow two of the same transfers to be started. + for (i=0; isource, source) == 0) && (strcmp(_activeSFTPs[i]->target, target) == 0)) { + // Return existing transfer handle. + return _activeSFTPs[i]; + } + } + + sftp = NEW(SFTPT); + + if (sftp) { + sftp->fileSize = utilFileSize(source); + sftp->local = fopen(source, "rb"); + if (sftp->local) { + sftp->fileSent = 0; + sftp->nread = 0; + sftp->ptr = NULL; + sftp->title = title; + sftp->source = source; + sftp->target = target; + sftp->sshData = sshData; + sftp->uploading = TRUE; + sftp->readMore = TRUE; + sftp->finished = FALSE; + sftp->success = FALSE; + sftp->callback = callback; + do { + sftp->session = libssh2_sftp_init(sshData->session); + if (!sftp->session) { + if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) { + break; + } + } + } while (!sftp->session); + do { + sftp->handle = libssh2_sftp_open(sftp->session, sftp->target, LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC, LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP | LIBSSH2_SFTP_S_IROTH); + if (!sftp->handle) { + if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) { + break; + } + } + } while (!sftp->handle); + if (sftp->handle) { + //***TODO*** SFTP Status Dialog + //sftp->status = new SFTPStatus(sftp); + arrput(_activeSFTPs, sftp); + return sftp; + } else { + message(MSG_SEVERE, "Failed to get SFTP handle! %d, %lu\n", libssh2_session_last_errno(sshData->session), libssh2_sftp_last_error(sftp->session)); + libssh2_sftp_shutdown(sftp->session); + DEL(sftp); + } + } else { + DEL(sftp); + } + } + + return NULL; +} + + +gboolean sshSFTPUpdate(gpointer userData) { + int i; + int rc; + int count = 0; + SFTPT *result = NULL; + + (void)userData; + + for (i=0; ireadMore) { + _activeSFTPs[i]->nread = fread(_activeSFTPs[i]->buffer, 1, sizeof(_activeSFTPs[i]->buffer), _activeSFTPs[i]->local); + if (_activeSFTPs[i]->nread <= 0) { + result = _activeSFTPs[i]; + arrdel(_activeSFTPs, i); + break; + } + _activeSFTPs[i]->ptr = _activeSFTPs[i]->buffer; + _activeSFTPs[i]->readMore = FALSE; + } + + // Is there data to send? + if (_activeSFTPs[i]->nread > 0) { + // Send data. + while ((rc = (int)libssh2_sftp_write(_activeSFTPs[i]->handle, _activeSFTPs[i]->ptr, _activeSFTPs[i]->nread)) == LIBSSH2_ERROR_EAGAIN) { + sshWaitSocket(_activeSFTPs[i]->sshData->sock, _activeSFTPs[i]->sshData->session); + } + if (rc >= 0) { + _activeSFTPs[i]->ptr += rc; + _activeSFTPs[i]->nread -= rc; + _activeSFTPs[i]->fileSent += rc; + } else { + // We need more data! + _activeSFTPs[i]->readMore = TRUE; + } + } else { + // We need more data! + _activeSFTPs[i]->readMore = TRUE; + } + } + + if (result) { + result->finished = TRUE; + result->success = TRUE; + libssh2_sftp_close(result->handle); + libssh2_sftp_shutdown(result->session); + //***TODO*** Display in status dialog + //result->status->Finished(); + //result->status->Close(); + if (result->callback) { + result->callback(result); + } + DEL(result); + } + + return count; +} void sshShutdown(void) { //***TODO*** Any active sessions? g_idle_remove_by_data(sshUpdate); + g_idle_remove_by_data(sshSFTPUpdate); DEL(_output); DEL(_buffer); @@ -240,6 +433,7 @@ void sshStartup(void) { utilEnsureBufferSize((unsigned char **)&_buffer, &_bufferLen, 0x4000); g_idle_add(sshUpdate, sshUpdate); + g_idle_add(sshSFTPUpdate, sshSFTPUpdate); } diff --git a/src/utils.c b/src/utils.c index 0d2b1fb..f329b23 100644 --- a/src/utils.c +++ b/src/utils.c @@ -177,6 +177,8 @@ char *utilFileBasename(char *path) { size_t length; char *newString = NULL; + // Returns filename without path. + cwk_path_get_basename(path, &basename, &length); if (basename != NULL) newString = strdup(basename); @@ -272,6 +274,21 @@ gboolean utilFileOpen(WindowDataT *self, char *extension, char *what) { } +char *utilFilePath(char *filename) { + int i; + char *temp = NULL; + + if (filename) { + // Derive the path from the filename. + temp = strdup(filename); + cwk_path_get_dirname(temp, &i); + if (i > 0) temp[i] = 0; + } + + return temp; +} + + char *utilFileRemoveExtension(char *filename) { int x = (int)strlen(filename) - 1; char c; @@ -347,6 +364,21 @@ gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, cha } +size_t utilFileSize(char *filename) { + size_t bytes = 0; + + FILE *f = fopen(filename, "rb"); + + if (f) { + fseek(f, 0, SEEK_END); + bytes = ftell(f); + fclose(f); + } + + return bytes; +} + + GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name) { GList *children = NULL; GtkWidget *widget = NULL; @@ -599,16 +631,8 @@ void utilSetDirty(WindowDataT *self, gboolean dirty) { void utilUpdatePath(WindowDataT *self) { - size_t i; - DEL(self->path); - - if (self->filename) { - // Derive the path from the filename. - self->path = strdup(self->filename); - cwk_path_get_dirname(self->path, &i); - if (i > 0) self->path[i] = 0; - } + self->path = utilFilePath(self->filename); }