diff -rupN castget-1.1.0//castgetrc.5.in castget-1.1.1//castgetrc.5.in
--- castget-1.1.0//castgetrc.5.in	2009-07-21 22:32:48.000000000 +0200
+++ castget-1.1.1//castgetrc.5.in	2011-12-14 13:07:52.445759302 +0100
@@ -62,6 +62,9 @@ add or overwrite the `year' (TYER) ID3v2
 .TP
 \fBid3comment\fR
 add or overwrite the `comment' (COMM) ID3v2 tag in enclosures that support this.
+.TP
+\fBfilespec\fR
+use a user specified name to save enclosure with instead of the original enclosure name. 2 dynamic variables can be used: %(date) and %(title), which are replaced with the publication date and the title of the RSS entry including the enclosure.
 .SH GLOBAL CONFIGURATION
 A channel definition with the channel identifier `*' will define a global configuration affecting all channels. The global configuration
 .PP
diff -rupN castget-1.1.0//castgetrc.example castget-1.1.1//castgetrc.example
--- castget-1.1.0//castgetrc.example	2006-09-27 20:25:00.000000000 +0200
+++ castget-1.1.1//castgetrc.example	2011-12-14 13:07:52.445759302 +0100
@@ -38,3 +38,17 @@ id3comment=
 id3title=Yeast Radio
 id3year=2005
 
+# One of my podcast subscriptions uses enclosures of the form:
+#
+# url="http://www.pheedo.com/e/088e77a6eeb28f48873f663cdcca92a6/podcast.mp3?e_id=B4878618-D783-F0EC-4DB17B3507BF4B1C&amp;ref=p_itune"
+#
+# When castget tries to determine the name of the .mp3 file it ends up with a bit of a mess.
+# So I added support to 1.0.1 for user naming of the .mp3 file via an entry in the .castgetrc file. 
+#
+# I only supported the %(date) and %(title) fields, but others could be added.
+#
+[ScientificAmerican]
+url=http://rss.sciam.com/sciam/science-talk
+spool=/home/tony/podcasts/ScientificAmerican
+id3album=ScientificAmerican
+filespec=%(date)-%(title).mp3 
diff -rupN castget-1.1.0//configure castget-1.1.1//configure
--- castget-1.1.0//configure	2010-02-20 21:20:37.000000000 +0100
+++ castget-1.1.1//configure	2011-12-14 13:07:52.448759285 +0100
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for castget 1.1.0.
+# Generated by GNU Autoconf 2.64 for castget 1.1.1.
 #
 # Report bugs to <mariuslj@ifi.uio.no>.
 #
@@ -698,8 +698,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='castget'
 PACKAGE_TARNAME='castget'
-PACKAGE_VERSION='1.1.0'
-PACKAGE_STRING='castget 1.1.0'
+PACKAGE_VERSION='1.1.1'
+PACKAGE_STRING='castget 1.1.1'
 PACKAGE_BUGREPORT='mariuslj@ifi.uio.no'
 PACKAGE_URL=''
 
@@ -1419,7 +1419,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures castget 1.1.0 to adapt to many kinds of systems.
+\`configure' configures castget 1.1.1 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1489,7 +1489,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of castget 1.1.0:";;
+     short | recursive ) echo "Configuration of castget 1.1.1:";;
    esac
   cat <<\_ACEOF
 
@@ -1594,7 +1594,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-castget configure 1.1.0
+castget configure 1.1.1
 generated by GNU Autoconf 2.64
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -1965,7 +1965,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by castget $as_me 1.1.0, which was
+It was created by castget $as_me 1.1.1, which was
 generated by GNU Autoconf 2.64.  Invocation command line was
 
   $ $0 $@
@@ -2644,7 +2644,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='castget'
- VERSION='1.1.0'
+ VERSION='1.1.1'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -11537,7 +11537,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_wri
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by castget $as_me 1.1.0, which was
+This file was extended by castget $as_me 1.1.1, which was
 generated by GNU Autoconf 2.64.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -11601,7 +11601,7 @@ Report bugs to <mariuslj@ifi.uio.no>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-castget config.status 1.1.0
+castget config.status 1.1.1
 configured by $0, generated by GNU Autoconf 2.64,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
diff -rupN castget-1.1.0//configure.ac castget-1.1.1//configure.ac
--- castget-1.1.0//configure.ac	2010-02-20 21:17:29.000000000 +0100
+++ castget-1.1.1//configure.ac	2011-12-14 13:07:52.448759285 +0100
@@ -20,7 +20,7 @@
 #
 
 AC_PREREQ(2.59)
-AC_INIT(castget, 1.1.0, mariuslj@ifi.uio.no)
+AC_INIT(castget, 1.1.1, mariuslj@ifi.uio.no)
 AM_INIT_AUTOMAKE([1.8 dist-bzip2 no-dist-gzip])
 AC_CONFIG_SRCDIR([src/castget.c])
 AC_CONFIG_HEADER([config.h])
diff -rupN castget-1.1.0//src/castget.c castget-1.1.1//src/castget.c
--- castget-1.1.0//src/castget.c	2010-02-20 21:19:13.000000000 +0100
+++ castget-1.1.1//src/castget.c	2011-12-14 13:07:52.448759285 +0100
@@ -450,7 +450,8 @@ static int _process_channel(const gchar
   }
 
   c = channel_new(channel_configuration->url, channel_file, 
-                  channel_configuration->spool_directory, resume);
+                  channel_configuration->spool_directory,
+                  channel_configuration->user_filename_spec, resume);
   g_free(channel_file);
 
   if (!c) {
diff -rupN castget-1.1.0//src/channel.c castget-1.1.1//src/channel.c
--- castget-1.1.0//src/channel.c	2009-07-21 22:32:48.000000000 +0200
+++ castget-1.1.1//src/channel.c	2011-12-14 13:07:52.449759352 +0100
@@ -1,5 +1,6 @@
 /*
   Copyright (C) 2005, 2006, 2007 Marius L. Jøhndal
+  Copyright (C) 2010 Tony Armistead
  
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -55,8 +56,12 @@ static void _enclosure_iterator(const vo
                       (gpointer)downloadtime);
 }
 
-channel *channel_new(const char *url, const char *channel_file, 
-                     const char *spool_directory, int resume)
+channel *channel_new(
+		     const char *url, 
+		     const char *channel_file, 
+                     const char *spool_directory, 
+                     const char *user_filename_spec, 
+		     int resume)
 {
   channel *c;
   xmlDocPtr doc;
@@ -67,6 +72,7 @@ channel *channel_new(const char *url, co
   c->url = g_strdup(url);
   c->channel_filename = g_strdup(channel_file);
   c->spool_directory = g_strdup(spool_directory);
+  c->user_filename_spec = g_strdup(user_filename_spec);
   //  c->resume = resume;
   c->rss_last_fetched = NULL;
   c->downloaded_enclosures = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
@@ -175,6 +181,129 @@ static rss_file *_get_rss(channel *c, vo
   return f;
 }
 
+
+/*!
+ * Returns a string with all characters removed which may cause problems if
+ * included as part of a filename.
+ * @param filename the input filename
+ * @return a gchar* string which is the input string with risky chars removed.
+ *         This string should be freed with g_free().
+ */
+static gchar* remove_bad_filename_chars(const char* filename)
+{
+  static const gchar* bad_filename_chars = "/\\?%*:|\"<>.,'";
+  gchar** parts = g_strsplit_set(filename,  bad_filename_chars, -1);
+  gchar* good_filename = g_strjoinv(NULL, parts);
+  g_strfreev(parts);
+  return good_filename;
+}
+
+/*!
+ * Forms the field string for one of the know field names. Supported field names
+ * are:
+ *  	date 	- returns the publication date or the current date if no publication
+ *  		  date was included in the rss entry
+ *  	title	- the episode title which has been modified to remove any chars
+ *  		  which could cause problems if used as part of a filename
+ *  If an unknown field name is specified it is mapped to a single '_' character.
+ *  @param item the episode rss info
+ *  @param field_name one of the supported field names
+ */
+static gchar* form_field_string(
+                                rss_item *item,
+                                const gchar* field_name
+                                )
+{
+  if (g_ascii_strcasecmp("date", field_name) == 0) {
+    gchar str_date[20];
+    /* Try to get date from RSS feed pubDate entry */
+    GDate* rfc822_date = libcastget_parse_rfc822_date(item->pub_date);
+    if (!g_date_valid(rfc822_date)) {
+      /* If that date is bad or missing use current date */
+      GTimeVal today;
+      g_get_current_time(&today);
+      g_date_set_time_val(rfc822_date, &today);
+    }
+    g_date_strftime(str_date, sizeof(str_date), "%d-%m-%y", rfc822_date);
+    g_date_free(rfc822_date);
+    return g_strdup(str_date);
+  }
+  else if (g_ascii_strcasecmp("title", field_name) == 0) {
+    return remove_bad_filename_chars(item->title);
+  }
+  /* Unknown field string so just use an '_' */
+  return g_strnfill(1, '_');
+}
+
+/*!
+ * Forms a user specified filename for an rss episode.
+ * @param directory the directory path for the filename
+ * @param user_file_spec the pattern string which specifies how we construct
+ * 	  the filename part
+ * @param item the rss episode info
+ */
+
+#define DIM(a) sizeof(a)/sizeof(a[0])
+
+static gchar* form_userspec_filename(
+                                     const gchar* directory,
+                                     const gchar* user_file_spec,
+                                     rss_item *item
+                                     )
+{
+  enum {STATE_COPY, STATE_FIELD, STATE_DONE } state = STATE_COPY;
+  gchar* filename_parts[20];
+  int part = 0;
+  gchar fieldname[80];
+  int fieldname_idx = 0;
+  gchar* processed_filename = NULL;
+  const gchar* cp_start = user_file_spec;
+  const gchar* cp_end = user_file_spec;
+  while (state != STATE_DONE) {
+    switch (state) {
+    case STATE_COPY:
+      /* Process */
+      if (*cp_end == '\0' || *cp_end == '%') {
+        if (cp_end > cp_start)
+          filename_parts[part++] = g_strndup(cp_start, cp_end-cp_start);
+      }
+      /* State update */
+      if (*cp_end == '%') {
+        state = STATE_FIELD;
+        fieldname_idx = 0;
+      }
+      if (*cp_end == '\0')
+        state = STATE_DONE;
+      break;
+    case STATE_FIELD:
+      /* Process */
+      if (*cp_end == '\0' || *cp_end == ')') {
+        fieldname[fieldname_idx] = '\0';
+        if (part < DIM(filename_parts)-1)
+          filename_parts[part++] = form_field_string(item, fieldname);
+      }
+      else if ((*cp_end != '(') && (fieldname_idx < DIM(fieldname)-1))
+        fieldname[fieldname_idx++] = *cp_end;
+      /* State update */
+      if (*cp_end == '\0')
+        state = STATE_DONE;
+      else if (*cp_end == ')') {
+        state = STATE_COPY;
+        cp_start = cp_end + 1;
+      }
+      break;
+    case STATE_DONE:
+      break;
+    }
+    ++cp_end;
+  }
+  filename_parts[part] = NULL;
+  processed_filename = g_strjoinv(NULL, filename_parts);
+  while (part--) g_free(filename_parts[part]);
+  return g_build_filename(directory, processed_filename, NULL);
+}
+
+
 static int _do_download(channel *c, channel_info *channel_info, rss_item *item, 
                         void *user_data, channel_callback cb, int resume)
 {
@@ -191,6 +320,13 @@ static int _do_download(channel *c, chan
   }
 
   /* Build enclosure file name and open file. */
+  
+  /* If we have a user filename spec ... */
+  if (c->user_filename_spec)
+    /* ... we use it to construct the filename */
+    enclosure_full_filename = form_userspec_filename(c->spool_directory, c->user_filename_spec, item);
+  else
+    /* ... otherwise we user the filename we derived from the download url */
   enclosure_full_filename = g_build_filename(c->spool_directory, item->enclosure->filename, NULL);
 
   if (resume) {
@@ -209,9 +345,8 @@ static int _do_download(channel *c, chan
   enclosure_file = fopen(enclosure_full_filename, resume_from ? "ab" : "wb");
 
   if (!enclosure_file) {
-    g_free(enclosure_full_filename);
-    
     g_fprintf(stderr, "Error opening enclosure file %s.\n", enclosure_full_filename);
+    g_free(enclosure_full_filename);
     return 1;
   }
   
diff -rupN castget-1.1.0//src/channel.h castget-1.1.1//src/channel.h
--- castget-1.1.0//src/channel.h	2009-07-21 22:32:48.000000000 +0200
+++ castget-1.1.1//src/channel.h	2011-12-14 13:07:52.449759352 +0100
@@ -33,6 +33,7 @@ typedef struct _channel {
   gchar *url;
   gchar *channel_filename;
   gchar *spool_directory;
+  gchar *user_filename_spec;
   GHashTable *downloaded_enclosures;
   gchar *rss_last_fetched;
 } channel;
@@ -60,10 +61,10 @@ typedef void (*channel_callback)(void *u
                                  channel_action action, 
                                  channel_info *channel_info, 
                                  enclosure *enclosure,
-                                 const char *filename);
+                                 const char *user_filename_spec);
 
 channel *channel_new(const char *url, const char *channel_file, 
-                     const char *spool_directory, int resume);
+                     const char *spool_directory, const char *filename, int resume);
 void channel_free(channel *c);
 int channel_update(channel *c, void *user_data, channel_callback cb, int no_download, 
                    int no_mark_read, int first_only, int resume, 
diff -rupN castget-1.1.0//src/configuration.c castget-1.1.1//src/configuration.c
--- castget-1.1.0//src/configuration.c	2009-07-21 22:32:48.000000000 +0200
+++ castget-1.1.1//src/configuration.c	2011-12-14 13:07:52.449759352 +0100
@@ -1,5 +1,6 @@
 /*
   Copyright (C) 2005, 2007 Marius L. Jøhndal
+  Copyright (C) 2010 Tony Armitstead
  
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
@@ -47,6 +48,9 @@ void channel_configuration_free(struct c
   if (c->spool_directory)
     g_free(c->spool_directory);
 
+  if (c->user_filename_spec)
+    g_free(c->user_filename_spec);
+
   if (c->playlist)
     g_free(c->playlist);
 
@@ -92,6 +96,7 @@ struct channel_configuration *channel_co
   /* Read keys from configuration file. */
   c->url = _read_channel_configuration_key(kf, identifier, "url");
   c->spool_directory = _read_channel_configuration_key(kf, identifier, "spool");
+  c->user_filename_spec = _read_channel_configuration_key(kf, identifier, "filespec");
   c->playlist = _read_channel_configuration_key(kf, identifier, "playlist");
   c->id3_lead_artist = _read_channel_configuration_key(kf, identifier, "id3leadartist");
   c->id3_content_group = _read_channel_configuration_key(kf, identifier, "id3contentgroup");
@@ -110,6 +115,10 @@ struct channel_configuration *channel_co
     if (!c->spool_directory && defaults->spool_directory)
       c->spool_directory = g_strdup(defaults->spool_directory);
 
+    if (!c->user_filename_spec && defaults->user_filename_spec)
+      c->user_filename_spec = g_strdup(defaults->user_filename_spec);
+
+    if (!c->playlist && defaults->playlist)
     if (!c->playlist && defaults->playlist)
       c->playlist = g_strdup(defaults->playlist);
 
@@ -157,6 +166,7 @@ int channel_configuration_verify_keys(GK
   for (i = 0; key_list[i]; i++) {
     if (! (!strcmp(key_list[i], "url") ||
            !strcmp(key_list[i], "spool") ||
+           !strcmp(key_list[i], "filespec") ||
            !strcmp(key_list[i], "playlist") ||
            !strcmp(key_list[i], "id3leadartist") ||
            !strcmp(key_list[i], "id3contentgroup") ||
diff -rupN castget-1.1.0//src/configuration.h castget-1.1.1//src/configuration.h
--- castget-1.1.0//src/configuration.h	2009-07-21 22:32:48.000000000 +0200
+++ castget-1.1.1//src/configuration.h	2011-12-14 13:07:52.449759352 +0100
@@ -28,6 +28,7 @@ struct channel_configuration {
   gchar *identifier;
   gchar *url;
   gchar *spool_directory;
+  gchar *user_filename_spec;
   gchar *playlist;
   gchar *id3_lead_artist;
   gchar *id3_content_group;
diff -rupN castget-1.1.0//src/rss.c castget-1.1.1//src/rss.c
--- castget-1.1.0//src/rss.c	2007-09-20 20:10:00.000000000 +0200
+++ castget-1.1.1//src/rss.c	2011-12-14 13:07:52.449759352 +0100
@@ -63,6 +63,7 @@ static void _item_iterator(const void *u
   f->items[i]->title = _dup_child_node_value(node, "title");
   f->items[i]->link = _dup_child_node_value(node, "link");
   f->items[i]->description = _dup_child_node_value(node, "description");
+  f->items[i]->pub_date = _dup_child_node_value(node, "pubDate");
 
   /* Look for mrss information first, if there is any. It may be
      located either directly under the "item" tag, or inside an mrss
@@ -190,8 +191,8 @@ static xmlEntityPtr _get_entity(void *ct
       entity = (xmlEntityPtr)g_new0(xmlEntity, 1);
       entity->type = XML_ENTITY_DECL;
       entity->name = name;
-      entity->orig = contents;
-      entity->content = contents;
+      entity->orig = (unsigned char*)contents;
+      entity->content = (unsigned char*)contents;
       entity->length = g_utf8_strlen(contents, -1);
       entity->etype = XML_INTERNAL_PREDEFINED_ENTITY;
     }
@@ -296,6 +297,9 @@ void rss_close(rss_file *f)
     if (item->title)
       free(item->title);
 
+    if (item->pub_date)
+      free(item->pub_date);
+
     free(item);
   }
 
diff -rupN castget-1.1.0//src/rss.h castget-1.1.1//src/rss.h
--- castget-1.1.0//src/rss.h	2007-09-20 20:10:00.000000000 +0200
+++ castget-1.1.1//src/rss.h	2011-12-14 13:07:52.449759352 +0100
@@ -1,6 +1,7 @@
 /*
   Copyright (C) 2005, 2007 Marius L. J�hndal
  
+ 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
@@ -28,6 +29,7 @@ typedef struct _rss_item {
   char *title;
   char *link;
   char *description;
+  char *pub_date;
   enclosure *enclosure;
 } rss_item;
 
diff -rupN castget-1.1.0//src/utils.c castget-1.1.1//src/utils.c
--- castget-1.1.0//src/utils.c	2009-07-21 22:35:09.000000000 +0200
+++ castget-1.1.1//src/utils.c	2011-12-14 13:07:52.450759290 +0100
@@ -26,6 +26,9 @@
 #include <errno.h>
 #include <unistd.h>
 #include <string.h>
+#include <math.h>
+#include <stdio.h>
+#include <ctype.h>
 #include <glib/gprintf.h>
 #include <glib/gstdio.h>
 #include "utils.h"
@@ -118,6 +121,55 @@ gchar *get_rfc822_time(void)
     return NULL;
 }
 
+static const char *dayStr[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
+static const char *monthStr[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
+
+GDate* libcastget_parse_rfc822_date(const char *rfc822_date_str)
+{
+   GDate* rfc822_date = g_date_new(); /* Create invalid date */
+   const char* dstr = rfc822_date_str;
+   int i = 0;
+
+   while (isspace(*dstr)) dstr++;
+   if (*dstr == '\0') return rfc822_date;
+
+   /* Skip past any valid day, field */
+   for (i=0; i < sizeof(dayStr)/sizeof(dayStr[0]); i++) {
+     if (strncmp(dstr, dayStr[i], 3) == 0)
+       break;
+   }
+   if (i < sizeof(dayStr)/sizeof(dayStr[0])) {
+     dstr += 3;
+     while (isspace(*dstr)) dstr++;
+     if (*dstr == '\0') return rfc822_date;
+     if (*dstr == ',') dstr++;
+     while (isspace(*dstr)) dstr++;
+     if (*dstr == '\0') return rfc822_date;
+   }
+   /* Decode day, month, year */
+   int day;
+   int month;
+   int year;
+   char mStr[20];
+   if (sscanf(dstr, "%d %s %d", &day, mStr, &year) != 3)
+     return rfc822_date;
+   for (i=0; i < sizeof(monthStr)/sizeof(monthStr[0]); i++) {
+     if (strncmp(mStr, monthStr[i], 3) == 0)
+       break;
+  }
+   if (i == sizeof(monthStr)/sizeof(monthStr[0])) return rfc822_date;
+   month = i+1;
+   if (year < 1900) {
+     if (year < 50)
+       year += 2000;
+     else
+       year += 1900;
+   }
+   g_date_set_dmy(rfc822_date, day, month, year);
+   return rfc822_date;
+ }
+
+
 /* 
    Local Variables:
    mode:c
diff -rupN castget-1.1.0//src/utils.h castget-1.1.1//src/utils.h
--- castget-1.1.0//src/utils.h	2007-09-20 20:10:00.000000000 +0200
+++ castget-1.1.1//src/utils.h	2011-12-14 13:07:52.450759290 +0100
@@ -31,6 +31,8 @@ int write_by_temporary_file(const gchar
                             **used_filename);
 gchar *get_rfc822_time(void);
 
+GDate* libcastget_parse_rfc822_date(const char *rfc822_date_str);
+
 #endif /* UTILS_H */
 
 /* 
