Builds being sent and received over SFTP! Now to unpack them!
This commit is contained in:
parent
f34af2f6ff
commit
8de2ffc18f
6 changed files with 253 additions and 82 deletions
|
@ -44,9 +44,7 @@ typedef struct SSHS {
|
||||||
int sock;
|
int sock;
|
||||||
int result;
|
int result;
|
||||||
gboolean finished;
|
gboolean finished;
|
||||||
char *title;
|
|
||||||
SSHCallback callback;
|
SSHCallback callback;
|
||||||
GtkWidget *status;
|
|
||||||
} SSHT;
|
} SSHT;
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,14 +59,12 @@ typedef struct SFTPS {
|
||||||
uint64_t fileSize;
|
uint64_t fileSize;
|
||||||
uint64_t fileSent;
|
uint64_t fileSent;
|
||||||
size_t nread;
|
size_t nread;
|
||||||
char *source;
|
char *localName;
|
||||||
char *target;
|
char *remoteName;
|
||||||
char *title;
|
|
||||||
gboolean uploading;
|
gboolean uploading;
|
||||||
gboolean readMore;
|
gboolean readMore;
|
||||||
gboolean finished;
|
gboolean finished;
|
||||||
gboolean success;
|
gboolean success;
|
||||||
GtkWidget *status;
|
|
||||||
SFTPCallback callback;
|
SFTPCallback callback;
|
||||||
} SFTPT;
|
} SFTPT;
|
||||||
|
|
||||||
|
@ -77,7 +73,8 @@ SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password);
|
||||||
void sshDisconnect(SSHT **sshData);
|
void sshDisconnect(SSHT **sshData);
|
||||||
//int sshExecute(SSHT *sshData, char *command, char **output);
|
//int sshExecute(SSHT *sshData, char *command, char **output);
|
||||||
gboolean sshSFTPFileExists(SSHT *sshData, char *target);
|
gboolean sshSFTPFileExists(SSHT *sshData, char *target);
|
||||||
SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPCallback callback);
|
SFTPT *sshSFTPReceive(SSHT *sshData, char *remote, char *local, SFTPCallback callback);
|
||||||
|
SFTPT *sshSFTPSend(SSHT *sshData, char *local, char *remote, SFTPCallback callback);
|
||||||
void sshShutdown(void);
|
void sshShutdown(void);
|
||||||
void sshStartup(void);
|
void sshStartup(void);
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ gboolean utilFileSaveAs(WindowDataT *self, char *extension, char *what);
|
||||||
gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, char **filename);
|
gboolean utilFileSaveOtherAs(WindowDataT *self, char *extension, char *what, char **filename);
|
||||||
size_t utilFileSize(char *filename);
|
size_t utilFileSize(char *filename);
|
||||||
GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name);
|
GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name);
|
||||||
|
void utilForceUpdate(void);
|
||||||
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock);
|
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock);
|
||||||
WindowDataT *utilGetWindowData(GtkWidget *window);
|
WindowDataT *utilGetWindowData(GtkWidget *window);
|
||||||
gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData);
|
gboolean utilGetWidgetsFromMemory(char *resource, char *name[], GtkWidget **widgets[], gpointer userData);
|
||||||
|
|
|
@ -26,8 +26,10 @@
|
||||||
|
|
||||||
|
|
||||||
static GtkWidget *_lstMessages = NULL;
|
static GtkWidget *_lstMessages = NULL;
|
||||||
|
static int _autoScroll = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean messagesScroll(gpointer userData);
|
||||||
EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData);
|
EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData);
|
||||||
static void winMessagesDelete(gpointer userData);
|
static void winMessagesDelete(gpointer userData);
|
||||||
|
|
||||||
|
@ -43,19 +45,19 @@ void message(MessageTypesT level, char *format, ...) {
|
||||||
NULL,
|
NULL,
|
||||||
&_lstMessages
|
&_lstMessages
|
||||||
};
|
};
|
||||||
GtkWidget *row;
|
GtkWidget *row;
|
||||||
GtkWidget *box;
|
GtkWidget *box;
|
||||||
GtkWidget *label;
|
GtkWidget *label;
|
||||||
va_list args;
|
va_list args;
|
||||||
char *string;
|
char *string;
|
||||||
char *msg;
|
char *msg;
|
||||||
char *tok;
|
char *tok;
|
||||||
char *labels[MSG_COUNT] = {
|
char *labels[MSG_COUNT] = {
|
||||||
"<span foreground=\"gray\"> Info:</span>",
|
"<span foreground=\"gray\"> Info:</span>",
|
||||||
"<span foreground=\"yellow\">Warning:</span>",
|
"<span foreground=\"yellow\">Warning:</span>",
|
||||||
"<span foreground=\"red\"> Error:</span>",
|
"<span foreground=\"red\"> Error:</span>",
|
||||||
"<span foreground=\"red\"><b> Severe:</b></span>"
|
"<span foreground=\"red\"><b> Severe:</b></span>"
|
||||||
};
|
};
|
||||||
|
|
||||||
// Do we need to open this window?
|
// Do we need to open this window?
|
||||||
if (!_lstMessages) {
|
if (!_lstMessages) {
|
||||||
|
@ -71,6 +73,9 @@ void message(MessageTypesT level, char *format, ...) {
|
||||||
|
|
||||||
// Show window.
|
// Show window.
|
||||||
gtk_widget_show_all(self->window);
|
gtk_widget_show_all(self->window);
|
||||||
|
|
||||||
|
// Set up automatic scrolling.
|
||||||
|
g_idle_add(messagesScroll, messagesScroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display message.
|
// Display message.
|
||||||
|
@ -96,13 +101,35 @@ void message(MessageTypesT level, char *format, ...) {
|
||||||
gtk_container_add(GTK_CONTAINER(row), box);
|
gtk_container_add(GTK_CONTAINER(row), box);
|
||||||
gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1);
|
gtk_list_box_insert(GTK_LIST_BOX(_lstMessages), row, -1);
|
||||||
|
|
||||||
|
// Force paint.
|
||||||
gtk_widget_show_all(row);
|
gtk_widget_show_all(row);
|
||||||
|
utilForceUpdate();
|
||||||
|
_autoScroll = 5; // Try 5 times to show the new row.
|
||||||
|
|
||||||
tok = strtok(NULL, "\n");
|
tok = strtok(NULL, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean messagesScroll(gpointer userData) {
|
||||||
|
GtkAdjustment *adjustment;
|
||||||
|
|
||||||
|
(void)userData;
|
||||||
|
|
||||||
|
if (_autoScroll <= 0) return G_SOURCE_CONTINUE;
|
||||||
|
|
||||||
|
// Scroll to show new line.
|
||||||
|
adjustment = gtk_list_box_get_adjustment(GTK_LIST_BOX(_lstMessages));
|
||||||
|
gtk_adjustment_set_value(adjustment, gtk_adjustment_get_upper(adjustment));
|
||||||
|
gtk_widget_show_all(_lstMessages);
|
||||||
|
utilForceUpdate();
|
||||||
|
|
||||||
|
_autoScroll--;
|
||||||
|
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData) {
|
EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData) {
|
||||||
// userData is not reliable due to util indirectly calling us.
|
// userData is not reliable due to util indirectly calling us.
|
||||||
WindowDataT *self = (WindowDataT *)utilGetWindowData(object);
|
WindowDataT *self = (WindowDataT *)utilGetWindowData(object);
|
||||||
|
@ -115,6 +142,7 @@ EVENT gboolean winMessagesClose(GtkWidget *object, gpointer userData) {
|
||||||
|
|
||||||
|
|
||||||
static void winMessagesDelete(gpointer userData) {
|
static void winMessagesDelete(gpointer userData) {
|
||||||
|
g_idle_remove_by_data(messagesScroll);
|
||||||
utilWindowUnRegister(userData);
|
utilWindowUnRegister(userData);
|
||||||
_lstMessages = NULL;
|
_lstMessages = NULL;
|
||||||
DEL(userData);
|
DEL(userData);
|
||||||
|
|
106
src/project.c
106
src/project.c
|
@ -132,12 +132,14 @@ EVENT void menuProjectBuildTargets(GtkWidget *object, gpointer userData
|
||||||
EVENT void menuProjectBuildCookRecipes(GtkWidget *object, gpointer userData);
|
EVENT void menuProjectBuildCookRecipes(GtkWidget *object, gpointer userData);
|
||||||
EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData);
|
EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData);
|
||||||
EVENT void menuProjectHelpProject(GtkWidget *object, gpointer userData);
|
EVENT void menuProjectHelpProject(GtkWidget *object, gpointer userData);
|
||||||
|
static void receiveSFTP(SFTPT *sftp);
|
||||||
static void saveConfig(ProjectDataT *self);
|
static void saveConfig(ProjectDataT *self);
|
||||||
static void sendSFTP(SFTPT *sftp);
|
static void sendSFTP(SFTPT *sftp);
|
||||||
static TargetT **targetArrayCopy(TargetT **targets);
|
static TargetT **targetArrayCopy(TargetT **targets);
|
||||||
static void targetArrayDelete(TargetT ***array);
|
static void targetArrayDelete(TargetT ***array);
|
||||||
EVENT void treeProjectRowActivated(GtkTreeView *treeView, GtkTreePath *path, GtkTreeViewColumn *column, gpointer userData);
|
EVENT void treeProjectRowActivated(GtkTreeView *treeView, GtkTreePath *path, GtkTreeViewColumn *column, gpointer userData);
|
||||||
static gboolean updateBuildOptions(ProjectDataT *self);
|
static gboolean updateBuildOptions(ProjectDataT *self);
|
||||||
|
static gboolean waitForBuild(gpointer userData);
|
||||||
EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData);
|
EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData);
|
||||||
static void winProjectDelete(gpointer userData);
|
static void winProjectDelete(gpointer userData);
|
||||||
|
|
||||||
|
@ -955,20 +957,28 @@ EVENT void menuProjectBuildBuild(GtkWidget *object, gpointer userData) {
|
||||||
gboolean archPrinted;
|
gboolean archPrinted;
|
||||||
FILE *out;
|
FILE *out;
|
||||||
|
|
||||||
|
menuProjectBuildCookRecipes(object, userData);
|
||||||
|
|
||||||
ssh = NEW(SSHT);
|
ssh = NEW(SSHT);
|
||||||
ssh = sshConnect(self->buildHost, self->buildSSHPort, self->buildUser, self->buildPassword);
|
ssh = sshConnect(self->buildHost, self->buildSSHPort, self->buildUser, self->buildPassword);
|
||||||
|
|
||||||
if (!ssh) {
|
if (!ssh) {
|
||||||
message(MSG_ERROR, "Unable to connect to SSH port.");
|
message(MSG_ERROR, "Unable to connect to SSH port");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do we have a build package to clean up?
|
||||||
|
if (sshSFTPFileExists(ssh, "build/build.tar.bz2")) {
|
||||||
|
message(MSG_INFO, "Removing stale build results");
|
||||||
|
}
|
||||||
|
|
||||||
// Generate build.start.
|
// Generate build.start.
|
||||||
buildStart = utilCreateString("%sbuild.start", self->windowData.path);
|
buildStart = utilCreateString("%sbuild.start", self->windowData.path);
|
||||||
out = fopen(buildStart, "wt");
|
out = fopen(buildStart, "wt");
|
||||||
if (!out) {
|
if (!out) {
|
||||||
message(MSG_SEVERE, "Unable to write temporary build.start file.");
|
message(MSG_SEVERE, "Unable to write temporary build.start file");
|
||||||
unlink(buildStart); // Just in case.
|
unlink(buildStart); // Just in case.
|
||||||
|
message(MSG_INFO, "Build canceled");
|
||||||
sshDisconnect(&ssh);
|
sshDisconnect(&ssh);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1085,6 +1095,25 @@ gboolean projectAddToTree(ProjectDataT *self, char *filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void receiveSFTP(SFTPT *sftp) {
|
||||||
|
ProjectDataT *self = (ProjectDataT *)sftp->userData;
|
||||||
|
|
||||||
|
if (sftp->finished) {
|
||||||
|
if (sftp->success) {
|
||||||
|
//***TODO*** Unpack results
|
||||||
|
message(MSG_INFO, "Unpacking build");
|
||||||
|
} else {
|
||||||
|
message(MSG_ERROR, "Receiving %s from build server - FAILED", sftp->remoteName);
|
||||||
|
message(MSG_INFO, "Build canceled");
|
||||||
|
sshDisconnect(&sftp->sshData);
|
||||||
|
}
|
||||||
|
DEL(sftp->localName);
|
||||||
|
DEL(sftp->remoteName);
|
||||||
|
DEL(sftp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void saveConfig(ProjectDataT *self) {
|
static void saveConfig(ProjectDataT *self) {
|
||||||
char *temp;
|
char *temp;
|
||||||
FILE *out;
|
FILE *out;
|
||||||
|
@ -1249,32 +1278,56 @@ static gboolean updateBuildOptions(ProjectDataT *self) {
|
||||||
|
|
||||||
static void sendSFTP(SFTPT *sftp) {
|
static void sendSFTP(SFTPT *sftp) {
|
||||||
ProjectDataT *self = (ProjectDataT *)sftp->userData;
|
ProjectDataT *self = (ProjectDataT *)sftp->userData;
|
||||||
SFTPT *next;
|
SFTPT *last;
|
||||||
char *title;
|
|
||||||
char *target;
|
char *target;
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
last = sftp;
|
||||||
|
|
||||||
// If source and target are missing, this is the first file - start sending.
|
// If source and target are missing, this is the first file - start sending.
|
||||||
// Or, did the current transfer succeed? If so, send next file.
|
// Or, did the current transfer succeed? If so, send next file.
|
||||||
if ((sftp->source == NULL && sftp->target == NULL) || (sftp->finished && sftp->success)) {
|
if ((sftp->localName == NULL && sftp->remoteName == NULL) || (sftp->finished && sftp->success)) {
|
||||||
|
if (sftp->localName == NULL && sftp->remoteName == NULL) {
|
||||||
|
message(MSG_INFO, "Building %s", self->windowData.filename);
|
||||||
|
}
|
||||||
// Are there more files to send?
|
// Are there more files to send?
|
||||||
if (arrlen(_sendList) > 0) {
|
if (arrlen(_sendList) > 0) {
|
||||||
// Send next entry in the file list.
|
// Send next entry in the file list.
|
||||||
title = utilCreateString("Building %s", self->windowData.filename);
|
name = utilFileBasename(_sendList[0]);
|
||||||
target = utilFileBasename(_sendList[0]);
|
target = utilCreateString("build/%s", name);
|
||||||
sftp = sshSFTPSend(title, sftp->sshData, _sendList[0], target, sendSFTP);
|
message(MSG_INFO, "Sending %s to build server", name);
|
||||||
|
sftp = sshSFTPSend(last->sshData, _sendList[0], target, sendSFTP);
|
||||||
|
sftp->userData = self;
|
||||||
DEL(target);
|
DEL(target);
|
||||||
DEL(title);
|
DEL(name);
|
||||||
arrdel(_sendList, 0);
|
arrdel(_sendList, 0);
|
||||||
return;
|
|
||||||
} else {
|
} else {
|
||||||
// Finished!
|
// Finished!
|
||||||
//***TODO***
|
message(MSG_INFO, "Waiting for build to complete");
|
||||||
|
g_timeout_add_seconds(5, waitForBuild, last->sshData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Did the transfer fail?
|
// Do we have a transfer? Did the transfer fail?
|
||||||
if (sftp->finished && !sftp->success) {
|
if ((!sftp) || (sftp->finished && !sftp->success)) {
|
||||||
//***TODO***
|
if (sftp) {
|
||||||
|
message(MSG_ERROR, "Sending %s to build server - FAILED", sftp->remoteName);
|
||||||
|
}
|
||||||
|
message(MSG_INFO, "Build canceled");
|
||||||
|
sshDisconnect(&last->sshData);
|
||||||
|
// Clear any remaining transfers.
|
||||||
|
while (arrlen(_sendList) > 0) {
|
||||||
|
arrdel(_sendList, 0);
|
||||||
|
}
|
||||||
|
ARRFREE(_sendList);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do we need to free this?
|
||||||
|
if (last->finished) {
|
||||||
|
// Do not delete last->sshData as we continue to need it until everything is finished.
|
||||||
|
DEL(last->localName);
|
||||||
|
DEL(last->remoteName);
|
||||||
|
DEL(last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1326,6 +1379,31 @@ static void targetArrayDelete(TargetT ***array) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean waitForBuild(gpointer userData) {
|
||||||
|
SSHT *ssh = (SSHT *)userData;
|
||||||
|
SFTPT *sftp;
|
||||||
|
char *temp;
|
||||||
|
|
||||||
|
if (sshSFTPFileExists(ssh, "build/build.tar.bz2")) {
|
||||||
|
// Build complete! Next step!
|
||||||
|
message(MSG_INFO, "Retrieving build results");
|
||||||
|
temp = utilCreateString("%s%cbuild.tar.bz2", g_get_user_config_dir(), UTIL_PATH_CHAR);
|
||||||
|
sftp = sshSFTPReceive(ssh, "build/build.tar.bz2", temp, receiveSFTP);
|
||||||
|
DEL(temp);
|
||||||
|
if (!sftp) {
|
||||||
|
message(MSG_ERROR, "Receiving build from build server - FAILED");
|
||||||
|
message(MSG_INFO, "Build canceled");
|
||||||
|
sshDisconnect(&ssh);
|
||||||
|
}
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep waiting.
|
||||||
|
//***TODO*** Add a timeout of some kind here and sshDisconnect.
|
||||||
|
return G_SOURCE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData) {
|
EVENT gboolean winProjectClose(GtkWidget *object, gpointer userData) {
|
||||||
// userData is not reliable due to menuVectorFileClose and util indirectly calling us.
|
// userData is not reliable due to menuVectorFileClose and util indirectly calling us.
|
||||||
ProjectDataT *self = (ProjectDataT *)utilGetWindowData(object);
|
ProjectDataT *self = (ProjectDataT *)utilGetWindowData(object);
|
||||||
|
|
158
src/ssh.c
158
src/ssh.c
|
@ -47,9 +47,10 @@ static char *_buffer = NULL;
|
||||||
static int _bufferLen = 0;
|
static int _bufferLen = 0;
|
||||||
|
|
||||||
|
|
||||||
gboolean sshUpdate(gpointer userData); // Not static
|
gboolean sshUpdate(gpointer userData); // Not static
|
||||||
gboolean sshSFTPUpdate(gpointer userData); // Not static
|
static SFTPT *sshSFTPTransfer(SSHT *sshData, char *local, char *remote, SFTPCallback callback, gboolean uploading);
|
||||||
static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session);
|
gboolean sshSFTPUpdate(gpointer userData); // Not static
|
||||||
|
static int sshWaitSocket(int socket_fd, LIBSSH2_SESSION *session);
|
||||||
|
|
||||||
|
|
||||||
SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
|
SSHT *sshConnect(char *hostname, uint16_t port, char *user, char *password) {
|
||||||
|
@ -220,6 +221,7 @@ gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
|
||||||
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||||
char *path;
|
char *path;
|
||||||
char *file;
|
char *file;
|
||||||
|
char *temp;
|
||||||
char buffer[512];
|
char buffer[512];
|
||||||
int rc;
|
int rc;
|
||||||
gboolean result = FALSE;
|
gboolean result = FALSE;
|
||||||
|
@ -233,8 +235,25 @@ gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
|
||||||
}
|
}
|
||||||
} while (!session);
|
} while (!session);
|
||||||
|
|
||||||
path = utilFilePath(target);
|
// Split filename and path.
|
||||||
file = utilFileBasename(target);
|
// Cannot use utilFilePath and friends because this is a remote path.
|
||||||
|
temp = strdup(target); // Make copy in case they pass in a constant.
|
||||||
|
path = strdup("/"); // Set some defaults.
|
||||||
|
file = strdup(target); // Set some defaults.
|
||||||
|
rc = (int)strlen(temp);
|
||||||
|
while (rc > 0) {
|
||||||
|
if (temp[rc] == '/') {
|
||||||
|
// Found it.
|
||||||
|
temp[rc] = 0;
|
||||||
|
DEL(path);
|
||||||
|
DEL(file);
|
||||||
|
path = strdup(temp);
|
||||||
|
file = strdup(&temp[rc + 1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rc--;
|
||||||
|
}
|
||||||
|
DEL(temp);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
handle = libssh2_sftp_opendir(session, path);
|
handle = libssh2_sftp_opendir(session, path);
|
||||||
|
@ -276,13 +295,23 @@ gboolean sshSFTPFileExists(SSHT *sshData, char *target) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPCallback callback) {
|
SFTPT *sshSFTPReceive(SSHT *sshData, char *remote, char *local, SFTPCallback callback) {
|
||||||
|
return sshSFTPTransfer(sshData, local, remote, callback, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SFTPT *sshSFTPSend(SSHT *sshData, char *local, char *remote, SFTPCallback callback) {
|
||||||
|
return sshSFTPTransfer(sshData, local, remote, callback, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static SFTPT *sshSFTPTransfer(SSHT *sshData, char *local, char *remote, SFTPCallback callback, gboolean uploading) {
|
||||||
SFTPT *sftp = NULL;
|
SFTPT *sftp = NULL;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Do not allow two of the same transfers to be started.
|
// Do not allow two of the same transfers to be started.
|
||||||
for (i=0; i<arrlen(_activeSFTPs); i++) {
|
for (i=0; i<arrlen(_activeSFTPs); i++) {
|
||||||
if ((strcmp(_activeSFTPs[i]->source, source) == 0) && (strcmp(_activeSFTPs[i]->target, target) == 0)) {
|
if ((strcmp(_activeSFTPs[i]->localName, local) == 0) && (strcmp(_activeSFTPs[i]->remoteName, remote) == 0)) {
|
||||||
// Return existing transfer handle.
|
// Return existing transfer handle.
|
||||||
return _activeSFTPs[i];
|
return _activeSFTPs[i];
|
||||||
}
|
}
|
||||||
|
@ -291,21 +320,20 @@ SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPC
|
||||||
sftp = NEW(SFTPT);
|
sftp = NEW(SFTPT);
|
||||||
|
|
||||||
if (sftp) {
|
if (sftp) {
|
||||||
sftp->fileSize = utilFileSize(source);
|
sftp->fileSize = uploading ? utilFileSize(local) : 0;
|
||||||
sftp->local = fopen(source, "rb");
|
sftp->local = fopen(local, uploading ? "rb" : "wb");
|
||||||
if (sftp->local) {
|
if (sftp->local) {
|
||||||
sftp->fileSent = 0;
|
sftp->fileSent = 0;
|
||||||
sftp->nread = 0;
|
sftp->nread = 0;
|
||||||
sftp->ptr = NULL;
|
sftp->ptr = NULL;
|
||||||
sftp->title = strdup(title);
|
sftp->localName = strdup(local);
|
||||||
sftp->source = strdup(source);
|
sftp->remoteName = strdup(remote);
|
||||||
sftp->target = strdup(target);
|
sftp->sshData = sshData;
|
||||||
sftp->sshData = sshData;
|
sftp->uploading = uploading;
|
||||||
sftp->uploading = TRUE;
|
sftp->readMore = TRUE;
|
||||||
sftp->readMore = TRUE;
|
sftp->finished = FALSE;
|
||||||
sftp->finished = FALSE;
|
sftp->success = FALSE;
|
||||||
sftp->success = FALSE;
|
sftp->callback = callback;
|
||||||
sftp->callback = callback;
|
|
||||||
do {
|
do {
|
||||||
sftp->session = libssh2_sftp_init(sshData->session);
|
sftp->session = libssh2_sftp_init(sshData->session);
|
||||||
if (!sftp->session) {
|
if (!sftp->session) {
|
||||||
|
@ -315,7 +343,17 @@ SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPC
|
||||||
}
|
}
|
||||||
} while (!sftp->session);
|
} while (!sftp->session);
|
||||||
do {
|
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 (uploading) {
|
||||||
|
sftp->handle = libssh2_sftp_open(sftp->session, sftp->remoteName,
|
||||||
|
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);
|
||||||
|
} else {
|
||||||
|
sftp->handle = libssh2_sftp_open(sftp->session, sftp->remoteName,
|
||||||
|
LIBSSH2_FXF_READ,
|
||||||
|
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR | LIBSSH2_SFTP_S_IRGRP |
|
||||||
|
LIBSSH2_SFTP_S_IROTH);
|
||||||
|
}
|
||||||
if (!sftp->handle) {
|
if (!sftp->handle) {
|
||||||
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
|
if (libssh2_session_last_errno(sshData->session) != LIBSSH2_ERROR_EAGAIN) {
|
||||||
break;
|
break;
|
||||||
|
@ -323,8 +361,6 @@ SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPC
|
||||||
}
|
}
|
||||||
} while (!sftp->handle);
|
} while (!sftp->handle);
|
||||||
if (sftp->handle) {
|
if (sftp->handle) {
|
||||||
//***TODO*** SFTP Status Dialog
|
|
||||||
//sftp->status = new SFTPStatus(sftp);
|
|
||||||
arrput(_activeSFTPs, sftp);
|
arrput(_activeSFTPs, sftp);
|
||||||
return sftp;
|
return sftp;
|
||||||
} else {
|
} else {
|
||||||
|
@ -344,60 +380,78 @@ SFTPT *sshSFTPSend(char *title, SSHT *sshData, char *source, char *target, SFTPC
|
||||||
gboolean sshSFTPUpdate(gpointer userData) {
|
gboolean sshSFTPUpdate(gpointer userData) {
|
||||||
int i;
|
int i;
|
||||||
int rc;
|
int rc;
|
||||||
int count = 0;
|
|
||||||
SFTPT *result = NULL;
|
SFTPT *result = NULL;
|
||||||
|
|
||||||
(void)userData;
|
(void)userData;
|
||||||
|
|
||||||
for (i=0; i<arrlen(_activeSFTPs); i++) {
|
for (i=0; i<arrlen(_activeSFTPs); i++) {
|
||||||
count++;
|
// Uploading or downloading?
|
||||||
// More data to read?
|
if (_activeSFTPs[i]->uploading) {
|
||||||
if (_activeSFTPs[i]->readMore) {
|
// Uploading
|
||||||
_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?
|
// More data to read?
|
||||||
if (_activeSFTPs[i]->nread > 0) {
|
if (_activeSFTPs[i]->readMore) {
|
||||||
// Send data.
|
_activeSFTPs[i]->nread = fread(_activeSFTPs[i]->buffer, 1, sizeof(_activeSFTPs[i]->buffer), _activeSFTPs[i]->local);
|
||||||
while ((rc = (int)libssh2_sftp_write(_activeSFTPs[i]->handle, _activeSFTPs[i]->ptr, _activeSFTPs[i]->nread)) == LIBSSH2_ERROR_EAGAIN) {
|
if (_activeSFTPs[i]->nread <= 0) {
|
||||||
sshWaitSocket(_activeSFTPs[i]->sshData->sock, _activeSFTPs[i]->sshData->session);
|
result = _activeSFTPs[i];
|
||||||
|
arrdel(_activeSFTPs, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_activeSFTPs[i]->ptr = _activeSFTPs[i]->buffer;
|
||||||
|
_activeSFTPs[i]->readMore = FALSE;
|
||||||
}
|
}
|
||||||
if (rc >= 0) {
|
|
||||||
_activeSFTPs[i]->ptr += rc;
|
// Is there data to send?
|
||||||
_activeSFTPs[i]->nread -= rc;
|
if (_activeSFTPs[i]->nread > 0) {
|
||||||
_activeSFTPs[i]->fileSent += rc;
|
// 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 {
|
} else {
|
||||||
// We need more data!
|
// We need more data!
|
||||||
_activeSFTPs[i]->readMore = TRUE;
|
_activeSFTPs[i]->readMore = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// We need more data!
|
// Downloading
|
||||||
_activeSFTPs[i]->readMore = TRUE;
|
|
||||||
|
// Data to read?
|
||||||
|
while ((rc = libssh2_sftp_read(_activeSFTPs[i]->handle, _activeSFTPs[i]->buffer, sizeof(_activeSFTPs[i]->buffer))) == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
sshWaitSocket(_activeSFTPs[i]->sshData->sock, _activeSFTPs[i]->sshData->session);
|
||||||
|
}
|
||||||
|
if (rc > 0) {
|
||||||
|
_activeSFTPs[i]->fileSize += rc;
|
||||||
|
fwrite(_activeSFTPs[i]->buffer, 1, rc, _activeSFTPs[i]->local);
|
||||||
|
} else {
|
||||||
|
result = _activeSFTPs[i];
|
||||||
|
arrdel(_activeSFTPs, i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
result->finished = TRUE;
|
result->finished = TRUE;
|
||||||
result->success = TRUE;
|
result->success = TRUE;
|
||||||
|
fclose(result->local);
|
||||||
libssh2_sftp_close(result->handle);
|
libssh2_sftp_close(result->handle);
|
||||||
libssh2_sftp_shutdown(result->session);
|
libssh2_sftp_shutdown(result->session);
|
||||||
//***TODO*** Display in status dialog
|
|
||||||
//result->status->Finished();
|
|
||||||
//result->status->Close();
|
|
||||||
if (result->callback) {
|
if (result->callback) {
|
||||||
result->callback(result);
|
result->callback(result);
|
||||||
}
|
}
|
||||||
DEL(result);
|
DEL(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return G_SOURCE_CONTINUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
13
src/utils.c
13
src/utils.c
|
@ -409,6 +409,16 @@ GtkWidget *utilFindChildWidget(GtkWidget *parent, const gchar *name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void utilForceUpdate(void) {
|
||||||
|
//***TODO*** This is supposed to force any pending paint operations.
|
||||||
|
// It doesn't work.
|
||||||
|
|
||||||
|
//while (g_main_context_pending(NULL)) {
|
||||||
|
g_main_context_iteration(NULL,FALSE);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock) {
|
char *utilGetToken(char *input, char *delimit, char *openblock, char *closeblock) {
|
||||||
static char *token = NULL;
|
static char *token = NULL;
|
||||||
char *lead = NULL;
|
char *lead = NULL;
|
||||||
|
@ -642,6 +652,9 @@ void utilWindowRegister(gpointer windowData) {
|
||||||
// Grab title.
|
// Grab title.
|
||||||
w->title = strdup(gtk_window_get_title(GTK_WINDOW(w->window)));
|
w->title = strdup(gtk_window_get_title(GTK_WINDOW(w->window)));
|
||||||
|
|
||||||
|
gtk_widget_show_all(w->window);
|
||||||
|
utilForceUpdate();
|
||||||
|
|
||||||
hmput(_windowList, w->window, windowData);
|
hmput(_windowList, w->window, windowData);
|
||||||
debug("Window Registered: %ld\n", hmlen(_windowList));
|
debug("Window Registered: %ld\n", hmlen(_windowList));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue