Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py	(revision 8339)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/pages.py	(revision 8346)
@@ -45,5 +45,6 @@
     IUniversity, IFacultiesContainer, IFaculty, IFacultyAdd,
     IDepartment, IDepartmentAdd, ICourse, ICourseAdd, ICertificate,
-    ICertificateAdd, ICertificateCourse, ICertificateCourseAdd)
+    ICertificateAdd, ICertificateCourse, ICertificateCourseAdd,
+    ICaptchaManager)
 from waeup.kofa.browser.layout import jsaction, action, UtilityView
 from waeup.kofa.browser.resources import warning, datepicker, tabs, datatable
@@ -54,5 +55,6 @@
     ILocalRolesAssignable, DuplicationError, IConfigurationContainer,
     ISessionConfiguration, ISessionConfigurationAdd,
-    IPasswordValidator, IContactForm, IKofaUtils, ICSVExporter)
+    IPasswordValidator, IContactForm, IKofaUtils, ICSVExporter,
+    IChangePassword)
 from waeup.kofa.permissions import get_users_with_local_roles, get_all_roles
 from waeup.kofa.students.catalog import search as searchstudents
@@ -1957,2 +1959,74 @@
         return
 
+class ChangePasswordRequestPage(KofaForm):
+    """Captcha'd page for all kind of users to request a password change.
+    """
+    grok.context(IUniversity)
+    grok.name('sendpw')
+    grok.require('waeup.Anonymous')
+    grok.template('sendpassword')
+    label = _('Send me a new password')
+    form_fields = grok.AutoFields(IChangePassword)
+
+    def update(self):
+        # Handle captcha
+        self.captcha = getUtility(ICaptchaManager).getCaptcha()
+        self.captcha_result = self.captcha.verify(self.request)
+        self.captcha_code = self.captcha.display(self.captcha_result.error_code)
+        return
+
+    def _searchUser(self, identifier, email):
+        # Search student
+        cat = queryUtility(ICatalog, name='students_catalog')
+        results = cat.searchResults(
+            #reg_number=(identifier, identifier),
+            email=(email,email))
+        for result in results:
+            if result.student_id == identifier or \
+                result.reg_number == identifier or \
+                result.matric_number == identifier:
+                return result
+        # Search applicant
+        cat = queryUtility(ICatalog, name='applicants_catalog')
+        if cat is not None:
+            results = cat.searchResults(
+                #reg_number=(identifier, identifier),
+                email=(email,email))
+            for result in results:
+                if result.applicant_id == identifier or \
+                    result.reg_number == identifier:
+                    return result
+        # Search portal user
+        user = grok.getSite()['users'].get(identifier, None)
+        if user is not None and user.email == email:
+            return user
+        return None
+
+    @action(_('Get login credentials'), style='primary')
+    def request(self, **data):
+        if not self.captcha_result.is_valid:
+            # Captcha will display error messages automatically.
+            # No need to flash something.
+            return
+        # Search student or applicant
+        identifier = data['identifier']
+        email = data['email']
+        user = self._searchUser(identifier, email)
+        if user is None:
+            self.flash(_('No record found.'))
+            return
+        # Change password
+        kofa_utils = getUtility(IKofaUtils)
+        pwd = kofa_utils.genPassword()
+        IUserAccount(user).setPassword(pwd)
+        # Send email with new redentials
+        msg = _('You have successfully changed your password for the')
+        login_url = self.url(grok.getSite(), 'login')
+        success = kofa_utils.sendCredentials(
+            IUserAccount(user),pwd,login_url,msg)
+        if success:
+            self.flash(_('An email with your user name and password ' +
+                'has been sent to ${a}.', mapping = {'a':email}))
+        else:
+            self.flash(_('An smtp server error occurred.'))
+        return
Index: main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/sendpassword.pt
===================================================================
--- main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/sendpassword.pt	(revision 8346)
+++ main/waeup.kofa/trunk/src/waeup/kofa/browser/templates/sendpassword.pt	(revision 8346)
@@ -0,0 +1,33 @@
+<form action="." tal:attributes="action request/URL" method="post"
+      i18n:domain="waeup.kofa" enctype="multipart/form-data">
+
+  <table class="form-table">
+    <tbody>
+      <tal:widgets content="structure provider:widgets" />
+      <tr tal:condition="view/captcha_code">
+        <td i18n:translate="solve_captcha">
+          Please solve the captcha<br />to prevent misuse of this service:
+        </td>
+        <td>
+          <div tal:content="structure view/captcha_code"></div>
+        </td>
+      </tr>
+
+    </tbody>
+  </table>
+
+  <p i18n:translate="email_address_problem">
+    Enter the email address stored in Kofa.
+    You can't change your email address here.
+    If you've forgotten your email address or the email
+    address stored in Kofa is wrong or no longer valid,
+    use the enquiries form to request a change
+    of address.
+  </p>
+  <br />
+  <div tal:condition="view/availableActions">
+    <input tal:repeat="action view/actions"
+           tal:replace="structure action/render"
+           />
+  </div>
+</form>
