diff --git a/config.py.example b/config.py.example
index 8e2c4b74a227b6d40dc27b8aa9cf81bb4ad3b345..8c6ba8dfe716ce43e2086c65520e6b28f1bd077f 100644
--- a/config.py.example
+++ b/config.py.example
@@ -28,3 +28,4 @@ LDAP_PORT = 636
 #ICAL_URL = 'https://user:password@mail.fsmpi.rwth-aachen.de/SOGo/....ics'
 ERROR_PAGE = 'static/500.html'
 RWTH_IP_RANGES = ['134.130.0.0/16', '137.226.0.0/16', '134.61.0.0/16', '192.35.229.0/24', '2a00:8a60::/32']
+FSMPI_IP_RANGES = []
diff --git a/icalexport.py b/icalexport.py
new file mode 100644
index 0000000000000000000000000000000000000000..f669d0fdfd5ed178957d13fa169674a742f6da64
--- /dev/null
+++ b/icalexport.py
@@ -0,0 +1,60 @@
+from server import *
+import icalendar
+from werkzeug.datastructures import Headers
+from datetime import timedelta
+
+def export_lectures(lectures, name):
+	cal = icalendar.Calendar()
+	cal.add('prodid', '-//Video AG//rwth.video//')
+	cal.add('version', '1.0')
+
+	courses = {};
+	for l in lectures:
+		event = icalendar.Event()
+		if not l['course_id'] in courses:
+			courses[l['course_id']] = query('SELECT * from courses WHERE id = ?',l['course_id'])[0]
+		c = courses[l['course_id']]
+
+		event.add('summary', c['short']+' : '+l['title'])
+		event.add('description', l['internal'])
+		event.add('comment', l['comment'])
+		event.add('categories', c['short'])
+		event.add('dtstart', l['time'])
+		event.add('location', l['place'])
+		event.add('dtend', l['time'] + timedelta(minutes=l['duration']))
+		cal.add_component(event)
+
+	H = Headers()
+	H.add_header("Content-Disposition", "inline", filename=name)
+	return Response(cal.to_ical(), mimetype="text/calendar", headers=H)
+
+def calperm(func):
+	@wraps(func)
+	def decorator(*args, **kwargs):
+		permission = ismod()
+		if 'X-Real-IP' in request.headers:
+			ip = ip_address(request.headers['X-Real-IP'])
+			for net in config['FSMPI_IP_RANGES']:
+				if ip in ip_network(net):
+					permission = True
+		if permission:
+			return func(*args, **kwargs)
+		else:
+			flash('Diese Funktion ist nur aus dem FSMPI-Netz(für SOGO-Import) oder eingeloggt verfügbar!')
+			return redirect(url_for('index'))
+	return decorator
+
+@app.route('/internal/ical/semester/<semester>')
+@calperm
+def ical_semester(semester):
+	return export_lectures(query('SELECT lectures.* FROM lectures JOIN courses ON courses.id = lectures.course_id WHERE courses.semester = ? AND lectures.visible = 1', semester),'videoag_semester_'+semester+'.ics')
+
+@app.route('/internal/ical/all')
+@calperm
+def ical_all():
+	return export_lectures(query('SELECT lectures.* FROM lectures lectures.visible = 1', semester),'videoag_all.ics')
+
+@app.route('/internal/ical/handle/<course>')
+@calperm
+def ical_course(course):
+	return export_lectures(query('SELECT lectures.* FROM lectures JOIN handles ON courses.id = lectures.course_id WHERE courses.handle = ? AND lectures.visible = 1', course),'videoag_course_'+course+'.ics')
diff --git a/server.py b/server.py
index bf47cdd1916af7e129e3224844c09a52708aaaec..7f78f610749a3f48e562648a92ae92470573a656 100644
--- a/server.py
+++ b/server.py
@@ -681,3 +681,4 @@ if 'JOBS_API_KEY' in config:
 	import jobs
 import timetable
 import chapters
+import icalexport