diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java
index 71e1470b1e354e1d83b4d3eaaad7372796b71a21..b8814ce068015e1ad0e5c8a01405ebbd02cfdfac 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/richText/RichTextElementComponent.java
@@ -189,8 +189,9 @@ class RichTextElementComponent extends FormBaseComponentImpl implements Controll
 			escapedUrl = escapeUrl(url);
 		}
 		
-		StringBuilder cmd = new StringBuilder();
-		cmd.append("BTinyHelper.writeLinkSelectionToTiny('").append(escapedUrl).append("'");
+		StringBuilder cmd = new StringBuilder(128);
+		String apo = escapedUrl.contains("'") ? "\"" : "'";
+		cmd.append("BTinyHelper.writeLinkSelectionToTiny(").append(apo).append(escapedUrl).append(apo);
 		if(urlChoosenEvent.getWidth() > 0) {
 			cmd.append(",").append(urlChoosenEvent.getWidth());
 		}
@@ -200,7 +201,7 @@ class RichTextElementComponent extends FormBaseComponentImpl implements Controll
 		cmd.append(");");
 		
 		JSCommand writeLinkSelectionToTiny = new JSCommand(cmd.toString());
-		 Windows.getWindows(ureq).getWindow(ureq).getWindowBackOffice().sendCommandTo(writeLinkSelectionToTiny);
+		Windows.getWindows(ureq).getWindow(ureq).getWindowBackOffice().sendCommandTo(writeLinkSelectionToTiny);
 	}
 	
 	private String escapeUrl(String url) {
diff --git a/src/main/java/org/olat/course/nodes/pf/manager/FileSystemExport.java b/src/main/java/org/olat/course/nodes/pf/manager/FileSystemExport.java
index 16698cec761bca1108ee72345824eb23c895cbc5..02c49ab77c6540f3a10d11c5988a913fa7d48df3 100644
--- a/src/main/java/org/olat/course/nodes/pf/manager/FileSystemExport.java
+++ b/src/main/java/org/olat/course/nodes/pf/manager/FileSystemExport.java
@@ -22,12 +22,14 @@ package org.olat.course.nodes.pf.manager;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
@@ -44,12 +46,15 @@ import org.olat.core.gui.media.ServletUtil;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
+import org.olat.core.util.io.ShieldOutputStream;
 import org.olat.core.util.io.SystemFileFilter;
 import org.olat.course.nodes.PFCourseNode;
 import org.olat.course.nodes.pf.ui.PFParticipantController;
 import org.olat.course.run.environment.CourseEnvironment;
+import org.olat.repository.RepositoryEntry;
 import org.olat.user.UserManager;
 /**
 *
@@ -107,6 +112,14 @@ public class FileSystemExport implements MediaResource {
 
 	@Override
 	public void prepare(HttpServletResponse hres) {
+		RepositoryEntry entry = courseEnv.getCourseGroupManager().getCourseEntry();
+		String label = StringHelper.transformDisplayNameToFileSystemName(pfNode.getShortName() + "_" + entry.getDisplayname())
+				+ "_" + Formatter.formatDatetimeWithMinutes(new Date())
+				+ ".zip";
+		String urlEncodedLabel = StringHelper.urlEncodeUTF8(label);
+		hres.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + urlEncodedLabel);
+		hres.setHeader("Content-Description", urlEncodedLabel);
+		
 		try (ZipOutputStream zout = new ZipOutputStream(hres.getOutputStream())) {
 			zout.setLevel(9);
 			Path relPath = Paths.get(courseEnv.getCourseBaseContainer().getBasefile().getAbsolutePath(),
@@ -132,8 +145,8 @@ public class FileSystemExport implements MediaResource {
 	 * @param translator
 	 * @throws IOException Signals that an I/O exception has occurred.
 	 */
-	public static boolean fsToZip(ZipOutputStream zout, String zipPath, final Path sourceFolder, PFCourseNode pfNode,
-			List<Identity> identities, Translator translator) {
+	public static boolean fsToZip(final ZipOutputStream zout, String zipPath, final Path sourceFolder, PFCourseNode pfNode,
+			List<Identity> identities, final Translator translator) {
 		
 		if(StringHelper.containsNonWhitespace(zipPath)) {
 			if(!zipPath.endsWith("/")) {
@@ -143,7 +156,7 @@ public class FileSystemExport implements MediaResource {
 			zipPath = "";
 		}
 		
-		final String targetPath = zipPath + translator.translate("participant.folder") + "/";
+		final String targetPath = zipPath;
 		final UserManager userManager = CoreSpringFactory.getImpl(UserManager.class);
 		Set<String> idKeys = new HashSet<>();
 		if (identities != null) {
@@ -188,7 +201,7 @@ public class FileSystemExport implements MediaResource {
 					String relPath = sourceFolder.relativize(file).toString();
 					if ((relPath = containsID(relPath)) != null && (relPath = boxesEnabled(relPath)) != null) {
 						zout.putNextEntry(new ZipEntry(targetPath + relPath));
-						Files.copy(file, zout);
+						copyFile(file, zout);
 						zout.closeEntry();
 					}
 					return FileVisitResult.CONTINUE;
@@ -204,7 +217,6 @@ public class FileSystemExport implements MediaResource {
 					return FileVisitResult.CONTINUE;
 				}
 			});
-			zout.close();
 			return true;
 		} catch (IOException e) {
 			log.error("Unable to export zip",e);
@@ -212,4 +224,12 @@ public class FileSystemExport implements MediaResource {
 		}
 	}
 	
+	private static void copyFile(Path file, ZipOutputStream zout) {
+		try(OutputStream out= new ShieldOutputStream(zout)) {
+			Files.copy(file, zout);
+		} catch(Exception e) {
+			log.error("Cannot zip {}", file, e);
+		}
+	}
+	
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java b/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java
index 9b4de7fbac4e687590c7221c0537923e98530285..61cb2f9675e0d114864c7547137c019160aa995b 100644
--- a/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java
+++ b/src/main/java/org/olat/ims/qti21/resultexport/QTI21ResultsExportMediaResource.java
@@ -63,7 +63,6 @@ import org.olat.core.gui.util.SyntheticUserRequest;
 import org.olat.core.gui.util.WindowControlMocker;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
-import org.olat.core.id.UserConstants;
 import org.olat.core.logging.Tracing;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.Formatter;
@@ -300,12 +299,24 @@ public class QTI21ResultsExportMediaResource implements MediaResource {
 			if(identity == null || identity.getStatus() == null || identity.getStatus().equals(Identity.STATUS_DELETED)) {
 				continue;
 			}
-			String lastNameOrAnoymous = identity.getUser().getLastName();
-			if(!StringHelper.containsNonWhitespace(lastNameOrAnoymous)) {
-				lastNameOrAnoymous = "anonym";
+			String nickname = identity.getUser().getNickName();
+			String firstName = identity.getUser().getFirstName();
+			String lastNameOrAnonymous = identity.getUser().getLastName();
+			if(!StringHelper.containsNonWhitespace(lastNameOrAnonymous)) {
+				lastNameOrAnonymous = "anonym";
 			}
-			String lastname = StringHelper.transformDisplayNameToFileSystemName(lastNameOrAnoymous);
-			String idDir = exportFolderName + "/" + DATA + lastname + "_" + identity.getKey();
+			String nameOrAnonymous = lastNameOrAnonymous;
+			if(StringHelper.containsNonWhitespace(firstName)) {
+				nameOrAnonymous += "_" + firstName;
+			}
+			if(StringHelper.containsNonWhitespace(nickname)) {
+				nameOrAnonymous += "_" + nickname;
+			} else {
+				nameOrAnonymous += "_" + identity.getKey();
+			}
+			
+			String names = StringHelper.transformDisplayNameToFileSystemName(nameOrAnonymous);
+			String idDir = exportFolderName + "/" + DATA + names;
 			idDir = idDir.endsWith(SEP) ? idDir : idDir + SEP;
 			createZipDirectory(zout, idDir);				
 			
@@ -323,8 +334,7 @@ public class QTI21ResultsExportMediaResource implements MediaResource {
 			
 			String linkToUser = idDir.replace(exportFolderName + "/", "") + "index.html";
 			String memberEmail = userManager.getUserDisplayEmail(identity, ureq.getLocale());
-			AssessedMember member = new AssessedMember(identity.getUser().getProperty(UserConstants.NICKNAME, null),
-					lastNameOrAnoymous, identity.getUser().getFirstName(),
+			AssessedMember member = new AssessedMember(nickname, lastNameOrAnonymous, firstName,
 					memberEmail, assessments.size(), passed, score, linkToUser);
 			
 			String singleUserInfoHTML = createResultListingHTML(assessments, assessmentDocuments, member);
diff --git a/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiListing.html b/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiListing.html
index ffeffa5b9c1c3d5114735cd9596b39d472c51d3e..ec085c0cccc04b7f8091311683ed2205ba8eafc2 100644
--- a/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiListing.html
+++ b/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiListing.html
@@ -21,13 +21,13 @@
 		<table id='oneUser' class='table table-striped table-hover'>
 			<thead>
 				<tr>
-					<th>$t.translate("table.all.username")</th>
-					<th>$t.translate("table.all.lastname")</th>
-					<th>$t.translate("table.all.firstname")</th>
-					<th>$t.translate("table.user.email")</th>
-					<th>$t.translate("table.all.node.score")</th>
-					<th>$t.translate("table.all.node.passed")</th>
-					<th>$t.translate("table.all.tries")</th>
+					<th scope="col">$t.translate("table.all.username")</th>
+					<th scope="col">$t.translate("table.all.lastname")</th>
+					<th scope="col">$t.translate("table.all.firstname")</th>
+					<th scope="col">$t.translate("table.user.email")</th>
+					<th scope="col">$t.translate("table.all.node.score")</th>
+					<th scope="col">$t.translate("table.all.node.passed")</th>
+					<th scope="col">$t.translate("table.all.tries")</th>
 				</tr>
 			</thead>
 			<tbody>
@@ -48,17 +48,17 @@
 		<table id='results' class='table table-striped table-hover'>
 			<thead>
 				<tr>
-					<th colspan="8">$t.translate("table.test.sessions")</th>
+					<th colspan="8" scope="col">$t.translate("table.test.sessions")</th>
 				</tr>
 				<tr>
-					<th>$t.translate("table.user.id")</th>
-					<th>$t.translate("table.user.date")</th>
-					<th>$t.translate("table.user.duration")</th>
-					<th>$t.translate("table.user.score")</th>
-					<th>$t.translate("table.user.manualScore")</th>
-					<th>$t.translate("table.user.finalScore")</th>
-					<th>$t.translate("table.all.passed")</th>
-					<th>$t.translate("button.show")</th>					
+					<th scope="col">$t.translate("table.user.id")</th>
+					<th scope="col">$t.translate("table.user.date")</th>
+					<th scope="col">$t.translate("table.user.duration")</th>
+					<th scope="col">$t.translate("table.user.score")</th>
+					<th scope="col">$t.translate("table.user.manualScore")</th>
+					<th scope="col">$t.translate("table.user.finalScore")</th>
+					<th scope="col">$t.translate("table.all.passed")</th>
+					<th scope="col">$t.translate("button.show")</th>					
 				</tr>
 			</thead>
 			<tbody>
@@ -84,7 +84,7 @@
 		<table id='assessmentDocuments' class='table table-striped table-hover'>
 			<thead>
 				<tr>
-					<th>$t.translate("assessment.docs")</th>
+					<th scope="col">$t.translate("assessment.docs")</th>
 				</tr>
 			</thead>
 			<tbody>
diff --git a/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiUserlisting.html b/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiUserlisting.html
index bf87ab2ad0238e573010ebd3017368cc26ccc3e3..7a0ba6e2d4ae4a617c464395e13ad2605ff4e6c5 100644
--- a/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiUserlisting.html
+++ b/src/main/java/org/olat/ims/qti21/resultexport/_content/qtiUserlisting.html
@@ -11,12 +11,12 @@
 		<table id='allUsers' class='table table-striped table-hover'>
 			<thead>
 				<tr>
-					<th>$t.translate("table.all.username")</th>
-					<th>$t.translate("table.all.lastname")</th>
-					<th>$t.translate("table.all.firstname")</th>
-					<th>$t.translate("table.all.score")</th>
-					<th>$t.translate("table.all.passed")</th>
-					<th>$t.translate("table.all.tries")</th>
+					<th scope="col">$t.translate("table.all.username")</th>
+					<th scope="col">$t.translate("table.all.lastname")</th>
+					<th scope="col">$t.translate("table.all.firstname")</th>
+					<th scope="col">$t.translate("table.all.score")</th>
+					<th scope="col">$t.translate("table.all.passed")</th>
+					<th scope="col">$t.translate("table.all.tries")</th>
 				</tr>
 			</thead>
 			<tbody>
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties
index 99230e77fb387b5aad6d177a46b5a6d9458d5545..5e2bc84a87e2ced0b6f99a4baf3f2dde38914440 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_de.properties
@@ -51,8 +51,8 @@ error.end.past=Der Online-Termin kann nicht in der Vergangenheit geplant werden.
 error.first.date.in.past=Der erste Termin kann sich nicht in der Vergangenheit befinden.
 error.identifier.in.use=Name ist schon verwendet. Bitte einen anderen w\u00e4hlen.
 error.identifier.url.not.valid=Die URL ist nicht g\u00fcltig. Bitte Sonderzeichen wie $, ?, Leerschl\u00e4ge entfernen.
-error.slides.size=Total Gr\u00f6sse den Pr\u00e4sentationsfolien muss kleiner als {0}MB sein.
-error.slides.type=Pr\u00e4sentationsfolien sind limitiert zu Office und PDF Dokumenten und Bilder.
+error.slides.size=Die Gesamtgr\u00F6\u00DFe aller Pr\u00E4sentationsdateien pro Meeting darf <strong>{0} MB</strong> nicht \u00FCberschreiten.
+error.slides.type=Folgende Formate f\u00FCr Pr\u00E4sentationsfolien werden unterst\u00FCtzt: Office-Dokumente, PDF, jpeg, jpg, png.
 error.password=Passwort ist falsch.
 error.prefix=Ein Fehler ist aufgetreten\:
 error.same.day=Sie haben schon ein Meeting an diesem Tag geplant.
@@ -157,7 +157,7 @@ servers.title=Server
 server.status.available=Verf\u00fcgbar
 server.status.offline=Scheint offline zu sein
 server.status.disabled=Abgeschaltet
-slides.upload.limit=Max. Grösse den Pr\u00e4sentationsfolien (in MB)
+slides.upload.limit=Limit aller Pr\u00E4sentationsdateien pro Meeting (MB) Max.
 table.header.actions=Aktionen
 table.header.available=Verf\u00fcgbarkeit
 table.header.breakout.meetings=\# Breakout
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties
index cab812549adca2935e5514b1cbfa1d5fdb711eb0..10aca06b5b28f67641e778cb95452d8efe197a88 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_en.properties
@@ -57,8 +57,8 @@ error.same.day=You already have a meeting planed at this date.
 error.server.exists=A server with this URL already exists.
 error.server.raw={1} <small>Key {0}</small>
 error.serverDisabled=Server is currently not available.
-error.slides.size=Total size of the slides needs to be smaller than {0}MB.
-error.slides.type=Slides are limited to office and PDF documents and images.
+error.slides.size=The total size of all presentation files per meeting must not exceed <strong>{0} MB</strong>.
+error.slides.type=The following formats are supported for presentation slides: Office documents, PDF, jpeg, jpg, png.
 error.start.after.end=The end date must not be before the start date.
 error.too.long.time=Time is too long. It is limited to {0} minutes.
 error.url.invalid=Invalid server URL
@@ -158,7 +158,7 @@ server.status.available=Available
 server.status.offline=Seems to be offline
 server.status.disabled=Disabled
 servers.title=Servers
-slides.upload.limit=Max. size of slides (in MB)
+slides.upload.limit=Limit of all presentation files per meeting (MB)
 table.header.actions=Aktionen
 table.header.available=Availability
 table.header.breakout.meetings=\# Breakout
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_fr.properties
index b4efc8fd11a28eb48d4dc8d01b95e7be6bd4d465..0563895e7be2d1bc758eaf3f73ba88e062e97467 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_i18n/LocalStrings_fr.properties
@@ -58,7 +58,7 @@ error.server.exists=Un serveur avec cette URL existe d\u00E9j\u00E0.
 error.server.raw={1} <small>Cl\u00E9\: {0}</small>
 error.serverDisabled=Le serveur n'est pas disponible pour l'instant.
 error.slides.size=La taille totale des diapositives ne doit pas d\u00E9passer {0}MB.
-error.slides.type=Les diapositives sont limit\u00E9s aux documents Office et PDF ainsi que les images.
+error.slides.type=Les diapositives sont limit\u00E9s aux documents Office, PDF, jpeg, jpg, png.
 error.start.after.end=La date de fin du rendez-vous ne peut se trouver avant la date de d\u00E9but.
 error.too.long.time=Le temps est trop long. Il est limit\u00E9 \u00E0 {0} minutes.
 error.url.invalid=L'URL du serveur n'est pas valide.
@@ -160,7 +160,7 @@ server.status.available=Disponible
 server.status.disabled=D\u00E9sactiv\u00E9
 server.status.offline=Semble entre hors-ligne
 servers.title=Serveurs
-slides.upload.limit=Taille max. des diapositives (en MB)
+slides.upload.limit=Limite des fichiers de pr\u00E9sentation par meeting (MB)
 table.header.actions=Actions
 table.header.available=Disponibilit\u00E9
 table.header.breakout.meetings=\# R\u00E9unions priv\u00E9es