diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java
index 13ffa1cdfba71f4970f2821bd4086dad5bcf16ad..59d1c688f5bef8e26ffdeb02dec85cb7d8265d21 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonManager.java
@@ -26,6 +26,7 @@ import java.util.List;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Roles;
 import org.olat.core.util.UserSession;
+import org.olat.core.util.vfs.VFSContainer;
 import org.olat.group.BusinessGroup;
 import org.olat.modules.bigbluebutton.manager.BigBlueButtonUriBuilder;
 import org.olat.modules.bigbluebutton.model.BigBlueButtonErrors;
@@ -103,6 +104,18 @@ public interface BigBlueButtonManager {
 
 	public BigBlueButtonMeeting getMeeting(BigBlueButtonMeeting meeting);
 	
+	public VFSContainer getSlidesContainer(BigBlueButtonMeeting meeting);
+	
+	/**
+	 * The method will create a meeting and uploaded the slides to the
+	 * BigBlueButton server but it will only doing it during the leading
+	 * time.
+	 * 
+	 * @param meetingKey The meeting primary key
+	 * @return true if slides were effectively uploaded
+	 */
+	public boolean preloadSlides(Long meetingKey);
+	
 	/**
 	 * Return the first meeting which matches the specified identifier
 	 * as the meeting's identifier or readable identifier.
diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java
index 00acfd92d555586fd534d13c3a96a6b338d7aaec..07c55aaf23536ee4ca97d4c6b3d7f6d6c683667c 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonMeeting.java
@@ -134,6 +134,14 @@ public interface BigBlueButtonMeeting extends ModifiedInfo, CreateInfo {
 
 	public void setPassword(String password);
 	
+	/**
+	 * This is the relative path to the container for the slides. Generated
+	 * only if needed.
+	 * 
+	 * @return
+	 */
+	public String getDirectory();
+	
 	
 	/**
 	 * If not a permanent meeting, the meetings starts at this date. Participants
diff --git a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java
index 2f567905cee8b016fe00f5dffc6029d6cb70b7e9..8a3021f4d61b9802a3b6f16bb7623fa91d635878 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/BigBlueButtonModule.java
@@ -20,6 +20,7 @@
 package org.olat.modules.bigbluebutton;
 
 import java.net.URI;
+import java.util.Set;
 
 import javax.ws.rs.core.UriBuilder;
 
@@ -55,7 +56,13 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 	private static final String PROP_ADHOC_MEETING = "vc.bigbluebutton.adhoc.meeting";
 	private static final String PROP_USER_BANDWIDTH_REQUIREMENT = "vc.bigbluebutton.user.bandwidth.requirement";
 	private static final String PROP_RECORDING_HANDLER_ID = "vc.bigbluebutton.recording.handler.id";
+	private static final String PROP_MAX_UPLOAD_SIZE = "vc.bigbluebutton.max.upload.size";
 	
+	public static final Set<String> SLIDES_MIME_TYPES = Set.of("image/gif", "image/jpg", "image/jpeg", "image/png", "application/pdf",
+			"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+			"application/vnd.openxmlformats-officedocument.presentationml.presentation",
+			"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+
 	@Value("${vc.bigbluebutton.enabled}")
 	private boolean enabled;
 	
@@ -78,6 +85,9 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 	private String secret;
 	@Value("${vc.bigbluebutton.shared.secret}")
 	private String sharedSecret;
+
+	@Value("${vc.bigbluebutton.max.upload.size:100}")
+	private Integer maxUploadSize;
 	
 	@Value("${vc.bigbluebutton.permanent.meeting:false}")
 	private String permanentMeetingEnabled;
@@ -123,6 +133,11 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 		groupsEnabled = getStringPropertyValue(PROP_GROUP_ENABLED, groupsEnabled);
 		coursesEnabled = getStringPropertyValue(PROP_COURSE_ENABLED, coursesEnabled);
 		appointmentsEnabled = getStringPropertyValue(PROP_APPOINTMENTS_ENABLED, appointmentsEnabled);
+
+		String maxUploadSizeObj = getStringPropertyValue(PROP_MAX_UPLOAD_SIZE, maxUploadSize.toString());
+		if(StringHelper.containsNonWhitespace(maxUploadSizeObj)) {
+			maxUploadSize = Integer.valueOf(maxUploadSizeObj);
+		}
 		
 		String bandwidthReqObj = getStringPropertyValue(PROP_USER_BANDWIDTH_REQUIREMENT, true);
 		if(StringHelper.containsNonWhitespace(bandwidthReqObj)) {
@@ -283,6 +298,20 @@ public class BigBlueButtonModule extends AbstractSpringModule implements ConfigO
 		setStringProperty(PROP_SHARED_SECRET, sharedSecret, true);
 	}
 
+	/**
+	 * 
+	 * @return The max. size of the slides to upload to BigBlueButton servers
+	 * 		in MB.
+	 */
+	public Integer getMaxUploadSize() {
+		return maxUploadSize;
+	}
+
+	public void setMaxUploadSize(Integer maxUploadSize) {
+		this.maxUploadSize = maxUploadSize;
+		setStringProperty(PROP_MAX_UPLOAD_SIZE, maxUploadSize.toString(), true);
+	}
+
 	public Double getUserBandwidhtRequirement() {
 		return userBandwidhtRequirement;
 	}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
index d2144bc3dad7d23e62c3d6b22269e53a5144f039..f905f476b1704b75ca0feb0c291eb689ba0b1b48 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonManagerImpl.java
@@ -20,6 +20,7 @@
 package org.olat.modules.bigbluebutton.manager;
 
 import java.net.URI;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
@@ -34,9 +35,13 @@ import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
+import org.apache.http.HttpEntity;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
 import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.logging.log4j.Logger;
@@ -47,7 +52,13 @@ import org.olat.commons.calendar.model.KalendarEvent;
 import org.olat.commons.calendar.model.KalendarEventLink;
 import org.olat.commons.calendar.ui.components.KalendarRenderWrapper;
 import org.olat.core.commons.persistence.DB;
+import org.olat.core.commons.services.taskexecutor.Task;
+import org.olat.core.commons.services.taskexecutor.TaskExecutorManager;
+import org.olat.core.dispatcher.mapper.MapperService;
+import org.olat.core.dispatcher.mapper.manager.MapperKey;
+import org.olat.core.helpers.Settings;
 import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Roles;
 import org.olat.core.id.User;
 import org.olat.core.id.context.BusinessControlFactory;
@@ -56,6 +67,11 @@ import org.olat.core.util.CodeHelper;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.WebappHelper;
+import org.olat.core.util.resource.OresHelper;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.VFSLeafButSystemFilter;
 import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.group.BusinessGroup;
@@ -90,6 +106,8 @@ import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryEntrySecurity;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.manager.RepositoryEntryDAO;
+import org.olat.resource.OLATResource;
+import org.olat.resource.OLATResourceManager;
 import org.olat.user.UserDataDeletable;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -108,12 +126,19 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 	DeletableGroupData, RepositoryEntryDataDeletable, UserDataDeletable, InitializingBean {
 	
 	private static final Logger log = Tracing.createLoggerFor(BigBlueButtonManagerImpl.class);
+	private static final String TASK_MEETING_RESNAME = BigBlueButtonMeeting.class.getSimpleName();
 
 	@Autowired
 	private DB dbInstance;
 	@Autowired
+	private MapperService mapperService;
+	@Autowired
 	private CalendarManager calendarManager;
 	@Autowired
+	private TaskExecutorManager taskManager;
+	@Autowired
+	private OLATResourceManager resourceManager;
+	@Autowired
 	private RepositoryManager repositoryManager;
 	@Autowired
 	private RepositoryEntryDAO repositoryEntryDao;
@@ -128,6 +153,8 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 	@Autowired
 	private BigBlueButtonAttendeeDAO bigBlueButtonAttendeeDao;
 	@Autowired
+	private BigBlueButtonSlidesStorage bigBlueButtonSlidesStorage;
+	@Autowired
 	private BigBlueButtonMeetingTemplateDAO bigBlueButtonMeetingTemplateDao;
 	@Autowired
 	private BigBlueButtonRecordingReferenceDAO bigBlueButtonRecordingReferenceDao;
@@ -386,6 +413,41 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 		return null;
 	}
 
+	@Override
+	public VFSContainer getSlidesContainer(BigBlueButtonMeeting meeting) {
+		VFSContainer container;
+		if(StringHelper.containsNonWhitespace(meeting.getDirectory())) {
+			container = bigBlueButtonSlidesStorage.getStorage(meeting);
+		} else {
+			container = bigBlueButtonSlidesStorage.createStorage(meeting);
+		}
+		return container;
+	}
+
+	@Override
+	public boolean preloadSlides(Long meetingKey) {
+		BigBlueButtonMeeting meeting = bigBlueButtonMeetingDao.loadByKey(meetingKey);
+		if(meeting == null) {
+			return false;
+		}
+
+		boolean loaded = false;
+		Date now = new Date();
+		Date start = meeting.getStartDate();
+		Date startWithLeadingTime = meeting.getStartWithLeadTime();
+		if(startWithLeadingTime.compareTo(now) <= 0 && start.compareTo(now) >= 0) {
+			List<VFSLeaf> slides = getSlides(meeting);
+			if(!slides.isEmpty()) {
+				BigBlueButtonErrors errors = new BigBlueButtonErrors();
+				meeting = getMeetingWithServer(meeting);
+				createBigBlueButtonMeeting(meeting, errors);
+				loaded = !errors.hasErrors();
+				log.info(Tracing.M_AUDIT, "Slides preloaded: {}", meeting);
+			}
+		}
+		return loaded;
+	}
+
 	@Override
 	public boolean isIdentifierInUse(String identifier, BigBlueButtonMeeting reference) {
 		if(StringHelper.containsNonWhitespace(identifier)) {
@@ -397,7 +459,23 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 	@Override
 	public BigBlueButtonMeeting updateMeeting(BigBlueButtonMeeting meeting) {
 		updateCalendarEvent(meeting);
-		return bigBlueButtonMeetingDao.updateMeeting(meeting);
+		meeting = bigBlueButtonMeetingDao.updateMeeting(meeting);
+		if(StringHelper.containsNonWhitespace(meeting.getDirectory())) {
+			OLATResource resource = resourceManager.findResourceable(meeting.getKey(), TASK_MEETING_RESNAME);
+			if(resource == null) {
+				OLATResourceable res = OresHelper.createOLATResourceableInstance(TASK_MEETING_RESNAME, meeting.getKey());
+				resource = resourceManager.createAndPersistOLATResourceInstance(res);
+				SlidesPreloaderTask loader = new SlidesPreloaderTask(meeting.getKey());
+				taskManager.execute(loader, null, resource, null, meeting.getStartWithLeadTime());
+			} else {
+				List<Task> currentTasks = taskManager.getTasks(resource);
+				if(!currentTasks.isEmpty()) {
+					SlidesPreloaderTask loader = new SlidesPreloaderTask(meeting.getKey());
+					taskManager.updateAndReturn(currentTasks.get(0), loader, null, meeting.getStartWithLeadTime());
+				}
+			}
+		}
+		return meeting;
 	}	
 
 	@Override
@@ -460,12 +538,28 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 			bigBlueButtonMeetingDeletionHandlers.forEach(h -> h.onBeforeDelete(reloadedMeeting));
 			removeCalendarEvent(reloadedMeeting);
 			deleteRecordings(meeting, errors);
+			deleteSlides(meeting);
 			bigBlueButtonAttendeeDao.deleteAttendee(reloadedMeeting);
 			bigBlueButtonMeetingDao.deleteMeeting(reloadedMeeting);
 		}
 		return false;
 	}
 	
+	private void deleteSlides(BigBlueButtonMeeting meeting) {
+		if(StringHelper.containsNonWhitespace(meeting.getDirectory())) {
+			VFSContainer slidesContainer = bigBlueButtonSlidesStorage.getStorage(meeting);
+			if(slidesContainer != null && slidesContainer.exists()) {
+				slidesContainer.deleteSilently();
+			}
+			
+			OLATResource resource = resourceManager.findResourceable(meeting.getKey(), TASK_MEETING_RESNAME);
+			if(resource != null) {
+				taskManager.delete(resource);
+				resourceManager.deleteOLATResource(resource);
+			}
+		}
+	}
+	
 	public BigBlueButtonServer getAvailableServer() {
 		List<BigBlueButtonServer> servers = getServers();
 		List<BigBlueButtonServer> availableServers = servers.stream()
@@ -948,10 +1042,52 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 		// metadata
 		getRecordingsHandler().appendMetadata(uriBuilder, meeting);
 		
+		// slides
+		if(StringHelper.containsNonWhitespace(meeting.getDirectory())) {
+			VFSContainer slidesContainer = bigBlueButtonSlidesStorage.getStorage(meeting);
+			List<VFSLeaf> slides = getSlides(meeting);
+			if(!slides.isEmpty()) {
+				MapperKey mapperKey = mapperService.register(null,  meeting.getMeetingId(), new SlidesContainerMapper(slidesContainer), 360);
+				String url = Settings.createServerURI() + mapperKey.getUrl() + "/slides/";
+				String slidesXml = slidesDocument(url, slides);
+				uriBuilder.xmlPayload(slidesXml);
+			}
+		}
+
 		Document doc = sendRequest(uriBuilder, errors);
 		return BigBlueButtonUtils.checkSuccess(doc, errors);
 	}
 	
+	private String slidesDocument(String url, List<VFSLeaf> slides) {
+		StringBuilder sb = new StringBuilder();
+		sb.append("<?xml version='1.0' encoding='UTF-8'?>")
+		  .append("<modules><module name='presentation'>");
+		
+		for(VFSLeaf slide:slides) {
+			sb.append("<document url='").append(url).append(slide.getName()).append("' />");
+		}
+		sb.append("</module></modules>");
+		return sb.toString();
+	}
+	
+	private List<VFSLeaf> getSlides(BigBlueButtonMeeting meeting) {
+		List<VFSLeaf> slides = new ArrayList<>();
+		
+		if(StringHelper.containsNonWhitespace(meeting.getDirectory())) {
+			VFSContainer slidesContainer = bigBlueButtonSlidesStorage.getStorage(meeting);
+			if(slidesContainer != null && slidesContainer.exists()) {
+				List<VFSItem> items = slidesContainer.getItems(new VFSLeafButSystemFilter());
+				for(VFSItem item:items) {
+					if(item instanceof VFSLeaf) {
+						slides.add((VFSLeaf)item);
+					}
+				}
+			}
+		}
+		
+		return slides;
+	}
+	
 	@Override
 	public BigBlueButtonAttendee getAttendee(Identity identity, BigBlueButtonMeeting meeting) {
 		return bigBlueButtonAttendeeDao.getAttendee(identity, meeting);
@@ -1032,14 +1168,41 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 	@Override
 	public Document sendRequest(BigBlueButtonUriBuilder builder, BigBlueButtonErrors errors) {
 		dbInstance.commit();
+		if(StringHelper.containsNonWhitespace(builder.getXmlPayload())) {
+			return sendPostRequest(builder, errors);
+		}
+		return sendGetRequest(builder, errors);
+	}
+
+	private Document sendPostRequest(BigBlueButtonUriBuilder builder, BigBlueButtonErrors errors) {
+		URI uri = builder.build();
+		HttpPost post = new HttpPost(uri);
+		String payload = builder.getXmlPayload();
+		post.addHeader("Content-Language", "en-US");
+		ContentType cType = ContentType.create("text/xml", StandardCharsets.UTF_8);
+		HttpEntity myEntity = new StringEntity(payload, cType);
+		post.setEntity(myEntity);
 		
+		RequestConfig requestConfig = getRequestConfiguration();
+		try(CloseableHttpClient httpClient = HttpClientBuilder.create()
+				.setDefaultRequestConfig(requestConfig)
+				.disableAutomaticRetries()
+				.build();
+				CloseableHttpResponse response = httpClient.execute(post)) {
+			int statusCode = response.getStatusLine().getStatusCode();
+			log.debug("Status code of: {} {}", uri, statusCode);
+			return BigBlueButtonUtils.getDocumentFromEntity(response.getEntity());
+		} catch(Exception e) {
+			errors.append(new BigBlueButtonError(BigBlueButtonErrorCodes.unkown));
+			log.error("Cannot send: {}", uri, e);
+			return null;
+		}
+	}
+	
+	private Document sendGetRequest(BigBlueButtonUriBuilder builder, BigBlueButtonErrors errors) {
 		URI uri = builder.build();
 		HttpGet get = new HttpGet(uri);
-		RequestConfig requestConfig = RequestConfig.copy(RequestConfig.DEFAULT)
-				.setConnectTimeout(bigBlueButtonModule.getHttpConnectTimeout())
-				.setConnectionRequestTimeout(bigBlueButtonModule.getHttpConnectRequestTimeout())
-				.setSocketTimeout(bigBlueButtonModule.getHttpSocketTimeout())
-				.build();
+		RequestConfig requestConfig = getRequestConfiguration();
 		try(CloseableHttpClient httpClient = HttpClientBuilder.create()
 				.setDefaultRequestConfig(requestConfig)
 				.disableAutomaticRetries()
@@ -1055,6 +1218,14 @@ public class BigBlueButtonManagerImpl implements BigBlueButtonManager,
 		}
 	}
 	
+	private RequestConfig getRequestConfiguration() {
+		return RequestConfig.copy(RequestConfig.DEFAULT)
+				.setConnectTimeout(bigBlueButtonModule.getHttpConnectTimeout())
+				.setConnectionRequestTimeout(bigBlueButtonModule.getHttpConnectRequestTimeout())
+				.setSocketTimeout(bigBlueButtonModule.getHttpSocketTimeout())
+				.build();
+	}
+	
 	private static class ServerLoadComparator implements Comparator<BigBlueButtonServerInfos> {
 
 		@Override
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java
index e90f713ac04997dfbeea17faba4f805b7da245a4..5d1dc7bfab2b94694f97fa8a9076bdc99060159c 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonMeetingDAO.java
@@ -79,6 +79,7 @@ public class BigBlueButtonMeetingDAO {
 		meeting.setCreator(creator);
 		
 		dbInstance.getCurrentEntityManager().persist(meeting);
+		
 		return meeting;
 	}
 	
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonSlidesStorage.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonSlidesStorage.java
new file mode 100644
index 0000000000000000000000000000000000000000..2f975b1d7db75d137e196191cc4a8ca4a6edda71
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonSlidesStorage.java
@@ -0,0 +1,78 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.bigbluebutton.manager;
+
+import java.io.File;
+
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSManager;
+import org.olat.modules.bigbluebutton.BigBlueButtonMeeting;
+import org.olat.modules.bigbluebutton.model.BigBlueButtonMeetingImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * Initial date: 22 déc. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+public class BigBlueButtonSlidesStorage {
+	
+	private static final String DIRECTORY = "bigbluebutton";
+
+	private VFSContainer rootContainer;
+	
+	public VFSContainer getRootContainer() {
+		if(rootContainer == null) {
+			rootContainer = VFSManager.olatRootContainer(File.separator + DIRECTORY, null);
+		}
+		return rootContainer;
+	}
+	
+	public VFSContainer getStorage(BigBlueButtonMeeting meeting) {
+		VFSItem dir = getRootContainer().resolve(meeting.getDirectory());
+		return dir instanceof VFSContainer ? (VFSContainer)dir : null;
+	}
+	
+	public VFSContainer createStorage(BigBlueButtonMeeting meeting) {
+		StringBuilder sb = new StringBuilder();
+		if(meeting.getBusinessGroup() != null) {
+			VFSManager.getOrCreateContainer(getRootContainer(), sb.toString());
+			sb.append("group").append(File.separator).append(meeting.getBusinessGroup().getKey());
+		} else if(meeting.getEntry() != null) {
+			sb.append("course").append(File.separator).append(meeting.getEntry().getKey()).append(File.separator);
+			if(StringHelper.containsNonWhitespace(meeting.getSubIdent())) {
+				sb.append(meeting.getSubIdent());
+			} else {
+				sb.append("tool");
+			}	
+		}
+		
+		sb.append(File.separator).append(meeting.getKey());
+
+		VFSContainer cont = VFSManager.olatRootContainer(File.separator + DIRECTORY + File.separator + sb.toString());
+
+		((BigBlueButtonMeetingImpl)meeting).setDirectory(sb.toString());
+		return cont;
+	}
+}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUriBuilder.java b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUriBuilder.java
index dd2d71132ce1b2b21b5f01ea743f90fb4333f7bc..dff97948f5817b0ea8355b7e9b8216e5ed09feb8 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUriBuilder.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/BigBlueButtonUriBuilder.java
@@ -42,6 +42,7 @@ public class BigBlueButtonUriBuilder {
 	private String scheme;
 	private int port;
 	private String startPath;
+	private String xmlPayload;
 
 	private final String sharedSecret;
 	
@@ -64,6 +65,11 @@ public class BigBlueButtonUriBuilder {
     	return new BigBlueButtonUriBuilder(uri, sharedSecret);
     }
     
+    public BigBlueButtonUriBuilder xmlPayload(String xml) {
+    	xmlPayload = xml;
+    	return this;
+    }
+    
     public BigBlueButtonUriBuilder operation(String operation) {
     	this.operation = operation;
     	return this;
@@ -133,6 +139,10 @@ public class BigBlueButtonUriBuilder {
 		}
     }
     
+    public String getXmlPayload() {
+    	return xmlPayload;
+    }
+    
     public static String urlEncode(String s) {
     	try {
     		return URLEncoder.encode(s, "UTF-8");
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/SlidesContainerMapper.java b/src/main/java/org/olat/modules/bigbluebutton/manager/SlidesContainerMapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..cacf113b41d16abe9cce5bf9881c7311b88527b0
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/SlidesContainerMapper.java
@@ -0,0 +1,77 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.bigbluebutton.manager;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.olat.core.dispatcher.mapper.Mapper;
+import org.olat.core.gui.media.ForbiddenMediaResource;
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.gui.media.NotFoundMediaResource;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.VFSMediaResource;
+
+/**
+ * 
+ * Initial date: 23 déc. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SlidesContainerMapper implements Mapper {
+	
+	public static final String DOWNLOAD_PREFIX = "/slides/";
+	
+	private final VFSContainer container;
+	private final VFSContainer tempContainer;
+	
+	public SlidesContainerMapper(VFSContainer container) {
+		this(null, container);
+	}
+	
+	public SlidesContainerMapper(VFSContainer tempContainer, VFSContainer container) {
+		this.container = container;
+		this.tempContainer = tempContainer;
+	}
+
+	@Override
+	public MediaResource handle(String relPath, HttpServletRequest request) {
+		MediaResource resource = null;
+		if(relPath.startsWith(DOWNLOAD_PREFIX)) {
+			String filename = relPath.substring(DOWNLOAD_PREFIX.length());
+			VFSItem slide = null;
+			if(tempContainer != null) {
+				slide = tempContainer.resolve(filename);
+			}
+			if(slide == null && container != null) {
+				slide = container.resolve(filename);
+			}
+			if(slide instanceof VFSLeaf) {
+				resource = new VFSMediaResource((VFSLeaf)slide);
+			} else {
+				resource = new NotFoundMediaResource();
+			}	
+		} else {
+			resource = new ForbiddenMediaResource();
+		}
+		return resource;
+	}
+}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/manager/SlidesPreloaderTask.java b/src/main/java/org/olat/modules/bigbluebutton/manager/SlidesPreloaderTask.java
new file mode 100644
index 0000000000000000000000000000000000000000..466ed7eb189b77be811242dc55294a633b90fe14
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/manager/SlidesPreloaderTask.java
@@ -0,0 +1,47 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.bigbluebutton.manager;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.commons.services.taskexecutor.LongRunnable;
+import org.olat.modules.bigbluebutton.BigBlueButtonManager;
+
+/**
+ * 
+ * Initial date: 23 déc. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SlidesPreloaderTask implements LongRunnable {
+
+	private static final long serialVersionUID = -1753449764226330508L;
+	
+	private Long meetingKey;
+	
+	public SlidesPreloaderTask(Long meetingKey) {
+		this.meetingKey = meetingKey;
+	}
+
+	@Override
+	public void run() {
+		CoreSpringFactory.getImpl(BigBlueButtonManager.class)
+			.preloadSlides(meetingKey);
+	}
+}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java
index e5176ddefc7b4cc1413fae3ffe3b72db4149780e..4cc0c3771f8f9f49647f6ccd5cd7a55cd83a17f4 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/model/BigBlueButtonMeetingImpl.java
@@ -107,6 +107,9 @@ public class BigBlueButtonMeetingImpl implements Persistable, BigBlueButtonMeeti
 	@Column(name="b_layout", nullable=false, insertable=true, updatable=true)
 	private String layout;
 
+	@Column(name="b_directory", nullable=true, insertable=true, updatable=true)
+	private String directory;
+
 	@Column(name="b_meeting_id", nullable=false, insertable=true, updatable=false)
 	private String meetingId;
 	@Column(name="b_attendee_pw", nullable=false, insertable=true, updatable=false)
@@ -228,8 +231,14 @@ public class BigBlueButtonMeetingImpl implements Persistable, BigBlueButtonMeeti
 	public void setWelcome(String welcome) {
 		this.welcome = welcome;
 	}
-	
-	
+
+	public String getDirectory() {
+		return directory;
+	}
+
+	public void setDirectory(String directory) {
+		this.directory = directory;
+	}
 
 	public String getLayout() {
 		return layout;
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java
index bb6e97ca7cae860f1a7e9a072f2eb35748b4ad60..d39d4c26a21faf0a5cc56265ffd113da725b8259 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonConfigurationController.java
@@ -29,6 +29,7 @@ import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
@@ -42,6 +43,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
+import org.olat.core.util.StringHelper;
 import org.olat.modules.bigbluebutton.BigBlueButtonManager;
 import org.olat.modules.bigbluebutton.BigBlueButtonModule;
 import org.olat.modules.bigbluebutton.BigBlueButtonRecordingsHandler;
@@ -65,6 +67,7 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 	private MultipleSelectionElement enabledForEl;
 	private MultipleSelectionElement permanentForEl;
 	private SingleSelection recordingsHandlerEl;
+	private TextElement slidesUploadLimitEl;
 	
 	private FormLink addServerButton;
 	private FlexiTableElement serversTableEl;
@@ -140,6 +143,11 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 		} else {
 			recordingsHandlerEl.select(BigBlueButtonNativeRecordingsHandler.NATIVE_RECORDING_HANDLER_ID, true);
 		}
+		
+		Integer maxSize = bigBlueButtonModule.getMaxUploadSize();
+		String maxSizeStr = maxSize == null ? null : maxSize.toString();
+		slidesUploadLimitEl = uifactory.addTextElement("slides.upload.limit", 8, maxSizeStr, formLayout);
+		slidesUploadLimitEl.setMandatory(true);
 
 		//buttons save - check
 		FormLayoutContainer buttonLayout = FormLayoutContainer.createButtonLayout("save", getTranslator());
@@ -185,6 +193,19 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 			}
 		}
 		
+		slidesUploadLimitEl.clearError();
+		if(StringHelper.containsNonWhitespace(slidesUploadLimitEl.getValue())) {
+			try {
+				Integer.parseInt(slidesUploadLimitEl.getValue());
+			} catch (NumberFormatException e) {
+				slidesUploadLimitEl.setErrorKey("form.error.nointeger", null);
+				allOk &= false;
+			}
+		} else {
+			slidesUploadLimitEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
 		return allOk;
 	}
 
@@ -241,6 +262,7 @@ public class BigBlueButtonConfigurationController extends FormBasicController {
 			bigBlueButtonModule.setGroupsEnabled(enabledForEl.isSelected(2));
 			bigBlueButtonModule.setPermanentMeetingEnabled(permanentForEl.isAtLeastSelected(1));
 			bigBlueButtonModule.setRecordingHandlerId(recordingsHandlerEl.getSelectedKey());
+			bigBlueButtonModule.setMaxUploadSize(Integer.valueOf(slidesUploadLimitEl.getValue()));
 		}
 		CollaborationToolsFactory.getInstance().initAvailableTools();
 	}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java
index 00e682482f1a44cd8537429b5c8bf1a845c274b2..2b81cb3ccd6c3722b1b6298ed7436ea1ca928be0 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonMeetingController.java
@@ -46,6 +46,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController;
+import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
 import org.olat.core.gui.control.generic.modal.DialogBoxController;
 import org.olat.core.gui.control.generic.modal.DialogBoxUIFactory;
 import org.olat.core.gui.control.winmgr.CommandFactory;
@@ -57,6 +58,10 @@ import org.olat.core.util.UserSession;
 import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.VFSLeafButSystemFilter;
 import org.olat.modules.bigbluebutton.BigBlueButtonAttendee;
 import org.olat.modules.bigbluebutton.BigBlueButtonAttendeeRoles;
 import org.olat.modules.bigbluebutton.BigBlueButtonDispatcher;
@@ -66,6 +71,7 @@ import org.olat.modules.bigbluebutton.BigBlueButtonModule;
 import org.olat.modules.bigbluebutton.BigBlueButtonRecording;
 import org.olat.modules.bigbluebutton.BigBlueButtonRecordingReference;
 import org.olat.modules.bigbluebutton.BigBlueButtonRecordingsPublishedRoles;
+import org.olat.modules.bigbluebutton.manager.SlidesContainerMapper;
 import org.olat.modules.bigbluebutton.model.BigBlueButtonErrors;
 import org.olat.modules.bigbluebutton.model.BigBlueButtonRecordingWithReference;
 import org.olat.modules.bigbluebutton.ui.BigBlueButtonRecordingTableModel.BRecordingsCols;
@@ -84,16 +90,22 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 	private final boolean administrator;
 	private BigBlueButtonMeeting meeting;
 	
+	private int count = 0;
 	private final boolean guest;
 	private final boolean moderatorStartMeeting;
 	private final OLATResourceable meetingOres;
 
 	private FormLink joinButton;
+	private FormLink uploadButton;
 	private FormLink guestJoinButton;
 	private MultipleSelectionElement acknowledgeRecordingEl;
 	private FlexiTableElement tableEl;
 	private BigBlueButtonRecordingTableModel recordingTableModel;
+	
+	private SlidesContainerMapper slidesMapper; 
 
+	private CloseableModalController cmc;
+	private SlideUploadController uploadSlideCtrl;
 	private PublishRecordingController publishCtrl;
 	private DialogBoxController confirmDeleteRecordingDialog;
 	private CloseableCalloutWindowController publishCalloutCtrl;
@@ -162,6 +174,11 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 				layoutCont.contextPut("externalPassword", password);
 			}
 			
+			if(administrator || moderator) {
+				loadSlides(layoutCont);
+				uploadButton = uifactory.addFormLink("meeting.slides.upload", formLayout, Link.BUTTON_SMALL);
+			}
+			
 			if(StringHelper.containsNonWhitespace(meeting.getMainPresenter())) {
 				layoutCont.contextPut("mainPresenter", meeting.getMainPresenter());
 			}
@@ -185,6 +202,38 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 				acknowledgeKeyValue.keys(), acknowledgeKeyValue.values());
 	}
 	
+	private void loadSlides(FormLayoutContainer layoutCont) {
+		List<SlideWrapper> documentWrappers = new ArrayList<>();
+		if(StringHelper.containsNonWhitespace(meeting.getDirectory())) {
+			VFSContainer slidesContainer = bigBlueButtonManager.getSlidesContainer(meeting);
+			if(slidesMapper == null) {
+				slidesMapper = new SlidesContainerMapper(slidesContainer);
+				String mapperUri = registerCacheableMapper(null, "BigBlueButtonSlides::" + meeting.getKey(), slidesMapper);
+				layoutCont.contextPut("mapperUri", mapperUri);
+			}
+			
+			if(slidesContainer != null && slidesContainer.exists()) {
+				boolean slidesEditable = isSlidesEditable();
+				List<VFSItem> items = slidesContainer.getItems(new VFSLeafButSystemFilter());
+				for(VFSItem item:items) {
+					if(item instanceof VFSLeaf) {
+						VFSLeaf slide = (VFSLeaf)item;
+						SlideWrapper wrapper = new SlideWrapper(slide, false);
+						if(slidesEditable) {
+							FormLink deleteButton = uifactory
+									.addFormLink("delete_" + (++count), "delete", "delete", null, layoutCont, Link.BUTTON_XSMALL);
+							deleteButton.setUserObject(wrapper);
+							wrapper.setDeleteButton(deleteButton);
+						}
+						documentWrappers.add(wrapper);
+					}
+				}
+			}
+		}
+		
+		layoutCont.contextPut("documents", documentWrappers);
+	}
+	
 	private void initRecordings(FormItemContainer formLayout) {
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(BRecordingsCols.name));
@@ -273,6 +322,17 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 		return !((start != null && start.compareTo(now) >= 0) || (end != null && end.compareTo(now) <= 0));
 	}
 	
+	private boolean isSlidesEditable() {
+		if(meeting == null) return false;
+		if(meeting.isPermanent()) {
+			return true;
+		}
+
+		Date now = new Date();
+		Date start = meeting.getStartDate();
+		return start != null && start.compareTo(now) > 0;
+	}
+	
 	private void reloadButtonsAndStatus() {
 		meeting = bigBlueButtonManager.getMeeting(meeting);
 		updateButtonsAndStatus();
@@ -300,6 +360,11 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 			guestJoinButton.setVisible(accessible && !disabled && guest);
 		}
 		guestJoinButton.setEnabled(!readOnly && accessible && !disabled && guest);
+		
+		if(uploadButton != null) {
+			boolean slidesEditable = isSlidesEditable();
+			uploadButton.setVisible(slidesEditable);
+		}
 			
 		if(accessible && !disabled) {
 			boolean running = bigBlueButtonManager.isMeetingRunning(meeting);
@@ -364,7 +429,14 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 			}
 			publishCalloutCtrl.deactivate();
 			cleanUp();
-		} else if(publishCalloutCtrl == source) {
+		} else if(uploadSlideCtrl == source) {
+			if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
+				meeting = bigBlueButtonManager.getMeeting(meeting);
+				loadSlides(flc);
+			}
+			cmc.deactivate();
+			cleanUp();
+		} else if(publishCalloutCtrl == source || cmc == source) {
 			cleanUp();
 		}
 		super.event(ureq, source, event);
@@ -373,10 +445,14 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 	private void cleanUp() {
 		removeAsListenerAndDispose(confirmDeleteRecordingDialog);
 		removeAsListenerAndDispose(publishCalloutCtrl);
+		removeAsListenerAndDispose(uploadSlideCtrl);
 		removeAsListenerAndDispose(publishCtrl);
+		removeAsListenerAndDispose(cmc);
 		confirmDeleteRecordingDialog = null;
 		publishCalloutCtrl = null;
+		uploadSlideCtrl = null;
 		publishCtrl = null;
+		cmc = null;
 	}
 
 	@Override
@@ -401,6 +477,8 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 			doJoin(ureq);
 		} else if(this.guestJoinButton == source) {
 			doGuestJoin(ureq);
+		} else if(uploadButton == source) {
+			doUploadSlides(ureq);
 		} else if(tableEl == source) {
 			if(event instanceof SelectionEvent) {
 				SelectionEvent se = (SelectionEvent)event;
@@ -414,6 +492,9 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 			FormLink link = (FormLink)source;
 			if("publish".equals(link.getCmd()) && link.getUserObject() instanceof BigBlueButtonRecordingRow) {
 				doPublish(ureq, link, (BigBlueButtonRecordingRow)link.getUserObject());
+			} else if("delete".equals(link.getCmd()) && link.getUserObject() instanceof SlideWrapper) {
+				doDeleteSlide((SlideWrapper)link.getUserObject());
+				loadSlides(flc);
 			}
 		}
 		super.formInnerEvent(ureq, source, event);
@@ -424,6 +505,25 @@ public class BigBlueButtonMeetingController extends FormBasicController implemen
 		//
 	}
 	
+	private void doUploadSlides(UserRequest ureq) {
+		uploadSlideCtrl = new SlideUploadController(ureq, getWindowControl(), meeting);
+		listenTo(uploadSlideCtrl);
+		
+		String title = translate("meeting.slides.upload");
+		cmc = new CloseableModalController(getWindowControl(), translate("close"), uploadSlideCtrl.getInitialComponent(), true, title);
+		listenTo(cmc);
+		cmc.activate();
+	}
+	
+	private void doDeleteSlide(SlideWrapper slide) {
+		VFSLeaf document = slide.getDocument();
+		VFSContainer slidesContainer = bigBlueButtonManager.getSlidesContainer(meeting);
+		VFSItem reloadedDocument = slidesContainer.resolve(document.getName());
+		if(reloadedDocument != null && reloadedDocument.exists()) {
+			reloadedDocument.delete();
+		}
+	}
+	
 	private void doPublish(UserRequest ureq, FormLink link, BigBlueButtonRecordingRow row) {
 		publishCtrl = new PublishRecordingController(ureq, getWindowControl(), row);
 		listenTo(publishCtrl); 
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
index 15ce960d1d57ae749f6e316cf1612939057b8fb6..8ded0af2c06952b9af081aebd49b4c4c95cf2211 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/EditBigBlueButtonMeetingController.java
@@ -22,14 +22,19 @@ package org.olat.modules.bigbluebutton.ui;
 import static org.olat.modules.bigbluebutton.ui.BigBlueButtonUIHelper.getSelectedTemplate;
 import static org.olat.modules.bigbluebutton.ui.BigBlueButtonUIHelper.isWebcamLayoutAvailable;
 
+import java.io.File;
+import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.DateChooser;
+import org.olat.core.gui.components.form.flexible.elements.FileElement;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
 import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
@@ -37,6 +42,7 @@ import org.olat.core.gui.components.form.flexible.elements.TextElement;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.util.KeyValues;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
@@ -45,6 +51,14 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle
 import org.olat.core.id.Identity;
 import org.olat.core.util.CodeHelper;
 import org.olat.core.util.StringHelper;
+import org.olat.core.util.ValidationStatus;
+import org.olat.core.util.WebappHelper;
+import org.olat.core.util.vfs.LocalFolderImpl;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.VFSManager;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
 import org.olat.group.BusinessGroup;
 import org.olat.modules.bigbluebutton.BigBlueButtonDispatcher;
 import org.olat.modules.bigbluebutton.BigBlueButtonManager;
@@ -55,6 +69,7 @@ import org.olat.modules.bigbluebutton.BigBlueButtonModule;
 import org.olat.modules.bigbluebutton.BigBlueButtonRecordingsPublishingEnum;
 import org.olat.modules.bigbluebutton.BigBlueButtonServer;
 import org.olat.modules.bigbluebutton.BigBlueButtonTemplatePermissions;
+import org.olat.modules.bigbluebutton.manager.SlidesContainerMapper;
 import org.olat.repository.RepositoryEntry;
 import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -88,6 +103,8 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 	private TextElement externalLinkEl;
 	private MultipleSelectionElement passwordEnableEl;
 	private TextElement passwordEl;
+	private FileElement uploadSlidesEl;
+	private FormLayoutContainer slidesCont;
 
 	private final Mode mode;
 	private final String subIdent;
@@ -97,6 +114,12 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 	private BigBlueButtonMeeting meeting;
 	private final List<BigBlueButtonTemplatePermissions> permissions;
 	private List<BigBlueButtonMeetingTemplate> templates;
+	private SlidesContainerMapper slidesMapper;
+	private final String mapperUri;
+	private VFSContainer slidesContainer;
+	private VFSContainer temporaryContainer;
+	private List<SlideWrapper> documentWrappers = new ArrayList<>();
+	private int count = 0;
 	
 	private final boolean running;
 	private final boolean editable;
@@ -129,8 +152,13 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		this.businessGroup = businessGroup;
 		this.permissions = permissions;
 		templates = bigBlueButtonManager.getTemplates();
+
+		temporaryContainer = new LocalFolderImpl(new File(WebappHelper.getTmpDir(), CodeHelper.getUniqueID()));
+		slidesMapper = new SlidesContainerMapper(temporaryContainer);
+		mapperUri = registerCacheableMapper(null, null, slidesMapper);
 		
 		initForm(ureq);
+		reloadSlides();
 	}
 	
 	public EditBigBlueButtonMeetingController(UserRequest ureq, WindowControl wControl,
@@ -149,8 +177,14 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		editable = isEditable(meeting, ureq);
 		editableInternal = isEditableInternal(meeting, ureq);
 		administrator = ureq.getUserSession().getRoles().isAdministrator();
+
+		slidesContainer = bigBlueButtonManager.getSlidesContainer(meeting);
+		temporaryContainer = new LocalFolderImpl(new File(WebappHelper.getTmpDir(), CodeHelper.getUniqueID()));
+		slidesMapper = new SlidesContainerMapper(temporaryContainer, slidesContainer);
+		mapperUri = registerCacheableMapper(null, null, slidesMapper);
 		
 		initForm(ureq);
+		reloadSlides();
 	}
 	
 	private boolean isEditable(BigBlueButtonMeeting m, UserRequest ureq) {
@@ -209,6 +243,18 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		mainPresenterEl.setElementCssClass("o_sel_bbb_edit_meeting_presenter");
 		mainPresenterEl.setEnabled(editable || editableInternal);
 		
+		// slides
+		String page = velocity_root + "/meeting_slides.html"; 
+		slidesCont = FormLayoutContainer.createCustomFormLayout("meeting.slides.container", getTranslator(), page);
+		slidesCont.setLabel("meeting.slides", null);
+		slidesCont.contextPut("mapperUri", mapperUri);
+		formLayout.add(slidesCont);
+		
+		uploadSlidesEl = uifactory.addFileElement(getWindowControl(), "meeting.slides.upload", "meeting.slides", formLayout);
+		uploadSlidesEl.addActionListener(FormEvent.ONCHANGE);
+		uploadSlidesEl.setVisible(editable || editableInternal);
+		uploadSlidesEl.limitToMimeType(BigBlueButtonModule.SLIDES_MIME_TYPES, "error.slides.type", null);
+		
 		Long selectedTemplateKey = meeting == null || meeting.getTemplate() == null
 				? null : meeting.getTemplate().getKey();
 		KeyValues templatesKeyValues = new KeyValues();
@@ -385,9 +431,58 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 		listenTo(cmc);
 	}
 	
+	private void reloadSlides() {
+		Map<String,SlideWrapper> docsMap = documentWrappers.stream()
+				.collect(Collectors.toMap(SlideWrapper::getFilename, doc -> doc));
+		
+		List<SlideWrapper> wrappers = new ArrayList<>();
+		if(temporaryContainer != null && temporaryContainer.exists()) {
+			reloadSlides(temporaryContainer, true, wrappers, docsMap);
+		}
+		if(slidesContainer != null && slidesContainer.exists()) {
+			reloadSlides(slidesContainer, false, wrappers, docsMap);
+		}
+		
+		slidesCont.contextPut("documents", wrappers);
+		slidesCont.setVisible(!wrappers.isEmpty());
+
+		if(uploadSlidesEl != null && uploadSlidesEl.isVisible()) {
+			if(wrappers.isEmpty()) {
+				uploadSlidesEl.setLabel("meeting.slides.upload", null);
+				slidesCont.setDirty(true);
+			} else {
+				uploadSlidesEl.setLabel(null, null);
+			}
+		}
+	}
+	
+	private void reloadSlides(VFSContainer container, boolean temporary, List<SlideWrapper> wrappers, Map<String,SlideWrapper> docsMap) {
+		List<VFSItem>  documents = container.getItems(new VFSSystemItemFilter());
+		for (VFSItem document : documents) {
+			if(document instanceof VFSLeaf) {
+				SlideWrapper wrapper = docsMap.get(document.getName());
+				if(wrapper == null) {
+					wrapper = new SlideWrapper((VFSLeaf)document, temporary);
+					documentWrappers.add(wrapper);
+					if(editable || editableInternal) {
+						FormLink deleteButton = uifactory
+								.addFormLink("delete_" + (++count), "delete", "delete", null, slidesCont, Link.BUTTON_XSMALL);
+						deleteButton.setUserObject(wrapper);
+						wrapper.setDeleteButton(deleteButton);
+					}
+				}
+				if(!wrapper.isDeleted()) {
+					wrappers.add(wrapper);
+				}
+			}
+		}
+	}
+	
 	@Override
 	protected void doDispose() {
-		//
+		if(temporaryContainer != null) {
+			temporaryContainer.deleteSilently();
+		}
 	}
 
 	@Override
@@ -465,10 +560,31 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 			allOk &= false;
 		}
 		
+		allOk &= validateSlidesSize();
+
 		return allOk;
 	}
 	
-	
+	private boolean validateSlidesSize() {
+		boolean allOk = true;
+		
+		Integer maxSizeInMb = bigBlueButtonModule.getMaxUploadSize();
+		slidesCont.clearError();
+		if(maxSizeInMb != null && maxSizeInMb.intValue() > 0) {
+			long total = 0l;
+			for(SlideWrapper doc:documentWrappers) {
+				if(!doc.isDeleted()) {
+					total += doc.getDocument().getSize();
+				}
+			}
+			if(total > (maxSizeInMb.intValue() * 1000 * 1000)) {
+				slidesCont.setErrorKey("error.slides.size", new String[] { maxSizeInMb.toString() });
+				allOk &= false;
+			}
+		}
+		
+		return allOk;
+	}
 	
 	@Override
 	protected void event(UserRequest ureq, Controller source, Event event) {
@@ -502,6 +618,19 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 			BigBlueButtonUIHelper.validateReadableIdentifier(externalLinkEl, meeting);
 		} else if (serverEl == source) {
 			serverChangeWarning();
+		} else if(uploadSlidesEl == source) {
+			if(uploadSlidesEl.getUploadFile() != null && StringHelper.containsNonWhitespace(uploadSlidesEl.getUploadFileName())) {
+				doUploadSlide(uploadSlidesEl.getUploadFile(), uploadSlidesEl.getUploadFileName());
+				reloadSlides();
+				validateSlidesSize();
+				uploadSlidesEl.reset();
+			}
+		} else if(source instanceof FormLink) {
+			FormLink link = (FormLink)source;
+			if("delete".equals(link.getCmd()) && link.getUserObject() instanceof SlideWrapper) {
+				doDeleteSlide((SlideWrapper)link.getUserObject());
+				reloadSlides();
+			}
 		}
 		super.formInnerEvent(ureq, source, event);
 	}
@@ -587,11 +716,48 @@ public class EditBigBlueButtonMeetingController extends FormBasicController {
 			BigBlueButtonServer server = bigBlueButtonManager.getServer(Long.valueOf(selectedServerKey));
 			meeting.setServer(server);
 		}
+		
+		// copy the slides, eventually update the directory field
+		doCopySlides();
 
 		meeting = bigBlueButtonManager.updateMeeting(meeting);
 
 		fireEvent(ureq, Event.DONE_EVENT);
 	}
+	
+	private void doCopySlides() {
+		if(documentWrappers.isEmpty()) return;
+
+		VFSContainer storage = bigBlueButtonManager.getSlidesContainer(meeting);
+		for(SlideWrapper doc:documentWrappers) {
+			if(doc.isDeleted()) {
+				doc.getDocument().deleteSilently();
+			} else if(doc.isTemporary()) {
+				VFSLeaf target = storage.createChildLeaf(doc.getFilename());
+				VFSManager.copyContent(doc.getDocument(), target, true);
+			}
+		}
+	}
+	
+	private void doUploadSlide(File file, String filename) {
+		List<ValidationStatus> validationResults = new ArrayList<>();
+		uploadSlidesEl.validate(validationResults);
+		if(validationResults.isEmpty()) {
+			VFSLeaf newSlide = VFSManager.resolveOrCreateLeafFromPath(temporaryContainer, filename);
+			VFSManager.copyContent(file, newSlide);
+			
+			for(SlideWrapper doc:documentWrappers) {
+				if(filename.equals(doc.getFilename())) {
+					doc.setDeleted(false);
+				}
+			}
+		}
+	}
+	
+	private void doDeleteSlide(SlideWrapper slide) {
+		slide.setDeleted(true);
+		slidesCont.setDirty(true);
+	}
 
 	@Override
 	protected void formCancelled(UserRequest ureq) {
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/SlideUploadController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/SlideUploadController.java
new file mode 100644
index 0000000000000000000000000000000000000000..685809d28c37c504b68fc42120098945f0be4b88
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/SlideUploadController.java
@@ -0,0 +1,135 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.bigbluebutton.ui;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.olat.core.commons.persistence.DB;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.FileElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.ValidationStatus;
+import org.olat.core.util.vfs.VFSContainer;
+import org.olat.core.util.vfs.VFSItem;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.filters.VFSSystemItemFilter;
+import org.olat.modules.bigbluebutton.BigBlueButtonManager;
+import org.olat.modules.bigbluebutton.BigBlueButtonMeeting;
+import org.olat.modules.bigbluebutton.BigBlueButtonModule;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 24 déc. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SlideUploadController extends FormBasicController {
+
+	private FileElement fileEl;
+	
+	private BigBlueButtonMeeting meeting;
+	
+	@Autowired
+	private DB dbInstance;
+	@Autowired
+	private BigBlueButtonModule bigBlueButtonModule;
+	@Autowired
+	private BigBlueButtonManager bigBlueButtonManager;
+
+	public SlideUploadController(UserRequest ureq, WindowControl wControl, BigBlueButtonMeeting meeting) {
+		super(ureq, wControl);
+		this.meeting = meeting;
+		initForm(ureq);
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_course_gta_upload_form");
+
+		fileEl = uifactory.addFileElement(getWindowControl(), "file", "meeting.slides", formLayout);
+		fileEl.setMandatory(true);
+		fileEl.addActionListener(FormEvent.ONCHANGE);
+		fileEl.limitToMimeType(BigBlueButtonModule.SLIDES_MIME_TYPES, "error.slides.type", null);
+
+		FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		buttonCont.setRootForm(mainForm);
+		formLayout.add(buttonCont);
+		uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl());
+		uifactory.addFormSubmitButton("save", buttonCont);
+	}
+
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		fileEl.clearError();
+		List<ValidationStatus> validationResults = new ArrayList<>();
+		fileEl.validate(validationResults);
+		if(validationResults.isEmpty()) {
+			Integer maxSizeInMb = bigBlueButtonModule.getMaxUploadSize();
+			if(maxSizeInMb != null && maxSizeInMb.intValue() > 0) {
+				long total = fileEl.getUploadSize();
+				VFSContainer slidesContainer = bigBlueButtonManager.getSlidesContainer(meeting);
+				List<VFSItem>  documents = slidesContainer.getItems(new VFSSystemItemFilter());
+				for(VFSItem doc:documents) {
+					if(doc instanceof VFSLeaf) {
+						total += ((VFSLeaf)doc).getSize();
+					}
+				}
+				
+				if(total > (maxSizeInMb.intValue() * 1000 * 1000)) {
+					fileEl.setErrorKey("error.slides.size", new String[] { maxSizeInMb.toString() });
+					allOk &= false;
+				}
+			}
+		} else {
+			allOk &= false;
+		}
+
+		return allOk;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		VFSContainer slidesContainer = bigBlueButtonManager.getSlidesContainer(meeting);
+		fileEl.moveUploadFileTo(slidesContainer);
+		meeting = bigBlueButtonManager.updateMeeting(meeting);
+		dbInstance.commit();
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/SlideWrapper.java b/src/main/java/org/olat/modules/bigbluebutton/ui/SlideWrapper.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e6cd69ac6dadb24e8bd54ddb13e7600b7b79655
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/SlideWrapper.java
@@ -0,0 +1,77 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.bigbluebutton.ui;
+
+import org.olat.core.gui.components.form.flexible.elements.FormLink;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.vfs.VFSLeaf;
+
+/**
+ * 
+ * Initial date: 23 déc. 2020<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class SlideWrapper {
+	
+	private final VFSLeaf document;
+	private FormLink deleteButton;
+	private boolean deleted = false;
+	private boolean temporary = false;
+	
+	public SlideWrapper(VFSLeaf document, boolean temporary) {
+		this.document = document;
+		this.temporary = temporary;
+	}
+	
+	public String getFilename() {
+		return document.getName();
+	}
+	
+	public boolean isTemporary() {
+		return temporary;
+	}
+	
+	public String getLabel() {
+		return document.getName() + " (" + Formatter.formatBytes(document.getSize()) + ")";
+	}
+	
+	public boolean isDeleted() {
+		return deleted;
+	}
+
+	public void setDeleted(boolean deleted) {
+		this.deleted = deleted;
+	}
+
+	public VFSLeaf getDocument() {
+		return document;
+	}
+
+	public FormLink getDeleteButton() {
+		return deleteButton;
+	}
+
+	public void setDeleteButton(FormLink deleteButton) {
+		this.deleteButton = deleteButton;
+		deleteButton.setUserObject(this);
+	}
+
+}
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting.html b/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting.html
index c01dd7435d2ac909feceb7dac473966e1e648da9..b04e8abb20aa52d53239fa409b6b3a42d59db681 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting.html
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting.html
@@ -30,6 +30,18 @@
 </div>
 #end
 
+#if($r.isNotEmpty($documents))
+<label forid="meeting-slides"><i class="o_icon o_filetype_file"> </i> $r.translate("meeting.slides")</label>
+<ul id="meeting-slides" class="list-unstyled o_slides">
+	#foreach($document in $documents)
+		<li><a href="$mapperUri/slides/$r.encodeUrl($document.filename)" target="_blank"><i class="o_icon o_icon-fw $r.getFiletypeIconCss($document.filename)"> </i> $r.escapeHtml($document.label)</a> #if($r.visible($document.deleteButton))$r.render($document.deleteButton)#end</li>
+	#end
+</ul>
+#end
+#if($r.available("meeting.slides.upload"))
+	$r.render("meeting.slides.upload")
+#end
+
 #if($r.isTrue($ended))
 	<div class="o_block_large o_warning">$r.translate("meeting.ended")</div>
 #end
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting_slides.html b/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting_slides.html
new file mode 100644
index 0000000000000000000000000000000000000000..00e2aa009664851207a6784d479446fea5ba89dc
--- /dev/null
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/_content/meeting_slides.html
@@ -0,0 +1,9 @@
+#if($r.isNotEmpty($documents))
+<ul class="form-static list-unstyled o_slides">
+	#foreach($document in $documents)
+		#if($r.isFalse($document.deleted))
+			<li><a href="$mapperUri/slides/$r.encodeUrl($document.filename)" target="_blank"><i class="o_icon o_icon-fw $r.getFiletypeIconCss($document.filename)"> </i> $r.escapeHtml($document.label)</a> #if($r.visible($document.deleteButton))$r.render($document.deleteButton)#end</li>
+		#end
+	#end
+</ul>
+#end
\ No newline at end of file
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 939511dbb240a381720c0ccd93a81d8d0515cc5a..a2f992faca377134b382310612d9a1729462f2c7 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
@@ -50,6 +50,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.password=Passwort ist falsch.
 error.prefix=Ein Fehler ist aufgetreten\:
 error.same.day=Sie haben schon ein Meeting an diesem Tag geplant.
@@ -104,6 +106,8 @@ meeting.recurring.start=Start wiederkehrendes Datum
 meeting.resource=Kontext
 meeting.server=Bevorzugter Server
 meeting.server.auto=Automatisch (beste Performance)
+meeting.slides=Pr\u00e4sentationsfolien
+meeting.slides.upload=Pr\u00e4sentationsfolien hochladen
 meeting.start=Beginn
 meeting.start.button=Online-Termin starten
 meeting.template=Raumvorlage
@@ -149,6 +153,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)
 table.header.available=Verf\u00fcgbarkeit
 table.header.breakout.meetings=\# Breakout
 table.header.breakout.recording.meetings=\# Breakout Recording
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 f707ee5d73b7b7aa1d7e75e6fc9b846174c439e1..7ddfca48a942f9f837433bf7f83b36a0c43b4acf 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
@@ -56,6 +56,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.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
@@ -104,6 +106,8 @@ meeting.recurring.start=Start recurring date
 meeting.resource=Context
 meeting.server=Preferred server
 meeting.server.auto=Automatically (best performance)
+meeting.slides=Slides
+meeting.slides.upload=Upload slides
 meeting.start=Start date
 meeting.start.button=Start the online-meeting
 meeting.template=Room-template
@@ -149,6 +153,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)
 table.header.available=Availability
 table.header.breakout.meetings=\# Breakout
 table.header.breakout.recording.meetings=\# Breakout Recording
diff --git a/src/main/resources/database/mysql/alter_15_3_x_to_15_3_8.sql b/src/main/resources/database/mysql/alter_15_3_x_to_15_3_8.sql
index 9599fc8ee828769a654778541ec5b11334ff0bb3..9587559c727e9cdaf0bbdbfb7743115d4f850ccd 100644
--- a/src/main/resources/database/mysql/alter_15_3_x_to_15_3_8.sql
+++ b/src/main/resources/database/mysql/alter_15_3_x_to_15_3_8.sql
@@ -1,3 +1,5 @@
 -- BigBlueButton
 alter table o_bbb_meeting add column b_password varchar(64) default null;
+alter table o_bbb_meeting add column b_directory varchar(64) default null;
+alter table o_bbb_meeting add constraint bbb_dir_idx unique (b_directory);
 
diff --git a/src/main/resources/database/mysql/setupDatabase.sql b/src/main/resources/database/mysql/setupDatabase.sql
index a6b8ea2e3c7599f372ed86a125d5617774d308a8..3761aa106cf17cb68cfc106ba8858adc441d020b 100644
--- a/src/main/resources/database/mysql/setupDatabase.sql
+++ b/src/main/resources/database/mysql/setupDatabase.sql
@@ -1225,6 +1225,7 @@ create table o_bbb_meeting (
    b_followuptime bigint default 0 not null,
    b_end_with_followuptime datetime,
    b_main_presenter varchar(255),
+   b_directory varchar(64) default null,
    b_recordings_publishing varchar(16) default 'auto',
    b_record bool default null,
    fk_creator_id bigint default null,
@@ -3884,6 +3885,7 @@ alter table o_bbb_meeting add constraint bbb_meet_grp_idx foreign key (fk_group_
 alter table o_bbb_meeting add constraint bbb_meet_template_idx foreign key (fk_template_id) references o_bbb_template (id);
 alter table o_bbb_meeting add constraint bbb_meet_creator_idx foreign key (fk_creator_id) references o_bs_identity (id);
 alter table o_bbb_meeting add constraint bbb_meet_serv_idx foreign key (fk_server_id) references o_bbb_server (id);
+alter table o_bbb_meeting add constraint bbb_dir_idx unique (b_directory);
 
 alter table o_bbb_attendee add constraint bbb_attend_ident_idx foreign key (fk_identity_id) references o_bs_identity (id);
 alter table o_bbb_attendee add constraint bbb_attend_meet_idx foreign key (fk_meeting_id) references o_bbb_meeting (id);
diff --git a/src/main/resources/database/oracle/alter_15_3_x_to_15_3_8.sql b/src/main/resources/database/oracle/alter_15_3_x_to_15_3_8.sql
index 7e344ad046f0c88ebd214298d4eef271dccb8e2f..65ea60c3d100da045d0902317ef3182dbea8db13 100644
--- a/src/main/resources/database/oracle/alter_15_3_x_to_15_3_8.sql
+++ b/src/main/resources/database/oracle/alter_15_3_x_to_15_3_8.sql
@@ -1,3 +1,5 @@
 -- BigBlueButton
 alter table o_bbb_meeting add b_password varchar2(64) default null;
+alter table o_bbb_meeting add b_directory varchar2(64) default null;
+alter table o_bbb_meeting add constraint bbb_dir_idx unique (b_directory);
 
diff --git a/src/main/resources/database/oracle/setupDatabase.sql b/src/main/resources/database/oracle/setupDatabase.sql
index 4624c197e40d86ab91f197454594ade6cbd90280..8b52bea73b300b66e48604a1a44633f60edf2e3c 100644
--- a/src/main/resources/database/oracle/setupDatabase.sql
+++ b/src/main/resources/database/oracle/setupDatabase.sql
@@ -1289,6 +1289,7 @@ create table o_bbb_meeting (
    b_followuptime number(20) default 0 not null,
    b_end_with_followuptime timestamp,
    b_main_presenter varchar2(255),
+   b_directory varchar2(64) default null,
    b_recordings_publishing varchar2(16) default 'auto',
    b_record number default null,
    fk_creator_id number(20),
@@ -3900,6 +3901,7 @@ alter table o_bbb_meeting add constraint bbb_meet_serv_idx foreign key (fk_serve
 create index idx_bbb_meet_serv_idx on o_bbb_meeting(fk_server_id);
 alter table o_bbb_meeting add constraint bbb_meet_creator_idx foreign key (fk_creator_id) references o_bs_identity (id);
 create index idx_bbb_meet_creator_idx on o_bbb_meeting(fk_creator_id);
+alter table o_bbb_meeting add constraint bbb_dir_idx unique (b_directory);
 
 alter table o_bbb_attendee add constraint bbb_attend_ident_idx foreign key (fk_identity_id) references o_bs_identity (id);
 create index idx_bbb_attend_ident_idx on o_bbb_attendee(fk_identity_id);
diff --git a/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_8.sql b/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_8.sql
index 9599fc8ee828769a654778541ec5b11334ff0bb3..9587559c727e9cdaf0bbdbfb7743115d4f850ccd 100644
--- a/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_8.sql
+++ b/src/main/resources/database/postgresql/alter_15_3_x_to_15_3_8.sql
@@ -1,3 +1,5 @@
 -- BigBlueButton
 alter table o_bbb_meeting add column b_password varchar(64) default null;
+alter table o_bbb_meeting add column b_directory varchar(64) default null;
+alter table o_bbb_meeting add constraint bbb_dir_idx unique (b_directory);
 
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index 65898a4e216c8c45a91a1e052f2a6cf8931f7331..5895c609db930f377c2322065fa6b11cc30b7c1a 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1247,6 +1247,7 @@ create table o_bbb_meeting (
    b_followuptime bigint default 0 not null,
    b_end_with_followuptime timestamp,
    b_main_presenter varchar(255),
+   b_directory varchar(64) default null,
    b_recordings_publishing varchar(16) default 'auto',
    b_record bool default null,
    fk_creator_id int8,
@@ -3794,6 +3795,7 @@ alter table o_bbb_meeting add constraint bbb_meet_serv_idx foreign key (fk_serve
 create index idx_bbb_meet_serv_idx on o_bbb_meeting(fk_server_id);
 alter table o_bbb_meeting add constraint bbb_meet_creator_idx foreign key (fk_creator_id) references o_bs_identity (id);
 create index idx_bbb_meet_creator_idx on o_bbb_meeting(fk_creator_id);
+alter table o_bbb_meeting add constraint bbb_dir_idx unique (b_directory);
 
 alter table o_bbb_attendee add constraint bbb_attend_ident_idx foreign key (fk_identity_id) references o_bs_identity (id);
 create index idx_bbb_attend_ident_idx on o_bbb_attendee(fk_identity_id);