diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp
index 0241ee9ab..d9c79c5c3 100644
--- a/Telegram/SourceFiles/app.cpp
+++ b/Telegram/SourceFiles/app.cpp
@@ -1632,8 +1632,9 @@ namespace App {
 				convert->sticker()->loc = thumbLocation;
 			}
 
-			if (convert->location.check()) {
-				Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), convert->location);
+			const FileLocation &loc(convert->location(true));
+			if (!loc.isEmpty()) {
+				Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), loc);
 			}
 		}
 		DocumentsData::const_iterator i = documentsData.constFind(document);
diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp
index 14db723a7..4a84c87ab 100644
--- a/Telegram/SourceFiles/application.cpp
+++ b/Telegram/SourceFiles/application.cpp
@@ -709,6 +709,9 @@ void Application::checkMapVersion() {
 			}
 		}
 	}
+	if (cNeedConfigResave()) {
+		Local::writeUserSettings();
+	}
 }
 
 void Application::startApp() {
diff --git a/Telegram/SourceFiles/audio.cpp b/Telegram/SourceFiles/audio.cpp
index 9bcb19641..433e549d3 100644
--- a/Telegram/SourceFiles/audio.cpp
+++ b/Telegram/SourceFiles/audio.cpp
@@ -270,7 +270,7 @@ void audioFinish() {
 }
 
 void AudioPlayer::Msg::clearData() {
-	fname = QString();
+	file = FileLocation();
 	data = QByteArray();
 	position = duration = 0;
 	frequency = AudioVoiceMsgFrequency;
@@ -463,9 +463,9 @@ void AudioPlayer::play(const AudioMsgId &audio, int64 position) {
 			current = &_audioData[_audioCurrent];
 		}
 		current->audio = audio;
-		current->fname = audio.audio->already(true);
+		current->file = audio.audio->location(true);
 		current->data = audio.audio->data;
-		if (current->fname.isEmpty() && current->data.isEmpty()) {
+		if (current->file.isEmpty() && current->data.isEmpty()) {
 			setStoppedState(current, AudioPlayerStoppedAtError);
 			onError(audio);
 		} else {
@@ -507,9 +507,9 @@ void AudioPlayer::play(const SongMsgId &song, int64 position) {
 			current = &_songData[_songCurrent];
 		}
 		current->song = song;
-		current->fname = song.song->already(true);
+		current->file = song.song->location(true);
 		current->data = song.song->data;
-		if (current->fname.isEmpty() && current->data.isEmpty()) {
+		if (current->file.isEmpty() && current->data.isEmpty()) {
 			setStoppedState(current);
 			if (!song.song->loader) {
 				DocumentOpenLink::doOpen(song.song);
@@ -1076,13 +1076,17 @@ void AudioPlayerFader::resumeDevice() {
 
 class AudioPlayerLoader {
 public:
-	AudioPlayerLoader(const QString &fname, const QByteArray &data) : fname(fname), data(data), dataPos(0) {
+	AudioPlayerLoader(const FileLocation &file, const QByteArray &data) : file(file), access(false), data(data), dataPos(0) {
 	}
 	virtual ~AudioPlayerLoader() {
+		if (access) {
+			file.accessDisable();
+			access = false;
+		}
 	}
 
-	bool check(const QString &fname, const QByteArray &data) {
-		return this->fname == fname && this->data.size() == data.size();
+	bool check(const FileLocation &file, const QByteArray &data) {
+		return this->file == file && this->data.size() == data.size();
 	}
 
 	virtual bool open(qint64 position = 0) = 0;
@@ -1093,7 +1097,8 @@ public:
 
 protected:
 
-	QString fname;
+	FileLocation file;
+	bool access;
 	QByteArray data;
 
 	QFile f;
@@ -1102,9 +1107,16 @@ protected:
 	bool openFile() {
 		if (data.isEmpty()) {
 			if (f.isOpen()) f.close();
-			f.setFileName(fname);
+			if (!access) {
+				if (!file.accessEnable()) {
+					LOG(("Audio Error: could not open file access '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(f.error()).arg(f.errorString()));
+					return false;
+				}
+				access = true;
+			}
+			f.setFileName(file.name());
 			if (!f.open(QIODevice::ReadOnly)) {
-				LOG(("Audio Error: could not open file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(f.error()).arg(f.errorString()));
+				LOG(("Audio Error: could not open file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(f.error()).arg(f.errorString()));
 				return false;
 			}
 		}
@@ -1121,7 +1133,7 @@ static const int32 _toChannels = 2;
 class FFMpegLoader : public AudioPlayerLoader {
 public:
 
-	FFMpegLoader(const QString &fname, const QByteArray &data) : AudioPlayerLoader(fname, data),
+	FFMpegLoader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data),
 		freq(AudioVoiceMsgFrequency), fmt(AL_FORMAT_STEREO16),
 		sampleSize(2 * sizeof(short)), srcRate(AudioVoiceMsgFrequency), dstRate(AudioVoiceMsgFrequency),
 		maxResampleSamples(1024), dstSamplesData(0), len(0),
@@ -1143,7 +1155,7 @@ public:
 		}
 		fmtContext = avformat_alloc_context();
 		if (!fmtContext) {
-			LOG(("Audio Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(fname).arg(data.size()));
+			LOG(("Audio Error: Unable to avformat_alloc_context for file '%1', data size '%2'").arg(file.name()).arg(data.size()));
 			return false;
 		}
 		fmtContext->pb = ioContext;
@@ -1153,19 +1165,19 @@ public:
 		if ((res = avformat_open_input(&fmtContext, 0, 0, 0)) < 0) {
 			ioBuffer = 0;
 
-			LOG(("Audio Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+			LOG(("Audio Error: Unable to avformat_open_input for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 			return false;
 		}
 		_opened = true;
 
 		if ((res = avformat_find_stream_info(fmtContext, 0)) < 0) {
-			LOG(("Audio Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+			LOG(("Audio Error: Unable to avformat_find_stream_info for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 			return false;
 		}
 
 		streamId = av_find_best_stream(fmtContext, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
 		if (streamId < 0) {
-			LOG(("Audio Error: Unable to av_find_best_stream for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(streamId).arg(av_make_error_string(err, sizeof(err), streamId)));
+			LOG(("Audio Error: Unable to av_find_best_stream for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(streamId).arg(av_make_error_string(err, sizeof(err), streamId)));
 			return false;
 		}
 
@@ -1173,7 +1185,7 @@ public:
 		codecContext = fmtContext->streams[streamId]->codec;
 		av_opt_set_int(codecContext, "refcounted_frames", 1, 0);
 		if ((res = avcodec_open2(codecContext, codec, 0)) < 0) {
-			LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+			LOG(("Audio Error: Unable to avcodec_open2 for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 			return false;
 		}
 
@@ -1217,7 +1229,7 @@ public:
 		if (sampleSize < 0) {
 			swrContext = swr_alloc();
 			if (!swrContext) {
-				LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(fname).arg(data.size()));
+				LOG(("Audio Error: Unable to swr_alloc for file '%1', data size '%2'").arg(file.name()).arg(data.size()));
 				return false;
 			}
 			int64_t src_ch_layout = layout, dst_ch_layout = _toChannelLayout;
@@ -1233,7 +1245,7 @@ public:
 			av_opt_set_sample_fmt(swrContext, "out_sample_fmt", dst_sample_fmt, 0);
 
 			if ((res = swr_init(swrContext)) < 0) {
-				LOG(("Audio Error: Unable to swr_init for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+				LOG(("Audio Error: Unable to swr_init for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 				return false;
 			}
 
@@ -1244,7 +1256,7 @@ public:
 
 			maxResampleSamples = av_rescale_rnd(AVBlockSize / sampleSize, dstRate, srcRate, AV_ROUND_UP);
 			if ((res = av_samples_alloc_array_and_samples(&dstSamplesData, 0, _toChannels, maxResampleSamples, _toFormat, 0)) < 0) {
-				LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+				LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 				return false;
 			}
 		}
@@ -1279,7 +1291,7 @@ public:
 		if ((res = av_read_frame(fmtContext, &avpkt)) < 0) {
 			if (res != AVERROR_EOF) {
 				char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
-				LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+				LOG(("Audio Error: Unable to av_read_frame() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 			}
 			return -1;
 		}
@@ -1288,7 +1300,7 @@ public:
 			int got_frame = 0;
 			if ((res = avcodec_decode_audio4(codecContext, frame, &got_frame, &avpkt)) < 0) {
 				char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
-				LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+				LOG(("Audio Error: Unable to avcodec_decode_audio4() file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 
 				av_free_packet(&avpkt);
 				if (res == AVERROR_INVALIDDATA) return 0; // try to skip bad packet
@@ -1305,7 +1317,7 @@ public:
 						if ((res = av_samples_alloc(dstSamplesData, 0, _toChannels, maxResampleSamples, _toFormat, 1)) < 0) {
 							dstSamplesData[0] = 0;
 							char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
-							LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+							LOG(("Audio Error: Unable to av_samples_alloc for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 
 							av_free_packet(&avpkt);
 							return -1;
@@ -1313,7 +1325,7 @@ public:
 					}
 					if ((res = swr_convert(swrContext, dstSamplesData, dstSamples, (const uint8_t**)frame->extended_data, frame->nb_samples)) < 0) {
 						char err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
-						LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(fname).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
+						LOG(("Audio Error: Unable to swr_convert for file '%1', data size '%2', error %3, %4").arg(file.name()).arg(data.size()).arg(res).arg(av_make_error_string(err, sizeof(err), res)));
 
 						av_free_packet(&avpkt);
 						return -1;
@@ -1678,7 +1690,7 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
 		return 0;
 	}
 
-	if (*l && (!isGoodId || !(*l)->check(m->fname, m->data))) {
+	if (*l && (!isGoodId || !(*l)->check(m->file, m->data))) {
 		delete *l;
 		*l = 0;
 		switch (type) {
@@ -1693,23 +1705,23 @@ AudioPlayerLoader *AudioPlayerLoaders::setupLoader(MediaOverviewType type, const
 		case OverviewDocuments: _song = *static_cast<const SongMsgId*>(objId); break;
 		}
 
-		QByteArray header = m->data.mid(0, 8);
-		if (header.isEmpty()) {
-			QFile f(m->fname);
-			if (!f.open(QIODevice::ReadOnly)) {
-				LOG(("Audio Error: could not open file '%1'").arg(m->fname));
-				m->state = AudioPlayerStoppedAtStart;
-				return 0;
-			}
-			header = f.read(8);
-		}
-		if (header.size() < 8) {
-			LOG(("Audio Error: could not read header from file '%1', data size %2").arg(m->fname).arg(m->data.isEmpty() ? QFileInfo(m->fname).size() : m->data.size()));
-			m->state = AudioPlayerStoppedAtStart;
-			return 0;
-		}
+//		QByteArray header = m->data.mid(0, 8);
+//		if (header.isEmpty()) {
+//			QFile f(m->fname);
+//			if (!f.open(QIODevice::ReadOnly)) {
+//				LOG(("Audio Error: could not open file '%1'").arg(m->fname));
+//				m->state = AudioPlayerStoppedAtStart;
+//				return 0;
+//			}
+//			header = f.read(8);
+//		}
+//		if (header.size() < 8) {
+//			LOG(("Audio Error: could not read header from file '%1', data size %2").arg(m->fname).arg(m->data.isEmpty() ? QFileInfo(m->fname).size() : m->data.size()));
+//			m->state = AudioPlayerStoppedAtStart;
+//			return 0;
+//		}
 
-		*l = new FFMpegLoader(m->fname, m->data);
+		*l = new FFMpegLoader(m->file, m->data);
 
 		int ret;
 		if (!(*l)->open(position)) {
@@ -1758,7 +1770,7 @@ AudioPlayer::Msg *AudioPlayerLoaders::checkLoader(MediaOverviewType type) {
 	}
 	if (!l || !m) return 0;
 
-	if (!isGoodId || !m->loading || !(*l)->check(m->fname, m->data)) {
+	if (!isGoodId || !m->loading || !(*l)->check(m->file, m->data)) {
 		LOG(("Audio Error: playing changed while loading"));
 		return 0;
 	}
@@ -2278,7 +2290,7 @@ void AudioCaptureInner::writeFrame(int32 offset, int32 framesize) {
 class FFMpegAttributesReader : public AudioPlayerLoader {
 public:
 
-	FFMpegAttributesReader(const QString &fname, const QByteArray &data) : AudioPlayerLoader(fname, data),
+	FFMpegAttributesReader(const FileLocation &file, const QByteArray &data) : AudioPlayerLoader(file, data),
 		ioBuffer(0), ioContext(0), fmtContext(0), codec(0), streamId(0),
 		_opened(false) {
 	}
@@ -2488,7 +2500,7 @@ private:
 };
 
 MTPDocumentAttribute audioReadSongAttributes(const QString &fname, const QByteArray &data, QImage &cover, QByteArray &coverBytes, QByteArray &coverFormat) {
-	FFMpegAttributesReader reader(fname, data);
+	FFMpegAttributesReader reader(FileLocation(StorageFilePartial, fname), data);
 	if (reader.open()) {
 		int32 duration = reader.duration() / reader.frequency();
 		if (reader.duration() > 0) {
diff --git a/Telegram/SourceFiles/audio.h b/Telegram/SourceFiles/audio.h
index 97fa0c342..941323350 100644
--- a/Telegram/SourceFiles/audio.h
+++ b/Telegram/SourceFiles/audio.h
@@ -127,7 +127,7 @@ private:
 
 		void clearData();
 
-		QString fname;
+		FileLocation file;
 		QByteArray data;
 		int64 position, duration;
 		int32 frequency;
diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.cpp b/Telegram/SourceFiles/boxes/downloadpathbox.cpp
index f9a53d54c..b5d7f5d58 100644
--- a/Telegram/SourceFiles/boxes/downloadpathbox.cpp
+++ b/Telegram/SourceFiles/boxes/downloadpathbox.cpp
@@ -25,15 +25,17 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
 
 #include "downloadpathbox.h"
 #include "gui/filedialog.h"
+#include "pspecific.h"
 
-DownloadPathBox::DownloadPathBox() :
-	_path(cDownloadPath()),
-	_default(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty()),
-	_temp(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), _path == qsl("tmp")),
-	_dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp")),
-	_pathLink(this, QString(), st::defaultBoxLinkButton),
-	_save(this, lang(lng_connection_save), st::defaultBoxButton),
-	_cancel(this, lang(lng_cancel), st::cancelBoxButton) {
+DownloadPathBox::DownloadPathBox() : AbstractBox()
+, _path(cDownloadPath())
+, _pathBookmark(cDownloadPathBookmark())
+, _default(this, qsl("dir_type"), 0, lang(lng_download_path_default_radio), _path.isEmpty())
+, _temp(this, qsl("dir_type"), 1, lang(lng_download_path_temp_radio), _path == qsl("tmp"))
+, _dir(this, qsl("dir_type"), 2, lang(lng_download_path_dir_radio), !_path.isEmpty() && _path != qsl("tmp"))
+, _pathLink(this, QString(), st::defaultBoxLinkButton)
+, _save(this, lang(lng_connection_save), st::defaultBoxButton)
+, _cancel(this, lang(lng_cancel), st::cancelBoxButton) {
 
 	connect(&_save, SIGNAL(clicked()), this, SLOT(onSave()));
 	connect(&_cancel, SIGNAL(clicked()), this, SLOT(onClose()));
@@ -124,12 +126,13 @@ void DownloadPathBox::onChange() {
 void DownloadPathBox::onEditPath() {
 	filedialogInit();
 	QString path, lastPath = cDialogLastPath();
-	if (!cDownloadPath().isEmpty()) {
-		cSetDialogLastPath(cDownloadPath());
+	if (!cDownloadPath().isEmpty() && cDownloadPath() != qstr("tmp")) {
+		cSetDialogLastPath(cDownloadPath().left(cDownloadPath().size() - (cDownloadPath().endsWith('/') ? 1 : 0)));
 	}
 	if (filedialogGetDir(path, lang(lng_download_path_choose))) {
 		if (!path.isEmpty()) {
 			_path = path + '/';
+			_pathBookmark = psDownloadPathBookmark(_path);
 			setPathText(QDir::toNativeSeparators(_path));
 		}
 	}
@@ -138,6 +141,7 @@ void DownloadPathBox::onEditPath() {
 
 void DownloadPathBox::onSave() {
 	cSetDownloadPath(_default.checked() ? QString() : (_temp.checked() ? qsl("tmp") : _path));
+	cSetDownloadPathBookmark((_default.checked() || _temp.checked()) ? QByteArray() : _pathBookmark);
 	Local::writeUserSettings();
 	emit closed();
 }
diff --git a/Telegram/SourceFiles/boxes/downloadpathbox.h b/Telegram/SourceFiles/boxes/downloadpathbox.h
index 2b0432f24..c4a335e30 100644
--- a/Telegram/SourceFiles/boxes/downloadpathbox.h
+++ b/Telegram/SourceFiles/boxes/downloadpathbox.h
@@ -47,6 +47,7 @@ private:
 	void setPathText(const QString &text);
 
 	QString _path;
+	QByteArray _pathBookmark;
 
 	Radiobutton _default, _temp, _dir;
 	LinkButton _pathLink;
diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h
index 4f82b094c..21d0f725e 100644
--- a/Telegram/SourceFiles/config.h
+++ b/Telegram/SourceFiles/config.h
@@ -20,9 +20,9 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
 */
 #pragma once
 
-static const int32 AppVersion = 9013;
-static const wchar_t *AppVersionStr = L"0.9.13";
-static const bool DevVersion = false;
+static const int32 AppVersion = 9014;
+static const wchar_t *AppVersionStr = L"0.9.14";
+static const bool DevVersion = true;
 
 static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
 static const wchar_t *AppName = L"Telegram Desktop";
diff --git a/Telegram/SourceFiles/fileuploader.cpp b/Telegram/SourceFiles/fileuploader.cpp
index 12f5b4e85..3a2c7eae2 100644
--- a/Telegram/SourceFiles/fileuploader.cpp
+++ b/Telegram/SourceFiles/fileuploader.cpp
@@ -41,7 +41,7 @@ void FileUploader::uploadMedia(const FullMsgId &msgId, const ReadyLocalMedia &me
 		}
 		document->status = FileUploading;
 		if (!media.file.isEmpty()) {
-			document->location = FileLocation(StorageFilePartial, media.file);
+			document->setLocation(FileLocation(StorageFilePartial, media.file));
 		}
 	} else if (media.type == PrepareAudio) {
 		AudioData *audio = App::feedAudio(media.audio);
@@ -64,7 +64,7 @@ void FileUploader::upload(const FullMsgId &msgId, const FileLoadResultPtr &file)
 		}
 		document->status = FileUploading;
 		if (!file->filepath.isEmpty()) {
-			document->location = FileLocation(StorageFilePartial, file->filepath);
+			document->setLocation(FileLocation(StorageFilePartial, file->filepath));
 		}
 	} else if (file->type == PrepareAudio) {
 		AudioData *audio = App::feedAudio(file->audio);
diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp
index 8cd76f8b0..72a2a8d27 100644
--- a/Telegram/SourceFiles/gui/animation.cpp
+++ b/Telegram/SourceFiles/gui/animation.cpp
@@ -161,10 +161,17 @@ bool AnimatedGif::animStep(float64 ms) {
 	return true;
 }
 
-void AnimatedGif::start(HistoryItem *row, const QString &file) {
+void AnimatedGif::start(HistoryItem *row, const FileLocation &f) {
 	stop();
 
-	reader = new QImageReader(file);
+	file = new FileLocation(f);
+	if (!file->accessEnable()) {
+		stop();
+		return;
+	}
+	access = true;
+
+	reader = new QImageReader(file->name());
 	if (!reader->canRead() || !reader->supportsAnimation()) {
 		stop();
 		return;
@@ -206,6 +213,15 @@ void AnimatedGif::start(HistoryItem *row, const QString &file) {
 }
 
 void AnimatedGif::stop(bool onItemRemoved) {
+	if (file) {
+		if (access) {
+			file->accessDisable();
+		}
+		delete file;
+		file = 0;
+	}
+	access = false;
+
 	if (isNull()) return;
 
 	delete reader;
diff --git a/Telegram/SourceFiles/gui/animation.h b/Telegram/SourceFiles/gui/animation.h
index 7ed62ca0d..4f92671ed 100644
--- a/Telegram/SourceFiles/gui/animation.h
+++ b/Telegram/SourceFiles/gui/animation.h
@@ -387,17 +387,18 @@ private:
 };
 
 class HistoryItem;
+class FileLocation;
 class AnimatedGif : public QObject, public Animated {
 	Q_OBJECT
 
 public:
 
-	AnimatedGif() : msg(0), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
+	AnimatedGif() : msg(0), file(0), access(false), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
 	}
 
 	bool animStep(float64 ms);
 
-	void start(HistoryItem *row, const QString &file);
+	void start(HistoryItem *row, const FileLocation &file);
 	void stop(bool onItemRemoved = false);
 
 	bool isNull() const {
@@ -418,6 +419,8 @@ public:
 
 	HistoryItem *msg;
 	QImage img;
+	FileLocation *file;
+	bool access;
 	QImageReader *reader;
 	int32 w, h, frame;
 
diff --git a/Telegram/SourceFiles/gui/filedialog.cpp b/Telegram/SourceFiles/gui/filedialog.cpp
index 8d8ea291e..4727f81c7 100644
--- a/Telegram/SourceFiles/gui/filedialog.cpp
+++ b/Telegram/SourceFiles/gui/filedialog.cpp
@@ -89,7 +89,7 @@ bool _filedialogGetFiles(QStringList &files, QByteArray &remoteContent, const QS
 		}
         return !files.isEmpty();
     } else if (multipleFiles < -1) {
-		file = QFileDialog::getExistingDirectory(App::wnd() ? App::wnd()->filedialogParent() : 0, caption);
+		file = QFileDialog::getExistingDirectory(App::wnd() ? App::wnd()->filedialogParent() : 0, caption, startFile);
     } else if (multipleFiles < 0) {
 		file = QFileDialog::getSaveFileName(App::wnd() ? App::wnd()->filedialogParent() : 0, caption, startFile, filter);
     } else {
diff --git a/Telegram/SourceFiles/gui/images.cpp b/Telegram/SourceFiles/gui/images.cpp
index c155e512f..15cb5d552 100644
--- a/Telegram/SourceFiles/gui/images.cpp
+++ b/Telegram/SourceFiles/gui/images.cpp
@@ -24,6 +24,8 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
 #include "mainwidget.h"
 #include "localstorage.h"
 
+#include "pspecific.h"
+
 namespace {
 	typedef QMap<QString, LocalImage*> LocalImages;
 	LocalImages localImages;
@@ -712,3 +714,82 @@ StorageImage *getImage(const StorageImageLocation &location, const QByteArray &b
 	}
 	return i.value();
 }
+
+ReadAccessEnabler::ReadAccessEnabler(const PsFileBookmark *bookmark) : _bookmark(bookmark), _failed(_bookmark ? !_bookmark->enable() : false) {
+}
+
+ReadAccessEnabler::ReadAccessEnabler(const QSharedPointer<PsFileBookmark> &bookmark) : _bookmark(bookmark.data()), _failed(_bookmark ? !_bookmark->enable() : false) {
+}
+
+ReadAccessEnabler::~ReadAccessEnabler() {
+	if (_bookmark && !_failed) _bookmark->disable();
+}
+
+FileLocation::FileLocation(StorageFileType type, const QString &name) : type(type), fname(name) {
+	if (fname.isEmpty()) {
+		size = 0;
+		type = StorageFileUnknown;
+	} else {
+		setBookmark(psPathBookmark(name));
+
+		QFileInfo f(name);
+		if (f.exists()) {
+			qint64 s = f.size();
+			if (s > INT_MAX) {
+				fname = QString();
+				_bookmark.reset(0);
+				size = 0;
+				type = StorageFileUnknown;
+			} else {
+				modified = f.lastModified();
+				size = qint32(s);
+			}
+		} else {
+			fname = QString();
+			_bookmark.reset(0);
+			size = 0;
+			type = StorageFileUnknown;
+		}
+	}
+}
+
+bool FileLocation::check() const {
+	if (fname.isEmpty()) return false;
+
+	ReadAccessEnabler enabler(_bookmark);
+	if (enabler.failed()) {
+		const_cast<FileLocation*>(this)->_bookmark.reset(0);
+	}
+
+	QFileInfo f(name());
+	if (!f.exists() || !f.isReadable()) return false;
+
+	quint64 s = f.size();
+	if (s > INT_MAX) return false;
+
+	return (f.lastModified() == modified) && (qint32(s) == size);
+}
+
+const QString &FileLocation::name() const {
+	return _bookmark ? _bookmark->name(fname) : fname;
+}
+
+QByteArray FileLocation::bookmark() const {
+	return _bookmark ? _bookmark->bookmark() : QByteArray();
+}
+
+void FileLocation::setBookmark(const QByteArray &bm) {
+	if (bm.isEmpty()) {
+		_bookmark.reset(0);
+	} else {
+		_bookmark.reset(new PsFileBookmark(bm));
+	}
+}
+
+bool FileLocation::accessEnable() const {
+	return isEmpty() ? false : (_bookmark ? _bookmark->enable() : true);
+}
+
+void FileLocation::accessDisable() const {
+	return _bookmark ? _bookmark->disable() : (void)0;
+}
diff --git a/Telegram/SourceFiles/gui/images.h b/Telegram/SourceFiles/gui/images.h
index d625f0e03..384da3da1 100644
--- a/Telegram/SourceFiles/gui/images.h
+++ b/Telegram/SourceFiles/gui/images.h
@@ -240,46 +240,50 @@ void clearStorageImages();
 void clearAllImages();
 int64 imageCacheSize();
 
-struct FileLocation {
-	FileLocation(StorageFileType type, const QString &name, const QDateTime &modified, qint32 size) : type(type), name(name), modified(modified), size(size) {
-	}
-	FileLocation(StorageFileType type, const QString &name) : type(type), name(name) {
-		QFileInfo f(name);
-		if (f.exists()) {
-			qint64 s = f.size();
-			if (s > INT_MAX) {
-				this->name = QString();
-				size = 0;
-				type = StorageFileUnknown;
-			} else {
-				modified = f.lastModified();
-				size = qint32(s);
-			}
-		} else {
-			this->name = QString();
-			size = 0;
-			type = StorageFileUnknown;
-		}
+class PsFileBookmark;
+class ReadAccessEnabler {
+public:
+	ReadAccessEnabler(const PsFileBookmark *bookmark);
+	ReadAccessEnabler(const QSharedPointer<PsFileBookmark> &bookmark);
+	bool failed() const {
+		return _failed;
 	}
+	~ReadAccessEnabler();
+
+private:
+	const PsFileBookmark *_bookmark;
+	bool _failed;
+
+};
+
+class FileLocation {
+public:
+	FileLocation(StorageFileType type, const QString &name);
 	FileLocation() : size(0) {
 	}
-	bool check() const {
-		if (name.isEmpty()) return false;
-		QFileInfo f(name);
-		if (!f.exists()) return false;
 
-		quint64 s = f.size();
-		if (s > INT_MAX) return false;
-
-		return (f.lastModified() == modified) && (qint32(s) == size);
+	bool check() const;
+	const QString &name() const;
+	void setBookmark(const QByteArray &bookmark);
+	QByteArray bookmark() const;
+	bool isEmpty() const {
+		return name().isEmpty();
 	}
+
+	bool accessEnable() const;
+	void accessDisable() const;
+
 	StorageFileType type;
-	QString name;
+	QString fname;
 	QDateTime modified;
 	qint32 size;
+
+private:
+	QSharedPointer<PsFileBookmark> _bookmark;
+
 };
 inline bool operator==(const FileLocation &a, const FileLocation &b) {
-	return a.type == b.type && a.name == b.name && a.modified == b.modified && a.size == b.size;
+	return a.type == b.type && a.name() == b.name() && a.modified == b.modified && a.size == b.size;
 }
 inline bool operator!=(const FileLocation &a, const FileLocation &b) {
 	return !(a == b);
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index b909a4c86..28854b397 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -150,7 +150,7 @@ void historyInit() {
 	_initTextOptions();
 }
 
-void startGif(HistoryItem *row, const QString &file) {
+void startGif(HistoryItem *row, const FileLocation &file) {
 	if (row == animated.msg) {
 		stopGif();
 	} else {
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index fd6f49e18..8abc9b95b 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -24,7 +24,7 @@ void historyInit();
 
 class HistoryItem;
 
-void startGif(HistoryItem *row, const QString &file);
+void startGif(HistoryItem *row, const FileLocation &file);
 void itemRemovedGif(HistoryItem *item);
 void itemReplacedGif(HistoryItem *oldItem, HistoryItem *newItem);
 void stopGif();
diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp
index b1dfaecdf..bd3767822 100644
--- a/Telegram/SourceFiles/localstorage.cpp
+++ b/Telegram/SourceFiles/localstorage.cpp
@@ -579,11 +579,23 @@ namespace {
 			}
 			quint32 size = 0;
 			for (FileLocations::const_iterator i = _fileLocations.cbegin(), e = _fileLocations.cend(); i != e; ++i) {
-				// location + type + namelen + name + date + size
-				size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(i.value().name) + _dateTimeSize() + sizeof(quint32);
+				// location + type + namelen + name
+				size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(i.value().name());
+				if (AppVersion > 9013) {
+					// bookmark
+					size += _bytearraySize(i.value().bookmark());
+				}
+				// date + size
+				size += _dateTimeSize() + sizeof(quint32);
 			}
+
 			//end mark
-			size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(QString()) + _dateTimeSize() + sizeof(quint32);
+			size += sizeof(quint64) * 2 + sizeof(quint32) + _stringSize(QString());
+			if (AppVersion > 9013) {
+				size += _bytearraySize(QByteArray());
+			}
+			size += _dateTimeSize() + sizeof(quint32);
+
 			size += sizeof(quint32); // aliases count
 			for (FileLocationAliases::const_iterator i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
 				// alias + location
@@ -592,9 +604,19 @@ namespace {
 
 			EncryptedDescriptor data(size);
 			for (FileLocations::const_iterator i = _fileLocations.cbegin(); i != _fileLocations.cend(); ++i) {
-				data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(i.value().type) << i.value().name << i.value().modified << quint32(i.value().size);
+				data.stream << quint64(i.key().first) << quint64(i.key().second) << quint32(i.value().type) << i.value().name();
+				if (AppVersion > 9013) {
+					data.stream << i.value().bookmark();
+				}
+				data.stream << i.value().modified << quint32(i.value().size);
 			}
-			data.stream << quint64(0) << quint64(0) << quint32(0) << QString() << QDateTime::currentDateTime() << quint32(0);
+
+			data.stream << quint64(0) << quint64(0) << quint32(0) << QString();
+			if (AppVersion > 9013) {
+				data.stream << QByteArray();
+			}
+			data.stream << QDateTime::currentDateTime() << quint32(0);
+
 			data.stream << quint32(_fileLocationAliases.size());
 			for (FileLocationAliases::const_iterator i = _fileLocationAliases.cbegin(), e = _fileLocationAliases.cend(); i != e; ++i) {
 				data.stream << quint64(i.key().first) << quint64(i.key().second) << quint64(i.value().first) << quint64(i.value().second);
@@ -617,11 +639,17 @@ namespace {
 		bool endMarkFound = false;
 		while (!locations.stream.atEnd()) {
 			quint64 first, second;
+			QByteArray bookmark;
 			FileLocation loc;
 			quint32 type;
-			locations.stream >> first >> second >> type >> loc.name >> loc.modified >> loc.size;
+			locations.stream >> first >> second >> type >> loc.fname;
+			if (locations.version > 9013) {
+				locations.stream >> bookmark;
+			}
+			locations.stream >> loc.modified >> loc.size;
+			loc.setBookmark(bookmark);
 
-			if (!first && !second && !type && loc.name.isEmpty() && !loc.size) { // end mark
+			if (!first && !second && !type && loc.fname.isEmpty() && !loc.size) { // end mark
 				endMarkFound = true;
 				break;
 			}
@@ -629,12 +657,8 @@ namespace {
 			MediaKey key(first, second);
 			loc.type = StorageFileType(type);
 
-			if (loc.check()) {
-				_fileLocations.insert(key, loc);
-				_fileLocationPairs.insert(loc.name, FileLocationPair(key, loc));
-			} else {
-				_writeLocations();
-			}
+			_fileLocations.insert(key, loc);
+			_fileLocationPairs.insert(loc.fname, FileLocationPair(key, loc));
 		}
 
 		if (endMarkFound) {
@@ -1038,12 +1062,26 @@ namespace {
 			cSetAskDownloadPath(v == 1);
 		} break;
 
-		case dbiDownloadPath: {
+		case dbiDownloadPathOld: {
 			QString v;
 			stream >> v;
 			if (!_checkStreamStatus(stream)) return false;
 
+			if (!v.isEmpty() && v != qstr("tmp") && !v.endsWith('/')) v += '/';
 			cSetDownloadPath(v);
+			cSetDownloadPathBookmark(QByteArray());
+		} break;
+
+		case dbiDownloadPath: {
+			QString v;
+			QByteArray bookmark;
+			stream >> v >> bookmark;
+			if (!_checkStreamStatus(stream)) return false;
+
+			if (!v.isEmpty() && v != qstr("tmp") && !v.endsWith('/')) v += '/';
+			cSetDownloadPath(v);
+			cSetDownloadPathBookmark(bookmark);
+			psDownloadPathEnableAccess();
 		} break;
 
 		case dbiCompressPastedImage: {
@@ -1362,7 +1400,7 @@ namespace {
 		}
 
 		uint32 size = 14 * (sizeof(quint32) + sizeof(qint32));
-		size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath());
+		size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath()) + _bytearraySize(cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
 		size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
 		size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
 		size += sizeof(quint32) + sizeof(qint32) + (cRecentStickersPreload().isEmpty() ? cGetRecentStickers().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort));
@@ -1380,7 +1418,7 @@ namespace {
 		data.stream << quint32(dbiNotifyView) << qint32(cNotifyView());
 		data.stream << quint32(dbiWindowsNotifications) << qint32(cWindowsNotifications());
 		data.stream << quint32(dbiAskDownloadPath) << qint32(cAskDownloadPath());
-		data.stream << quint32(dbiDownloadPath) << (cAskDownloadPath() ? QString() : cDownloadPath());
+		data.stream << quint32(dbiDownloadPath) << (cAskDownloadPath() ? QString() : cDownloadPath()) << (cAskDownloadPath() ? QByteArray() : cDownloadPathBookmark());
 		data.stream << quint32(dbiCompressPastedImage) << qint32(cCompressPastedImage());
 		data.stream << quint32(dbiEmojiTab) << qint32(cEmojiTab());
 		data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
@@ -2178,14 +2216,14 @@ namespace Local {
 	}
 
 	void writeFileLocation(MediaKey location, const FileLocation &local) {
-		if (local.name.isEmpty()) return;
+		if (local.fname.isEmpty()) return;
 
 		FileLocationAliases::const_iterator aliasIt = _fileLocationAliases.constFind(location);
 		if (aliasIt != _fileLocationAliases.cend()) {
 			location = aliasIt.value();
 		}
 
-		FileLocationPairs::iterator i = _fileLocationPairs.find(local.name);
+		FileLocationPairs::iterator i = _fileLocationPairs.find(local.fname);
 		if (i != _fileLocationPairs.cend()) {
 			if (i.value().second == local) {
 				if (i.value().first != location) {
@@ -2205,7 +2243,7 @@ namespace Local {
 			}
 		}
 		_fileLocations.insert(location, local);
-		_fileLocationPairs.insert(local.name, FileLocationPair(location, local));
+		_fileLocationPairs.insert(local.fname, FileLocationPair(location, local));
 		_writeLocations(WriteMapFast);
 	}
 
@@ -2218,9 +2256,8 @@ namespace Local {
 		FileLocations::iterator i = _fileLocations.find(location);
 		for (FileLocations::iterator i = _fileLocations.find(location); (i != _fileLocations.end()) && (i.key() == location);) {
 			if (check) {
-				QFileInfo info(i.value().name);
-				if (!info.exists() || info.lastModified() != i.value().modified || info.size() != i.value().size) {
-					_fileLocationPairs.remove(i.value().name);
+				if (!i.value().check()) {
+					_fileLocationPairs.remove(i.value().fname);
 					i = _fileLocations.erase(i);
 					_writeLocations();
 					continue;
diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp
index 1d981960f..1fb04b95f 100644
--- a/Telegram/SourceFiles/mainwidget.cpp
+++ b/Telegram/SourceFiles/mainwidget.cpp
@@ -30,6 +30,7 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
 #include "boxes/confirmbox.h"
 #include "boxes/stickersetbox.h"
 #include "boxes/contactsbox.h"
+#include "boxes/downloadpathbox.h"
 
 #include "localstorage.h"
 
@@ -1585,6 +1586,7 @@ void MainWidget::messagesAffected(PeerData *peer, const MTPmessages_AffectedMess
 void MainWidget::videoLoadProgress(mtpFileLoader *loader) {
 	VideoData *video = App::video(loader->objId());
 	if (video->loader) {
+		video->status = FileReady;
 		if (video->loader->done()) {
 			video->finish();
 			QString already = video->already();
@@ -1614,7 +1616,17 @@ void MainWidget::loadFailed(mtpFileLoader *loader, bool started, const char *ret
 	if (started) {
 		connect(box, SIGNAL(confirmed()), this, retrySlot);
 	} else {
-		connect(box, SIGNAL(confirmed()), App::wnd(), SLOT(showSettings()));
+		connect(box, SIGNAL(confirmed()), this, SLOT(onDownloadPathSettings()));
+	}
+	App::wnd()->showLayer(box);
+}
+
+void MainWidget::onDownloadPathSettings() {
+	cSetDownloadPath(QString());
+	cSetDownloadPathBookmark(QByteArray());
+	DownloadPathBox *box = new DownloadPathBox();
+	if (App::wnd() && App::wnd()->settingsWidget()) {
+		connect(box, SIGNAL(closed()), App::wnd()->settingsWidget(), SLOT(onDownloadPathEdited()));
 	}
 	App::wnd()->showLayer(box);
 }
@@ -1634,6 +1646,7 @@ void MainWidget::videoLoadRetry() {
 void MainWidget::audioLoadProgress(mtpFileLoader *loader) {
 	AudioData *audio = App::audio(loader->objId());
 	if (audio->loader) {
+		audio->status = FileReady;
 		if (audio->loader->done()) {
 			audio->finish();
 			QString already = audio->already();
@@ -1688,7 +1701,7 @@ void MainWidget::audioPlayProgress(const AudioMsgId &audioId) {
 					if (f.write(audio->data) == audio->data.size()) {
 						f.close();
 						already = filename;
-						audio->location = FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename);
+						audio->setLocation(FileLocation(StorageFilePartial, filename));
 						Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputAudioFileLocation), audio->dc, audio->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
 					}
 				}
@@ -1736,7 +1749,7 @@ void MainWidget::documentPlayProgress(const SongMsgId &songId) {
 					if (f.write(document->data) == document->data.size()) {
 						f.close();
 						already = filename;
-						document->location = FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename);
+						document->setLocation(FileLocation(StorageFilePartial, filename));
 						Local::writeFileLocation(mediaKey(mtpToLocationType(mtpc_inputDocumentFileLocation), document->dc, document->id), FileLocation(mtpToStorageType(mtpc_storage_filePartial), filename));
 					}
 				}
@@ -1793,6 +1806,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
 	bool songPlayActivated = false;
 	DocumentData *document = App::document(loader->objId());
 	if (document->loader) {
+		document->status = FileReady;
 		if (document->loader->done()) {
 			document->finish();
 			QString already = document->already();
@@ -1813,16 +1827,22 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
 					}
 
 					songPlayActivated = true;
-				} else if(document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
-					QImageReader reader(already);
-					if (reader.canRead()) {
-						if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
-							startGif(item, already);
-						} else if (item) {
-							App::wnd()->showDocument(document, item);
+				} else if (document->openOnSave > 0 && document->size < MediaViewImageSizeLimit) {
+					const FileLocation &location(document->location(true));
+					if (location.accessEnable()) {
+						QImageReader reader(location.name());
+						if (reader.canRead()) {
+							if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
+								startGif(item, location);
+							} else if (item) {
+								App::wnd()->showDocument(document, item);
+							} else {
+								psOpenFile(already);
+							}
 						} else {
 							psOpenFile(already);
 						}
+						location.accessDisable();
 					} else {
 						psOpenFile(already);
 					}
diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h
index 0c64c9f9a..8393d67a9 100644
--- a/Telegram/SourceFiles/mainwidget.h
+++ b/Telegram/SourceFiles/mainwidget.h
@@ -482,6 +482,8 @@ public slots:
 	void onViewsIncrement();
 	void onActiveChannelUpdateFull();
 
+	void onDownloadPathSettings();
+
 private:
 
 	void sendReadRequest(PeerData *peer, MsgId upTo);
diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp
index aca6465ed..ef30be06e 100644
--- a/Telegram/SourceFiles/mediaview.cpp
+++ b/Telegram/SourceFiles/mediaview.cpp
@@ -453,10 +453,13 @@ bool MediaView::animStep(float64 msp) {
 			_docRadialFirst = _docRadialLast = _docRadialStart = 0;
 			a_docRadial = anim::fvalue(0, 0);
 			if (!_doc->already().isEmpty() && _doc->size < MediaViewImageSizeLimit) {
-				QString fname(_doc->already(true));
-				QImageReader reader(fname);
-				if (reader.canRead()) {
-					displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
+				const FileLocation &location(_doc->location(true));
+				if (location.accessEnable()) {
+					QImageReader reader(location.name());
+					if (reader.canRead()) {
+						displayDocument(_doc, App::histItemById(_msgmigrated ? 0 : _channel, _msgid));
+					}
+					location.accessDisable();
 				}
 			}
 		} else {
@@ -529,8 +532,33 @@ void MediaView::onToMessage() {
 void MediaView::onSaveAs() {
 	QString file;
 	if (_doc) {
-		QString cur = _doc->already(true);
-		if (cur.isEmpty()) {
+		const FileLocation &location(_doc->location(true));
+		if (location.accessEnable()) {
+			QFileInfo alreadyInfo(location.name());
+			QDir alreadyDir(alreadyInfo.dir());
+			QString name = alreadyInfo.fileName(), filter;
+			MimeType mimeType = mimeTypeForName(_doc->mime);
+			QStringList p = mimeType.globPatterns();
+			QString pattern = p.isEmpty() ? QString() : p.front();
+			if (name.isEmpty()) {
+				name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
+			}
+
+			if (pattern.isEmpty()) {
+				filter = QString();
+			} else {
+				filter = mimeType.filterString() + qsl(";;All files (*.*)");
+			}
+
+			psBringToBack(this);
+			file = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, true, alreadyDir);
+			psShowOverAll(this);
+			if (!file.isEmpty() && file != location.name()) {
+				QFile(location.name()).copy(file);
+			}
+
+			location.accessDisable();
+		} else {
 			if (_current.isNull() && _currentGif.isNull()) {
 				DocumentSaveLink::doSave(_doc, true);
 				updateControls();
@@ -539,30 +567,6 @@ void MediaView::onSaveAs() {
 				update(_saveNav);
 			}
 			updateOver(_lastMouseMovePos);
-			return;
-		}
-
-		QFileInfo alreadyInfo(cur);
-		QDir alreadyDir(alreadyInfo.dir());
-		QString name = alreadyInfo.fileName(), filter;
-		MimeType mimeType = mimeTypeForName(_doc->mime);
-		QStringList p = mimeType.globPatterns();
-		QString pattern = p.isEmpty() ? QString() : p.front();
-		if (name.isEmpty()) {
-			name = pattern.isEmpty() ? qsl(".unknown") : pattern.replace('*', QString());
-		}
-
-		if (pattern.isEmpty()) {
-			filter = QString();
-		} else {
-			filter = mimeType.filterString() + qsl(";;All files (*.*)");
-		}
-
-		psBringToBack(this);
-		file = saveFileName(lang(lng_save_file), filter, qsl("doc"), name, true, alreadyDir);
-		psShowOverAll(this);
-		if (!file.isEmpty() && file != cur) {
-			QFile(cur).copy(file);
 		}
 	} else {
 		if (!_photo || !_photo->full->loaded()) return;
@@ -609,8 +613,15 @@ void MediaView::onDownload() {
 	}
 	QString toName;
 	if (_doc) {
-		QString cur = _doc->already(true);
-		if (cur.isEmpty()) {
+		const FileLocation &location(_doc->location(true));
+		if (location.accessEnable()) {
+			if (!QDir().exists(path)) QDir().mkpath(path);
+			toName = filedialogNextFilename(_doc->name, location.name(), path);
+			if (toName != location.name() && !QFile(location.name()).copy(toName)) {
+				toName = QString();
+			}
+			location.accessDisable();
+		} else {
 			if (_current.isNull() && _currentGif.isNull()) {
 				DocumentSaveLink::doSave(_doc);
 				updateControls();
@@ -619,12 +630,6 @@ void MediaView::onDownload() {
 				update(_saveNav);
 			}
 			updateOver(_lastMouseMovePos);
-		} else {
-			if (!QDir().exists(path)) QDir().mkpath(path);
-			toName = filedialogNextFilename(_doc->name, cur, path);
-			if (toName != cur && !QFile(cur).copy(toName)) {
-				toName = QString();
-			}
 		}
 	} else {
 		if (!_photo || !_photo->full->loaded()) {
@@ -902,25 +907,26 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) { // empty
 
 	_caption = Text();
 	if (_doc) {
-		QString already = _doc->already(true);
+		const FileLocation &location(_doc->location(true));
 		if (_doc->sticker() && !_doc->sticker()->img->isNull() && _doc->sticker()->img->loaded()) {
 			_currentGif.stop();
 			_current = _doc->sticker()->img->pix();
-		} else if (!already.isEmpty()) {
-			QImageReader reader(already);
+		} else if (location.accessEnable()) {
+			QImageReader reader(location.name());
 			if (reader.canRead()) {
 				if (reader.supportsAnimation() && reader.imageCount() > 1) {
-					_currentGif.start(0, already);
+					_currentGif.start(0, location);
 					_current = QPixmap();
 				} else {
 					_currentGif.stop();
-					QPixmap pix = QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly);
+					QPixmap pix = QPixmap::fromImage(App::readImage(location.name(), 0, false), Qt::ColorOnly);
 					_current = pix;
 				}
 			} else {
 				_currentGif.stop();
 				_current = QPixmap();
 			}
+			location.accessDisable();
 		} else {
 			_currentGif.stop();
 			_current = QPixmap();
diff --git a/Telegram/SourceFiles/passcodewidget.cpp b/Telegram/SourceFiles/passcodewidget.cpp
index ff26cf5ed..5e97dc7a2 100644
--- a/Telegram/SourceFiles/passcodewidget.cpp
+++ b/Telegram/SourceFiles/passcodewidget.cpp
@@ -78,7 +78,6 @@ void PasscodeWidget::onSubmit() {
 	} else {
 		if (Local::readMap(_passcode.text().toUtf8()) != Local::ReadMapPassNeeded) {
 			cSetPasscodeBadTries(0);
-			App::app()->checkMapVersion();
 
 			MTP::start();
 			if (MTP::authedId()) {
@@ -86,6 +85,8 @@ void PasscodeWidget::onSubmit() {
 			} else {
 				App::wnd()->setupIntro(true);
 			}
+
+			App::app()->checkMapVersion();
 		} else {
 			cSetPasscodeBadTries(cPasscodeBadTries() + 1);
 			cSetPasscodeLastTry(getms(true));
diff --git a/Telegram/SourceFiles/playerwidget.cpp b/Telegram/SourceFiles/playerwidget.cpp
index a4b269de4..5a76d3f51 100644
--- a/Telegram/SourceFiles/playerwidget.cpp
+++ b/Telegram/SourceFiles/playerwidget.cpp
@@ -323,7 +323,7 @@ void PlayerWidget::preloadNext() {
 	}
 	if (next) {
 		if (HistoryDocument *document = static_cast<HistoryDocument*>(next->getMedia())) {
-			if (document->document()->already(true).isEmpty() && document->document()->data.isEmpty()) {
+			if (document->document()->location(true).isEmpty() && document->document()->data.isEmpty()) {
 				if (!document->document()->loader) {
 					DocumentOpenLink::doOpen(document->document());
 					document->document()->openOnSave = 0;
diff --git a/Telegram/SourceFiles/pspecific_linux.h b/Telegram/SourceFiles/pspecific_linux.h
index 35885c475..4aac22c21 100644
--- a/Telegram/SourceFiles/pspecific_linux.h
+++ b/Telegram/SourceFiles/pspecific_linux.h
@@ -175,5 +175,34 @@ void psUpdateOverlayed(QWidget *widget);
 inline QString psConvertFileUrl(const QString &url) {
 	return url;
 }
+inline QByteArray psDownloadPathBookmark(const QString &path) {
+	return QByteArray();
+}
+inline QByteArray psPathBookmark(const QString &path) {
+	return QByteArray();
+}
+inline void psDownloadPathEnableAccess() {
+}
+
+class PsFileBookmark {
+public:
+	PsFileBookmark(const QByteArray &bookmark) {
+	}
+	bool check() const {
+		return true;
+	}
+	bool enable() const {
+		return true;
+	}
+	void disable() const {
+	}
+	const QString &name(const QString &original) const {
+		return original;
+	}
+	QByteArray bookmark() const {
+		return QByteArray();
+	}
+
+};
 
 bool linuxMoveFile(const char *from, const char *to);
diff --git a/Telegram/SourceFiles/pspecific_mac.cpp b/Telegram/SourceFiles/pspecific_mac.cpp
index 0b0a12eb4..61cc6d1db 100644
--- a/Telegram/SourceFiles/pspecific_mac.cpp
+++ b/Telegram/SourceFiles/pspecific_mac.cpp
@@ -684,6 +684,18 @@ QString psConvertFileUrl(const QString &url) {
 	return objc_convertFileUrl(url);
 }
 
+void psDownloadPathEnableAccess() {
+	objc_downloadPathEnableAccess(cDownloadPathBookmark());
+}
+
+QByteArray psDownloadPathBookmark(const QString &path) {
+	return objc_downloadPathBookmark(path);
+}
+
+QByteArray psPathBookmark(const QString &path) {
+	return objc_pathBookmark(path);
+}
+
 QString strNotificationAboutThemeChange() {
 	const uint32 letters[] = { 0xE9005541, 0x5600DC70, 0x88001570, 0xF500D86C, 0x8100E165, 0xEE005949, 0x2900526E, 0xAE00FB74, 0x96000865, 0x7000CD72, 0x3B001566, 0x5F007361, 0xAE00B663, 0x74009A65, 0x29003054, 0xC6002668, 0x98003865, 0xFA00336D, 0xA3007A65, 0x93001443, 0xBB007868, 0xE100E561, 0x3500366E, 0xC0007A67, 0x200CA65, 0xBE00DF64, 0xE300BB4E, 0x2900D26F, 0xD500D374, 0xE900E269, 0x86008F66, 0xC4006669, 0x1C00A863, 0xE600A761, 0x8E00EE74, 0xB300B169, 0xCF00B36F, 0xE600D36E };
 	return strMakeFromLetters(letters, sizeof(letters) / sizeof(letters[0]));
diff --git a/Telegram/SourceFiles/pspecific_mac.h b/Telegram/SourceFiles/pspecific_mac.h
index 4ba32f458..1ac5a4294 100644
--- a/Telegram/SourceFiles/pspecific_mac.h
+++ b/Telegram/SourceFiles/pspecific_mac.h
@@ -198,6 +198,35 @@ void psNewVersion();
 void psUpdateOverlayed(QWidget *widget);
 QString psConvertFileUrl(const QString &url);
 
+void psDownloadPathEnableAccess();
+QByteArray psDownloadPathBookmark(const QString &path);
+QByteArray psPathBookmark(const QString &path);
+
+class PsFileBookmark {
+public:
+	PsFileBookmark(const QByteArray &bookmark) : _inner(bookmark) {
+	}
+	bool check() const {
+		return _inner.valid();
+	}
+	bool enable() const {
+		return _inner.enable();
+	}
+	void disable() const {
+		return _inner.disable();
+	}
+	const QString &name(const QString &original) const {
+		return _inner.name(original);
+	}
+	QByteArray bookmark() const {
+		return _inner.bookmark();
+	}
+
+private:
+	objc_FileBookmark _inner;
+
+};
+
 QString strNotificationAboutThemeChange();
 QString strStyleOfInterface();
 QString strNeedToReload();
diff --git a/Telegram/SourceFiles/pspecific_mac_p.h b/Telegram/SourceFiles/pspecific_mac_p.h
index b5ade3c85..b55366c0a 100644
--- a/Telegram/SourceFiles/pspecific_mac_p.h
+++ b/Telegram/SourceFiles/pspecific_mac_p.h
@@ -82,3 +82,20 @@ QString objc_downloadPath();
 QString objc_currentCountry();
 QString objc_currentLang();
 QString objc_convertFileUrl(const QString &url);
+QByteArray objc_downloadPathBookmark(const QString &path);
+QByteArray objc_pathBookmark(const QString &path);
+void objc_downloadPathEnableAccess(const QByteArray &bookmark);
+
+class objc_FileBookmark {
+public:
+	objc_FileBookmark(const QByteArray &bookmark);
+	bool valid() const;
+	bool enable() const;
+	void disable() const;
+
+	const QString &name(const QString &original) const;
+	QByteArray bookmark() const;
+
+	~objc_FileBookmark();
+
+};
diff --git a/Telegram/SourceFiles/pspecific_mac_p.mm b/Telegram/SourceFiles/pspecific_mac_p.mm
index d02aede57..edcf51948 100644
--- a/Telegram/SourceFiles/pspecific_mac_p.mm
+++ b/Telegram/SourceFiles/pspecific_mac_p.mm
@@ -931,8 +931,16 @@ void objc_start() {
 															   name: NSWorkspaceDidWakeNotification object: NULL];
 }
 
+namespace {
+	NSURL *_downloadPathUrl = nil;
+}
+
 void objc_finish() {
 	[_sharedDelegate release];
+	if (_downloadPathUrl) {
+		[_downloadPathUrl stopAccessingSecurityScopedResource];
+		_downloadPathUrl = nil;
+	}
 }
 
 void objc_registerCustomScheme() {
@@ -1054,3 +1062,38 @@ QString objc_convertFileUrl(const QString &url) {
 	return objcString(nsurl);
 }
 
+QByteArray objc_downloadPathBookmark(const QString &path) {
+	return QByteArray();
+}
+
+QByteArray objc_pathBookmark(const QString &path) {
+	return QByteArray();
+}
+
+void objc_downloadPathEnableAccess(const QByteArray &bookmark) {
+}
+
+objc_FileBookmark::objc_FileBookmark(const QByteArray &bookmark) {
+}
+
+bool objc_FileBookmark::valid() const {
+	return true;
+}
+
+bool objc_FileBookmark::enable() const {
+	return true;
+}
+
+void objc_FileBookmark::disable() const {
+}
+
+const QString &objc_FileBookmark::name(const QString &original) const {
+	return original;
+}
+
+QByteArray objc_FileBookmark::bookmark() const {
+	return QByteArray();
+}
+
+objc_FileBookmark::~objc_FileBookmark() {
+}
diff --git a/Telegram/SourceFiles/pspecific_wnd.h b/Telegram/SourceFiles/pspecific_wnd.h
index be9bb8b6f..279de4c60 100644
--- a/Telegram/SourceFiles/pspecific_wnd.h
+++ b/Telegram/SourceFiles/pspecific_wnd.h
@@ -177,3 +177,32 @@ void psUpdateOverlayed(TWidget *widget);
 inline QString psConvertFileUrl(const QString &url) {
 	return url;
 }
+inline QByteArray psDownloadPathBookmark(const QString &path) {
+	return QByteArray();
+}
+inline QByteArray psPathBookmark(const QString &path) {
+	return QByteArray();
+}
+inline void psDownloadPathEnableAccess() {
+}
+
+class PsFileBookmark {
+public:
+	PsFileBookmark(const QByteArray &bookmark) {
+	}
+	bool check() const {
+		return true;
+	}
+	bool enable() const {
+		return true;
+	}
+	void disable() const {
+	}
+	const QString &name(const QString &original) const {
+		return original;
+	}
+	QByteArray bookmark() const {
+		return QByteArray();
+	}
+
+};
diff --git a/Telegram/SourceFiles/settings.cpp b/Telegram/SourceFiles/settings.cpp
index 99e07e946..4ada1bf2d 100644
--- a/Telegram/SourceFiles/settings.cpp
+++ b/Telegram/SourceFiles/settings.cpp
@@ -74,6 +74,7 @@ DBIDefaultAttach gDefaultAttach = dbidaDocument;
 bool gReplaceEmojis = true;
 bool gAskDownloadPath = false;
 QString gDownloadPath;
+QByteArray gDownloadPathBookmark;
 
 bool gNeedConfigResave = false;
 
diff --git a/Telegram/SourceFiles/settings.h b/Telegram/SourceFiles/settings.h
index 5e9145025..b336e6ec0 100644
--- a/Telegram/SourceFiles/settings.h
+++ b/Telegram/SourceFiles/settings.h
@@ -134,6 +134,7 @@ DeclareSetting(bool, ReplaceEmojis);
 DeclareReadSetting(bool, ManyInstance);
 DeclareSetting(bool, AskDownloadPath);
 DeclareSetting(QString, DownloadPath);
+DeclareSetting(QByteArray, DownloadPathBookmark);
 DeclareSetting(QByteArray, LocalSalt);
 DeclareSetting(DBIScale, RealScale);
 DeclareSetting(DBIScale, ScreenScale);
diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp
index 8934fa08c..4731fd57e 100644
--- a/Telegram/SourceFiles/structs.cpp
+++ b/Telegram/SourceFiles/structs.cpp
@@ -710,7 +710,7 @@ void VideoCancelLink::onClick(Qt::MouseButton button) const {
 
 VideoData::VideoData(const VideoId &id, const uint64 &access, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size) :
 id(id), access(access), date(date), duration(duration), w(w), h(h), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), fileType(0), openOnSave(0), loader(0) {
-	location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
+	_location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
 }
 
 void VideoData::save(const QString &toFile) {
@@ -722,9 +722,12 @@ void VideoData::save(const QString &toFile) {
 }
 
 QString VideoData::already(bool check) {
-	if (!check) return location.name;
-	if (!location.check()) location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
-	return location.name;
+	return location(check).name();
+}
+
+const FileLocation &VideoData::location(bool check) {
+	if (check && !_location.check()) _location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
+	return _location;
 }
 
 void AudioOpenLink::onClick(Qt::MouseButton button) const {
@@ -818,7 +821,7 @@ bool StickerData::setInstalled() const {
 
 AudioData::AudioData(const AudioId &id, const uint64 &access, int32 date, const QString &mime, int32 duration, int32 dc, int32 size) :
 id(id), access(access), date(date), mime(mime), duration(duration), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), loader(0) {
-	location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
+	_location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
 }
 
 void AudioData::save(const QString &toFile) {
@@ -830,17 +833,20 @@ void AudioData::save(const QString &toFile) {
 }
 
 QString AudioData::already(bool check) {
-	if (!check) return location.name;
-	if (!location.check()) location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
-	return location.name;
+	return location(check).name();
+}
+
+const FileLocation &AudioData::location(bool check) {
+	if (check && !_location.check()) _location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
+	return _location;
 }
 
 void DocumentOpenLink::doOpen(DocumentData *data) {
 	if (!data->date) return;
 
 	bool play = data->song() && App::hoveredLinkItem() && audioPlayer();
-	QString already = data->already(true);
-	if (!already.isEmpty() || (!data->data.isEmpty() && play)) {
+	const FileLocation &location(data->location(true));
+	if (!location.isEmpty() || (!data->data.isEmpty() && play)) {
 		if (play) {
 			SongMsgId playing;
 			AudioPlayerState playingState = AudioPlayerStopped;
@@ -852,21 +858,22 @@ void DocumentOpenLink::doOpen(DocumentData *data) {
 				audioPlayer()->play(song);
 				if (App::main()) App::main()->documentPlayProgress(song);
 			}
-		} else if (data->size < MediaViewImageSizeLimit) {
-			QImageReader reader(already);
+		} else if (data->size < MediaViewImageSizeLimit && location.accessEnable()) {
+			QImageReader reader(location.name());
 			if (reader.canRead()) {
 				if (reader.supportsAnimation() && reader.imageCount() > 1 && App::hoveredLinkItem()) {
-					startGif(App::hoveredLinkItem(), already);
+					startGif(App::hoveredLinkItem(), location);
 				} else if (App::hoveredLinkItem() || App::contextItem()) {
 					App::wnd()->showDocument(data, App::hoveredLinkItem() ? App::hoveredLinkItem() : App::contextItem());
 				} else {
-					psOpenFile(already);
+					psOpenFile(location.name());
 				}
 			} else {
-				psOpenFile(already);
+				psOpenFile(location.name());
 			}
+			location.accessDisable();
 		} else {
-			psOpenFile(already);
+			psOpenFile(location.name());
 		}
 		return;
 	}
@@ -954,7 +961,7 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
 DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) :
 id(id), type(FileDocument), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), loader(0), _additional(0) {
 	setattributes(attributes);
-	location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
+	_location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
 }
 
 void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) {
@@ -1016,9 +1023,12 @@ void DocumentData::save(const QString &toFile) {
 }
 
 QString DocumentData::already(bool check) {
-	if (!check) return location.name;
-	if (!location.check()) location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
-	return location.name;
+	return location(check).name();
+}
+
+const FileLocation &DocumentData::location(bool check) {
+	if (check && !_location.check()) _location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
+	return _location;
 }
 
 WebPageData::WebPageData(const WebPageId &id, WebPageType type, const QString &url, const QString &displayUrl, const QString &siteName, const QString &title, const QString &description, PhotoData *photo, DocumentData *doc, int32 duration, const QString &author, int32 pendingTill) :
diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h
index c29b5fd85..1bc85bf05 100644
--- a/Telegram/SourceFiles/structs.h
+++ b/Telegram/SourceFiles/structs.h
@@ -807,7 +807,7 @@ struct VideoData {
 			l->deleteLater();
 			l->rpcInvalidate();
 		}
-		location = FileLocation();
+		_location = FileLocation();
 		if (!beforeDownload) {
 			openOnSave = 0;
 			openOnSaveMsgId = FullMsgId();
@@ -816,7 +816,7 @@ struct VideoData {
 
 	void finish() {
 		if (loader->done()) {
-			location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
+			_location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
 		}
 		loader->deleteLater();
 		loader->rpcInvalidate();
@@ -824,6 +824,7 @@ struct VideoData {
 	}
 
 	QString already(bool check = false);
+	const FileLocation &location(bool check = false);
 
 	VideoId id;
 	uint64 access;
@@ -841,7 +842,10 @@ struct VideoData {
 	int32 openOnSave;
 	FullMsgId openOnSaveMsgId;
 	mtpFileLoader *loader;
-	FileLocation location;
+
+private:
+	FileLocation _location;
+
 };
 
 class VideoLink : public ITextLink {
@@ -902,7 +906,7 @@ struct AudioData {
 			l->deleteLater();
 			l->rpcInvalidate();
 		}
-		location = FileLocation();
+		_location = FileLocation();
 		if (!beforeDownload) {
 			openOnSave = 0;
 			openOnSaveMsgId = FullMsgId();
@@ -911,7 +915,7 @@ struct AudioData {
 
 	void finish() {
 		if (loader->done()) {
-			location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
+			_location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
 			data = loader->bytes();
 		}
 		loader->deleteLater();
@@ -920,6 +924,12 @@ struct AudioData {
 	}
 
 	QString already(bool check = false);
+	const FileLocation &location(bool check = false);
+	void setLocation(const FileLocation &loc) {
+		if (loc.check()) {
+			_location = loc;
+		}
+	}
 
 	AudioId id;
 	uint64 access;
@@ -935,9 +945,12 @@ struct AudioData {
 	int32 openOnSave;
 	FullMsgId openOnSaveMsgId;
 	mtpFileLoader *loader;
-	FileLocation location;
 	QByteArray data;
 	int32 md5[8];
+
+private:
+	FileLocation _location;
+
 };
 
 struct AudioMsgId {
@@ -1068,7 +1081,7 @@ struct DocumentData {
 			l->deleteLater();
 			l->rpcInvalidate();
 		}
-		location = FileLocation();
+		_location = FileLocation();
 		if (!beforeDownload) {
 			openOnSave = 0;
 			openOnSaveMsgId = FullMsgId();
@@ -1077,7 +1090,7 @@ struct DocumentData {
 
 	void finish() {
 		if (loader->done()) {
-			location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
+			_location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
 			data = loader->bytes();
 			if (sticker() && !loader->imagePixmap().isNull()) {
 				sticker()->img = ImagePtr(data, loader->imageFormat(), loader->imagePixmap());
@@ -1092,6 +1105,12 @@ struct DocumentData {
 	}
 
 	QString already(bool check = false);
+	const FileLocation &location(bool check = false);
+	void setLocation(const FileLocation &loc) {
+		if (loc.check()) {
+			_location = loc;
+		}
+	}
 	StickerData *sticker() {
 		return (type == StickerDocument) ? static_cast<StickerData*>(_additional) : 0;
 	}
@@ -1115,12 +1134,15 @@ struct DocumentData {
 	int32 openOnSave;
 	FullMsgId openOnSaveMsgId;
 	mtpFileLoader *loader;
-	FileLocation location;
 
 	QByteArray data;
 	DocumentAdditionalData *_additional;
 
 	int32 md5[8];
+
+private:
+
+	FileLocation _location;
 };
 
 struct SongMsgId {
diff --git a/Telegram/SourceFiles/types.h b/Telegram/SourceFiles/types.h
index c93a6746e..48aa03522 100644
--- a/Telegram/SourceFiles/types.h
+++ b/Telegram/SourceFiles/types.h
@@ -258,7 +258,7 @@ enum DataBlockId {
 	dbiCatsAndDogs          = 0x12,
 	dbiReplaceEmojis        = 0x13,
 	dbiAskDownloadPath      = 0x14,
-	dbiDownloadPath         = 0x15,
+	dbiDownloadPathOld      = 0x15,
 	dbiScale                = 0x16,
 	dbiEmojiTab             = 0x17,
 	dbiRecentEmojisOld      = 0x18,
@@ -282,6 +282,7 @@ enum DataBlockId {
 	dbiWindowsNotifications = 0x30,
 	dbiIncludeMuted         = 0x31,
 	dbiMaxMegaGroupCount    = 0x32,
+	dbiDownloadPath         = 0x33,
 
 	dbiEncryptedWithSalt    = 333,
 	dbiEncrypted            = 444,