/*
* Queued FTP Client
*
* $Revision: 1.9 $
* $Date: 2003/03/11 01:26:39 $
* vim: sw=4 ts=4
*
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <dirent.h>
#include <glob.h>
#ifndef __GLIBC__
#include <term.h>
#endif
#include "ftp.h"
#include "text.h"
#include "rc.h"
#include "quftp.h"
/* Increase this for a steadier but less accurate ETA and Speed readout */
#define SPEEDS_AVERAGE 5
/* Maximum number of concurrent connections */
#define MAX_CONNECTIONS 3
/* Define a couple of very handy macros */
#define CURRENT_CONNECTION connection[atoi(config(variables, "CURRENT_CONNECTION"))]
#define LAST_CONNECTION connection[atoi(config(variables, "LAST_CONNECTION"))]
struct ftpconnection *connection[MAX_CONNECTIONS];
struct qitem *leftqueue = NULL;
struct variable_list *variables = NULL;
struct alias_list *aliases = NULL;
struct COMMAND command_list[] = {
{"ls", cmd_ls, "List current directory", NULL},
{"lls", cmd_lls, "List local directory", NULL},
{"dir", cmd_ls, "Synonym for \"ls\"", NULL},
{"cd", cmd_cd, "Change the current directory", NULL},
{"lcd", cmd_lcd, "Change the current local directory", NULL},
{"pwd", cmd_pwd, "Show current working directory", NULL},
{"get", cmd_get, "Queue a file for download", NULL},
{"put", cmd_put, "Queue a file for upload", NULL},
{"fxp", cmd_fxp, "Queue a file to be transferred between connections", NULL},
{"go", cmd_go, "Start transferring the queue", NULL},
{"clear", cmd_clear, "Delete all items from the queue", NULL},
{"queue", cmd_queue, "List all items on the queue", NULL},
{"quit", cmd_quit, "Exit the program", NULL},
{"close", cmd_close, "Disconnect from the server", NULL},
{"open", cmd_open, "Connect to a server", NULL},
{"status", cmd_status, "Show current status", NULL},
{"stat", cmd_stat, "Display file statistics", NULL},
{"nlst", cmd_nlst, "List filenames in current directory only", NULL},
{"switch", NULL, "Switch to another connection", NULL},
{"debug", NULL, "Set debugging level", "Specify the debug level from 1 to 5"},
{"user", cmd_user, "Enter username and password for the server", "Syntax: user username [password]\nPassword is optional and should be separated from username by a space."},
{"cat", cmd_cat, "Output a text file to stdout", NULL},
{"more", cmd_more, "Page a text file", NULL},
{"set", cmd_set, "Set a variable", NULL},
{"unset", cmd_unset, "Remove a variable", NULL},
{"rm", cmd_dele, "Delete a remote file", NULL},
{"run", NULL, "Run a script file", NULL},
{"alias", cmd_alias, "Define a command alias", NULL},
{"getlist", cmd_getlist, "Get all files listed in param.txt", NULL},
{"assert", cmd_assert, "Die if the last operation was not successful", NULL},
{"quote", cmd_quote, "Send a command directly to the server", NULL},
{"exit", cmd_quit, "Synonym for quit", NULL},
{"mkdir", cmd_mkdir, "Make directory", NULL},
{"rmdir", cmd_rmdir, "Remove directory", NULL},
{NULL, NULL, NULL, NULL}
};
int main(int argc, char **argv) {
int arg, ignoreerrors = 0;
int i;
FILE *scriptfile = NULL;
FILE *rcfilehandle = NULL;
char *rcfile = NULL;
log_set_level(5);
log_show_function = false;
log_show_pid = false;
log_show_file = false;
log_show_level = false;
log_show_date = false;
setbuf(stdout, NULL);
log(LOG_CRITICAL, "quftp version %s David Parrish (david@dparrish.com)\n\n", VERSION);
leftqueue = NULL;
rl_attempted_completion_function = (CPPFunction *)quftp_completion;
setconfig(&variables, "PROGRAM_NAME", "quftp");
setconfig(&variables, "VERSION", VERSION);
setconfig(&variables, "CURRENT_CONNECTION", "0");
setconfig(&variables, "LAST_CONNECTION", "1");
for (i = 0; i < MAX_CONNECTIONS; i++) {
connection[i] = ftp_new();
connection[i]->variables = variables;
getcwd((char *)connection[i]->localdir, 256);
}
/* Process command line arguments */
while ((arg = getopt(argc, argv, "d::r:s:ih")) != -1)
switch (arg) {
case 'd': if (optarg)
log_set_level(atoi(optarg));
else
log_set_level(log_get_level() + 1);
log(log_get_level(), __FILE__, __LINE__, __FUNCTION__, "Debugging level is now %d", log_get_level());
break;
case 'i': ignoreerrors = 1;
break;
case 'r': rcfile = strdup(optarg);
log(LOG_WARNING, "Reading configuration from %s\n", rcfile);
break;
case 's': if (!(scriptfile = fopen(optarg, "r"))) {
perror("fopen");
if (!ignoreerrors) exit(0);
}
break;
case 'h': printf("Usage: quftp [-vhi] [-d[n]] [-rfilename] [-sfilename] [URL]\n\n");
printf(" -h Print this help, then exit\n");
printf(" -d Increase debugging level (optional argument)\n");
printf(" -i Ignore errors in a script\n");
printf(" -r Read configuration from filename instead of %s\n", DEFAULT_RC_FILENAME);
printf(" -s Process script filename\n");
printf(" URL Connect to any valid ftp url.. Read man 1 quftp for more information\n");
printf("\n");
exit(0);
break;
}
if (!rcfile) {
rcfile = strdup(DEFAULT_RC_FILENAME);
}
if (rcfile) {
rcfile = expand_home(rcfile);
rcfilehandle = fopen(rcfile, "r");
if (!rcfilehandle) log(LOG_WARNING, "Can't find rcfile %s", rcfile);
}
if (optind < argc) {
if (!parseurl(argv[optind], CURRENT_CONNECTION)) {
log(LOG_ALERT, "There was an error parsing \"%s\"\n", argv[optind]);
} else {
if (strlen(CURRENT_CONNECTION->password) == 0) {
if (config(variables, "email"))
strncpy((char *)CURRENT_CONNECTION->password, config(variables, "email"), 32);
else
strncpy((char *)CURRENT_CONNECTION->password, "user@quftp.com", 32);
}
CURRENT_CONNECTION->status = STATUS_WAIT_CONNECT;
if (CURRENT_CONNECTION->remotedir[0] != '\0')
(void)getconnected(CURRENT_CONNECTION);
}
}
while (1) {
char *line = NULL, *command_word = NULL;
struct COMMAND *command = NULL;
register int i;
int result;
if (line) {
free(line);
line = NULL;
}
if (rcfilehandle) {
char *temp;
line = (char *)malloc(4096);
fgets(line, 4096, rcfilehandle);
if (!*line) { /* End of script? */
fclose(rcfilehandle);
rcfilehandle = NULL;
continue;
}
if (*line == '#') continue; // Comment
temp = strchr(line, '\n');
if (temp == line) continue; // Zero length line?
else *temp = '\0'; // Strip \n
log(LOG_INFO, "%s> %s", rcfile, line);
} else if (scriptfile) { /* Reading from a script or command line? */
char *temp;
line = (char *)malloc(4096);
fgets(line, 4096, scriptfile);
if (!*line) { /* End of script? */
fclose(scriptfile);
scriptfile = NULL;
continue;
}
if (*line == '#') continue;
temp = strchr(line, '\n');
if (temp == line) continue; // Zero length line?
else *temp = '\0'; // Strip \n
add_history(line);
printf("quftp> %s\n", line);
} else {
line = readline("quftp> ");
if (!line) { // NULL returned from readline is CTRL-D
line=strdup("quit");
} else if(!*line) { // "" returned from readline is an empty line
continue;
}
add_history(line);
}
line = parseline(line);
line = expand_alias(line);
command_word = getnextword(line, GNW_START);
if (!command_word || !*command_word) continue;
/* Match core command set */
if (strcasecmp(command_word, "switch") == 0) {
char *temp;
char *param = getnextword(line, GNW_NEXT);
if (!param) {
int curr = atoi(config(variables, "CURRENT_CONNECTION"));
int last = atoi(config(variables, "LAST_CONNECTION"));
temp = (char *)malloc(4096);
sprintf(temp, "%d", last);
setconfig(&variables, "CURRENT_CONNECTION", temp);
sprintf(temp, "%d", curr);
setconfig(&variables, "LAST_CONNECTION", temp);
free(temp);
} else {
int new_connection = atoi(param);
if (new_connection >= MAX_CONNECTIONS) {
log(LOG_CRITICAL, "Only %d number of connections avaliable (0-%d)\n",
MAX_CONNECTIONS, MAX_CONNECTIONS-1);
continue;
} else {
temp = (char *)malloc(4096);
if (new_connection == atoi(config(variables, "CURRENT_CONNECTION"))) continue;
setconfig(&variables, "LAST_CONNECTION", config(variables, "CURRENT_CONNECTION"));
sprintf(temp, "%d", new_connection);
setconfig(&variables, "CURRENT_CONNECTION", temp);
free(temp);
}
}
log(LOG_WARNING, "Switched to connection %s\n", config(variables, "CURRENT_CONNECTION"));
setconfig(&variables, "HOSTNAME", *CURRENT_CONNECTION->hostname ? CURRENT_CONNECTION->hostname : NULL);
setconfig(&variables, "USERNAME", *CURRENT_CONNECTION->username ? CURRENT_CONNECTION->username : NULL);
continue;
} else if (strstr(command_word, "!") == command_word) {
char *temp;
int rval;
temp = line + 1;
rval = system(temp);
if (rval) log(LOG_ALERT, "Return value from \"%s\": %d\n", temp, rval);
continue;
} else if (strcasecmp(command_word, "run") == 0) {
char *filename;
filename = getnextword(line, GNW_NEXT);
if (!filename || !*filename) {
log(LOG_CRITICAL, "You must specify a script file to run\n");
continue;
}
if (!(scriptfile = fopen(filename, "r"))) {
perror("fopen");
if (!ignoreerrors) continue;
}
continue;
} else if (strcasecmp(command_word, "debug") == 0) {
char *param;
if ((param = getnextword(line, GNW_NEXT)))
log_set_level(atoi(param));
else
log_set_level(log_get_level());
log(log_get_level(), __FILE__, __LINE__, __FUNCTION__, "Debugging level is now %d", log_get_level());
continue;
} else if (strcasecmp(command_word, "help") == 0 || strcmp(command_word, "?") == 0) {
char *param;
int foundit = 0;
if ((param = getnextword(line, GNW_NEXT))) {
for (i = 0; command_list[i].name && *command_list[i].name; i++) {
if (strcmp(command_list[i].name, param) == 0) {
if (command_list[i].longhelp) {
printf("%s\n", command_list[i].longhelp);
} else {
printf("No extra help available for %s\n", param);
}
foundit = 1;
}
}
if (!foundit) {
printf("Command %s does not exist\n", param);
}
} else {
for (i = 0; command_list[i].name && *command_list[i].name; i++)
printf("%-10s%s\n", command_list[i].name,
command_list[i].description);
}
continue;
}
/* Match dynamic command set */
for (i = 0; command_list[i].name; i++) {
if (strcasecmp (command_word, command_list[i].name) == 0) {
command = &command_list[i];
break;
}
}
if (!command) {
printf("Unknown command \"%s\"\n", command_word);
if (scriptfile && !ignoreerrors) break;
continue;
}
result = (command->function)(line);
if (result < 0) {
break;
} else if (result > 0) { // Successful command
setconfig(&variables, "SUCCESSFUL_OPERATION", "true");
} else { // Unsuccessful command
setconfig(&variables, "SUCCESSFUL_OPERATION", "false");
if (scriptfile && !ignoreerrors) {
log(LOG_CRITICAL, "Error processing script\n");
break;
}
}
continue;
}
ftp_disconnect(CURRENT_CONNECTION);
return 0;
}
struct qitem *addtoqueue(struct qitem **queue, struct qitem *item) {
struct qitem *newitem = 0;
struct qitem *tempitem = 0, *lastgooditem = 0;
int id = 0;
if (!(newitem = (struct qitem *)malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(-1);
}
memcpy(newitem, item, sizeof(struct qitem));
tempitem = *queue; /* Find the last item on the queue */
while (tempitem) {
lastgooditem = tempitem;
if (strcmp(newitem->remotefilename, tempitem->remotefilename) == 0) return NULL;
if (tempitem->id > id) id = tempitem->id;
tempitem = tempitem->next;
}
newitem->id = ++id;
if (lastgooditem) lastgooditem->next = newitem;
if (!*queue) *queue = newitem;
newitem->next = 0;
return newitem;
}
struct qitem *delfromqueue(struct qitem **queue, int id) {
struct qitem *item, *last;
int counter;
item = last = *queue;
while (item) {
if (item->id == id) {
last->next = item->next;
if (item == *queue) {
if (item->next) *queue = item->next;
else *queue = NULL;
}
free(item);
item = *queue;
counter = 1; /* Straighten out counter */
while (item) {
item->id = counter;
counter++;
item = item->next;
}
return NULL;
}
last = item;
item = item->next;
}
return *queue;
}
void clearqueue(struct qitem *queue) {
struct qitem *item, *next = NULL;
item = queue;
while (item) {
next = item->next;
free(item);
item = next;
}
}
struct qitem *runqueue(struct qitem *queue) {
struct qitem *item;
int id, n;
double starttime, timelength, endtime, speed;
struct timeval tv;
item = queue;
while (item) {
id = item->id;
if (item->direction == DIRECTION_GET) {
int result;
result = chdir(item->localdir);
if (result) switch(errno) {
case ENOENT : log(LOG_ERROR, "Creating directory %s\n", item->localdir);
mkdir(item->localdir, 0755);
break;
case ENOTDIR : log(LOG_ERROR, "A component of path is not a directory.\n");
item = item->next;
delfromqueue(&queue, id);
break;
case EACCES :
default : log(LOG_ERROR, "Can't change to %s: ", item->localdir, strerror(errno));
item = item->next;
delfromqueue(&queue, id);
continue;
break;
}
result = chdir(item->localdir);
ftp_cwd(item->remoteconnection, item->remotedir);
gettimeofday(&tv, NULL);
if ((item->permissions & 2048) == 2048) {
struct qitem *newitem, *newitem2;
char *param, *filenamelist[500];
char path[4096];
struct filedetails details;
int count = 0;
sprintf(path, "%s/%s", item->remotedir, item->remotefilename);
ftp_cwd(item->remoteconnection, path);
memset(filenamelist, 0, 500 * sizeof(char *));
ftp_nlst(item->remoteconnection, NULL, filenamelist, 500);
while (count < 500 && filenamelist[count]) {
param = filenamelist[count];
if (!param || !*param) {
free(param);
count++;
continue;
}
if (!(newitem = malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(1);
}
memset(newitem, 0, sizeof(struct qitem));
strncpy(newitem->localfilename, param, 256);
strncpy(newitem->remotefilename, param, 256);
result = ftp_exists(CURRENT_CONNECTION, param);
if (result == 0) {
log(LOG_ALERT, "%s does not exist\n", param);
free(newitem);
free(param);
continue;
}
if (result < 0) {
log(LOG_ALERT, "Can't verify existance of %s.. Don't blame me if this fails!\n", param);
}
if (result > 0) {
ftp_stat(CURRENT_CONNECTION, param, &details);
newitem->permissions = details.permissions;
newitem->size = details.size;
}
newitem->direction = DIRECTION_GET;
sprintf(newitem->remotedir, "%s/%s", item->remotedir,
item->remotefilename);
sprintf(newitem->localdir, "%s/%s", item->localdir,
item->localfilename);
newitem->remoteconnection = item->remoteconnection;
newitem->localconnection = item->localconnection;
if ((newitem2 = addtoqueue(&queue, newitem))) {
log(LOG_INFO, "Queued %s/%s for download, position %d\n", newitem2->remotedir, newitem2->localfilename, newitem2->id);
}
free(newitem);
free(param);
count++;
}
item = item->next;
delfromqueue(&queue, id);
continue;
}
starttime = ((tv.tv_sec * 1.0) + (tv.tv_usec / 1000000.0));
n = ftp_get_file(item->remoteconnection, item);
if (n > 0) {
gettimeofday(&tv, NULL);
endtime = ((double)tv.tv_sec + (tv.tv_usec / 1000000));
timelength = abs(endtime - starttime);
if (timelength == 0) timelength = 1;
log(LOG_INFO, "Received %s (%d bytes)",
item->remotefilename, n);
speed = (n / 1000) / timelength;
log(LOG_INFO, " in %lu seconds (%1.2fKb/s)\n",
(unsigned long)timelength, speed);
}
} else if (item->direction == DIRECTION_PUT) {
if (!ftp_cwd(item->remoteconnection, item->remotedir)) {
if (!ftp_mkd(item->remoteconnection, item->remotedir)) {
item = item->next;
delfromqueue(&queue, id);
continue;
}
if (!ftp_cwd(item->remoteconnection, item->remotedir)) {
item = item->next;
delfromqueue(&queue, id);
continue;
}
}
chdir(item->localdir);
if (S_ISDIR(item->permissions)) {
struct qitem *newitem, *newitem2;
struct dirent *dirent;
DIR *dir;
char path[4096];
int count = 0;
sprintf(path, "%s/%s", item->localdir, item->localfilename);
dir = opendir(path);
if (!dir) {
log(LOG_ALERT, "Can't recursively put %s\n", path);
item = item->next;
delfromqueue(&queue, id);
continue;
}
while ((dirent = readdir(dir))) {
char fullname[4096];
struct stat statbuf;
if (strcmp(dirent->d_name, ".") == 0) continue;
if (strcmp(dirent->d_name, "..") == 0) continue;
if (strlen(dirent->d_name) == 0) continue;
if (!(newitem = malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(1);
}
sprintf(fullname, "%s/%s", path, dirent->d_name);
if (stat(fullname, &statbuf)) {
log(LOG_ALERT, "%s does not exist\n", fullname);
free(newitem);
continue;
}
memset(newitem, 0, sizeof(struct qitem));
strncpy(newitem->localfilename, dirent->d_name, 256);
strncpy(newitem->remotefilename, dirent->d_name, 256);
newitem->permissions = statbuf.st_mode;
newitem->size = statbuf.st_size;
newitem->direction = DIRECTION_PUT;
sprintf(newitem->remotedir, "%s/%s", item->remotedir,
item->remotefilename);
sprintf(newitem->localdir, "%s/%s", item->localdir,
item->localfilename);
newitem->remoteconnection = item->remoteconnection;
newitem->localconnection = item->localconnection;
if ((newitem2 = addtoqueue(&queue, newitem))) {
log(LOG_INFO, "Queued %s/%s for upload, position %d\n", newitem2->remotedir, newitem2->localfilename, newitem2->id);
}
free(newitem);
count++;
}
item = item->next;
delfromqueue(&queue, id);
continue;
}
starttime = ((tv.tv_sec * 1.0) + (tv.tv_usec / 1000000.0));
n = ftp_put_file(item->remoteconnection, item);
if (n > 0) {
gettimeofday(&tv, NULL);
endtime = ((double)tv.tv_sec + (tv.tv_usec / 1000000));
timelength = abs(endtime - starttime);
if (timelength == 0) timelength = 1;
log(LOG_INFO, "Sent %s (%d bytes)",
item->remotefilename, n);
speed = (n / 1000) / timelength;
log(LOG_INFO, " in %lu seconds (%1.2fKb/s)\n",
(unsigned long)timelength, speed);
}
} else if (item->direction == DIRECTION_FXP) {
char sourcefile[4096], destfile[4096];
if ((item->permissions & 2048) == 2048) {
struct qitem *newitem, *newitem2;
char *param, *filenamelist[500];
char path[4096];
struct filedetails details;
int count = 0;
sprintf(path, "%s/%s", item->remotedir, item->remotefilename);
ftp_cwd(item->localconnection, path);
memset(filenamelist, 0, 500 * sizeof(char *));
ftp_nlst(item->localconnection, NULL, filenamelist, 500);
while (count < 500 && filenamelist[count]) {
int result;
param = filenamelist[count];
if (!param || !*param) {
free(param);
count++;
continue;
}
if (!(newitem = malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(1);
}
result = ftp_exists(CURRENT_CONNECTION, param);
if (result == 0) {
log(LOG_WARNING, "%s does not exist\n", param);
free(newitem);
free(param);
continue;
}
if (result < 0) {
log(LOG_WARNING, "Can't verify existance of %s.. Don't blame me if this fails!\n", param);
}
if (result > 0) {
ftp_stat(CURRENT_CONNECTION, param, &details);
newitem->permissions = details.permissions;
newitem->size = details.size;
}
memset(newitem, 0, sizeof(struct qitem));
strncpy(newitem->localfilename, param, 256);
strncpy(newitem->remotefilename, param, 256);
newitem->direction = DIRECTION_GET;
sprintf(newitem->remotedir, "%s/%s", item->remotedir,
item->remotefilename);
sprintf(newitem->localdir, "%s/%s", item->localdir,
item->localfilename);
newitem->remoteconnection = item->remoteconnection;
newitem->localconnection = item->localconnection;
if ((newitem2 = addtoqueue(&queue, newitem))) {
log(LOG_INFO, "Queued %s/%s for FxP, position %d\n", newitem2->remotedir, newitem2->localfilename, newitem2->id);
}
free(newitem);
free(param);
count++;
}
item = item->next;
delfromqueue(&queue, id);
continue;
}
sprintf(sourcefile, "%s/%s", item->localdir, item->localfilename);
sprintf(destfile, "%s/%s", item->remotedir, item->remotefilename);
starttime = ((tv.tv_sec * 1.0) + (tv.tv_usec / 1000000.0));
log(LOG_WARNING, "Progress information not available for FxP transfers\n");
n = ftp_fxp(item->localconnection, item->remoteconnection,
sourcefile, destfile);
if (n == 0) {
gettimeofday(&tv, NULL);
endtime = ((double)tv.tv_sec + (tv.tv_usec / 1000000));
timelength = abs(endtime - starttime);
if (timelength == 0) timelength = 1;
log(LOG_INFO, "Sent %s (%lu bytes)",
item->remotefilename, item->size);
speed = (item->size / 1000) / timelength;
log(LOG_INFO, " in %lu seconds (%1.2fKb/s)\n",
(unsigned long)timelength, speed);
}
} else {
log(LOG_CRITICAL, "Corrupted item %d\n", id);
}
item = item->next;
delfromqueue(&queue, id);
}
return queue;
}
void printqueue(struct qitem *queue) {
struct qitem *item;
char fullname[200];
long totalsize = 0;
log(LOG_CALLS, "%p", queue);
item = queue;
printf("%-3s %-30s %-10s%-30s\n", "ID", "Source",
"Size", "Destination");
while (item) {
if (item->direction == DIRECTION_GET) {
sprintf(fullname, "%s/%s", item->remotedir, item->remotefilename);
printf("%-3d <- %-30s %-10lu%-30s\n", item->id, fullname, item->size,
item->localdir);
} else if (item->direction == DIRECTION_PUT) {
sprintf(fullname, "%s/%s", item->localdir, item->localfilename);
printf("%-3d -> %-30s %-10lu%-30s\n", item->id, fullname,
item->size, item->remotedir);
} else if (item->direction == DIRECTION_FXP) {
char remotename[200];
sprintf(fullname, "%s:%s%s%s%s", item->localconnection->hostname,
item->localdir, (item->remotefilename[0] == '/')
? "" : "/", item->localfilename,
((item->permissions & 2048) == 2048) ? "/" : "");
sprintf(remotename, "%s:%s%s%s%s", item->remoteconnection->hostname,
item->remotedir, (item->remotefilename[0] == '/')
? "" : "/", item->remotefilename,
((item->permissions & 2048) == 2048) ? "/" : "");
printf("%-3d -> %-30s %-10lu%-30s\n", item->id, fullname,
item->size, remotename);
} else {
log(LOG_CRITICAL, "Bad entry %d\n", item->id);
}
totalsize += item->size;
item = item->next;
}
printf("\nTotal queue size: %li bytes\n\n", totalsize);
}
int getconnected(struct ftpconnection *connection) {
char *dir = NULL;
log(LOG_CALLS, "%p", connection);
if (!connection) return 0;
if (!connection->hostname) return 0;
if (connection->status > STATUS_WAIT_CONNECT) return 1;
if (connection->remotedir[0] != '\0') {
dir = strdup(connection->remotedir);
}
if (ftp_connect(connection)) {
if (dir) free(dir);
return 0;
}
if (ftp_login(connection)) {
if (dir) free(dir);
ftp_disconnect(connection);
return 0;
}
if (dir) {
if (!ftp_cwd(connection, dir)) log(LOG_ALERT, "Can't change directory to %s\n", dir);
free(dir);
}
connection->status = STATUS_IDLE;
setconfig(&variables, "USERNAME", connection->username);
return 1;
}
char *complete_remote_filename(const char *text, int state) {
static char *filenamelist[500];
static int index = 0;
int response;
char *retstring = (char *)NULL;
if (state == 0) {
char *path;
memset(&filenamelist[0], 0, sizeof(char *) * 500);
if (!text || !*text) return NULL;
path = getpath(text);
response = ftp_nlst(CURRENT_CONNECTION, path, filenamelist, 500);
if (response < 0) return NULL;
index = 0;
}
while (filenamelist[index]) {
if (strstr(filenamelist[index], text) == filenamelist[index]) {
retstring = strdup(filenamelist[index]);
free(filenamelist[index]);
index++;
return retstring;
}
free(filenamelist[index]);
index++;
}
index = 0;
return NULL;
}
char *complete_command(const char *text, int state) {
/* Don't know how I'm going to do this yet */
return NULL;
}
char **quftp_completion(char *text, int start, int end) {
char **matches;
matches = (char **)NULL;
if (start == 0) {
/* It's a command */
matches = rl_completion_matches(text, complete_command);
} else if (strstr(text, "put") != text){
/* It's a filename */
matches = rl_completion_matches(text, complete_remote_filename);
}
return (matches);
}
int cmd_ls(char *command_line) {
int result;
char *params = NULL;
params = getnextword(command_line, GNW_REST);
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "ls: Not connected\n");
return 0;
}
result = ftp_list(CURRENT_CONNECTION, params, 1);
printf("\n");
if (result < 0) return 0;
return 1;
}
int cmd_cd(char *command_line) {
char *param;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "cd: Not connected\n");
return 0;
}
getnextword(command_line, GNW_START);
param = getnextword(command_line, GNW_NEXT);
if (!param || !*param) {
log(LOG_ALERT, "Must specify a directory to change\n");
return 0;
} else {
if (!ftp_cwd(CURRENT_CONNECTION, param)) return 0;
}
return 1;
}
int cmd_cdup (char *command_line) {
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "cdup: Not connected\n");
return 0;
}
if (!ftp_cwd(CURRENT_CONNECTION, "..")) return 0;
return 1;
}
int cmd_pwd (char *command_line) {
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "pwd: Not connected\n");
return 0;
}
ftp_pwd(CURRENT_CONNECTION);
log(LOG_INFO, "The current remote directory is %s\n", CURRENT_CONNECTION->remotedir);
log(LOG_INFO, "The current local directory is %s\n", CURRENT_CONNECTION->localdir);
return 1;
}
int cmd_lcd(char *command_line) {
char *param = NULL;
int rval;
getnextword(command_line, GNW_START);
param = getnextword(command_line, GNW_NEXT);
if (!param || !*param) {
log(LOG_ALERT, "Specify a directory to change to\n");
return 0;
}
rval = chdir(param);
if (rval) {
log(LOG_ALERT, "Can't change to \"%s\"\n", param);
return 0;
}
getcwd(CURRENT_CONNECTION->localdir, 256);
log(LOG_INFO, "Current local directory is now \"%s\"\n", CURRENT_CONNECTION->localdir);
return 1;
}
int cmd_get(char *command_line) {
struct qitem *item, *newitem;
char *expanded_line;
char *param;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "get: Not connected\n");
return 0;
}
expanded_line = expand_wildcard(command_line);
getnextword(expanded_line, GNW_START);
while ((param = getnextword(expanded_line, GNW_NEXT))) {
char path[4096], filename[4096];
int index;
struct filedetails details;
if (!param || !*param) continue;
if (ftp_stat(CURRENT_CONNECTION, param, &details)) {
log(LOG_ALERT, "%s does not exist\n", param);
continue;
}
if (!(item = malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(1);
}
memset(item, 0, sizeof(struct qitem));
memset(path, 0, 4096);
memset(filename, 0, 4096);
item->permissions = details.permissions;
item->size = details.size;
/* Split the path and filename from the paramater */
index = strlen(param);
while (index) {
if (param[index] == '/') {
strncpy(path, param, index);
strncpy(filename, ¶m[index + 1], 4096);
break;
}
index--;
}
if (strlen(filename) == 0) strncpy(filename, param, 4096);
strncpy(item->localfilename, filename, 256);
strncpy(item->remotefilename, filename, 256);
item->direction = DIRECTION_GET;
if (path[0] == '/') {
strncpy(item->remotedir, path, 256);
} else {
sprintf(item->remotedir, "%s%s%s", CURRENT_CONNECTION->remotedir,
(CURRENT_CONNECTION->remotedir[strlen(CURRENT_CONNECTION->remotedir)-1] != '/') ? "/" : "", path);
}
strncpy(item->localdir, CURRENT_CONNECTION->localdir, 256);
if (item->remotedir[strlen(item->remotedir) - 1] == '/')
item->remotedir[strlen(item->remotedir) - 1] = '\0';
if (item->localdir[strlen(item->localdir) - 1] == '/')
item->localdir[strlen(item->localdir) - 1] = '\0';
item->remoteconnection = CURRENT_CONNECTION;
item->localconnection = NULL;
newitem = addtoqueue(&leftqueue, item);
if (newitem) log(LOG_INFO, "Queued %s/%s for download, position %d\n",
item->remotedir, item->localfilename, newitem->id);
free(item);
}
if (config(variables, "queuefiles")) {
if (strcasecmp(config(variables, "queuefiles"), "false") == 0)
cmd_go(expanded_line);
}
free(expanded_line);
return 1;
}
int cmd_put(char *command_line) {
struct qitem *item, *newitem;
char *param, *expanded_line;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "put: Not connected\n");
return 0;
}
expanded_line = expand_wildcard(command_line);
getnextword(expanded_line, GNW_START);
while ((param = getnextword(expanded_line, GNW_NEXT))) {
char path[4096], filename[4096];
struct stat stat_buf;
int index;
if (!param || !*param) continue;
if (strcmp(param, "End") == 0) continue;
if (stat(param, &stat_buf) != 0)
switch (errno) {
case ENOENT : log(LOG_ALERT, "File %s does not exist\n", param);
continue;
break;
case EACCES : log(LOG_ALERT, "Permission denied to stat\n.");
continue;
break;
case ENOMEM : log(LOG_ALERT, "Out of memory\n");
exit(1);
break;
case ENAMETOOLONG : log(LOG_ALERT, "File name \"%s\" too long\n", param);
continue;
break;
default : log(LOG_ALERT, "Unknown error doing stat: %d\n", errno);
continue;
break;
}
if (!(item = malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(1);
}
memset(item, 0, sizeof(struct qitem));
memset(path, 0, 4096);
memset(filename, 0, 4096);
/* Split the path and filename from the paramater */
index = strlen(param);
while (index) {
if (param[index] == '/') {
strncpy(path, param, index);
strncpy(filename, ¶m[index + 1], 4096);
break;
}
index--;
}
if (strlen(filename) == 0) strncpy(filename, param, 4096);
strncpy(item->localfilename, filename, 256);
strncpy(item->remotefilename, filename, 256);
item->direction = DIRECTION_PUT;
if (path[0] == '/') {
strncpy(item->localdir, path, 256);
} else {
sprintf(item->localdir, "%s%s%s", CURRENT_CONNECTION->localdir,
(item->localdir[strlen(item->localdir)] != '/') ? "/" : "",
path);
}
strncpy(item->remotedir, CURRENT_CONNECTION->remotedir, 256);
if (strlen(item->remotedir) > 1)
if (item->remotedir[strlen(item->remotedir) - 1] == '/')
item->remotedir[strlen(item->remotedir) - 1] = '\0';
if (strlen(item->localdir) > 1)
if (item->localdir[strlen(item->localdir) - 1] == '/')
item->localdir[strlen(item->localdir) - 1] = '\0';
item->remoteconnection = CURRENT_CONNECTION;
item->localconnection = NULL;
item->permissions = stat_buf.st_mode;
item->size = stat_buf.st_size;
newitem = addtoqueue(&leftqueue, item);
if (newitem) log(LOG_INFO, "Queued %s/%s for upload, position %d\n",
item->remotedir, param, newitem->id);
free(item);
}
if (config(variables, "queuefiles")) {
if (strcasecmp(config(variables, "queuefiles"), "false") == 0)
cmd_go(expanded_line);
}
free(expanded_line);
return 1;
}
int cmd_fxp(char *command_line) {
struct qitem *item, *newitem;
char *param, *expanded_line;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "fxp: Not connected\n");
return 0;
}
if (!getconnected(LAST_CONNECTION)) {
log(LOG_ALERT, "fxp: Not connected\n");
return 0;
}
expanded_line = expand_wildcard(command_line);
getnextword(expanded_line, GNW_START);
while ((param = getnextword(expanded_line, GNW_NEXT))) {
char path[4096], filename[4096];
int index;
struct filedetails details;
if (!param || !*param) continue;
log(LOG_NOTICE, "FxP'ing \"%s\" from %s to %s", param,
CURRENT_CONNECTION->hostname,
LAST_CONNECTION->hostname);
if (!(item = malloc(sizeof(struct qitem)))) {
perror("malloc");
exit(1);
}
if (ftp_stat(CURRENT_CONNECTION, param, &details)) {
log(LOG_ALERT, "%s does not exist\n", param);
free(item);
continue;
}
memset(item, 0, sizeof(struct qitem));
memset(path, 0, 4096);
memset(filename, 0, 4096);
/* Split the path and filename from the paramater */
index = strlen(param);
while (index) {
if (param[index] == '/') {
strncpy(path, param, index);
strncpy(filename, ¶m[index + 1], 4096);
break;
}
index--;
}
if (strlen(filename) == 0) strncpy(filename, param, 4096);
strncpy(item->localfilename, param, 256);
strncpy(item->remotefilename, param, 256);
item->permissions = details.permissions;
item->size = details.size;
item->direction = DIRECTION_FXP;
if (path[0] == '/') {
strncpy(item->remotedir, path, 256);
} else {
sprintf(item->remotedir, "%s%s%s", LAST_CONNECTION->remotedir, (LAST_CONNECTION->remotedir[strlen(LAST_CONNECTION->remotedir)-1] != '/') ? "/" : "", path);
}
strncpy(item->localdir, CURRENT_CONNECTION->remotedir, 256);
if (item->remotedir[strlen(item->remotedir) - 1] == '/')
item->remotedir[strlen(item->remotedir) - 1] = '\0';
if (item->localdir[strlen(item->localdir) - 1] == '/')
item->localdir[strlen(item->localdir) - 1] = '\0';
item->remoteconnection = LAST_CONNECTION;
item->localconnection = CURRENT_CONNECTION;
newitem = addtoqueue(&leftqueue, item);
if (newitem) log(LOG_INFO, "Queued %s/%s for FxP, position %d\n",
item->remotedir, item->localfilename, newitem->id);
free(item);
}
if (config(variables, "queuefiles")) {
if (strcasecmp(config(variables, "queuefiles"), "false") == 0)
cmd_go(expanded_line);
}
free(expanded_line);
return 1;
}
int cmd_go (char *command_line) {
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "go: Not connected\n");
return 0;
}
leftqueue = runqueue(leftqueue);
return 1;
}
int cmd_clear (char *command_line) {
clearqueue(leftqueue);
leftqueue = NULL;
log(LOG_ALERT, "Queue cleared\n");
return 1;
}
int cmd_queue (char *command_line) {
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "queue: Not connected\n");
return 0;
}
printqueue(leftqueue);
return 1;
}
int cmd_rem (char *command_line) {
char *param;
int id;
getnextword(command_line, GNW_START);
while ((param = getnextword(command_line, GNW_NEXT))) {
id = atoi(param);
if (id > 0) {
if (delfromqueue(&leftqueue, id) == 0) {
log(LOG_WARNING, "Deleted item %d\n", id);
return 1;
} else {
log(LOG_ALERT, "Item %d doesn't exist!\n", id);
return 0;
}
}
}
return 1;
}
int cmd_quit (char *command_line) {
printf("\n");
return -1;
}
int cmd_close (char *command_line) {
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "close: Not connected\n");
return 0;
}
if (leftqueue) {
log(LOG_ALERT, "You still have untransferred items\n");
return 0;
}
ftp_disconnect(CURRENT_CONNECTION);
CURRENT_CONNECTION->status = STATUS_WAIT_CONNECT;
return 1;
}
int cmd_open(char *command_line) {
char *param;
getnextword(command_line, GNW_START);
if (!(param = getnextword(command_line, GNW_NEXT))) {
log(LOG_ALERT, "No address specified!\n");
return 1;
}
if (!*param) return 0;
if (!parseurl(param, CURRENT_CONNECTION)) {
log(LOG_ALERT, "Can't open %s\n", param);
return 0;
}
if (strlen(CURRENT_CONNECTION->password) == 0) {
if (config(variables, "email"))
strncpy(CURRENT_CONNECTION->password, config(variables, "email"), 32);
else
strncpy(CURRENT_CONNECTION->password, "user@quftp.com", 32);
}
if (CURRENT_CONNECTION->remotedir[0] != '\0') getconnected(CURRENT_CONNECTION);
setconfig(&variables, "HOSTNAME", CURRENT_CONNECTION->hostname);
return 1;
}
int cmd_user (char *command_line) {
char *param;
getnextword(command_line, GNW_START);
if (!(param = getnextword(command_line, GNW_NEXT))) {
log(LOG_ALERT, "No username specified!\n");
return 0;
}
if (CURRENT_CONNECTION->status >= STATUS_IDLE) {
ftp_disconnect(CURRENT_CONNECTION);
}
strncpy(CURRENT_CONNECTION->username, param, 32);
if ((param = getnextword(command_line, GNW_NEXT))) {
strncpy(CURRENT_CONNECTION->password, param, 32);
} else {
strncpy(CURRENT_CONNECTION->password, getpassword(CURRENT_CONNECTION->username), 32);
}
CURRENT_CONNECTION->status = STATUS_WAIT_CONNECT;
return 1;
}
int cmd_stat(char *command_line) {
struct filedetails details;
char *param;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "stat: Not connected\n");
return 0;
}
getnextword(command_line, GNW_START);
while ((param = getnextword(command_line, GNW_NEXT))) {
if (!*param) continue;
if (ftp_stat(CURRENT_CONNECTION, param, &details) == 0) {
log(LOG_INFO, "Details for %s\n", details.filename);
log(LOG_INFO, "File Size: %lu\n", details.size);
log(LOG_INFO, "Number of Hard Links: %d\n", details.links);
if (*details.owner) log(LOG_INFO, "Owner: %s\n", (char *)details.owner);
if (*details.group) log(LOG_INFO, "Group: %s\n", (char *)details.group);
if (details.permissions) log(LOG_INFO, "Permission: %o\n", (unsigned int)details.permissions);
}
}
return 1;
}
int cmd_status (char *command_line) {
int conn;
log(LOG_INFO, "Current connection: %s\n", config(variables, "CURRENT_CONNECTION"));
log(LOG_INFO, "\n");
for (conn = 0; conn < MAX_CONNECTIONS; conn++) {
if (connection[conn]->status == 0) continue;
log(LOG_INFO, "Connection %d:\n", conn);
log(LOG_INFO, " Host: %s:%d\n", connection[conn]->hostname, connection[conn]->port);
log(LOG_INFO, " Username: %s\n", connection[conn]->username);
log(LOG_INFO, " Directory: %s\n", connection[conn]->remotedir);
log(LOG_INFO, " Status: ");
switch(connection[conn]->status) {
case 0 : log(LOG_INFO, "No connection\n"); break;
case 1 : log(LOG_INFO, "Ready to connect\n"); break;
case 2 : log(LOG_INFO, "Waiting for login\n"); break;
case 3 : log(LOG_INFO, "Idle\n"); break;
case 4 : log(LOG_INFO, "Waiting...\n"); break;
case 5 : log(LOG_INFO, "Busy transferring\n"); break;
case 99 : log(LOG_INFO, "Error!\n"); break;
default : log(LOG_INFO, "Unknown!\n"); break;
}
}
return 1;
}
int cmd_nlst(char *command_line) {
char *list[200];
char *params = NULL;
register int index = 0;
getnextword(command_line, GNW_START);
params = getnextword(command_line, GNW_REST);
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "nlst: Not connected\n");
return 0;
}
if (ftp_nlst(CURRENT_CONNECTION, params, list, 200) < 0) return 0;
for (index = 0; list[index]; index++) {
printf("%s\n", list[index]);
free(list[index]);
}
return 1;
}
int cmd_lls(char *command_line) {
char *param = command_line;
param++;
system(param);
return 1;
}
int cmd_cat(char *command_line) {
char *param = (char *)NULL;
char *expanded_line;
expanded_line = expand_wildcard(command_line);
param = getnextword(expanded_line, GNW_START);
while ((param = getnextword(expanded_line, GNW_NEXT))) {
char *buffer;
int n;
buffer = (char *)malloc(4096);
sprintf(buffer, "%s", param);
if (ftp_read_file(CURRENT_CONNECTION, buffer, 4095, TRANS_START) < 0) {
free(expanded_line);
return 0;
}
while ((n = ftp_read_file(CURRENT_CONNECTION, buffer, 4095, TRANS_TRANS)) > 0) {
buffer[4095] = '\0';
printf("%s", buffer);
}
ftp_read_file(CURRENT_CONNECTION, buffer, 4095, TRANS_CLOSE);
free(buffer);
}
free(expanded_line);
return 1;
}
int cmd_more(char *command_line) {
char *param = (char *)NULL;
char *expanded_line;
FILE *fh;
expanded_line = expand_wildcard(command_line);
param = getnextword(expanded_line, GNW_START);
while ((param = getnextword(expanded_line, GNW_NEXT))) {
char *pager;
char *buffer;
int n;
if (ftp_read_file(CURRENT_CONNECTION, param, 4095, TRANS_START) < 0) {
free(expanded_line);
return 0;
}
pager = config(variables, "pager");
if (!pager) pager = strdup("/bin/more");
fh = popen(pager, "w");
if (!fh) {
perror("popen");
ftp_read_file(CURRENT_CONNECTION, NULL, 0, TRANS_CLOSE);
free(expanded_line);
return 0;
}
buffer = (char *)malloc(4096);
while ((n = ftp_read_file(CURRENT_CONNECTION, buffer, 4095, TRANS_TRANS)) > 0) {
buffer[4095] = '\0';
fputs(buffer, fh);
}
ftp_read_file(CURRENT_CONNECTION, buffer, 4095, TRANS_CLOSE);
free(buffer);
pclose(fh);
}
free(expanded_line);
return 1;
}
int cmd_set(char *command_line) {
char *key = NULL, *value;
value = getnextword(command_line, GNW_START);
value = getnextword(command_line, GNW_NEXT);
if (value) {
key = strdup(value);
value = getnextword(command_line, GNW_NEXT);
if (value) {
setconfig(&variables, strlower(key), value);
} else {
char *data = config(variables, key);
if (data) printf("%s: %s\n", key, data);
else log(LOG_ALERT, "%s does not exist\n", key);
}
} else {
struct variable_list *list = variables;
while (list) {
printf("%s: %s\n", list->key, list->value);
list = list->next;
}
}
if (key) free(key);
return 1;
}
int cmd_unset(char *command_line) {
char *key = NULL;
getnextword(command_line, GNW_START);
key = strlower(getnextword(command_line, GNW_NEXT));
if (key) {
setconfig(&variables, key, NULL);
free(key);
return 1;
}
return 0;
}
int cmd_assert(char *command_line) {
char *result;
result = config(variables, "SUCCESSFUL_OPERATION");
if (result && strcmp(result, "false") == 0) {
log(LOG_CRITICAL, "Assertion failed... quitting\n");
return -1;
}
return 1;
}
char *parseline(char *line) { /* Expand variables */
int index = 0;
char *linestart = line;
char *temp;
temp = (char *)malloc(4096);
memset(temp, 0, 4096);
while (*line) {
if (*line == '$') { // Expand variables
char *endbit;
line++;
endbit = line;
while (endbit && *endbit && *endbit != ' ') endbit++;
*endbit = '\0';
if (config(variables, line)) strcat((temp + index), config(variables, line));
index += (endbit - line);
line = endbit + 1;
} else {
temp[index] = *line;
}
line++;
if (line > (linestart + strlen(linestart))) break;
index++;
}
return temp;
}
int cmd_dele(char *command_line) {
char *filename, *expanded_line;
expanded_line = expand_wildcard(command_line);
getnextword(expanded_line, GNW_START);
while ((filename = getnextword(expanded_line, GNW_NEXT))) {
ftp_delete(CURRENT_CONNECTION, filename);
}
free(expanded_line);
return 1;
}
int cmd_alias(char *command_line) {
struct alias_list *item = aliases, *last = aliases;
char *alias = NULL, *expanded = NULL;
getnextword(command_line, GNW_START);
expanded = getnextword(command_line, GNW_NEXT);
if (expanded) {
alias = strdup(expanded);
}
expanded = getnextword(command_line, GNW_REST);
if (!alias || !*alias) {
if (!item) {
log(LOG_ALERT, "No aliases have been defined\n");
return 1;
}
printf("%-20s%s\n", "Alias", "Expands to");
while (item) {
printf("%-20s%s\n", item->alias, item->expanded);
item = item->next;
}
printf("\n");
return 1;
}
if (!expanded || !*expanded) {
while (item) {
if (strcasecmp(item->alias, alias) == 0) {
free(item->expanded);
free(item->alias);
last->next = item->next;
if (item == aliases) aliases = NULL;
free(item);
return 1;
}
last = item;
item = item->next;
}
log(LOG_ALERT, "Can't find \"%s\"\n", alias);
return 0;
}
while (item) {
if (strcasecmp(item->alias, alias) == 0) {
free(item->expanded);
item->expanded = strdup(expanded);
item->next = NULL;
return 1;
}
last = item;
item = item->next;
}
item = (struct alias_list *)malloc(sizeof(struct alias_list));
if (!aliases) aliases = item;
if (last) last->next = item;
item->alias = strdup(alias);
item->expanded = strdup(expanded);
item->next = NULL;
return 1;
}
char *expand_wildcard(char *inputstring) {
char *word, *tempstring, *retstring;
if (!inputstring) return NULL;
if ((strstr(inputstring, "*") == 0) && (strstr(inputstring, "?")) == 0)
return strdup(inputstring);
tempstring = (char *)malloc(65535);
sprintf(tempstring, "%s ", getnextword(inputstring, GNW_START));
if (strcasecmp(tempstring, "get ") == 0 || strcasecmp(tempstring, "fxp ") == 0) {
while ((word = getnextword(inputstring, GNW_NEXT))) {
int index = 0;
char *temp;
while ((temp = ftp_glob(CURRENT_CONNECTION, word, index++))) {
sprintf(tempstring, "%s %s", tempstring, temp);
}
}
retstring = strdup(tempstring);
free(tempstring);
return retstring;
} else if (strcasecmp(tempstring, "put ") == 0) {
glob_t globvec;
sprintf(tempstring, "%s ", getnextword(inputstring, GNW_START));
while ((word = getnextword(inputstring, GNW_NEXT))) {
int result, index;
memset(&globvec, 0, sizeof(glob_t));
result = glob(word, GLOB_TILDE, NULL, &globvec);
switch (result) {
case 0: for (index = 0; index < globvec.gl_pathc; index++)
sprintf(tempstring, "%s %s", tempstring,
globvec.gl_pathv[index]);
globfree(&globvec);
break;
case GLOB_NOSPACE: log(LOG_CRITICAL, "Ran out of memory for glob\n");
free(tempstring);
return strdup(inputstring);
case GLOB_ABORTED: log(LOG_CRITICAL, "Glob Read error\n");
free(tempstring);
return strdup(inputstring);
case GLOB_NOMATCH: log(LOG_ALERT, "Glob found no matches\n");
free(tempstring);
return strdup(inputstring);
default : log(LOG_ALERT, "Unknown glob error %d\n", result);
break;
}
}
retstring = strdup(tempstring);
free(tempstring);
return retstring;
} else {
free(tempstring);
return strdup(inputstring);
}
}
char *expand_alias(char *string) {
struct alias_list *item;
char *returnstring = (char *)NULL;
char firstword[500], *rest;
if (!string || !*string) return string;
memset(firstword, 0, 500);
strncpy(firstword, getnextword(string, GNW_START), 500);
rest = getnextword(string, GNW_REST);
item = aliases;
while (item) {
if (strcasecmp(item->alias, firstword) == 0) {
returnstring = (char *)malloc(strlen(item->expanded) + strlen(rest) + 2);
sprintf(returnstring, "%s %s", item->expanded, rest);
return returnstring;
}
item = item->next;
}
return strdup(string);
}
char *print_permissions(int permissions) {
char *returnstring;
returnstring = (char *)malloc(11);
memset(returnstring, '-', 10);
if ((permissions & 512) == 512) returnstring[0] = 'd';
if ((permissions & 256) == 256) returnstring[1] = 'r';
if ((permissions & 128) == 128) returnstring[2] = 'w';
if ((permissions & 64) == 64) returnstring[3] = 'x';
if ((permissions & 32) == 32) returnstring[4] = 'r';
if ((permissions & 16) == 16) returnstring[5] = 'w';
if ((permissions & 8) == 8) returnstring[6] = 'x';
if ((permissions & 4) == 4) returnstring[7] = 'r';
if ((permissions & 2) == 2) returnstring[8] = 'w';
if ((permissions & 1) == 1) returnstring[9] = 'x';
return returnstring;
}
int progress_bar(unsigned long current, unsigned long max, double speed) {
unsigned long etasec;
int index, width, count = 0;
double percent;
static double oldpercent = -1;
static double speeds[SPEEDS_AVERAGE];
static int speedindex = 0;
char *temp;
/* Don't display a progress bar for a 0 byte file */
if (max == 0) {
return 0;
}
/* If a new progress bar, clear the speed history */
if (current == 0) {
for (index = 0; index < SPEEDS_AVERAGE; index++) speeds[index] = 0.0;
speedindex = 0;
}
/* Record current speed */
speeds[++speedindex % SPEEDS_AVERAGE] = speed;
/* Get current average speed */
for (index = 0; index < SPEEDS_AVERAGE; index++) {
if (speeds[index] == 0.0) continue;
speed += speeds[index];
count++;
}
speed /= (count * 1.0);
percent = (current * 1.0) / (max * 1.0);
/* No movement? Return without displaying anything */
if (percent == oldpercent) return 0;
etasec = ((max - current) / 1024.00) / speed;
if ((temp = config(variables, "screenwidth"))) width = atoi(temp);
else if ((temp = getenv("COLUMNS"))) width = atoi(temp);
else width = 80;
width -= 20;
for (index = 0; index <= (width * percent); index++) printf("#");
for (index = (width * percent) + 1; index <= width; index++) printf("-");
printf(" %-6.6s %3.1fKb/s", timestring(etasec), speed);
printf("\r");
if (current == max) {
for (index = 0; index < (width + 20); index++) printf(" ");
printf("\r");
}
oldpercent = percent;
return 0;
}
char *timestring(unsigned long seconds) {
char *returnstring;
returnstring = (char *)malloc(15);
sprintf(returnstring, "%02lu:%02lu", seconds / 60, seconds % 60);
return returnstring;
}
int cmd_getlist(char *command_line) {
char *infile = NULL;
char line[MAX_LINE_SIZE];
FILE *fh;
getnextword(command_line, GNW_START);
infile = getnextword(command_line, GNW_NEXT);
fh = fopen(infile, "r");
if (!fh) {
log(LOG_CRITICAL, "Can't open file %s\n", infile);
return 0;
}
while (fgets(line, MAX_LINE_SIZE, fh)) {
char path[MAX_LINE_SIZE], filename[MAX_LINE_SIZE], *param;
int index;
int result;
struct qitem *item = NULL, *newitem;
struct filedetails details;
param = strchr(line, '\n');
*param = '\0';
if (line[0] == 0) continue;
param = getnextword(line, GNW_START);
result = ftp_stat(CURRENT_CONNECTION, param, &details);
switch (result) {
case 211 :
case 212 : log(LOG_ALERT, "%s does not exist\n", param);
continue;
break;
case 500 :
case 501 :
case 502 : break;
case 421 :
default : continue;
break;
}
item = (struct qitem *)malloc(sizeof(struct qitem));
memset(item, 0, sizeof(struct qitem));
memset(path, 0, MAX_LINE_SIZE);
memset(filename, 0, MAX_LINE_SIZE);
/* Split the path and filename from the paramater */
index = strlen(param);
while (index) {
if (param[index] == '/') {
strncpy(path, param, index);
strncpy(filename, ¶m[index + 1], MAX_LINE_SIZE);
break;
}
index--;
}
if (filename[0] == 0) strncpy(filename, param, MAX_LINE_SIZE);
strncpy(item->localfilename, filename, 256);
strncpy(item->remotefilename, filename, 256);
item->permissions = details.permissions;
item->size = details.size;
item->direction = DIRECTION_GET;
if (path[0] == '/') {
strncpy(item->remotedir, path, 256);
} else {
sprintf(item->remotedir, "%s%s%s", CURRENT_CONNECTION->remotedir,
(CURRENT_CONNECTION->remotedir[strlen(CURRENT_CONNECTION->remotedir)-1] != '/') ? "/" : "",
path);
}
strncpy(item->localdir, CURRENT_CONNECTION->localdir, 256);
if (item->remotedir[strlen(item->remotedir) - 1] == '/')
item->remotedir[strlen(item->remotedir) - 1] = '\0';
if (item->localdir[strlen(item->localdir) - 1] == '/')
item->localdir[strlen(item->localdir) - 1] = '\0';
item->remoteconnection = CURRENT_CONNECTION;
item->localconnection = NULL;
newitem = addtoqueue(&leftqueue, item);
if (newitem) log(LOG_INFO, "Queued %s/%s for download, position %d\n",
item->remotedir, item->localfilename, newitem->id);
free(item);
}
fclose(fh);
return 1;
}
int cmd_quote(char *command_line) {
char command[4096];
sprintf(command, "%s\r\n", getnextword(command_line, GNW_REST));
ftp_sendline(CURRENT_CONNECTION, command);
ftp_getrc(CURRENT_CONNECTION, NULL, 0, 1);
return 1;
}
int cmd_mkdir(char *command_line) {
char *param;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "mkdir: Not connected\n");
return 0;
}
getnextword(command_line, GNW_START);
param = getnextword(command_line, GNW_NEXT);
if (!param || !*param) {
log(LOG_ALERT, "Must specify a directory to create\n");
return 0;
} else {
if (!ftp_mkd(CURRENT_CONNECTION, param)) return 0;
else log(LOG_INFO, "Created directory %s on %s in %s\n", param, CURRENT_CONNECTION->hostname,
CURRENT_CONNECTION->remotedir);
}
return 1;
}
int cmd_rmdir(char *command_line) {
char *param;
if (!getconnected(CURRENT_CONNECTION)) {
log(LOG_ALERT, "rmdir: Not connected\n");
return 0;
}
getnextword(command_line, GNW_START);
param = getnextword(command_line, GNW_NEXT);
if (!param || !*param) {
log(LOG_ALERT, "Must specify a directory to remove\n");
return 0;
} else {
if (!ftp_rmd(CURRENT_CONNECTION, param)) return 0;
else log(LOG_INFO, "Removed directory %s on %s in %s\n", param, CURRENT_CONNECTION->hostname,
CURRENT_CONNECTION->remotedir);
}
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1