/* * Queued FTP Client * * $Revision: 1.9 $ * $Date: 2003/03/11 01:26:39 $ * vim: sw=4 ts=4 * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __GLIBC__ #include #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; }