Index: main/waeup.sirp/trunk/src/waeup/sirp/browser/templates/default_waeup_display_form.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/browser/templates/default_waeup_display_form.pt	(revision 7096)
+++ main/waeup.sirp/trunk/src/waeup/sirp/browser/templates/default_waeup_display_form.pt	(revision 7097)
@@ -15,4 +15,5 @@
       </tr>
     </tal:block>
+    <tal:actionbar content="structure provider:files" />
   </tbody>
   <tfoot>
Index: main/waeup.sirp/trunk/src/waeup/sirp/browser/templates/default_waeup_edit_form.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/browser/templates/default_waeup_edit_form.pt	(revision 7096)
+++ main/waeup.sirp/trunk/src/waeup/sirp/browser/templates/default_waeup_edit_form.pt	(revision 7097)
@@ -43,4 +43,5 @@
         </tr>
       </tal:block>
+      <tal:actionbar content="structure provider:files" />
     </tbody>
   </table>
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 7096)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py	(revision 7097)
@@ -470,4 +470,5 @@
     title = 'Clearance Data'
     pnav = 4
+    files_changed = []
 
     form_fields['date_of_birth'].custom_widget = FriendlyDateWidget('le-year')
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/filedisplay.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/filedisplay.pt	(revision 7097)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/filedisplay.pt	(revision 7097)
@@ -0,0 +1,15 @@
+<tr>
+  <td class="label">
+    <label i18n:translate="">
+        <span tal:replace="viewlet/label">FILENAME</span>
+    </label>
+  </td>
+  <td class="field">
+    <span class="widget">
+      <a tal:attributes="href viewlet/img_src"
+         tal:content="viewlet/img_src"
+         target="image">
+        LINK
+      </a>
+    </span>
+</tr>
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/fileupload.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/fileupload.pt	(revision 7097)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/fileupload.pt	(revision 7097)
@@ -0,0 +1,22 @@
+<tr>
+  <td class="label">
+    <label i18n:translate="" tal:attributes="for viewlet/input_name">
+        <span tal:replace="viewlet/label">FILENAME</span>
+    </label>
+  </td>
+  <td class="field">
+    <span class="widget">
+      <a tal:attributes="href viewlet/img_src"
+         tal:content="viewlet/img_src"
+         target="image">
+        LINK
+      </a>
+      <br />
+      <input type="file" tal:attributes="name viewlet/input_name"/>
+      <br />
+      <span i18n:translate="">
+        Max. file size:
+        <span tal:replace="viewlet/max_upload_size">10 KB</span>
+      </span>
+    </span>
+</tr>
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/imagedisplay.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/imagedisplay.pt	(revision 7097)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/imagedisplay.pt	(revision 7097)
@@ -0,0 +1,11 @@
+<tr>
+  <td class="label">
+    <label i18n:translate="" tal:attributes="for viewlet/input_name">
+        <span tal:replace="viewlet/label">FILENAME</span>
+    </label>
+  </td>
+  <td class="field">
+    <span class="widget">
+      <img tal:attributes="src viewlet/img_src" /><br />
+    </span>
+</tr>
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/imageupload.pt
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/imageupload.pt	(revision 7097)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/imageupload.pt	(revision 7097)
@@ -0,0 +1,17 @@
+<tr>
+  <td class="label">
+    <label i18n:translate="" tal:attributes="for viewlet/input_name">
+        <span tal:replace="viewlet/label">FILENAME</span>
+    </label>
+  </td>
+  <td class="field">
+    <span class="widget">
+      <img tal:attributes="src viewlet/img_src" /><br />
+      <input type="file" tal:attributes="name viewlet/input_name"/>
+      <br />
+      <span i18n:translate="">
+        Max. file size:
+        <span tal:replace="viewlet/max_upload_size">10 KB</span>
+      </span>
+    </span>
+</tr>
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/student.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/student.py	(revision 7096)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/student.py	(revision 7097)
@@ -17,4 +17,5 @@
 Container for the various objects owned by students.
 """
+import os
 import grok
 from grok import index
@@ -23,5 +24,8 @@
 from hurry.workflow.interfaces import IWorkflowState, IWorkflowInfo
 from zope.securitypolicy.interfaces import IPrincipalRoleManager
-from waeup.sirp.interfaces import IObjectHistory, IUserAccount
+from waeup.sirp.interfaces import (
+    IObjectHistory, IUserAccount, IFileStoreNameChooser, IFileStoreHandler)
+from waeup.sirp.image import WAeUPImageFile
+from waeup.sirp.imagestorage import DefaultFileStoreHandler
 from waeup.sirp.students.interfaces import (
     IStudent, IStudentNavigation, IStudentClearanceEdit,
@@ -136,2 +140,96 @@
         user, target, comment))
     return
+
+#: The file id marker for student files
+STUDENT_FILE_STORE_NAME = 'file-student'
+
+class StudentFileNameChooser(grok.Adapter):
+    """A file id chooser for :class:`Applicant` objects.
+
+    `context` is an :class:`Applicant` instance.
+
+    The :class:`ApplicantImageNameChooser` can build/check file ids
+    for :class:`Applicant` objects suitable for use with
+    :class:`ExtFileStore` instances. The delivered file_id contains
+    the file id marker for :class:`Applicant` object and the
+    registration number or access code of the context applicant. Also
+    the name of the connected applicant container will be part of the
+    generated file id.
+
+    This chooser is registered as an adapter providing
+    :class:`waeup.sirp.interfaces.IFileStoreNameChooser`.
+
+    File store name choosers like this one are only convenience
+    components to ease the task of creating file ids for applicant
+    objects. You are nevertheless encouraged to use them instead of
+    manually setting up filenames for applicants.
+
+    .. seealso:: :mod:`waeup.sirp.imagestorage`
+
+    """
+    grok.context(IStudent)
+    grok.implements(IFileStoreNameChooser)
+
+    def checkName(self, name=None, attr=None):
+        """Check whether the given name is a valid file id for the context.
+
+        Returns ``True`` only if `name` equals the result of
+        :meth:`chooseName`.
+
+        """
+        return name == self.chooseName()
+
+    def chooseName(self, name=None, attr=None):
+        """Get a valid file id for student context.
+
+        *Example:*
+
+        For a student with student id ``'A123456'`` and
+        with attr ``'nice_image'`` stored in
+        the students container this chooser would create:
+
+          ``'__file-student__students/A/A123456/nice_image_A123456.jpg'``
+
+        meaning that the nice image of this applicant would be
+        stored in the site-wide file storage in path:
+
+          ``students/A/A123456/nice_image_A123456.jpg``
+
+        """
+        first_character = self.context.student_id[0]
+        marked_filename = '__%s__%s/%s/%s_%s.jpg' % (
+            STUDENT_FILE_STORE_NAME, first_character,
+            self.context.student_id, attr, self.context.student_id)
+        return marked_filename
+
+
+class StudentFileStoreHandler(DefaultFileStoreHandler, grok.GlobalUtility):
+    """Student specific file handling.
+
+    This handler knows in which path in a filestore to store student
+    files and how to turn this kind of data into some (browsable)
+    file object.
+
+    It is called from the global file storage, when it wants to
+    get/store a file with a file id starting with
+    ``__file-student__`` (the marker string for student files).
+
+    Like each other file store handler it does not handle the files
+    really (this is done by the global file store) but only computes
+    paths and things like this.
+    """
+    grok.implements(IFileStoreHandler)
+    grok.name(STUDENT_FILE_STORE_NAME)
+
+    def pathFromFileID(self, store, root, file_id):
+        """All applicants images are filed in directory ``applicants``.
+        """
+        marker, filename, basename, ext = store.extractMarker(file_id)
+        return os.path.join(root, 'students', filename)
+
+    def createFile(self, store, root, filename, file_id, file):
+        """Create a browsable file-like object.
+        """
+        # possible other actions: check for jpeg format
+        path = self.pathFromFileID(store, root, file_id)
+        return file, path, WAeUPImageFile(filename, file_id)
Index: main/waeup.sirp/trunk/src/waeup/sirp/students/viewlets.py
===================================================================
--- main/waeup.sirp/trunk/src/waeup/sirp/students/viewlets.py	(revision 7096)
+++ main/waeup.sirp/trunk/src/waeup/sirp/students/viewlets.py	(revision 7097)
@@ -1,5 +1,11 @@
 import grok
+from zope.component import getUtility
 from zope.interface import Interface
-from waeup.sirp.interfaces import IWAeUPObject
+from waeup.sirp.interfaces import (
+    IWAeUPObject, IExtFileStore, IFileStoreNameChooser)
+from waeup.sirp.utils.helpers import string_from_bytes, file_size
+from waeup.sirp.browser import DEFAULT_IMAGE_PATH
+from waeup.sirp.students.browser import (
+    StudentClearanceDisplayFormPage, StudentClearanceManageFormPage)
 
 grok.context(IWAeUPObject) # Make IWAeUPObject the default context
@@ -190,2 +196,108 @@
         rel_link = '/students/%s' % self.request.principal.id
         return self.view.application_url() + rel_link
+
+def handle_img_upload(upload, context, view, max_size, attr=None):
+    """Handle upload of applicant image.
+
+    Returns `True` in case of success or `False`.
+
+    Please note that file pointer passed in (`upload`) most probably
+    points to end of file when leaving this function.
+    """
+    size = file_size(upload)
+    if size > max_size:
+        view.flash('Uploaded image is too big!')
+        return False
+    upload.seek(0) # file pointer moved when determining size
+    store = getUtility(IExtFileStore)
+    file_id = IFileStoreNameChooser(context).chooseName(attr=attr)
+    store.createFile(file_id, upload)
+    return True
+
+class FileManager(grok.ViewletManager):
+    """Viewlet manager for uploading files, preferably scanned images.
+    """
+    grok.name('files')
+
+class FileDisplay(grok.Viewlet):
+    """Base file display viewlet.
+    """
+    grok.baseclass()
+    grok.viewletmanager(FileManager)
+    grok.view(StudentClearanceDisplayFormPage)
+    grok.template('filedisplay')
+    grok.order(1)
+    grok.require('waeup.viewStudent')
+    label = u'Some Text:'
+    img_src = u'filename.jpg'
+    attr = None
+
+class FileUpload(FileDisplay):
+    """Base upload viewlet.
+    """
+    grok.baseclass()
+    grok.viewletmanager(FileManager)
+    grok.view(StudentClearanceManageFormPage)
+    grok.template('fileupload')
+    grok.require('waeup.manageStudents')
+    mus = 1024 * 150
+    input_name = u'form.filename'
+
+    def update(self):
+        self.max_upload_size = string_from_bytes(self.mus)
+        upload = self.request.form.get(self.input_name, None)
+        if upload:
+            # We got a fresh upload
+            file_changed = handle_img_upload(
+                upload, self.context, self.view, self.mus, self.attr)
+            if file_changed is False:  # False is not None!
+                self.redirect(self.view.url(self.context))
+                return # error during image upload. Ignore other values
+            else:
+                self.view.files_changed += self.img_src
+        return
+
+class BirthCertificateDisplay(FileDisplay):
+    """Birth Certificate upload viewlet.
+    """
+    grok.order(1)
+    label = u'Birth Certificate:'
+    img_src = u'birth_certificate.jpg'
+    attr = u'birth_certificate'
+
+class BirthCertificateUpload(FileUpload):
+    """Birth Certificate upload viewlet.
+    """
+    grok.order(1)
+    label = u'Birth Certificate:'
+    mus = 1024 * 150
+    img_src = u'birth_certificate.jpg'
+    input_name = u'form.birth_certificate'
+    attr = u'birth_certificate'
+
+class Image(grok.View):
+    """Renders image for students.
+    """
+    grok.name('none.jpg')
+    grok.view(StudentClearanceManageFormPage)
+    grok.require('waeup.viewStudent')
+    grok.baseclass()
+    attr = None
+
+    def render(self):
+        # A filename chooser turns a context into a filename suitable
+        # for file storage.
+        image = getUtility(IExtFileStore).getFileByContext(
+            self.context, attr=self.attr)
+        self.response.setHeader(
+            'Content-Type', 'image/jpeg')
+        if image is None:
+            # show placeholder image
+            return open(DEFAULT_IMAGE_PATH, 'rb').read()
+        return image
+
+class BirthCertificateImage(Image):
+    """Renders birth certificate.
+    """
+    grok.name('birth_certificate.jpg')
+    attr = u'birth_certificate'
