Commits

Anonymous committed a605864

[patch-0.94.4i.tlr.nametemplate.1] Fix nametemplate
support: We should not move the user's files around just
to make them match mailcap's idea of their file name.
This patch uses symbolic links instead.

Comments (0)

Files changed (3)

   can't be read from the other one.
 
 
+- Re-visit nametemplate support.  Currently, we use
+  symbolic links in our temporary directory for this.
+
+
 - BODY struct should probably have a pointer to its
   corresponding HEADER struct.  this is needed for
   mh/maildir mailboxes so the correct pathname can be
   STATE struct so that all of the MIME handlers can look
   up the corresponding HEADERs if need be?
 
-- rfc1524_expand_filename() doesn't work as expected, as
-  it doesn't honor $tmpdir under some conditions if
-  matching nametemplates exist.
-
 - option to not include attachments in replies
 
 - handle message/external-body in some fashion
 {
   char type[STRING];
   char command[STRING];
+  char newfile[_POSIX_PATH_MAX] = "";
   rfc1524_entry *entry = rfc1524_new_entry ();
-
+  short unlink_newfile = 0;
+  int rc = 0;
+  
   snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
   if (rfc1524_mailcap_lookup (a, type, entry, M_COMPOSE))
   {
     if (entry->composecommand || entry->composetypecommand)
     {
-      char newfile[_POSIX_PATH_MAX] = "";
 
       if (entry->composetypecommand)
 	strfcpy (command, entry->composetypecommand, sizeof (command));
       {
 	dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n",
 				  a->filename, newfile));
-	if (!mutt_rename_file (a->filename, newfile))
+	if (symlink (a->filename, newfile) == -1)
 	{
 	  if (!mutt_yesorno ("Can't match nametemplate, continue?", 1))
-	    return 0;
+	    goto bailout;
 	}
-	else
-	{
-	  safe_free ((void **) &a->filename);
-	  a->filename = safe_strdup (newfile);
-	}
+	unlink_newfile = 1;
       }
-
-      if (rfc1524_expand_command (a, a->filename, type,
+      else
+	strfcpy(newfile, a->filename, sizeof(newfile));
+      
+      if (rfc1524_expand_command (a, newfile, type,
 				      command, sizeof (command)))
       {
 	/* For now, editing requires a file, no piping */
 	  if ((fp = safe_fopen (a->filename, "r")) == NULL)
 	  {
 	    mutt_perror ("Failure to open file to parse headers.");
-	    return 0;
+	    goto bailout;
 	  }
 
 	  b = mutt_read_mime_header (fp, 0);
 	    if ((tfp = safe_fopen (tempfile, "w")) == NULL)
 	    {
 	      mutt_perror ("Failure to open file to strip headers.");
-	      return 0;
+	      goto bailout;
 	    }
 	    mutt_copy_stream (fp, tfp);
 	    fclose (fp);
     return 1;
   }
 
+  rc = 1;
+  
+  bailout:
+  
+  if(unlink_newfile)
+    unlink(newfile);
+
   rfc1524_free_entry (&entry);
-  return 1;
+  return rc;
 }
 
 /* 
 {
   char type[STRING];
   char command[STRING];
+  char newfile[_POSIX_PATH_MAX] = "";
   rfc1524_entry *entry = rfc1524_new_entry ();
-
+  short unlink_newfile = 0;
+  int rc = 0;
+  
   snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
   if (rfc1524_mailcap_lookup (a, type, entry, M_EDIT))
   {
     if (entry->editcommand)
     {
-      char newfile[_POSIX_PATH_MAX] = "";
 
       strfcpy (command, entry->editcommand, sizeof (command));
       if (rfc1524_expand_filename (entry->nametemplate,
       {
 	dprint(1, (debugfile, "oldfile: %s\t newfile: %s\n",
 				  a->filename, newfile));
-	if (mutt_rename_file (a->filename, newfile))
+	if (symlink (a->filename, newfile) == -1)
 	{
 	  if (!mutt_yesorno ("Can't match nametemplate, continue?", 1))
-	    return 0;
+	    goto bailout;
 	}
-	else
-	{
-	  safe_free ((void **) &a->filename);
-	  a->filename = safe_strdup (newfile);
-	}
+	unlink_newfile = 1;
       }
+      else
+	strfcpy(newfile, a->filename, sizeof(newfile));
 
-      if (rfc1524_expand_command (a, a->filename, type,
+      if (rfc1524_expand_command (a, newfile, type,
 				      command, sizeof (command)))
       {
 	/* For now, editing requires a file, no piping */
   {
     /* On text, default to editor */
     mutt_edit_file ((!Editor || strcmp ("builtin", Editor) == 0) ? 
-		    NONULL(Visual) : NONULL(Editor), a->filename);
+		    NONULL(Visual) : NONULL(Editor), newfile);
   }
   else
   {
     return 0;
   }
 
+  rc = 1;
+  
+  bailout:
+  
+  if(unlink_newfile)
+    unlink(newfile);
+  
   rfc1524_free_entry (&entry);
-  return 1;
+  return rc;
 }
 
 int mutt_is_autoview (char *type)
   char *fname;
   rfc1524_entry *entry = NULL;
   int rc = -1;
-
+  int unlink_tempfile = 0;
+  
   is_message = mutt_is_message_type(a->type, a->subtype);
 #ifdef _PGPPATH
   if (is_message && (a->hdr->pgp & PGPENCRYPT) && !pgp_valid_passphrase())
       if (fp == NULL)
       {
 	/* send case: the file is already there */
-	if (mutt_rename_file (a->filename, tempfile))
+	if (symlink (a->filename, tempfile) == -1)
 	{
 	  if (mutt_yesorno ("Can't match nametemplate, continue?", 1) == M_YES)
 	    strfcpy (tempfile, a->filename, sizeof (tempfile));
 	    goto return_error;
 	}
 	else
-	{
-	  safe_free ((void **) &a->filename);
-	  a->filename = safe_strdup (tempfile);
-	}
+	  unlink_tempfile = 1;
       }
     }
     else if (fp == NULL) /* send case */
     rfc1524_free_entry (&entry);
   if (fp && tempfile[0])
     mutt_unlink (tempfile);
+  else if (unlink_tempfile)
+    unlink(tempfile);
+
   if (pagerfile[0])
     mutt_unlink (pagerfile);
 
   char type[STRING];
   pid_t thepid;
   FILE *ifp, *fpout;
-
+  short unlink_newfile = 0;
+  
   snprintf (type, sizeof (type), "%s/%s", TYPE (a), a->subtype);
 
   if (rfc1524_mailcap_lookup (a, type, NULL, M_PRINT)) 
     {
       if (!fp)
       {
-	/* only attempt file move in send mode */
-
-	if (mutt_rename_file (a->filename, newfile))
+	if (symlink(a->filename, newfile) == -1)
 	{
 	  if (mutt_yesorno ("Can't match nametemplate, continue?", 1) != M_YES)
 	  {
 	  strfcpy (newfile, a->filename, sizeof (newfile));
 	}
 	else
-	{
-	  safe_free ((void **)&a->filename);
-	  a->filename = safe_strdup (newfile);
-	}
+	  unlink_newfile = 1;
       }
     }
 
 
     if (fp)
       mutt_unlink (newfile);
+    else if (unlink_newfile)
+      unlink(newfile);
 
     rfc1524_free_entry (&entry);
     return (1);
 
   if (!strcasecmp ("text/plain", a->subtype) ||
       !strcasecmp ("application/postscript", a->subtype))
+  {
     return (mutt_pipe_attachment (fp, a, NONULL(PrintCmd), NULL));
+  }
   else if (mutt_can_decode (a))
   {
     /* decode and print */
   int needspipe = TRUE;
   char buf[LONG_STRING];
 
-  while (command[x] && x<clen && y<sizeof(buf)) {
+  while (command[x] && x<clen && y<sizeof(buf)) 
+  {
     if (command[x] == '\\') {
       x++;
       buf[y++] = command[x++];
     }
-    else if (command[x] == '%') {
+    else if (command[x] == '%') 
+    {
       x++;
-      if (command[x] == '{') {
+      if (command[x] == '{') 
+      {
 	char param[STRING];
 	int z = 0;
 	char *ret = NULL;
   char buf[_POSIX_PATH_MAX];
   char tmp[_POSIX_PATH_MAX];
   char *period;
-
+  size_t sl;
+  
   strfcpy (buf, NONULL (Tempdir), sizeof (buf));
   mutt_expand_path (buf, sizeof (buf));
   if (s[0] == '\0')
     if (period != NULL)
     {
       *period = '.';
-      strcat (s, period);
+      sl = strlen(s);
+      strfcpy(s + sl, period, l - sl);
     }
   }
 }
 
-/* This routine expands the filename given to match the format of the
- * nametemplate given.  It returns various values based on what operations
- * it performs.
- *
+/* This routine will create a _temporary_ filename matching the
+ * name template given if this needs to be done.
+ * 
+ * Please note that only the last path element of the
+ * template and/or the old file name will be used for the
+ * comparison and the temporary file name.
+ * 
  * Returns 0 if oldfile is fine as is.
  * Returns 1 if newfile specified
  */
 
+static void strnfcpy(char *d, char *s, size_t siz, size_t len)
+{
+  if(len > siz)
+    len = siz - 1;
+  strfcpy(d, s, len);
+}
+
 int rfc1524_expand_filename (char *nametemplate,
 			     char *oldfile, 
 			     char *newfile,
 			     size_t nflen)
 {
-  int z = 0;
-  int i = 0, j = 0;
-  int lmatch = TRUE;
-  int match = TRUE;
-  size_t len = 0;
+  int i, j, k, ps, r;
   char *s;
-
+  short lmatch = 0, rmatch = 0; 
+  char left[_POSIX_PATH_MAX];
+  char right[_POSIX_PATH_MAX];
+  
   newfile[0] = 0;
 
+  /* first, ignore leading path components.
+   */
+  
   if (nametemplate && (s = strrchr (nametemplate, '/')))
     nametemplate = s + 1;
 
   if (oldfile && (s = strrchr (oldfile, '/')))
-  {
-    len = s - oldfile + 1;
-    if (len > nflen)
-      len = nflen;
-    strfcpy (newfile, oldfile, len + 1);
-    oldfile += len;
-  }
-
-  /* If nametemplate is NULL, create a newfile from oldfile and return 0 */
+    oldfile = s + 1;
+    
   if (!nametemplate)
   {
     if (oldfile)
       strfcpy (newfile, oldfile, nflen);
-    mutt_adv_mktemp (newfile, nflen);
-    return 0;
   }
-
-  /* If oldfile is NULL, just return a newfile name */
-  if (!oldfile)
+  else if (!oldfile)
   {
     snprintf (newfile, nflen, nametemplate, "mutt");
-    mutt_adv_mktemp (newfile, nflen);
-    return 0;
   }
+  else /* oldfile && nametemplate */
+  {
 
-  /* Next, attempt to determine if the oldfile already matches nametemplate */
-  /* Nametemplate is of the form pre%spost, only replace pre or post if
-   * they don't already match the oldfilename */
-  /* Test pre */
-
-  if ((s = strrchr (nametemplate, '%')) != NULL)
-  {
-    newfile[len] = '\0';
-
-    z = s - nametemplate;
-
-    for (i = 0; i < z && i < nflen; i++)
+    /* first, compare everything left from the "%s" 
+     * (if there is one).
+     */
+    
+    lmatch = 1; ps = 0;
+    for(i = 0; nametemplate[i]; i++)
     {
-      if (oldfile[i] != nametemplate[i])
-      {
-	lmatch=FALSE;
-	break;
-      }
-    }
-
-    if (!lmatch)
-    {
-      match = FALSE;
-      i = nflen - len;
-      if (i > z)
-	i = z;
-      strfcpy (newfile + len, nametemplate, i);
-    }
-
-    strfcpy (newfile + strlen (newfile), 
-	    oldfile, nflen - strlen (newfile));
-
-    dprint (1, (debugfile,"template: %s, oldfile: %s, newfile: %s\n",
-	      nametemplate, oldfile, newfile));
-
-    /* test post */
-    lmatch = TRUE;
-
-    for (z += 2, i = strlen (oldfile) - 1, j = strlen (nametemplate) - 1; 
-	i && j > z; i--, j--)
-      if (oldfile[i] != nametemplate[j])
-      {
-	lmatch = FALSE;
+      if(nametemplate[i] == '%' && nametemplate[i+1] == 's')
+      { 
+	ps = 1;
 	break;
       }
 
-    if (!lmatch)
-    {
-      match = FALSE;
-      strfcpy (newfile + strlen (newfile),
-	      nametemplate + z, nflen - strlen (newfile));
+      /* note that the following will _not_ read beyond oldfile's end. */
+
+      if(lmatch && nametemplate[i] != oldfile[i])
+	lmatch = 0;
     }
 
-    if (match) 
-      return 0;
+    if(ps)
+    {
+      
+      /* If we had a "%s", check the rest. */
+      
+      /* now, for the right part: compare everything right from 
+       * the "%s" to the final part of oldfile.
+       * 
+       * The logic here is as follows:
+       * 
+       * - We start reading from the end.
+       * - There must be a match _right_ from the "%s",
+       *   thus the i + 2.  
+       * - If there was a left hand match, this stuff
+       *   must not be counted again.  That's done by the
+       *   condition (j >= (lmatch ? i : 0)).
+       */
+      
+      rmatch = 1;
 
+      for(r = 0, j = strlen(oldfile) - 1, k = strlen(nametemplate) - 1 ;
+	  j >= (lmatch ? i : 0) && k >= i + 2;
+	  j--, k--)
+      {
+	if(nametemplate[k] != oldfile[j])
+	{
+	  rmatch = 0;
+	  break;
+	}
+      }
+      
+      /* Now, check if we had a full match. */
+      
+      if(k >= i + 2)
+	rmatch = 0;
+      
+      if(lmatch) *left = 0;
+      else strnfcpy(left, nametemplate, sizeof(left), i);
+      
+      if(rmatch) *right = 0;
+      else strfcpy(right, nametemplate + i + 2, sizeof(right));
+      
+      snprintf(newfile, nflen, "%s%s%s", left, oldfile, right);
+    }
+    else
+    {
+      /* no "%s" in the name template. */
+      strfcpy(newfile, nametemplate, nflen);
+    }
+  }
+  
+  mutt_adv_mktemp(newfile, nflen);
+
+  if(rmatch && lmatch)
+    return 0;
+  else 
     return 1;
-  }
-  else
-  {
-    /* no %s in nametemplate, graft unto path of oldfile */
-    strfcpy (newfile, nametemplate, nflen);
-    return 1;
-  }
+  
 }
 
-/* For nametemplate support, we may need to rename a file.
- * If rfc1524_expand_command() is used on a recv'd message, then
+/* If rfc1524_expand_command() is used on a recv'd message, then
  * the filename doesn't exist yet, but if its used while sending a message,
  * then we need to rename the existing file.
  *