int list_equal(list *a, list *b, listsortfunc cmpfunc) { listitem *ai, *bi; if(a == b) return 1; if(list_numitem(a) != list_numitem(b) || a == 0 || b == 0) return 0; for(ai = a->first, bi = b->first; ai && bi; ai = ai->next, bi = bi->next) { if(cmpfunc(ai->data, bi->data) != 0) return 0; } return 1; }
void save_ltaglist(const char *alt_filename) { FILE *fp; char *f, *e = 0; listitem *li; if(list_numitem(gvLocalTagList) == 0 || gvLoadTaglist == 0) return; if(alt_filename == 0) if (asprintf(&e, "%s/taglist.local", gvWorkingDirectory) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); return; } f = tilde_expand_home(alt_filename ? alt_filename : e, gvLocalHomeDir); free(e); fp = fopen(f, "w"); if(!fp) { perror(_("Unable to save local taglist file")); free(f); return; } fprintf(fp, "[yafc taglist]\n"); for(li=gvLocalTagList->first; li; li=li->next) fprintf(fp, "%s\n", (char *)li->data); fclose(fp); fprintf(stderr, _("Saved local taglist to %s\n"), f); free(f); }
void cmd_luntag(int argc, char **argv) { int i; OPT_HELP_NEW(_("Remove files from the local tag list."), "luntag [options] <filemask>...", NULL); minargs(1); if(list_numitem(gvLocalTagList) == 0) { printf(_("nothing tagged -- use 'ltag' to tag files\n")); return; } for(i=1;i<argc;i++) { bool del_done = false; listitem *li; while((li = list_search(gvLocalTagList, (listsearchfunc)ltagcmp, argv[i])) != 0) { printf("%s\n", (const char *)li->data); list_delitem(gvLocalTagList, li); del_done = true; } if(!del_done) printf(_("%s: no matches found\n"), argv[i]); } }
static void show_ltaglist_info(void) { int num = list_numitem(gvLocalTagList); if(num == 0) { fprintf(stderr, _("nothing tagged -- use 'ltag' to tag files\n")); return; } printf(_("%u files tagged\n"), num); }
void cmd_status(int argc, char **argv) { OPT_HELP_NEW(_("Show status."), "status [options]", NULL); maxargs(optind - 1); if(ftp_connected()) printf(_("connected to '%s'\n"), host_getoname(ftp->host)); else puts(_("not connected")); if(ftp_loggedin()) printf(_("logged in as '%s'\n"), ftp->url->username); #ifdef HAVE_KERBEROS if(ftp_connected()) sec_status(); #endif if(list_numitem(gvFtpList) > 1 || ftp_connected()) printf(_("There are totally %u connections open\n"), list_numitem(gvFtpList)); }
static void show_ltaglist(void) { listitem *li; if(list_numitem(gvLocalTagList) == 0) { fprintf(stderr, _("nothing tagged -- use 'ltag' to tag files\n")); return; } for(li=gvLocalTagList->first; li; li=li->next) printf("%s\n", (char *)li->data); }
void cmd_close(int argc, char **argv) { if(argv) { OPT_HELP_NEW(_("Close open connection"), "close [options]", NULL); maxargs(optind - 1); } ftp_quit(); if(list_numitem(gvFtpList) > 1) { list_delitem(gvFtpList, gvCurrentFtp); gvCurrentFtp = gvFtpList->first; ftp_use((Ftp *)gvCurrentFtp->data); } }
void cmd_status(int argc, char **argv) { OPT_HELP("Show status. Usage:\n" " status [options]\n" "Options:\n" " -h, --help show this help\n"); maxargs(optind - 1); if(ftp_connected()) printf(_("connected to '%s'\n"), ftp->host->ohostname); else puts(_("not connected")); if(ftp_loggedin()) printf(_("logged in as '%s'\n"), ftp->url->username); #ifdef HAVE_KERBEROS if(ftp_connected()) sec_status(); #endif if(list_numitem(gvFtpList) > 1 || ftp_connected()) printf(_("There are totally %u connections open\n"), list_numitem(gvFtpList)); }
void cmd_close(int argc, char **argv) { if(argv) { OPT_HELP("Close open connection. Usage:\n" " close [options]\n" "Options:\n" " -h, --help show this help\n"); maxargs(optind - 1); } ftp_quit(); if(list_numitem(gvFtpList) > 1) { list_delitem(gvFtpList, gvCurrentFtp); gvCurrentFtp = gvFtpList->first; ftp_use((Ftp *)gvCurrentFtp->data); } }
int rdir_parse(rdirectory *rdir, FILE *fp, const char *path, bool is_mlsd) { char tmp[257]; rfile *f; int r; bool failed = false; free(rdir->path); rdir->path = 0; list_clear(rdir->files); rdir->timestamp = time(0); f = rfile_create(); ftp_trace("*** start parsing directory listing of '%s' ***\n", path); while(!feof(fp)) { if(fgets(tmp, 256, fp) == 0) break; strip_trailing_chars(tmp, "\r\n"); if(tmp[0] == 0) break; ftp_trace("%s\n", tmp); rfile_clear(f); r = rfile_parse(f, tmp, path, is_mlsd); if(r == -1) { ftp_err("parsing failed on '%s'\n", tmp); list_clear(rdir->files); failed = true; } else if(r == 0) list_additem(rdir->files, (void *)rfile_clone(f)); /* else r == 1, ie a 'total ###' line, which isn't an error */ } ftp_trace("*** end parsing directory listing ***\n"); if(failed) { if(list_numitem(rdir->files) == 0) { ftp_err("directory parsing failed completely\n"); return -1; } } rdir->path = xstrdup(path); return 0; }
listitem *ftplist_search(const char *str) { if(isdigit((int)str[0]) && strchr(str, '.') == 0) { listitem *li; int i = 1; int n = atoi(str); if(n <= 0 || n > list_numitem(gvFtpList)) { ftp_err(_("invalid connection number: '%d'\n"), n); return 0; } for(li=gvFtpList->first; li; li=li->next, i++) { if(i == n) return li; } } else { listitem *li = list_search(gvFtpList, (listsearchfunc)switch_search, str); if(li) return li; else ftp_err(_("no such connection open: '%s'\n"), str); } return 0; }
static void putfiles(list *gl, unsigned opt, const char *output) { struct stat sb; char *path = 0; const char *file; listitem *li; list_sort(gl, put_sort_func, false); for(li=gl->first; li && !put_quit; li=li->next) { if(!ftp_connected()) return; if(gvSighupReceived) { if(!test(opt, PUT_RESUME)) opt |= PUT_UNIQUE; opt |= PUT_FORCE; } path = (char *)li->data; file = base_name_ptr(path); if(strcmp(file, ".") == 0 || strcmp(file, "..") == 0) continue; if(test(opt, PUT_INTERACTIVE) && !put_batch) { int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Put '%s'?"), shortpath(path, 42, gvLocalHomeDir)); if(a == ASKNO) continue; if(a == ASKCANCEL) { put_quit = true; break; } if(a == ASKALL) put_batch = true; /* else a==ASKYES */ } if(stat(path, &sb) != 0) { perror(path); continue; } if(S_ISDIR(sb.st_mode)) { if(test(opt, PUT_RECURSIVE)) { char *recurs_output; char *recurs_mask; list *rgl; int r; if((put_dir_glob_mask && fnmatch(put_dir_glob_mask, base_name_ptr(path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (put_dir_rx_mask_set && regexec(&put_dir_rx_mask, base_name_ptr(path), 0, 0, 0) == REG_NOMATCH) #endif ) { /*printf("skipping %s\n", path);*/ } else { if(!test(opt, PUT_PARENTS)) { asprintf(&recurs_output, "%s/%s", output ? output : ".", file); } else recurs_output = xstrdup(output ? output : "."); asprintf(&recurs_mask, "%s/*", path); rgl = lglob_create(); r = lglob_glob(rgl, recurs_mask, true, put_exclude_func); free(recurs_mask); if(list_numitem(rgl) > 0) putfiles(rgl, opt, recurs_output); free(recurs_output); } } else fprintf(stderr, _("%s: omitting directory\n"), shortpath(path, 42, gvLocalHomeDir)); continue; } if(!S_ISREG(sb.st_mode)) { fprintf(stderr, _("%s: not a regular file\n"), shortpath(path, 42, gvLocalHomeDir)); continue; } putfile(path, &sb, opt, output); if(gvInterrupted) { gvInterrupted = false; if(li->next && !put_quit && ftp_connected() && !gvSighupReceived) { int a = ask(ASKYES|ASKNO, ASKYES, _("Continue transfer?")); if(a == ASKNO) { put_quit = true; break; } /* else a == ASKYES */ fprintf(stderr, _("Excellent!!!\n")); } } } }
void cmd_get(int argc, char **argv) { list *gl; int opt=GET_VERBOSE, c; char *logfile = 0; pid_t pid; struct group *grp; char *get_output = 0; int stat_thresh = gvStatsThreshold; #ifdef HAVE_REGEX int ret; char get_rx_errbuf[129]; #endif struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"chmod", required_argument, 0, 'c'}, {"chgrp", required_argument, 0, '2'}, {"no-dereference", no_argument, 0, 'd'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"interactive", no_argument, 0, 'i'}, {"skip-empty", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"force-newer", no_argument, 0, 'F'}, {"logfile", required_argument, 0, 'L'}, {"mask", required_argument, 0, 'm'}, #ifdef HAVE_REGEX {"rx-mask", required_argument, 0, 'M'}, #endif {"newer", no_argument, 0, 'n'}, {"nohup", no_argument, 0, 'H'}, {"verbose", no_argument, 0, 'v'}, {"preserve", no_argument, 0, 'p'}, {"parents", no_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, {"resume", no_argument, 0, 'R'}, {"skip-existing", no_argument, 0, 's'}, {"stats", optional_argument, 0, 'S'}, {"tagged", no_argument, 0, 't'}, {"type", required_argument, 0, '1'}, {"unique", no_argument, 0, 'u'}, {"output", required_argument, 0, 'o'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}, }; if(cmod) { mode_free(cmod); cmod = 0; } if(get_glob_mask) { free(get_glob_mask); get_glob_mask = 0; } if(get_dir_glob_mask) { free(get_dir_glob_mask); get_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(get_rx_mask_set) { regfree(&get_rx_mask); get_rx_mask_set = 0; } if(get_dir_rx_mask_set) { regfree(&get_dir_rx_mask); get_dir_rx_mask_set = 0; } #endif get_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c=getopt_long(argc, argv, "abHc:dDeio:fFL:tnpPvqrRsuT:m:M:", longopts, 0)) != EOF) { switch(c) { case 'a': opt |= GET_APPEND; break; case 'c': cmod = mode_compile(optarg, MODE_MASK_ALL); if(cmod == NULL) { fprintf(stderr, _("Invalid mode for --chmod: %s\n"), optarg); return; } opt |= GET_CHMOD; break; case '2': /* --chgrp */ grp = getgrnam(optarg); if(grp == 0) { fprintf(stderr, _("%s is not a valid group name\n"), optarg); return; } { int i; for(i=0; grp->gr_mem && grp->gr_mem[i]; i++) { if(strcmp(gvUsername, grp->gr_mem[i]) == 0) break; } if(!grp->gr_mem[i]) { fprintf(stderr, _("you are not a member of group %s\n"), optarg); return; } } group_change = grp->gr_gid; opt |= GET_CHGRP; break; case 'D': opt |= GET_DELETE_AFTER; break; case 'd': opt |= GET_NO_DEREFERENCE; break; case 'e': opt |= GET_SKIP_EMPTY; get_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(get_dir_glob_mask); get_dir_glob_mask = xstrdup(optarg); unquote(get_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(get_dir_rx_mask_set) { regfree(&get_dir_rx_mask); get_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&get_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &get_dir_rx_mask, get_rx_errbuf, sizeof(get_rx_errbuf) - 1); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, get_rx_errbuf); return; } else get_dir_rx_mask_set = true; break; #endif case 'i': opt |= GET_INTERACTIVE; break; case 'f': opt |= GET_FORCE; break; case 'F': opt |= GET_FORCE_NEWER; break; case 'm': /* --mask */ free(get_glob_mask); get_glob_mask = xstrdup(optarg); unquote(get_glob_mask); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask */ if(get_rx_mask_set) { regfree(&get_rx_mask); get_rx_mask_set = false; } unquote(optarg); ret = regcomp(&get_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &get_rx_mask, get_rx_errbuf, sizeof(get_rx_errbuf) - 1); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, get_rx_errbuf); return; } else get_rx_mask_set = true; break; #endif case 'o': get_output = tilde_expand_home(optarg, gvLocalHomeDir); /*stripslash(get_output);*/ unquote(get_output); break; case 'v': opt |= GET_VERBOSE; break; case 'p': opt |= GET_PRESERVE; break; case 'P': opt |= GET_PARENTS; break; case 'H': opt |= GET_NOHUP; break; case 'q': opt &= ~GET_VERBOSE; break; case 'r': opt |= GET_RECURSIVE; break; case 's': opt |= GET_SKIP_EXISTING; break; case 'S': stat_thresh = optarg ? atoi(optarg) : 0; break; case 'R': opt |= GET_RESUME; break; case '1': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= GET_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= GET_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'u': opt |= GET_UNIQUE; break; case 'L': free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 't': opt |= GET_TAGGED; break; case 'n': opt |= GET_NEWER; break; case 'h': print_get_syntax(); return; case '?': return; } } if(optind>=argc && !test(opt, GET_TAGGED)) { minargs(optind); return; } need_connected(); need_loggedin(); gl = rglob_create(); while(optind < argc) { stripslash(argv[optind]); if(rglob_glob(gl, argv[optind], true, true, get_exclude_func) == -1) fprintf(stderr, _("%s: no matches found\n"), argv[optind]); optind++; } if(list_numitem(gl) == 0 && !test(opt, GET_TAGGED)) { rglob_destroy(gl); return; } if(test(opt, GET_TAGGED) && (!ftp->taglist || list_numitem(ftp->taglist)==0)) { printf(_("no tagged files\n")); if(list_numitem(gl) == 0) { rglob_destroy(gl); return; } } get_quit = false; get_batch = get_owbatch = get_delbatch = test(opt, GET_FORCE); if(test(opt, GET_FORCE)) opt &= ~GET_INTERACTIVE; if(get_output && !test(opt, GET_RECURSIVE) && list_numitem(gl) + (test(opt, GET_TAGGED) ? list_numitem(ftp->taglist) : 0) == 1) { /* if the argument to --output ends with a slash, we assume the * user wants the destination to be a directory */ char *e = strrchr(get_output, 0); if(e && e[-1] != '/') opt |= GET_OUTPUT_FILE; } stats_reset(gvStatsTransfer); gvInTransfer = true; gvInterrupted = false; if(test(opt, GET_NOHUP)) { int r = 0; pid = fork(); if(pid == 0) { r = transfer_init_nohup(logfile); if(r != 0) exit(0); } if(r != 0) return; if(pid == 0) { /* child process */ transfer_begin_nohup(argc, argv); if(!test(opt, GET_FORCE) && !test(opt, GET_RESUME)) opt |= GET_UNIQUE; opt |= GET_FORCE; if(list_numitem(gl)) getfiles(gl, opt, get_output); rglob_destroy(gl); if(ftp->taglist && test(opt, GET_TAGGED)) getfiles(ftp->taglist, opt, get_output); free(get_output); transfer_end_nohup(); } if(pid == -1) { perror("fork()"); return; } /* parent process */ sleep(1); printf("%d\n", pid); input_save_history(); gvars_destroy(); reset_xterm_title(); exit(0); } if(list_numitem(gl)) getfiles(gl, opt, get_output); rglob_destroy(gl); if(ftp->taglist && test(opt, GET_TAGGED)) getfiles(ftp->taglist, opt, get_output); free(get_output); mode_free(cmod); cmod = 0; gvInTransfer = false; stats_display(gvStatsTransfer, stat_thresh); }
static void getfiles(list *gl, unsigned int opt, const char *output) { listitem *li; rfile *fp, *lnfp; const char *opath, *ofile; char *link = 0; list_sort(gl, get_sort_func, false); li = gl->first; while(li && !get_quit) { fp = (rfile *)li->data; if(!ftp_connected()) return; if(gvSighupReceived) { if(!test(opt, GET_RESUME)) opt |= GET_UNIQUE; opt |= GET_FORCE; } opath = fp->path; ofile = base_name_ptr(opath); if(strcmp(ofile, ".")==0 || strcmp(ofile, "..")==0) { transfer_nextfile(gl, &li, true); continue; } if(test(opt, GET_INTERACTIVE) && !get_batch && !gvSighupReceived) { char* sp = shortpath(opath, 42, ftp->homedir); int a = ask(ASKYES|ASKNO|ASKCANCEL|ASKALL, ASKYES, _("Get '%s'?"), sp); free(sp); if(a == ASKNO) { transfer_nextfile(gl, &li, true); continue; } if(a == ASKCANCEL) { get_quit = true; break; } if(a == ASKALL) get_batch = true; /* else a==ASKYES */ } if(rislink(fp)) { link_to_link__duh: if(test(opt, GET_NO_DEREFERENCE)) { /* link the file, don't copy */ const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); continue; } { char *xcurdir = base_dir_xptr(opath); link = path_absolute(fp->link, xcurdir, ftp->homedir); stripslash(link); free(xcurdir); ftp_trace("found link: '%s' -> '%s'\n", opath, link); } lnfp = ftp_get_file(link); if(lnfp == 0) { /* couldn't dereference the link, try to RETR it */ ftp_trace("unable to dereference link\n"); const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); continue; } if(strncmp(opath, lnfp->path, strlen(lnfp->path)) == 0) { ftp_trace("opath == '%s', lnfp->path == '%s'\n", opath, lnfp->path); char* sp = shortpath(lnfp->path, 42, ftp->homedir); fprintf(stderr, _("%s: circular link -- skipping\n"), sp); free(sp); transfer_nextfile(gl, &li, true); continue; } fp = lnfp; if(rislink(fp)) /* found a link pointing to another link */ /* forgive me father, for I have goto'ed */ goto link_to_link__duh; } if(risdir(fp)) { if(test(opt, GET_RECURSIVE)) { char *recurs_output; char *recurs_mask; list *rgl; if((get_dir_glob_mask && fnmatch(get_dir_glob_mask, base_name_ptr(fp->path), FNM_EXTMATCH) == FNM_NOMATCH) #ifdef HAVE_REGEX || (get_dir_rx_mask_set && regexec(&get_dir_rx_mask, base_name_ptr(fp->path), 0, 0, 0) == REG_NOMATCH) #endif ) { } else { char *q_recurs_mask; bool success = true; if(!test(opt, GET_PARENTS)) success = asprintf(&recurs_output, "%s/%s", output ? output : ".", ofile) != -1; else success = asprintf(&recurs_output, "%s", output ? output : ".") != -1; if (!success) { fprintf(stderr, _("Failed to allocate memory.\n")); transfer_nextfile(gl, &li, true); continue; } if (asprintf(&recurs_mask, "%s/*", opath) == -1) { free(recurs_output); fprintf(stderr, _("Failed to allocate memory.\n")); transfer_nextfile(gl, &li, true); continue; } rgl = rglob_create(); q_recurs_mask = backslash_quote(recurs_mask); rglob_glob(rgl, q_recurs_mask, true, true, get_exclude_func); free(q_recurs_mask); if(list_numitem(rgl) > 0) getfiles(rgl, opt, recurs_output); if(test(opt, GET_PRESERVE)) get_preserve_attribs(fp, recurs_output); rglob_destroy(rgl); free(recurs_output); } } else if(test(opt, GET_VERBOSE)) { char* sp = shortpath(opath, 42, ftp->homedir); fprintf(stderr, _("%s: omitting directory\n"), sp); free(sp); } transfer_nextfile(gl, &li, true); continue; } if(!risreg(fp)) { if(test(opt, GET_VERBOSE)) { char* sp = shortpath(opath, 42, ftp->homedir); fprintf(stderr, _("%s: not a regular file\n"), sp); free(sp); } transfer_nextfile(gl, &li, true); continue; } const int r = getfile(fp, opt, output, ofile); transfer_nextfile(gl, &li, r == 0); if(gvInterrupted) { gvInterrupted = false; if(li && !get_quit && ftp_connected() && !gvSighupReceived) { int a = ask(ASKYES|ASKNO, ASKYES, _("Continue transfer?")); if(a == ASKNO) { get_quit = true; break; } /* else a == ASKYES */ fprintf(stderr, _("Excellent!!!\n")); } } } }
char *expand_prompt(const char *fmt) { unsigned maxlen; char *ins, *e; bool freeins; char *tmp; if(!fmt) return 0; char* prompt = (char *)xmalloc(strlen(fmt)+1); char* cp = prompt; while(fmt && *fmt) { if(*fmt == '%') { fmt++; ins = 0; freeins = false; maxlen = (unsigned)-1; if(isdigit((int)*fmt)) { maxlen = (unsigned)atoi(fmt); while(isdigit((int)*fmt)) fmt++; } switch(*fmt) { case 'c': if (asprintf(&ins, "%u", list_numitem(gvFtpList)) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(prompt); return NULL; } freeins = true; break; case 'C': if (asprintf(&ins, "%u", connection_number()) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); free(prompt); return NULL; } freeins = true; break; case 'u': /* username */ ins = ftp_loggedin() ? ftp->url->username : "******"; break; case 'h': /* remote hostname (as passed to cmd_open()) */ ins = ftp_connected() ? ftp->url->hostname : "?"; break; case 'H': /* %h up to first '.' */ if(!ftp_connected()) { ins = "?"; break; } e = strchr(ftp->url->hostname, '.'); if(e) { ins = xstrndup(ftp->url->hostname, e - ftp->url->hostname); freeins = true; } else ins = ftp->url->hostname; break; case 'm': /* remote machine name (as returned from gethostbynmame) */ ins = xstrdup(ftp_connected() ? host_getoname(ftp->host) : "?"); freeins = true; break; case 'M': /* %m up to first '.' */ if(!ftp_connected()) { ins = "?"; break; } e = strchr(host_getoname(ftp->host), '.'); if(e) { ins = xstrndup(host_getoname(ftp->host), e - host_getoname(ftp->host)); } else ins = xstrdup(host_getoname(ftp->host)); freeins = true; break; case 'n': /* remote ip number */ ins = xstrdup(ftp_connected() ? host_getoname(ftp->host) : "?"); freeins = true; break; case 'w': /* current remote directory */ if(!ftp_loggedin()) { ins = "?"; break; } ins = shortpath(ftp->curdir, maxlen, 0); freeins = true; break; case 'W': /* basename(%w) */ if(!ftp_loggedin()) { ins = "?"; break; } ins = (char *)base_name_ptr(ftp->curdir); break; case '~': /* %w but homedir replaced with '~' */ if(!ftp_loggedin()) { ins = "?"; break; } ins = shortpath(ftp->curdir, maxlen, ftp->homedir); freeins = true; break; case 'l': /* current local directory */ tmp = getcwd(NULL, 0); ins = shortpath(tmp, maxlen, 0); freeins = true; free(tmp); break; case 'L': /* basename(%l) */ tmp = getcwd(NULL, 0); ins = (char *)base_name_ptr(tmp); free(tmp); break; case '%': /* percent sign */ ins = "%"; break; case '#': /* local user == root ? '#' : '$' */ ins = getuid() == 0 ? "#" : "$"; break; case '{': /* begin non-printable character string */ #ifdef HAVE_LIBREADLINE ins = "\001\001"; /* \001 + RL_PROMPT_START_IGNORE */ #endif break; case '}': /* end non-printable character string */ #ifdef HAVE_LIBREADLINE ins = "\001\002"; /* \001 + RL_PROMPT_END_IGNORE */ #endif break; case 'e': /* escape (0x1B) */ ins = "\x1B"; break; default: /* illegal format specifier */ break; } if(ins) { const size_t len = strlen(prompt) + strlen(ins) + strlen(fmt+1) + 1; char* tmp = xmalloc(len); strlcpy(tmp, prompt, len); strlcat(tmp, ins, len); cp = tmp + strlen(prompt) + strlen(ins); free(prompt); prompt = tmp; if(freeins) free(ins); } } else *cp++ = *fmt; fmt++; } unquote_escapes(prompt); return prompt; }
/* store a local file on remote server */ void cmd_put(int argc, char **argv) { int c, opt=PUT_VERBOSE; list *gl; char *put_output = 0; char *logfile = 0; pid_t pid; #ifdef HAVE_REGEX int ret; char put_rx_errbuf[129]; #endif struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"skip-empty", no_argument, 0, 'e'}, {"force", no_argument, 0, 'f'}, {"nohup", no_argument, 0, 'H'}, {"interactive", no_argument, 0, 'i'}, {"logfile", required_argument, 0, 'L'}, {"mask", required_argument, 0, 'm'}, #ifdef HAVE_REGEX {"rx-mask", required_argument, 0, 'M'}, #endif {"newer", no_argument, 0, 'n'}, {"output", required_argument, 0, 'o'}, {"preserve", no_argument, 0, 'p'}, {"parents", no_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, {"resume", no_argument, 0, 'R'}, {"skip-existing", no_argument, 0, 's'}, {"tagged", no_argument, 0, 't'}, {"type", required_argument, 0, '1'}, {"verbose", no_argument, 0, 'v'}, {"unique", no_argument, 0, 'u'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0}, }; if(put_glob_mask) { free(put_glob_mask); put_glob_mask = 0; } if(put_dir_glob_mask) { free(put_dir_glob_mask); put_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(put_rx_mask_set) { regfree(&put_rx_mask); put_rx_mask_set = 0; } if(put_dir_rx_mask_set) { regfree(&put_dir_rx_mask); put_dir_rx_mask_set = 0; } #endif put_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c = getopt_long(argc, argv, "aDefHiL:no:pPqrRstvum:M:", longopts, 0)) != EOF) { switch(c) { case 'i': opt |= PUT_INTERACTIVE; break; case 'f': opt |= PUT_FORCE; break; case 'e': opt |= PUT_SKIP_EMPTY; put_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(put_dir_glob_mask); put_dir_glob_mask = xstrdup(optarg); unquote(put_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(put_dir_rx_mask_set) { regfree(&put_dir_rx_mask); put_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&put_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &put_dir_rx_mask, put_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, put_rx_errbuf); return; } else put_dir_rx_mask_set = true; break; #endif case 'o': put_output = tilde_expand_home(optarg, ftp->homedir); path_collapse(put_output); stripslash(put_output); break; case 'H': opt |= PUT_NOHUP; break; case 'L': free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 'm': /* --mask */ free(put_glob_mask); put_glob_mask = xstrdup(optarg); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask */ if(put_rx_mask_set) { regfree(&put_rx_mask); put_rx_mask_set = false; } ret = regcomp(&put_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &put_rx_mask, put_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optind, put_rx_errbuf); return; } else put_rx_mask_set = true; break; #endif case 'n': opt |= PUT_NEWER; break; case 'v': opt |= PUT_VERBOSE; break; case 'q': opt &= ~PUT_VERBOSE; break; case 'a': opt |= PUT_APPEND; break; case 'D': opt |= PUT_DELETE_AFTER; break; case 'u': opt |= PUT_UNIQUE; if(!ftp->has_stou_command) { fprintf(stderr, _("Remote doesn't support the STOU" " (store unique) command\n")); return; } break; case 'r': opt |= PUT_RECURSIVE; break; case 's': opt |= PUT_SKIP_EXISTING; break; case 'R': opt |= PUT_RESUME; break; case 't': opt |= PUT_TAGGED; break; case '1': if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= PUT_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= PUT_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'p': opt |= PUT_PRESERVE; break; case 'P': opt |= PUT_PARENTS; break; case 'h': print_put_syntax();; return; case '?': return; } } if(optind>=argc && !test(opt, PUT_TAGGED)) { /* fprintf(stderr, _("missing argument, try 'put --help'"*/ /* " for more information\n"));*/ minargs(optind); return; } if(test(opt, PUT_APPEND) && test(opt, PUT_SKIP_EXISTING)) { printf("Can't use --append and --skip-existing simultaneously\n"); return; } need_connected(); need_loggedin(); gl = lglob_create(); while(optind < argc) { char *f; f = tilde_expand_home(argv[optind], gvLocalHomeDir); stripslash(f); lglob_glob(gl, f, true, put_exclude_func); optind++; } if(list_numitem(gl) == 0) { if(!test(opt, PUT_TAGGED)) { list_free(gl); return; } else if(list_numitem(gvLocalTagList) == 0) { printf(_("no tagged files\n")); list_free(gl); return; } } free(ftp->last_mkpath); ftp->last_mkpath = 0; put_quit = false; put_batch = put_owbatch = put_delbatch = test(opt, PUT_FORCE); if(test(opt, PUT_FORCE)) opt &= ~PUT_INTERACTIVE; if(put_output && !test(opt, PUT_RECURSIVE) && list_numitem(gl) + (test(opt, PUT_TAGGED) ? list_numitem(gvLocalTagList) : 0) == 1) { opt |= PUT_OUTPUT_FILE; } gvInTransfer = true; gvInterrupted = false; if(test(opt, PUT_NOHUP)) { int r = 0; pid = fork(); if(pid == 0) { r = transfer_init_nohup(logfile); if(r != 0) exit(0); } if(r != 0) return; if(pid == 0) { /* child process */ transfer_begin_nohup(argc, argv); if(!test(opt, PUT_FORCE) && !test(opt, PUT_RESUME)) opt |= PUT_UNIQUE; opt |= PUT_FORCE; putfiles(gl, opt, put_output); list_free(gl); if(test(opt, PUT_TAGGED)) { putfiles(gvLocalTagList, opt, put_output); list_clear(gvLocalTagList); } free(put_output); transfer_end_nohup(); } if(pid == -1) { perror("fork()"); return; } /* parent process */ sleep(1); printf("%d\n", pid); input_save_history(); gvars_destroy(); reset_xterm_title(); exit(0); } putfiles(gl, opt, put_output); list_free(gl); if(test(opt, PUT_TAGGED)) { putfiles(gvLocalTagList, opt, put_output); list_clear(gvLocalTagList); } free(put_output); gvInTransfer = false; }
void cmd_fxp(int argc, char **argv) { list *gl; listitem *fxp_tmp = 0; char *logfile = 0; char *fxp_output = 0; #ifdef HAVE_REGEX int ret; char fxp_rx_errbuf[129]; #endif int c, opt = FXP_VERBOSE; struct option longopts[] = { {"append", no_argument, 0, 'a'}, {"delete-after", no_argument, 0, 'D'}, {"dir-mask", required_argument, 0, '3'}, #ifdef HAVE_REGEX {"dir-rx-mask", required_argument, 0, '4'}, #endif {"force", no_argument, 0, 'f'}, {"force-newer", no_argument, 0, 'F'}, {"nohup", no_argument, 0, 'H'}, {"interactive", no_argument, 0, 'i'}, {"logfile", required_argument, 0, 'L'}, {"mask", required_argument, 0, 'm'}, #ifdef HAVE_REGEX {"rx-mask", required_argument, 0, 'M'}, #endif {"newer", no_argument, 0, 'n'}, {"output", required_argument, 0, 'o'}, {"preserve", no_argument, 0, 'p'}, {"parents", no_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"recursive", no_argument, 0, 'r'}, {"resume", no_argument, 0, 'R'}, {"skip-existing", no_argument, 0, 's'}, {"tagged", no_argument, 0, 't'}, {"target", required_argument, 0, 'T'}, {"type", required_argument, 0, '1'}, {"unique", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; if(fxp_glob_mask) { free(fxp_glob_mask); fxp_glob_mask = 0; } if(fxp_dir_glob_mask) { free(fxp_dir_glob_mask); fxp_dir_glob_mask = 0; } #ifdef HAVE_REGEX if(fxp_rx_mask_set) { fxp_rx_mask_set = 0; } if(fxp_dir_rx_mask_set) { regfree(&fxp_dir_rx_mask); fxp_dir_rx_mask_set = 0; } #endif if(list_numitem(gvFtpList) == 2) { fxp_tmp = gvFtpList->first; if(fxp_tmp->data == ftp) fxp_target = fxp_tmp->next->data; else fxp_target = fxp_tmp->data; } else fxp_target = 0; fxp_skip_empty = false; optind = 0; /* force getopt() to re-initialize */ while((c=getopt_long(argc, argv, "aDefHiL:M:no:pPqrRstT:uvh", longopts, 0)) != EOF) { switch(c) { case 'a': /* --append */ opt |= FXP_APPEND; break; case 'D': /* --delete-after */ opt |= FXP_DELETE_AFTER; break; case 'f': /* --force */ opt |= FXP_FORCE; break; case 'F': opt |= FXP_FORCE_NEWER; break; case 'e': /* --skip-empty */ opt |= FXP_SKIP_EMPTY; fxp_skip_empty = true; break; case '3': /* --dir-mask=GLOB */ free(fxp_dir_glob_mask); fxp_dir_glob_mask = xstrdup(optarg); unquote(fxp_dir_glob_mask); break; #ifdef HAVE_REGEX case '4': /* --dir-rx-mask=REGEXP */ if(fxp_dir_rx_mask_set) { regfree(&fxp_dir_rx_mask); fxp_dir_rx_mask_set = false; } unquote(optarg); ret = regcomp(&fxp_dir_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &fxp_dir_rx_mask, fxp_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, fxp_rx_errbuf); return; } else fxp_dir_rx_mask_set = true; break; #endif case 'H': /* --nohup */ opt |= FXP_NOHUP; break; case 'i': /* --interactive */ opt |= FXP_INTERACTIVE; break; case 'L': /* --logfile=FILE */ free(logfile); logfile = xstrdup(optarg); unquote(logfile); break; case 'm': /* --mask=GLOB */ free(fxp_glob_mask); fxp_glob_mask = xstrdup(optarg); unquote(fxp_glob_mask); break; #ifdef HAVE_REGEX case 'M': /* --rx-mask=REGEXP */ if(fxp_rx_mask_set) { regfree(&fxp_rx_mask); fxp_rx_mask_set = false; } unquote(optarg); ret = regcomp(&fxp_rx_mask, optarg, REG_EXTENDED); if(ret != 0) { regerror(ret, &fxp_rx_mask, fxp_rx_errbuf, 128); ftp_err(_("Regexp '%s' failed: %s\n"), optarg, fxp_rx_errbuf); return; } else fxp_rx_mask_set = true; break; #endif case 'n': /* --newer */ opt |= FXP_NEWER; break; case 'o': /* --output=DIRECTORY */ if(fxp_target == 0) { printf(_("FxP target not set, use --target=NAME" " (as first option)\n")); return; } fxp_output = tilde_expand_home(optarg, fxp_target->homedir); stripslash(fxp_output); unquote(fxp_output); break; case 'p': /* --preserve */ opt |= FXP_PRESERVE; break; case 'P': /* --parents */ opt |= FXP_PARENTS; break; case 'q': /* --quiet */ opt &= ~FXP_VERBOSE; break; case 'r': /* --recursive */ opt |= FXP_RECURSIVE; break; case 'R': /* --resume */ opt |= FXP_RESUME; break; case 's': opt |= FXP_SKIP_EXISTING; break; case 't': /* --tagged */ opt |= FXP_TAGGED; break; case '1': /* --type=[ascii|binary] */ if(strncmp(optarg, "ascii", strlen(optarg)) == 0) opt |= FXP_ASCII; else if(strncmp(optarg, "binary", strlen(optarg)) == 0) opt |= FXP_BINARY; else { printf(_("Invalid option argument --type=%s\n"), optarg); return; } break; case 'T': /* --target=HOST */ fxp_tmp = ftplist_search(optarg); if(!fxp_tmp) return; fxp_target = (Ftp *)fxp_tmp->data; break; case 'u': /* --unique */ opt |= FXP_UNIQUE; break; case 'v': /* --verbose */ opt |= FXP_VERBOSE; break; case 'h': /* --help */ print_fxp_syntax(); return; case '?': default: return; } } if(optind >= argc && !test(opt, FXP_TAGGED)) { minargs(optind); return; } need_connected(); need_loggedin(); if(fxp_target == 0) { ftp_err(_("No target specified, try '%s --help'" " for more information\n"), argv[0]); return; } #ifdef HAVE_LIBSSH if(ftp->session || fxp_target->session) { ftp_err("FxP for SSH connections no implemented\n"); return; } #endif gl = rglob_create(); while(optind < argc) { stripslash(argv[optind]); if(rglob_glob(gl, argv[optind], true, true, fxp_exclude_func) == -1) fprintf(stderr, _("%s: no matches found\n"), argv[optind]); optind++; } if(list_numitem(gl) == 0 && !test(opt, FXP_TAGGED)) { rglob_destroy(gl); return; } if(test(opt, FXP_TAGGED) && (!ftp->taglist || list_numitem(ftp->taglist) == 0)) { printf(_("no tagged files\n")); if(list_numitem(gl) == 0) { rglob_destroy(gl); return; } } fxp_quit = false; fxp_batch = fxp_owbatch = fxp_delbatch = test(opt, FXP_FORCE); if(test(opt, FXP_FORCE)) opt &= ~FXP_INTERACTIVE; if(fxp_output && !test(opt, FXP_RECURSIVE) && list_numitem(gl) + (test(opt, FXP_TAGGED) ? list_numitem(ftp->taglist) : 0) == 1) { opt |= FXP_OUTPUT_FILE; } gvInTransfer = true; gvInterrupted = false; if(test(opt, FXP_NOHUP)) { int r = 0; pid_t pid = fork(); if(pid == 0) { r = transfer_init_nohup(logfile); if(r != 0) exit(0); } if(r != 0) return; if(pid == 0) { /* child process */ transfer_begin_nohup(argc, argv); if(!test(opt, FXP_FORCE) && !test(opt, FXP_RESUME)) opt |= FXP_UNIQUE; opt |= FXP_FORCE; if(list_numitem(gl)) fxpfiles(gl, opt, fxp_output); rglob_destroy(gl); if(ftp->taglist && test(opt, FXP_TAGGED)) fxpfiles(ftp->taglist, opt, fxp_output); free(fxp_output); transfer_end_nohup(); } if(pid == -1) { perror("fork()"); return; } /* parent process */ sleep(1); printf("%d\n", pid); input_save_history(); gvars_destroy(); reset_xterm_title(); exit(0); } if(list_numitem(gl)) fxpfiles(gl, opt, fxp_output); rglob_destroy(gl); if(ftp->taglist && test(opt, FXP_TAGGED)) fxpfiles(ftp->taglist, opt, fxp_output); free(fxp_output); gvInTransfer = false; }
void cmd_bookmark(int argc, char **argv) { struct option longopts[] = { {"save", optional_argument, 0, 's'}, {"edit", no_argument, 0, 'e'}, {"read", optional_argument, 0, 'r'}, {"delete", no_argument, 0, 'd'}, {"list", no_argument, 0, 'l'}, {"noupdate", no_argument, 0, 'u'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int action = BM_BOOKMARK; int c; char *bmfile = 0; optind = 0; while((c=getopt_long(argc, argv, "s::er::dluh", longopts, 0)) != EOF) { switch(c) { case 's': action = BM_SAVE; free(bmfile); bmfile = xstrdup(optarg); break; case 'e': action = BM_EDIT; break; case 'r': action = BM_READ; free(bmfile); bmfile = xstrdup(optarg); break; case 'd': action = BM_DELETE; break; case 'l': action = BM_LIST; break; case 'u': action = BM_TOGGLE_NOUPDATE; break; case 'h': print_bookmark_syntax(); /* fall through */ default: return; } } if(action == BM_SAVE) { bookmark_save(bmfile); if(bmfile) printf(_("bookmarks saved in %s\n"), bmfile); else printf(_("bookmarks saved in %s/bookmarks\n"), gvWorkingDirectory); return; } if(action == BM_READ) { char *tmp = 0; int ret; list_clear(gvBookmarks); if(bmfile) ret = parse_rc(bmfile, true); else { if (asprintf(&tmp, "%s/bookmarks", gvWorkingDirectory) == -1) { fprintf(stderr, _("Failed to allocate memory.\n")); return; } ret = parse_rc(tmp, false); } if(ret != -1) printf(_("bookmarks read from %s\n"), bmfile ? bmfile : tmp); free(tmp); return; } if(action == BM_EDIT) { invoke_shell("%s %s/bookmarks", gvEditor, gvWorkingDirectory); return; } if(action == BM_LIST) { listitem *li; printf(_("%zu bookmarks present in memory\n"), list_numitem(gvBookmarks)); for(li = gvBookmarks->first; li; li=li->next) { url_t *u = (url_t *)li->data; /* note: all info not printed */ printf("%-20s", u->alias ? u->alias : u->hostname); printf("%s://%s@%s", u->protocol ? u->protocol : "ftp", u->username, u->hostname); if(u->directory) { char* sp = shortpath(u->directory, 30, 0); printf("/%s", sp); free(sp); } putchar('\n'); } return; } if(action == BM_DELETE) { int i; bool del_done = false; minargs(optind); for(i = optind; i < argc; i++) { listitem *li; while((li = list_search(gvBookmarks, (listsearchfunc)urlcmp_name, argv[i])) != 0) { url_t *u = (url_t *)li->data; printf(_("deleted bookmark %s\n"), u->alias ? u->alias : u->hostname); list_delitem(gvBookmarks, li); del_done = true; } } if(del_done) { bookmark_save(0); printf(_("bookmarks saved in %s/bookmarks\n"), gvWorkingDirectory); } return; } if(action == BM_TOGGLE_NOUPDATE) { int i; bool toggle_done = false; if(argc == optind) { listitem *li; need_connected(); need_loggedin(); li = list_search(gvBookmarks, (listsearchfunc)urlcmp_name, ftp->url->alias); if(li) { url_t *u = (url_t *)li->data; u->noupdate = !u->noupdate; printf(_("%s: noupdate: %s\n"), u->alias ? u->alias : u->hostname, u->noupdate ? _("yes") : _("no")); toggle_done = true; } ftp->url->noupdate = !ftp->url->noupdate; if(!toggle_done) printf(_("%s: noupdate: %s\n"), ftp->url->alias ? ftp->url->alias : ftp->url->hostname, ftp->url->noupdate ? _("yes") : _("no")); } for(i = optind; i < argc; i++) { listitem *li; li = list_search(gvBookmarks, (listsearchfunc)urlcmp_name, argv[i]); if(li) { url_t *u = (url_t *)li->data; u->noupdate = !u->noupdate; printf(_("%s: noupdate: %s\n"), u->alias ? u->alias : u->hostname, u->noupdate ? _("yes") : _("no")); toggle_done = true; } } if(toggle_done) { bookmark_save(0); printf(_("bookmarks saved in %s/bookmarks\n"), gvWorkingDirectory); } return; } maxargs(1); need_connected(); need_loggedin(); create_bookmark(argc > 1 ? argv[1] : 0); }