Index: src/main.c =================================================================== RCS file: /cvsroot/curl/curl/src/main.c,v retrieving revision 1.547 diff -u -r1.547 main.c --- src/main.c 30 Dec 2009 17:59:57 -0000 1.547 +++ src/main.c 30 Dec 2009 23:00:00 -0000 @@ -614,6 +614,7 @@ bool post302; bool nokeepalive; /* for keepalive needs */ long alivetime; + bool content_disposition; /* use Content-disposition filename */ int default_node_flags; /* default flags to seach for each 'node', which is basically each given URL to transfer */ @@ -859,6 +860,7 @@ " -e/--referer Referer URL (H)", " -O/--remote-name Write output to a file named as the remote file", " --remote-name-all Use the remote file name for all URLs", + " --remote-header-name Use the header-provided filename", " -R/--remote-time Set the remote file's time on the local output", " -X/--request Specify request command to use", " --retry Retry request times if transient problems occur", @@ -1677,6 +1679,7 @@ #endif {"*g", "trace", TRUE}, {"*h", "trace-ascii", TRUE}, + {"*H", "remote-header-name", FALSE}, {"*i", "limit-rate", TRUE}, {"*j", "compressed", FALSE}, /* might take an arg someday */ {"*k", "digest", FALSE}, @@ -1946,6 +1949,13 @@ "--trace-ascii overrides an earlier trace/verbose option\n"); config->tracetype = TRACE_ASCII; break; + case 'H': /* --remote-header-name */ + if (config->include_headers) { + warnf(config, "--include and --remote-header-name cannot be combined.\n"); + return PARAM_BAD_USE; + } + config->content_disposition = toggle?TRUE:FALSE; + break; case 'i': /* --limit-rate */ { /* We support G, M, K too */ @@ -3307,10 +3317,26 @@ struct Configurable *config = out->config; if(!out->stream) { + if (!out->filename) { + warnf(config, "Remote filename has no length!\n"); + return (0 == (sz * nmemb)) ? 1 : 0; /* Failure */ + } + + if (config->content_disposition) { + /* don't overwrite existing files */ + FILE* f = fopen(out->filename, "r"); + if (f) { + fclose(f); + warnf(config, "Refusing to overwrite %s: %s\n", out->filename, strerror(EEXIST)); + return (0 == (sz * nmemb)) ? 1 : 0; /* Failure */ + } + } + /* open file for writing */ out->stream=fopen(out->filename, "wb"); if(!out->stream) { - warnf(config, "Failed to create the file %s\n", out->filename); + warnf(config, "Failed creating %s: %s\n", out->filename, strerror(errno)); + /* * Once that libcurl has called back my_fwrite() the returned value * is checked against the amount that was intended to be written, if @@ -4035,6 +4061,78 @@ return curlx_strequal(uploadfile, "-") || curlx_strequal(uploadfile, "."); } +static char* +parse_filename(char *ptr, int len) +{ + char* copy; + char* p; + char* q; + char quote = 0; + + copy = malloc(len+1); + if (!copy) + return NULL; + strncpy(copy, ptr, len); + copy[len] = 0; + + p = copy; + if (*p == '\'' || *p == '"') { + quote = *p; + p++; + } + + q = strrchr(copy, '/'); + if (q) { + p=q+1; + if (!*p) { + free(copy); + return NULL; + } + } + + q = strrchr(p, quote); + if (q) + *q = 0; + + if (copy!=p) + memmove(copy, p, strlen(p)+1); + + return copy; +} + +static size_t +header_callback(void *ptr, size_t size, size_t nmemb, void *stream) +{ + struct OutStruct* outs = stream; + + if (size*nmemb > 20 && curlx_strnequal(ptr, "Content-disposition:", 20)) { + char *p = (char*)ptr + 20; + while (1) { + /* encoded filenames (*=) are not supported */ + static const char *needle = "filename="; + char *filename; + int i; + + while (*p && !isalpha(*p)) + p++; + if (!*p) + break; + + for (i=0; i<9 && p[i]==needle[i]; i++); + if (i<9) + break; + p+=9; + filename = parse_filename(p, size*nmemb - (p - (char*)ptr)); + if (filename) { + outs->filename = filename; + break; + } + } + } + + return size*nmemb; +} + static int operate(struct Configurable *config, int argc, argv_item_t argv[]) { @@ -4417,7 +4515,7 @@ pc++; outfile = *pc ? strdup(pc): NULL; } - if(!outfile || !*outfile) { + if((!outfile || !*outfile) && !config->content_disposition) { helpf(config->errors, "Remote file name has no length!\n"); res = CURLE_WRITE_ERROR; free(url); @@ -5028,6 +5126,12 @@ if(config->mail_rcpt) my_setopt_str(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); + if ((urlnode->flags & GETOUT_USEREMOTE) + && config->content_disposition) { + my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); + my_setopt(curl, CURLOPT_HEADERDATA, &outs); + } + retry_numretries = config->req_retry; retrystart = cutil_tvnow(); @@ -5039,6 +5143,9 @@ break; } + if (config->content_disposition && outs.stream) + printf("curl: Saved to filename '%s'\n", outs.filename); + /* if retry-max-time is non-zero, make sure we haven't exceeded the time */ if(retry_numretries &&