Index: htdocs/css/trac.css
===================================================================
--- htdocs/css/trac.css	(revision 3303)
+++ htdocs/css/trac.css	(working copy)
@@ -319,7 +319,8 @@
 .attachment #preview { margin-top: 1em }
 
 /* Styles for the list of attachments. */
-#attachments { border: 1px outset #996; padding: 1em }
+#list-of-attachments { clear: both; }
+#attachments { border: 1px outset #996;  padding: 1em }
 #attachments .attachments { margin-left: 2em; padding: 0 }
 #attachments dt { display: list-item; list-style: square; }
 #attachments dd { font-style: italic; margin-left: 0; padding-left: 0; }
Index: trac/attachment.py
===================================================================
--- trac/attachment.py	(revision 3303)
+++ trac/attachment.py	(working copy)
@@ -256,7 +256,7 @@
     # IRequestHandler methods
 
     def match_request(self, req):
-        match = re.match(r'^/attachment/(ticket|wiki)(?:[/:](.*))?$',
+        match = re.match(r'^/attachment/([^/]+)(?:[/:](.*))?$',
                          req.path_info)
         if match:
             req.args['type'] = match.group(1)
@@ -268,8 +268,8 @@
         path = req.args.get('path')
         if not parent_type or not path:
             raise HTTPBadRequest('Bad request')
-        if not parent_type in ['ticket', 'wiki']:
-            raise HTTPBadRequest('Unknown attachment type')
+        #if not parent_type in ['ticket', 'wiki']:
+        #    raise HTTPBadRequest('Unknown attachment type')
 
         action = req.args.get('action', 'view')
         if action == 'new':
@@ -308,6 +308,8 @@
         parent_link = req.href(parent_type, parent_id)
         if parent_type == 'ticket':
             parent_text = 'Ticket #' + parent_id
+        elif parent_type == 'milestone':
+            parent_text = 'Milestone ' + parent_id
         else: # 'wiki'
             parent_text = parent_id
         req.hdf['attachment.parent'] = {
@@ -327,7 +329,8 @@
     # Internal methods
 
     def _do_save(self, req, attachment):
-        perm_map = {'ticket': 'TICKET_APPEND', 'wiki': 'WIKI_MODIFY'}
+        perm_map = {'ticket': 'TICKET_APPEND', 'wiki': 'WIKI_MODIFY',
+                    'milestone': 'MILESTONE_MODIFY'}
         req.perm.assert_permission(perm_map[attachment.parent_type])
 
         if req.args.has_key('cancel'):
@@ -367,7 +370,8 @@
                                             attachment.parent_id, filename)
                 if not (old_attachment.author and req.authname \
                         and old_attachment.author == req.authname):
-                    perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE'}
+                    perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE',
+                                'milestone': 'MILESTONE_DELETE'}
                     req.perm.assert_permission(perm_map[old_attachment.parent_type])
                 old_attachment.delete()
             except TracError:
@@ -399,14 +403,16 @@
                                  'mode': 'delete'}
 
     def _render_form(self, req, attachment):
-        perm_map = {'ticket': 'TICKET_APPEND', 'wiki': 'WIKI_MODIFY'}
+        perm_map = {'ticket': 'TICKET_APPEND', 'wiki': 'WIKI_MODIFY',
+                    'milestone': 'MILESTONE_MODIFY'}
         req.perm.assert_permission(perm_map[attachment.parent_type])
 
         req.hdf['attachment'] = {'mode': 'new',
                                  'author': util.get_reporter_id(req)}
 
     def _render_view(self, req, attachment):
-        perm_map = {'ticket': 'TICKET_VIEW', 'wiki': 'WIKI_VIEW'}
+        perm_map = {'ticket': 'TICKET_VIEW', 'wiki': 'WIKI_VIEW',
+                    'milestone': 'MILESTONE_MODIFY'}
         req.perm.assert_permission(perm_map[attachment.parent_type])
 
         req.check_modified(attachment.time)
@@ -416,7 +422,8 @@
         req.hdf['attachment'] = attachment_to_hdf(self.env, req, None,
                                                   attachment)
         
-        perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE'}
+        perm_map = {'ticket': 'TICKET_ADMIN', 'wiki': 'WIKI_DELETE',
+                    'milestone': 'MILESTONE_DELETE'}
         if req.perm.has_permission(perm_map[attachment.parent_type]):
             req.hdf['attachment.can_delete'] = 1
 
Index: trac/ticket/roadmap.py
===================================================================
--- trac/ticket/roadmap.py	(revision 3303)
+++ trac/ticket/roadmap.py	(working copy)
@@ -19,6 +19,7 @@
 from time import localtime, strftime, time
 
 from trac import __version__
+from trac.attachment import attachments_to_hdf
 from trac.core import *
 from trac.perm import IPermissionRequestor
 from trac.util import format_date, format_datetime, parse_date, \
@@ -445,10 +446,15 @@
 
     def _render_view(self, req, db, milestone):
         req.hdf['title'] = 'Milestone %s' % milestone.name
-        req.hdf['milestone.mode'] = 'view'
-
+        req.hdf['milestone'] = {
+            'mode': 'view',
+            'attachments': attachments_to_hdf(self.env, req, db,
+                                              'milestone', milestone.name),
+            }
+        if req.perm.has_permission('MILESTONE_MODIFY'):
+            req.hdf['milestone.attach_href'] = req.href.attachment('milestone',
+                                                                   milestone.name)
         req.hdf['milestone'] = milestone_to_hdf(self.env, db, req, milestone)
-
         available_groups = []
         component_group_available = False
         for field in TicketSystem(self.env).get_ticket_fields():
Index: templates/macros.cs
===================================================================
--- templates/macros.cs	(revision 3303)
+++ templates/macros.cs	(working copy)
@@ -172,6 +172,7 @@
 /def ?><?cs 
 
 def:list_of_attachments(attachments, attach_href) ?>
+<div id="list-of-attachments">
 <h2>Attachments</h2><?cs
  if:len(attachments) ?><div id="attachments">
   <dl class="attachments"><?cs each:attachment = attachments ?>
@@ -189,5 +190,5 @@
    <input type="hidden" name="action" value="new" />
    <input type="submit" value="Attach File" />
   </div></form><?cs
- /if ?><?cs if:len(attachments) ?></div><?cs /if ?><?cs
+ /if ?><?cs if:len(attachments) ?></div><?cs /if ?></div><?cs
 /def ?>
Index: templates/milestone.cs
===================================================================
--- templates/milestone.cs	(revision 3303)
+++ templates/milestone.cs	(working copy)
@@ -194,6 +194,9 @@
    </fieldset>
   </form>
   <div class="description"><?cs var:milestone.description ?></div><?cs
+  if:milestone.attach_href || len(milestone.attachments) ?><?cs 
+   call:list_of_attachments(milestone.attachments, milestone.attach_href) ?><?cs
+  /if ?><?cs
   if:trac.acl.MILESTONE_MODIFY || trac.acl.MILESTONE_DELETE ?>
    <div class="buttons"><?cs
     if:trac.acl.MILESTONE_MODIFY ?>
