diff --git a/src/main/java/org/olat/commons/calendar/CalendarWebDAVProvider.java b/src/main/java/org/olat/commons/calendar/CalendarWebDAVProvider.java
deleted file mode 100644
index 70e06196f974a587c3189d285f12a18919d7d7dd..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/commons/calendar/CalendarWebDAVProvider.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
-* OLAT - Online Learning and Training<br>
-* http://www.olat.org
-* <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
-* <p>
-* http://www.apache.org/licenses/LICENSE-2.0
-* <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>
-* Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br>
-* University of Zurich, Switzerland.
-* <hr>
-* <a href="http://www.openolat.org">
-* OpenOLAT - Online Learning and Training</a><br>
-* This file has been modified by the OpenOLAT community. Changes are licensed
-* under the Apache 2.0 license as the original file.
-*/
-
-package org.olat.commons.calendar;
-
-import java.io.File;
-
-import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.services.webdav.WebDAVProvider;
-import org.olat.core.id.IdentityEnvironment;
-import org.olat.core.util.vfs.LocalFileImpl;
-import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.VirtualContainer;
-import org.olat.core.util.vfs.callbacks.ReadOnlyCallback;
-
-public class CalendarWebDAVProvider implements WebDAVProvider {
-
-	private static final String MOUNT_POINT = "calendars";
-	
-	@Override
-	public boolean hasAccess(IdentityEnvironment identityEnv) {
-		return identityEnv != null;
-	}
-	
-	@Override
-	public VFSContainer getContainer(IdentityEnvironment identityEnv) {
-		VirtualContainer calendars = new VirtualContainer("calendars");
-		calendars.setLocalSecurityCallback(new ReadOnlyCallback());
-		// get private calendar
-		CalendarManager calendarManager = CoreSpringFactory.getImpl(CalendarManager.class);
-		File fPersonalCalendar = calendarManager.getCalendarICalFile(CalendarManager.TYPE_USER, identityEnv.getIdentity().getName());
-		calendars.addItem(new LocalFileImpl(fPersonalCalendar));
-		return calendars;
-	}
-
-	@Override
-	public String getMountPoint() {
-		return MOUNT_POINT;
-	}
-}
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/util/vfs/MergeSource.java b/src/main/java/org/olat/core/util/vfs/MergeSource.java
index 10eedc406b42bdc64792bc03fb348eb4246ef037..d57476827fdf8b692996d0547468f4734416c9fa 100644
--- a/src/main/java/org/olat/core/util/vfs/MergeSource.java
+++ b/src/main/java/org/olat/core/util/vfs/MergeSource.java
@@ -134,6 +134,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSItem#getParent()
 	 */
+	@Override
 	public VFSContainer getParentContainer() {
 		return parentContainer;
 	}
@@ -141,6 +142,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSItem#setParentContainer(org.olat.core.util.vfs.VFSContainer)
 	 */
+	@Override
 	public void setParentContainer(VFSContainer parentContainer) {
 		this.parentContainer = parentContainer;
 	}
@@ -148,6 +150,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSContainer#getItems()
 	 */
+	@Override
 	public List<VFSItem> getItems() {
 		return getItems(null);
 	}
@@ -155,6 +158,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSContainer#getItems(org.olat.core.util.vfs.filters.VFSItemFilter)
 	 */
+	@Override
 	public List<VFSItem> getItems(VFSItemFilter filter) {
 		// remember: security callback and parent was already set during add to this MergeSource
 		// and refreshed on any setSecurityCallback() so no need to handle the quota of children here.
@@ -183,6 +187,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSItem#canCopyTo()
 	 */
+	@Override
 	public VFSStatus canWrite() {
 		if (rootWriteContainer == null) return VFSConstants.NO;
 		return rootWriteContainer.canWrite();
@@ -191,6 +196,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSContainer#createChildContainer(java.lang.String)
 	 */
+	@Override
 	public VFSContainer createChildContainer(String name) {
 		if (canWrite() != VFSConstants.YES) return null;
 		VFSContainer newContainer = rootWriteContainer.createChildContainer(name);
@@ -201,6 +207,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSContainer#createChildLeaf(java.lang.String)
 	 */
+	@Override
 	public VFSLeaf createChildLeaf(String name) {
 		if (canWrite() != VFSConstants.YES) return null;
 		return rootWriteContainer.createChildLeaf(name);
@@ -209,6 +216,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSContainer#copyFrom(org.olat.core.util.vfs.VFSItem)
 	 */
+	@Override
 	public VFSStatus copyFrom(VFSItem source) {
 		if (canWrite() != VFSConstants.YES) throw new AssertException("Cannot create child container in merge source if not writable.");
 		return rootWriteContainer.copyFrom(source);
@@ -217,15 +225,29 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSItem#resolveFile(java.lang.String)
 	 */
+	@Override
 	public VFSItem resolve(String path) {
 		path = VFSManager.sanitizePath(path);
 		if (path.equals("/")) return this;
 		
 		String childName = VFSManager.extractChild(path);
-		VFSItem vfsItem = null; 
+		String nextPath = path.substring(childName.length() + 1);
+		// simple case
+		for (VFSContainer container:mergedContainers) {
+			if (container.getName().equals(childName)) {
+				VFSItem vfsItem = container.resolve(nextPath);
+				// set default filter on resolved file if it is a container
+				if (vfsItem != null && vfsItem instanceof VFSContainer) {
+					VFSContainer resolvedContainer = (VFSContainer) vfsItem;
+					resolvedContainer.setDefaultItemFilter(defaultFilter);
+				}
+				return vfsItem;
+			}
+		}
+		
+		// check delegates
 		for (VFSContainer container:mergedContainers) {
-			String nextPath = path.substring(childName.length() + 1);
-			// fxdiff FXOLAT-176 a namedContainer doesn't match with its own getName()! -> work with delegate
+			// A namedContainer doesn't match with its own getName()! -> work with delegate
 			boolean nameMatch = container.getName().equals(childName);
 			if (container instanceof NamedContainerImpl && !nameMatch) {
 				// Special case: sometimes the path refers to the named containers
@@ -245,7 +267,7 @@ public class MergeSource extends AbstractVirtualContainer {
 				nameMatch = name.equals(childName);
 			}
 			if (nameMatch) {
-				vfsItem = container.resolve(nextPath);
+				VFSItem vfsItem = container.resolve(nextPath);
 				// set default filter on resolved file if it is a container
 				if (vfsItem != null && vfsItem instanceof VFSContainer) {
 					VFSContainer resolvedContainer = (VFSContainer) vfsItem;
@@ -256,11 +278,11 @@ public class MergeSource extends AbstractVirtualContainer {
 		}
 
 		for (VFSContainer container : mergedContainersChildren) {
-			// fxdiff FXOLAT-176 a namedContainer doesn't match with its own getName()! -> work with delegate
+			// A namedContainer doesn't match with its own getName()! -> work with delegate
 			if (container instanceof NamedContainerImpl) {
 				container = ((NamedContainerImpl) container).getDelegate();
 			}
-			vfsItem = container.resolve(path);
+			VFSItem vfsItem = container.resolve(path);
 			if (vfsItem != null) {
 				// set default filter on resolved file if it is a container
 				if (vfsItem instanceof VFSContainer) {
@@ -276,6 +298,7 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSItem#getLocalSecurityCallback()
 	 */
+	@Override
 	public VFSSecurityCallback getLocalSecurityCallback() {
 		return securityCallback;
 	}
@@ -283,10 +306,12 @@ public class MergeSource extends AbstractVirtualContainer {
 	/**
 	 * @see org.olat.core.util.vfs.VFSItem#setLocalSecurityCallback(org.olat.core.util.vfs.callbacks.VFSSecurityCallback)
 	 */
+	@Override
 	public void setLocalSecurityCallback(VFSSecurityCallback secCallback) {
 		securityCallback = secCallback;
 	}
 
+	@Override
 	public boolean isSame(VFSItem vfsItem) {
 		if (rootWriteContainer == null) {
 			// Unwriteable merge source (e.g. users private folder), compare on object identity 
diff --git a/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithLazyQuotaCallback.java b/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithLazyQuotaCallback.java
new file mode 100644
index 0000000000000000000000000000000000000000..64cb697e66923d5cf52d7681a656415129077526
--- /dev/null
+++ b/src/main/java/org/olat/core/util/vfs/callbacks/FullAccessWithLazyQuotaCallback.java
@@ -0,0 +1,60 @@
+/**
+ * <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.core.util.vfs.callbacks;
+
+import org.olat.admin.quota.QuotaConstants;
+import org.olat.core.commons.services.notifications.SubscriptionContext;
+import org.olat.core.util.vfs.Quota;
+import org.olat.core.util.vfs.QuotaManager;
+
+/**
+ * 
+ * Initial date: 14 févr. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FullAccessWithLazyQuotaCallback extends FullAccessWithQuotaCallback {
+	
+	private final String folderPath;
+	
+	public FullAccessWithLazyQuotaCallback(String folderPath) {
+		super(null);
+		this.folderPath = folderPath;
+	}
+	
+	public FullAccessWithLazyQuotaCallback(String folderPath, SubscriptionContext subscriptionContext) {
+		super(null, subscriptionContext);
+		this.folderPath = folderPath;
+	}
+	
+	@Override
+	public Quota getQuota() {
+		if(super.getQuota() == null) {
+			QuotaManager qm = QuotaManager.getInstance();
+			Quota q = qm.getCustomQuota(folderPath);
+			if (q == null) {
+				Quota defQuota = qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_GROUPS);
+				q = QuotaManager.getInstance().createQuota(folderPath, defQuota.getQuotaKB(), defQuota.getUlLimitKB());
+			}
+			super.setQuota(q);
+		}
+		return super.getQuota();
+	}
+}
diff --git a/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java b/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java
index b328f248d33a5a190b7bddbba9f846f56446e8f4..6ca18689d6153b7ec4f7042b9e8b625ffbc9503a 100644
--- a/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java
+++ b/src/main/java/org/olat/course/CoursefolderWebDAVMergeSource.java
@@ -66,6 +66,7 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
 		
 		Map<String, VFSContainer> terms = null;
 		VirtualContainer noTermContainer = null;
+		VirtualContainer finishedContainer = new VirtualContainer("finished");
 		
 		boolean useTerms = webDAVModule.isTermsFoldersEnabled();
 		if (useTerms) {
@@ -77,18 +78,18 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
 		
 		UniqueNames container = new UniqueNames();
 		List<RepositoryEntry> editorEntries = repositoryManager.queryByOwner(getIdentity(), "CourseModule");
-		appendCourses(editorEntries, true, containers, useTerms, terms, noTermContainer, prependReference, container);
+		appendCourses(editorEntries, true, containers, useTerms, terms, noTermContainer, finishedContainer, prependReference, container);
 		
 		//add courses as participant and coaches
 		if(webDAVModule.isEnableLearnersParticipatingCourses()) {
 			List<RepositoryEntry> entries = repositoryManager.getLearningResourcesAsParticipantAndCoach(getIdentity(), "CourseModule");
-			appendCourses(entries, false, containers, useTerms, terms, noTermContainer, prependReference, container);
+			appendCourses(entries, false, containers, useTerms, terms, noTermContainer, finishedContainer, prependReference, container);
 		}
 		
 		//add bookmarked courses
 		if(webDAVModule.isEnableLearnersBookmarksCourse()) {
 			List<RepositoryEntry> bookmarkedEntries = repositoryManager.getLearningResourcesAsBookmark(getIdentity(), identityEnv.getRoles(), "CourseModule", 0, -1);
-			appendCourses(bookmarkedEntries, false, containers, useTerms, terms, noTermContainer, prependReference, container);
+			appendCourses(bookmarkedEntries, false, containers, useTerms, terms, noTermContainer, finishedContainer, prependReference, container);
 		}
 
 		if (useTerms) {
@@ -97,12 +98,16 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
 				addContainerToList(noTermContainer, containers);
 			}
 		}
+		
+		if(finishedContainer.getItems().size() > 0) {
+			addContainerToList(finishedContainer, containers);
+		}
 
 		return containers;
 	}
 	
 	private void appendCourses(List<RepositoryEntry> courseEntries, boolean editor, List<VFSContainer> containers,
-			boolean useTerms, Map<String, VFSContainer> terms, VirtualContainer noTermContainer,
+			boolean useTerms, Map<String, VFSContainer> terms, VirtualContainer noTermContainer, VirtualContainer finishedContainer,
 			boolean prependReference, UniqueNames container) {	
 		
 		// Add all found repo entries to merge source
@@ -118,7 +123,11 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
 			}
 			String courseTitle = RequestUtil.normalizeFilename(displayName);
 			
-			if (useTerms) {
+			if(re.getRepositoryEntryStatus().isClosed()) {
+				String name = container.getFinishedUniqueName(courseTitle);
+				NamedContainerImpl cfContainer = new CoursefolderWebDAVNamedContainer(name, re, editor ? null : identityEnv);
+				finishedContainer.getItems().add(cfContainer);
+			} else if (useTerms) {
 				RepositoryEntryLifecycle lc = re.getLifecycle();
 				if (lc != null && !lc.isPrivateCycle()) {
 					// when a semester term info is found, add it to corresponding term folder
@@ -157,6 +166,7 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
 		private final Set<RepositoryEntry> duplicates = new HashSet<>();
 		private final Set<String> containers = new HashSet<>();
 		private final Set<String> noTermContainer = new HashSet<>();
+		private final Set<String> finishedContainer = new HashSet<>();
 		private final Map<String,Set<String>> termContainers = new HashMap<>();
 		
 		public boolean isDuplicate(RepositoryEntry re) {
@@ -184,6 +194,10 @@ class CoursefolderWebDAVMergeSource extends WebDAVMergeSource {
 			return getUniqueName(courseTitle, noTermContainer);
 		}
 		
+		private String getFinishedUniqueName(String courseTitle) {
+			return getUniqueName(courseTitle, finishedContainer);
+		}
+		
 		private String getContainersUniqueName(String courseTitle) {
 			return getUniqueName(courseTitle, containers);
 		}
diff --git a/src/main/java/org/olat/course/PersistingCourseImpl.java b/src/main/java/org/olat/course/PersistingCourseImpl.java
index 33bd5dfc5787c89b4982ae0f9758b2c3a3ffe601..01b34af8ec32d5a92a4156dc4f5225a54ae597c6 100644
--- a/src/main/java/org/olat/course/PersistingCourseImpl.java
+++ b/src/main/java/org/olat/course/PersistingCourseImpl.java
@@ -28,7 +28,6 @@ package org.olat.course;
 import java.io.File;
 import java.io.Serializable;
 
-import org.olat.admin.quota.QuotaConstants;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.vfs.OlatRootFolderImpl;
 import org.olat.core.commons.persistence.DBFactory;
@@ -42,11 +41,10 @@ import org.olat.core.util.FileUtils;
 import org.olat.core.util.nodes.INode;
 import org.olat.core.util.tree.TreeVisitor;
 import org.olat.core.util.tree.Visitor;
-import org.olat.core.util.vfs.Quota;
-import org.olat.core.util.vfs.QuotaManager;
 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.callbacks.FullAccessWithLazyQuotaCallback;
 import org.olat.core.util.vfs.callbacks.FullAccessWithQuotaCallback;
 import org.olat.core.util.vfs.version.Versionable;
 import org.olat.core.util.vfs.version.VersionsFileManager;
@@ -249,13 +247,7 @@ public class PersistingCourseImpl implements ICourse, OLATResourceable, Serializ
 					"could not create course's coursefolder path:" + fCourseFolder.getAbsolutePath(), null);
 		}
 		
-		QuotaManager qm = QuotaManager.getInstance();
-		Quota q = qm.getCustomQuota(isolatedCourseFolder.getRelPath());
-		if (q == null){
-			Quota defQuota = qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_COURSE);
-			q = qm.createQuota(isolatedCourseFolder.getRelPath(), defQuota.getQuotaKB(), defQuota.getUlLimitKB());
-		}
-		FullAccessWithQuotaCallback secCallback = new FullAccessWithQuotaCallback(q);
+		FullAccessWithQuotaCallback secCallback = new FullAccessWithLazyQuotaCallback(isolatedCourseFolder.getRelPath());
 		isolatedCourseFolder.setLocalSecurityCallback(secCallback);
 		return isolatedCourseFolder;
 	}
diff --git a/src/main/java/org/olat/group/GroupfoldersWebDAVMergeSource.java b/src/main/java/org/olat/group/GroupfoldersWebDAVMergeSource.java
index 0c65a25fc13c5cd51ac6f4e405997ec9a42ad650..d0e4179b3fb5ff832525b85b5d7513c20833f3a3 100644
--- a/src/main/java/org/olat/group/GroupfoldersWebDAVMergeSource.java
+++ b/src/main/java/org/olat/group/GroupfoldersWebDAVMergeSource.java
@@ -24,7 +24,6 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import org.olat.admin.quota.QuotaConstants;
 import org.olat.collaboration.CollaborationManager;
 import org.olat.collaboration.CollaborationTools;
 import org.olat.core.CoreSpringFactory;
@@ -34,10 +33,8 @@ import org.olat.core.commons.services.webdav.manager.WebDAVMergeSource;
 import org.olat.core.commons.services.webdav.servlets.RequestUtil;
 import org.olat.core.id.Identity;
 import org.olat.core.util.vfs.NamedContainerImpl;
-import org.olat.core.util.vfs.Quota;
-import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.VFSContainer;
-import org.olat.core.util.vfs.callbacks.FullAccessWithQuotaCallback;
+import org.olat.core.util.vfs.callbacks.FullAccessWithLazyQuotaCallback;
 import org.olat.core.util.vfs.callbacks.ReadOnlyCallback;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
 import org.olat.group.model.SearchBusinessGroupParams;
@@ -144,28 +141,4 @@ class GroupfoldersWebDAVMergeSource extends WebDAVMergeSource {
 		grpContainer.setLocalSecurityCallback(secCallback);
 		return grpContainer;
 	}
-	
-	private static class FullAccessWithLazyQuotaCallback extends FullAccessWithQuotaCallback {
-		
-		private final String folderPath;
-		
-		public FullAccessWithLazyQuotaCallback(String folderPath, SubscriptionContext sc) {
-			super(null, sc);
-			this.folderPath = folderPath;
-		}
-		
-		@Override
-		public Quota getQuota() {
-			if(super.getQuota() == null) {
-				QuotaManager qm = QuotaManager.getInstance();
-				Quota q = qm.getCustomQuota(folderPath);
-				if (q == null) {
-					Quota defQuota = qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_GROUPS);
-					q = QuotaManager.getInstance().createQuota(folderPath, defQuota.getQuotaKB(), defQuota.getUlLimitKB());
-				}
-				super.setQuota(q);
-			}
-			return super.getQuota();
-		}
-	}
 }