Index: java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java
===================================================================
--- java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java	(revision 100)
+++ java/main/src/main/java/com/framsticks/communication/ClientSideManagedConnection.java	(revision 101)
@@ -3,4 +3,6 @@
 import com.framsticks.communication.queries.ApplicationRequest;
 import com.framsticks.communication.queries.CallRequest;
+import com.framsticks.communication.queries.NeedFile;
+import com.framsticks.communication.queries.NeedFileAcceptor;
 import com.framsticks.communication.queries.ProtocolRequest;
 import com.framsticks.communication.queries.RegisterRequest;
@@ -43,4 +45,19 @@
 	private boolean isHandshakeDone = false;
 
+	protected NeedFileAcceptor needFileAcceptor;
+
+	/**
+	 * @return the needFileAcceptor
+	 */
+	public NeedFileAcceptor getNeedFileAcceptor() {
+		return needFileAcceptor;
+	}
+
+	/**
+	 * @param needFileAcceptor the needFileAcceptor to set
+	 */
+	public void setNeedFileAcceptor(NeedFileAcceptor needFileAcceptor) {
+		this.needFileAcceptor = needFileAcceptor;
+	}
 
 	/**
@@ -64,6 +81,4 @@
 		protocolVersion = -1;
 	}
-
-
 
 	protected List<String> readFileContent() {
@@ -116,8 +131,4 @@
 	}
 
-	private Map<Integer, SentQuery<?>> queryMap = new HashMap<>();
-
-	private SentQuery<?> currentlySentQuery;
-
 	public void send(ProtocolRequest request, ClientSideResponseFuture callback) {
 		//TODO RunAt
@@ -154,25 +165,10 @@
 		sentQuery.dispatcher = dispatcher;
 
+
 		senderThread.dispatch(new RunAt<Connection>(callback) {
 			@Override
 			protected void runAt() {
-				Integer id;
-				synchronized (ClientSideManagedConnection.this) {
-
-					while (!(requestIdEnabled || currentlySentQuery == null)) {
-						try {
-							ClientSideManagedConnection.this.wait();
-						} catch (InterruptedException ignored) {
-							break;
-						}
-					}
-					if (requestIdEnabled) {
-						queryMap.put(nextQueryId, sentQuery);
-						id = nextQueryId++;
-					} else {
-						currentlySentQuery = sentQuery;
-						id = null;
-					}
-				}
+				Integer id = sentQueries.put(null, sentQuery);
+
 				String command = sentQuery.request.getCommand();
 				StringBuilder message = new StringBuilder();
@@ -188,14 +184,6 @@
 				flushOut();
 				log.debug("sending query: {}", out);
-
 			}
 		});
-		/*
-		synchronized (this) {
-			log.debug("queueing query: {}", query);
-			queryQueue.offer(sentQuery);
-			notifyAll();
-		}
-		 */
 	}
 
@@ -204,5 +192,4 @@
 		return "client connection " + address;
 	}
-
 
 	private void sendQueryVersion(final int version, final Future<Void> future) {
@@ -229,32 +216,70 @@
 	}
 
-	private synchronized @Nonnull SentQuery<?> fetchQuery(@Nullable Integer id, boolean remove) {
-		try {
-			if (id == null) {
-				if (requestIdEnabled) {
-					throw new FramsticksException().msg("request_id is enabled and id is missing");
-				}
-				SentQuery<?> result = currentlySentQuery;
-				if (remove) {
-					currentlySentQuery = null;
-					notifyAll();
-				}
-				return result;
-			}
-
-			if (!queryMap.containsKey(id)) {
-				throw new FramsticksException().msg("id is unknown").arg("id", id);
-			}
-
-			SentQuery<?> result = queryMap.get(id);
-			if (remove) {
-				queryMap.remove(id);
-			}
-			return result;
-
-		} catch (FramsticksException e) {
-			throw new FramsticksException().msg("failed to match response to sent query").cause(e);
-		}
-	}
+	protected class IdCollection<T> {
+
+
+		protected final Map<Integer, T> map = new HashMap<>();
+		protected T current;
+
+		public Integer put(Integer idProposition, T value) {
+			synchronized (ClientSideManagedConnection.this) {
+				while (!(requestIdEnabled || current == null)) {
+					try {
+						ClientSideManagedConnection.this.wait();
+					} catch (InterruptedException ignored) {
+						break;
+					}
+				}
+				if (!requestIdEnabled) {
+					current = value;
+					return null;
+				}
+				if (idProposition == null) {
+					idProposition = nextQueryId++;
+				}
+				map.put(idProposition, value);
+				return idProposition;
+			}
+		}
+
+		public void clear(Integer id) {
+			if (requestIdEnabled) {
+				current = null;
+			} else {
+				map.remove(id);
+			}
+		}
+
+		public @Nonnull T fetch(@Nullable Integer id, boolean remove) {
+			synchronized (ClientSideManagedConnection.this) {
+				try {
+					if (id == null) {
+						if (requestIdEnabled) {
+							throw new FramsticksException().msg("request_id is enabled and id is missing");
+						}
+						T result = current;
+						current = null;
+						ClientSideManagedConnection.this.notifyAll();
+						return result;
+					}
+					if (!map.containsKey(id)) {
+						throw new FramsticksException().msg("id is unknown").arg("id", id);
+					}
+
+					T result = map.get(id);
+					if (remove) {
+						map.remove(id);
+					}
+					return result;
+
+				} catch (FramsticksException e) {
+					throw new FramsticksException().msg("failed to match response to sent query").cause(e);
+				}
+			}
+		}
+	}
+
+	protected IdCollection<SentQuery<?>> sentQueries = new IdCollection<>();
+	protected IdCollection<NeedFile> needFiles = new IdCollection<>();
 
 	private int nextQueryId = 0;
@@ -269,6 +294,6 @@
 			throw new FramsticksException().msg("expected file line").arg("got", fileLine);
 		}
-		String eventObjectPath = Request.takeGroup(rest, matcher, 1).toString();
-		String eventCalleePath = Request.takeGroup(rest, matcher, 2).toString();
+		String eventObjectPath = Strings.takeGroup(rest, matcher, 1).toString();
+		String eventCalleePath = Strings.takeGroup(rest, matcher, 2).toString();
 		final File file = new File("", new ListSource(readFileContent()));
 		log.debug("firing event {}", eventObjectPath);
@@ -277,5 +302,5 @@
 			listener = registeredListeners.get(eventObjectPath);
 		}
-		if (listener  == null) {
+		if (listener == null) {
 			throw new FramsticksException().msg("failed to find registered event").arg("event path", eventObjectPath).arg("object", eventCalleePath);
 		}
@@ -283,6 +308,48 @@
 	}
 
+	protected void processNeedFile(Pair<Integer, CharSequence> rest) {
+		final Integer id = rest.first;
+		String suggestedName = null;
+		String description = null;
+		Pair<CharSequence, CharSequence> s = Request.takeString(rest.second);
+		if (s != null) {
+			suggestedName = s.first.toString();
+			Pair<CharSequence, CharSequence> d = Request.takeString(s.second);
+			if (d != null) {
+				description = d.first.toString();
+			}
+		}
+
+		final Future<File> future = new Future<File>() {
+
+			protected void send(final File result) {
+				log.info("sending file: " + result);
+				needFiles.clear(id);
+				sendFile(null, result, id, ClientSideManagedConnection.this);
+
+			}
+
+			@Override
+			protected void result(File result) {
+				send(result);
+			}
+
+			@Override
+			public void handle(FramsticksException exception) {
+				send(new File("", ListSource.createFrom("# invalid", "# " + exception.getMessage())));
+			}
+		};
+
+		NeedFile needFile = new NeedFile(suggestedName, description, future);
+
+		if (needFileAcceptor.acceptNeed(needFile)) {
+			return;
+		}
+
+		future.handle(new FramsticksException().msg("acceptor did not accepted need"));
+	}
+
 	protected void processFile(Pair<Integer, CharSequence> rest) {
-		final SentQuery<?> sentQuery = fetchQuery(rest.first, false);
+		final SentQuery<?> sentQuery = sentQueries.fetch(rest.first, false);
 
 		String currentFilePath = rest.second.toString();
@@ -292,5 +359,4 @@
 
 		sentQuery.files.add(new File(currentFilePath, new ListSource(readFileContent())));
-
 	}
 
@@ -318,9 +384,13 @@
 			if (keyword.equals("ok") || keyword.equals("error")) {
 
-				final SentQuery<?> sentQuery = fetchQuery(rest.first, true);
+				final SentQuery<?> sentQuery = sentQueries.fetch(rest.first, true);
 
 				log.debug("parsing response for request {}", sentQuery);
 
 				sentQuery.dispatchResponseProcess(new Response(command.first.equals("ok"), rest.second.toString(), sentQuery.getFiles()));
+				return;
+			}
+			if (keyword.equals("needfile")) {
+				processNeedFile(rest);
 				return;
 			}
@@ -336,5 +406,5 @@
 		@Override
 		public void handle(FramsticksException exception) {
-			interrupt();
+			interruptJoinable();
 			// finish();
 		}
