Index: src/main.c
===================================================================
RCS file: /cvsroot/curl/curl/src/main.c,v
retrieving revision 1.552
diff -u -r1.552 main.c
--- src/main.c	2 Jan 2010 22:09:32 -0000	1.552
+++ src/main.c	11 Jan 2010 20:34:32 -0000
@@ -615,6 +615,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 <command> Specify request command to use",
     "    --retry <num>   Retry request <num> times if transient problems occur",
@@ -1679,6 +1681,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},
@@ -1953,6 +1956,14 @@
                 "--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;
+        break;
       case 'i': /* --limit-rate */
         {
           /* We support G, M, K too */
@@ -3320,10 +3331,29 @@
   struct Configurable *config = out->config;
 
   if(!out->stream) {
+    const size_t rv = (sz * nmemb) ? 1 : 0;
+    if (!out->filename) {
+      warnf(config, "Remote filename has no length!\n");
+      return rv; /* 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 rv; /* 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 to create the file %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
@@ -4049,6 +4079,86 @@
   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 == '"') {
+    /* store the starting quote */
+    quote = *p;
+    p++;
+  }
+
+  /* if the filename contains a path, only use filename portion */
+  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 = (struct OutStruct*)stream;
+  const char* str = (char*)ptr;
+  const size_t cb = size*nmemb;
+  const char* end = (char*)ptr + cb;
+
+  if (cb > 20 && curlx_strnequal(str, "Content-disposition:", 20)) {
+    char *p = (char*)str + 20;
+
+    /* look for the 'filename=' parameter
+       (encoded filenames (*=) are not supported) */
+    while (1) {
+      char *filename;
+
+      while (p < end && !isalpha(*p))
+        p++;
+      if (p == end || p > end-9)
+        break;
+
+      if (memcmp(p, "filename=", 9)) {
+        /* no match, find next parameter */
+        while ((p < end) && (*p != ';'))
+          p++;
+        continue;
+      }
+      p+=9;
+      filename = parse_filename(p, cb - (p - str));
+      if (filename) {
+        outs->filename = filename;
+        break;
+      }
+    }
+  }
+
+  return cb;
+}
+
 static int
 operate(struct Configurable *config, int argc, argv_item_t argv[])
 {
@@ -4431,7 +4541,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);
@@ -5046,6 +5156,12 @@
         if(config->ftp_pret)
           my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
 
+        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();
@@ -5057,6 +5173,10 @@
             break;
           }
 
+          if (config->content_disposition && outs.stream)
+            if (!config->mute)
+              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 &&
Index: docs/curl.1
===================================================================
RCS file: /cvsroot/curl/curl/docs/curl.1,v
retrieving revision 1.285
diff -u -r1.285 curl.1
--- docs/curl.1	2 Jan 2010 22:09:31 -0000	1.285
+++ docs/curl.1	11 Jan 2010 20:34:32 -0000
@@ -907,6 +907,9 @@
 if \fI-O/--remote-name\fP were used for each one. So if you want to disable
 that for a specific URL after \fI--remote-name-all\fP has been used, you must
 use "-o -" or \fI--no-remote-name\fP. (Added in 7.19.0)
+.IP "--remote-header-name"
+This option tells the -O/--remote-name option to use the server-specified
+Content-Disposition filename instead of extracting the filename from the URL.
 .IP "--pass <phrase>"
 (SSL/SSH) Passphrase for the private key
 

