mod_netconf: refactoring
diff --git a/src/mod_netconf.c b/src/mod_netconf.c
index 7f5c2fb..d5ae61b 100644
--- a/src/mod_netconf.c
+++ b/src/mod_netconf.c
@@ -915,26 +915,454 @@
 	return buffer;
 }
 
+NC_DATASTORE parse_datastore(const char *ds)
+{
+	if (strcmp(ds, "running") == 0) {
+		return NC_DATASTORE_RUNNING;
+	} else if (strcmp(ds, "startup") == 0) {
+		return NC_DATASTORE_STARTUP;
+	} else if (strcmp(ds, "candidate") == 0) {
+		return NC_DATASTORE_CANDIDATE;
+	}
+	return -1;
+}
+
+json_object *create_error(const char *errmess)
+{
+	json_object *reply = json_object_new_object();
+	json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
+	json_object_object_add(reply, "error-message", json_object_new_string(errmess));
+	return reply;
+
+}
+
+json_object *create_data(const char *data)
+{
+	json_object *reply = json_object_new_object();
+	json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
+	json_object_object_add(reply, "data", json_object_new_string(data));
+	return reply;
+}
+
+json_object *handle_op_connect(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list)
+{
+	const char *host = NULL;
+	const char *port = NULL;
+	const char *user = NULL;
+	const char *pass = NULL;
+	json_object *capabilities = NULL;
+	json_object *reply = NULL;
+	char *session_key_hash = NULL;
+	struct nc_cpblts* cpblts = NULL;
+	unsigned int len, i;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: Connect");
+	host = json_object_get_string(json_object_object_get((json_object *) request, "host"));
+	port = json_object_get_string(json_object_object_get((json_object *) request, "port"));
+	user = json_object_get_string(json_object_object_get((json_object *) request, "user"));
+	pass = json_object_get_string(json_object_object_get((json_object *) request, "pass"));
+
+	capabilities = json_object_object_get((json_object *) request, "capabilities");
+	if ((capabilities != NULL) && ((len = json_object_array_length(capabilities)) > 0)) {
+		cpblts = nc_cpblts_new(NULL);
+		for (i=0; i<len; i++) {
+			nc_cpblts_add(cpblts, json_object_get_string(json_object_array_get_idx(capabilities, i)));
+		}
+	} else {
+		ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "no capabilities specified");
+	}
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "host: %s, port: %s, user: %s", host, port, user);
+	if ((host == NULL) || (user == NULL)) {
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Cannot connect - insufficient input.");
+		session_key_hash = NULL;
+	} else {
+		session_key_hash = netconf_connect(server, pool, netconf_sessions_list, host, port, user, pass, cpblts);
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "hash: %s", session_key_hash);
+	}
+	if (cpblts != NULL) {
+		nc_cpblts_free(cpblts);
+	}
+
+	if (session_key_hash == NULL) {
+		/* negative reply */
+		if (err_reply == NULL) {
+			reply = json_object_new_object();
+			json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
+			json_object_object_add(reply, "error-message", json_object_new_string("Connecting NETCONF server failed."));
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Connection failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Connect - error from libnetconf's callback.");
+		}
+	} else {
+		/* positive reply */
+		reply = json_object_new_object();
+		json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+		json_object_object_add(reply, "session", json_object_new_string(session_key_hash));
+
+		free(session_key_hash);
+	}
+	return reply;
+}
+
+json_object *handle_op_get(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	const char *filter = NULL;
+	const char *data = NULL;
+	json_object *reply = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get (session %s)", session_key);
+
+	filter = json_object_get_string(json_object_object_get(request, "filter"));
+
+	if ((data = netconf_get(server, netconf_sessions_list, session_key, filter)) == NULL) {
+		if (err_reply == NULL) {
+			reply = create_error("Get information from device failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		return create_data(data);
+	}
+	return reply;
+}
+
+json_object *handle_op_getconfig(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	NC_DATASTORE ds_type_s = -1;
+	NC_DATASTORE ds_type_t = -1;
+	const char *filter = NULL;
+	const char *data = NULL;
+	const char *source = NULL;
+	const char *target = NULL;
+	json_object *reply = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get-config (session %s)", session_key);
+
+	filter = json_object_get_string(json_object_object_get(request, "filter"));
+
+	/* get parameters */
+	if ((target = json_object_get_string(json_object_object_get(request, "target"))) != NULL) {
+		ds_type_t = parse_datastore(target);
+	}
+	if ((source = json_object_get_string(json_object_object_get(request, "source"))) != NULL) {
+		ds_type_s = parse_datastore(source);
+	}
+	if (ds_type_s == -1) {
+		return create_error("Invalid source repository type requested.");
+	}
+
+	if ((data = netconf_getconfig(server, netconf_sessions_list, session_key, ds_type_s, filter)) == NULL) {
+		if (err_reply == NULL) {
+			reply = create_error("Get configuration information from device failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		return create_data(data);
+	}
+	return reply;
+}
+
+json_object *handle_op_getschema(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	const char *data = NULL;
+	const char *identifier = NULL;
+	const char *version = NULL;
+	const char *format = NULL;
+	json_object *reply = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get-schema (session %s)", session_key);
+	identifier = json_object_get_string(json_object_object_get(request, "identifier"));
+	if (identifier == NULL) {
+		return create_error("No identifier for get-schema supplied.");
+	}
+	version = json_object_get_string(json_object_object_get(request, "version"));
+	format = json_object_get_string(json_object_object_get(request, "format"));
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "get-schema(version: %s, format: %s)", version, format);
+	if ((data = netconf_getschema(server, netconf_sessions_list, session_key, identifier, version, format)) == NULL) {
+		if (err_reply == NULL) {
+			reply = create_error("Get schema failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		return create_data(data);
+	}
+	return reply;
+}
+
+json_object *handle_op_editconfig(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	NC_DATASTORE ds_type_s = -1;
+	NC_DATASTORE ds_type_t = -1;
+	NC_EDIT_DEFOP_TYPE defop_type = NC_EDIT_DEFOP_NOTSET;
+	NC_EDIT_ERROPT_TYPE erropt_type = 0;
+	const char *defop = NULL;
+	const char *erropt = NULL;
+	const char *config = NULL;
+	const char *source = NULL;
+	const char *target = NULL;
+	json_object *reply = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: edit-config (session %s)", session_key);
+
+	defop = json_object_get_string(json_object_object_get(request, "default-operation"));
+	if (defop != NULL) {
+		if (strcmp(defop, "merge") == 0) {
+			defop_type = NC_EDIT_DEFOP_MERGE;
+		} else if (strcmp(defop, "replace") == 0) {
+			defop_type = NC_EDIT_DEFOP_REPLACE;
+		} else if (strcmp(defop, "none") == 0) {
+			defop_type = NC_EDIT_DEFOP_NONE;
+		} else {
+			return create_error("Invalid default-operation parameter.");
+		}
+	} else {
+		defop_type = NC_EDIT_DEFOP_NOTSET;
+	}
+
+	erropt = json_object_get_string(json_object_object_get(request, "error-option"));
+	if (erropt != NULL) {
+		if (strcmp(erropt, "continue-on-error") == 0) {
+			erropt_type = NC_EDIT_ERROPT_CONT;
+		} else if (strcmp(erropt, "stop-on-error") == 0) {
+			erropt_type = NC_EDIT_ERROPT_STOP;
+		} else if (strcmp(erropt, "rollback-on-error") == 0) {
+			erropt_type = NC_EDIT_ERROPT_ROLLBACK;
+		} else {
+			return create_error("Invalid error-option parameter.");
+		}
+	} else {
+		erropt_type = 0;
+	}
+
+	/* get parameters */
+	if ((target = json_object_get_string(json_object_object_get(request, "target"))) != NULL) {
+		ds_type_t = parse_datastore(target);
+	}
+	if ((source = json_object_get_string(json_object_object_get(request, "source"))) != NULL) {
+		ds_type_s = parse_datastore(source);
+	}
+	if (ds_type_t == -1) {
+		return create_error("Invalid target repository type requested.");
+	}
+
+	config = json_object_get_string(json_object_object_get(request, "config"));
+	if (config == NULL) {
+		return create_error("Invalid config data parameter.");
+	}
+
+	if (netconf_editconfig(server, netconf_sessions_list, session_key, ds_type_t, defop_type, erropt_type, NC_EDIT_TESTOPT_NOTSET, config) != EXIT_SUCCESS) {
+		if (err_reply == NULL) {
+			reply = create_error("Edit-config failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		reply = json_object_new_object();
+		json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+	}
+	return reply;
+}
+
+json_object *handle_op_copyconfig(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	NC_DATASTORE ds_type_s = -1;
+	NC_DATASTORE ds_type_t = -1;
+	const char *config = NULL;
+	const char *target = NULL;
+	const char *source = NULL;
+	json_object *reply = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: copy-config (session %s)", session_key);
+
+	/* get parameters */
+	if ((target = json_object_get_string(json_object_object_get(request, "target"))) != NULL) {
+		ds_type_t = parse_datastore(target);
+	}
+	if ((source = json_object_get_string(json_object_object_get(request, "source"))) != NULL) {
+		ds_type_s = parse_datastore(source);
+	}
+	if (source == NULL) {
+		/* no explicit source specified -> use config data */
+		ds_type_s = NC_DATASTORE_CONFIG;
+		config = json_object_get_string(json_object_object_get(request, "config"));
+	} else if (ds_type_s == -1) {
+		/* source datastore specified, but it is invalid */
+		return create_error("Invalid source repository type requested.");
+	}
+
+	if (ds_type_t == -1) {
+		/* invalid target datastore specified */
+		return create_error("Invalid target repository type requested.");
+	}
+
+	if (source == NULL && config == NULL) {
+		reply = create_error("invalid input parameters - one of source and config is required.");
+	} else {
+		if (netconf_copyconfig(server, netconf_sessions_list, session_key, ds_type_s, ds_type_t, config, "") != EXIT_SUCCESS) {
+			if (err_reply == NULL) {
+				reply = create_error("Copying of configuration failed.");
+			} else {
+				/* use filled err_reply from libnetconf's callback */
+				reply = err_reply;
+			}
+		} else {
+			reply = json_object_new_object();
+			json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+		}
+	}
+	return reply;
+}
+
+json_object *handle_op_generic(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	json_object *reply = NULL;
+	const char *config = NULL;
+	char *data = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: generic request for session %s", session_key);
+
+	config = json_object_get_string(json_object_object_get(request, "content"));
+
+	if (config == NULL) {
+		return create_error("Missing content parameter.");
+	}
+
+	if (netconf_generic(server, netconf_sessions_list, session_key, config, &data) != EXIT_SUCCESS) {
+		if (err_reply == NULL) {
+			reply = create_error("Killing of session failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		if (data == NULL) {
+			reply = json_object_new_object();
+			json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+		} else {
+			return create_data(data);
+		}
+	}
+	return reply;
+}
+
+json_object *handle_op_disconnect(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	json_object *reply = NULL;
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: Disconnect session %s", session_key);
+
+	if (netconf_close(server, netconf_sessions_list, session_key) != EXIT_SUCCESS) {
+		if (err_reply == NULL) {
+			reply = create_error("Invalid session identifier.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		reply = json_object_new_object();
+		json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+	}
+	return reply;
+}
+
+json_object *handle_op_kill(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	json_object *reply = NULL;
+	const char *sid = NULL;
+
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: kill-session, session %s", session_key);
+
+	sid = json_object_get_string(json_object_object_get(request, "session-id"));
+
+	if (sid == NULL) {
+		return create_error("Missing session-id parameter.");
+	}
+
+	if (netconf_killsession(server, netconf_sessions_list, session_key, sid) != EXIT_SUCCESS) {
+		if (err_reply == NULL) {
+			reply = create_error("Killing of session failed.");
+		} else {
+			/* use filled err_reply from libnetconf's callback */
+			reply = err_reply;
+		}
+	} else {
+		reply = json_object_new_object();
+		json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
+	}
+	return reply;
+}
+
+json_object *handle_op_reloadhello(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	struct session_with_mutex * locked_session = NULL;
+	json_object *reply = NULL;
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get info about session %s", session_key);
+
+	locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+	if ((locked_session != NULL) && (locked_session->hello_message != NULL)) {
+		ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "creating temporal NC session.");
+		struct nc_session *temp_session = nc_session_connect_channel(locked_session->session, NULL);
+		if (temp_session != NULL) {
+			prepare_status_message(server, locked_session, temp_session);
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "closing temporal NC session.");
+			nc_session_close(temp_session, NC_SESSION_TERM_CLOSED);
+		} else {
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Reload hello failed due to channel establishment");
+			reply = create_error("Reload was unsuccessful, connection failed.");
+		}
+	} else {
+		reply = create_error("Invalid session identifier.");
+	}
+
+	if ((reply == NULL) && (locked_session->hello_message != NULL)) {
+		reply = locked_session->hello_message;
+	}
+	return reply;
+}
+
+json_object *handle_op_info(server_rec *server, apr_pool_t *pool, json_object *request, apr_hash_t *netconf_sessions_list, const char *session_key)
+{
+	json_object *reply = NULL;
+	struct session_with_mutex * locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+	ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get info about session %s", session_key);
+
+	locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
+	if (locked_session != NULL) {
+		if (locked_session->hello_message != NULL) {
+			reply = locked_session->hello_message;
+		} else {
+			reply = create_error("Invalid session identifier.");
+		}
+	} else {
+		reply = create_error("Invalid session identifier.");
+	}
+
+	return reply;
+}
+
 void * thread_routine (void * arg)
 {
 	void * retval = NULL;
 	struct pollfd fds;
 	json_object *request = NULL;
 	json_object *reply = NULL;
-	json_object *capabilities = NULL;
 	int operation;
-	int i, len, status= 0;
-	char *session_key_hash = NULL;
-	char *data;
-	const char *host, *port, *user, *pass;
+	int status = 0;
 	const char *msgtext;
-	const char *target, *source, *filter, *config, *defop, *erropt, *sid, *session_key;
-	const char *identifier, *version, *format;
-	struct nc_cpblts* cpblts = NULL;
-	struct session_with_mutex * locked_session;
-	NC_DATASTORE ds_type_s, ds_type_t;
-	NC_EDIT_DEFOP_TYPE defop_type = NC_EDIT_DEFOP_NOTSET;
-	NC_EDIT_ERROPT_TYPE erropt_type = 0;
+	const char *session_key;
+	const char *target = NULL;
+	const char *source = NULL;
+	NC_DATASTORE ds_type_t = -1;
+	NC_DATASTORE ds_type_s = -1;
 	char *chunked_out_msg = NULL;
 	apr_pool_t * pool = ((struct pass_to_thread*)arg)->pool;
 	apr_hash_t *netconf_sessions_list = ((struct pass_to_thread*)arg)->netconf_sessions_list;
@@ -1002,290 +1430,59 @@
 				break;
 			}
 
-			/* get parameters */
-			/* TODO NC_DATASTORE_URL */
-			ds_type_t = -1;
-			if ((target = json_object_get_string(json_object_object_get(request, "target"))) != NULL) {
-				if (strcmp(target, "running") == 0) {
-					ds_type_t = NC_DATASTORE_RUNNING;
-				} else if (strcmp(target, "startup") == 0) {
-					ds_type_t = NC_DATASTORE_STARTUP;
-				} else if (strcmp(target, "candidate") == 0) {
-					ds_type_t = NC_DATASTORE_CANDIDATE;
-				}
-			}
-			ds_type_s = -1;
-			if ((source = json_object_get_string(json_object_object_get(request, "source"))) != NULL) {
-				if (strcmp(source, "running") == 0) {
-					ds_type_s = NC_DATASTORE_RUNNING;
-				} else if (strcmp(source, "startup") == 0) {
-					ds_type_s = NC_DATASTORE_STARTUP;
-				} else if (strcmp(source, "candidate") == 0) {
-					ds_type_s = NC_DATASTORE_CANDIDATE;
-				}
-			}
-
 			/* null global JSON error-reply */
 			err_reply = NULL;
 
 			/* prepare reply envelope */
-			reply =  json_object_new_object();
+			reply = NULL;
 
 			/* process required operation */
 			switch (operation) {
 			case MSG_CONNECT:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: Connect");
-
-				host = json_object_get_string(json_object_object_get(request, "host"));
-				port = json_object_get_string(json_object_object_get(request, "port"));
-				user = json_object_get_string(json_object_object_get(request, "user"));
-				pass = json_object_get_string(json_object_object_get(request, "pass"));
-				capabilities = json_object_object_get(request, "capabilities");
-				if ((capabilities != NULL) && ((len = json_object_array_length(capabilities)) > 0)) {
-					cpblts = nc_cpblts_new (NULL);
-					for (i=0; i<len; i++) {
-						nc_cpblts_add (cpblts, json_object_get_string(json_object_array_get_idx(capabilities, i)));
-					}
-				} else {
-					ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "no capabilities specified");
-				}
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "host: %s, port: %s, user: %s", host, port, user);
-				if ((host == NULL) || (user == NULL)) {
-					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Cannot connect - insufficient input.");
-					session_key_hash = NULL;
-				} else {
-					session_key_hash = netconf_connect(server, pool, netconf_sessions_list, host, port, user, pass, cpblts);
-					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "hash: %s", session_key_hash);
-				}
-				if (cpblts != NULL) {
-					nc_cpblts_free(cpblts);
-				}
-
-				if (session_key_hash == NULL) {
-					/* negative reply */
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("Connecting NETCONF server failed."));
-						ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Connection failed.");
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-						ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Connect - error from libnetconf's callback.");
-					}
-				} else {
-					/* positive reply */
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
-					json_object_object_add(reply, "session", json_object_new_string(session_key_hash));
-
-					free(session_key_hash);
-				}
-
+				reply = handle_op_connect(server, pool, request, netconf_sessions_list);
 				break;
 			case MSG_GET:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get (session %s)", session_key);
-
-				filter = json_object_get_string(json_object_object_get(request, "filter"));
-
-				//ap_log_error (APLOG_MARK, APLOG_ERR, 0, server, "get filter: %p", filter);
-
-				if ((data = netconf_get(server, netconf_sessions_list, session_key, filter)) == NULL) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("get failed."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
-					json_object_object_add(reply, "data", json_object_new_string(data));
-				}
+				reply = handle_op_get(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_GETCONFIG:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get-config (session %s)", session_key);
-
-				filter = json_object_get_string(json_object_object_get(request, "filter"));
-
-				if (ds_type_s == -1) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid source repository type requested."));
-					break;
-				}
-
-				if ((data = netconf_getconfig(server, netconf_sessions_list, session_key, ds_type_s, filter)) == NULL) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("get-config failed."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
-					json_object_object_add(reply, "data", json_object_new_string(data));
-				}
+				reply = handle_op_getconfig(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_GETSCHEMA:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get-schema (session %s)", session_key);
-				identifier = json_object_get_string(json_object_object_get(request, "identifier"));
-				if (identifier == NULL) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("No identifier for get-schema supplied."));
-					break;
-				}
-				version = json_object_get_string(json_object_object_get(request, "version"));
-				format = json_object_get_string(json_object_object_get(request, "format"));
-
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "get-schema(version: %s, format: %s)", version, format);
-				if ((data = netconf_getschema(server, netconf_sessions_list, session_key, identifier, version, format)) == NULL) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("get-config failed."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
-					json_object_object_add(reply, "data", json_object_new_string(data));
-				}
+				reply = handle_op_getschema(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_EDITCONFIG:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: edit-config (session %s)", session_key);
-
-				defop = json_object_get_string(json_object_object_get(request, "default-operation"));
-				if (defop != NULL) {
-					if (strcmp(defop, "merge") == 0) {
-						defop_type = NC_EDIT_DEFOP_MERGE;
-					} else if (strcmp(defop, "replace") == 0) {
-						defop_type = NC_EDIT_DEFOP_REPLACE;
-					} else if (strcmp(defop, "none") == 0) {
-						defop_type = NC_EDIT_DEFOP_NONE;
-					} else {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("Invalid default-operation parameter."));
-						break;
-					}
-				} else {
-					defop_type = NC_EDIT_DEFOP_NOTSET;
-				}
-
-				erropt = json_object_get_string(json_object_object_get(request, "error-option"));
-				if (erropt != NULL) {
-					if (strcmp(erropt, "continue-on-error") == 0) {
-						erropt_type = NC_EDIT_ERROPT_CONT;
-					} else if (strcmp(erropt, "stop-on-error") == 0) {
-						erropt_type = NC_EDIT_ERROPT_STOP;
-					} else if (strcmp(erropt, "rollback-on-error") == 0) {
-						erropt_type = NC_EDIT_ERROPT_ROLLBACK;
-					} else {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("Invalid error-option parameter."));
-						break;
-					}
-				} else {
-					erropt_type = 0;
-				}
-
-				if (ds_type_t == -1) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid target repository type requested."));
-					break;
-				}
-
-				config = json_object_get_string(json_object_object_get(request, "config"));
-				if (config == NULL) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid config data parameter."));
-					break;
-				}
-
-				/* TODO url capability see netconf_editconfig */
-				/* TODO TESTSET - :validate:1.1 capability? http://tools.ietf.org/html/rfc6241#section-7.2 */
-				if (netconf_editconfig(server, netconf_sessions_list, session_key, ds_type_t, defop_type, erropt_type, NC_EDIT_TESTOPT_NOTSET, config) != EXIT_SUCCESS) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("edit-config failed."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
-				}
+				reply = handle_op_editconfig(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_COPYCONFIG:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: copy-config (session %s)", session_key);
-				config = NULL;
-
-				if (source == NULL) {
-					/* no explicit source specified -> use config data */
-					ds_type_s = NC_DATASTORE_CONFIG;
-					config = json_object_get_string(json_object_object_get(request, "config"));
-				} else if (ds_type_s == -1) {
-					/* source datastore specified, but it is invalid */
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid source repository type requested."));
-					break;
-				}
-
-				if (ds_type_t == -1) {
-					/* invalid target datastore specified */
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid target repository type requested."));
-					break;
-				}
-
-				if (source == NULL && config == NULL) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("invalid input parameters - one of source and config is required."));
-				} else {
-					if (netconf_copyconfig(server, netconf_sessions_list, session_key, ds_type_s, ds_type_t, config, "") != EXIT_SUCCESS) {
-						if (err_reply == NULL) {
-							json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-							json_object_object_add(reply, "error-message", json_object_new_string("copy-config failed."));
-						} else {
-							/* use filled err_reply from libnetconf's callback */
-							json_object_put(reply);
-							reply = err_reply;
-						}
-					} else {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
-					}
-				}
+				reply = handle_op_copyconfig(server, pool, request, netconf_sessions_list, session_key);
 				break;
+
 			case MSG_DELETECONFIG:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: delete-config (session %s)", session_key);
-				/* no break - unifying code */
 			case MSG_LOCK:
-				if (operation == MSG_LOCK) {
-					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: lock (session %s)", session_key);
-				}
-				/* no break - unifying code */
 			case MSG_UNLOCK:
-				if (operation == MSG_UNLOCK) {
-					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: unlock (session %s)", session_key);
+				/* get parameters */
+				if ((target = json_object_get_string(json_object_object_get(request, "target"))) != NULL) {
+					ds_type_t = parse_datastore(target);
+				}
+				if ((source = json_object_get_string(json_object_object_get(request, "source"))) != NULL) {
+					ds_type_s = parse_datastore(source);
 				}
 
 				if (ds_type_t == -1) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid target repository type requested."));
+					reply = create_error("Invalid target repository type requested.");
 					break;
 				}
-
 				switch(operation) {
 				case MSG_DELETECONFIG:
+					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: delete-config (session %s)", session_key);
 					status = netconf_deleteconfig(server, netconf_sessions_list, session_key, ds_type_t);
 					break;
 				case MSG_LOCK:
+					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: lock (session %s)", session_key);
 					status = netconf_lock(server, netconf_sessions_list, session_key, ds_type_t);
 					break;
 				case MSG_UNLOCK:
+					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: unlock (session %s)", session_key);
 					status = netconf_unlock(server, netconf_sessions_list, session_key, ds_type_t);
 					break;
 				default:
@@ -1295,141 +1492,41 @@
 
 				if (status != EXIT_SUCCESS) {
 					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("operation failed."));
+						/** \todo more clever error message wanted */
+						reply = create_error("operation failed.");
 					} else {
 						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
 						reply = err_reply;
 					}
 				} else {
+					reply = json_object_new_object();
 					json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
 				}
 				break;
 			case MSG_KILL:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: kill-session, session %s", session_key);
-
-				sid = json_object_get_string(json_object_object_get(request, "session-id"));
-
-				if (sid == NULL) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Missing session-id parameter."));
-					break;
-				}
-
-				if (netconf_killsession(server, netconf_sessions_list, session_key, sid) != EXIT_SUCCESS) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("kill-session failed."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
-				}
+				reply = handle_op_kill(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_DISCONNECT:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: Disconnect session %s", session_key);
-
-				if (netconf_close(server, netconf_sessions_list, session_key) != EXIT_SUCCESS) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("Invalid session identifier."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
-				}
+				reply = handle_op_disconnect(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_RELOADHELLO:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get info about session %s", session_key);
-
-				locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
-				if ((locked_session != NULL) && (locked_session->hello_message != NULL)) {
-					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "creating temporal NC session.");
-					struct nc_session *temp_session = nc_session_connect_channel(locked_session->session, NULL);
-					if (temp_session != NULL) {
-						prepare_status_message(server, locked_session, temp_session);
-						ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "closing temporal NC session.");
-						nc_session_close(temp_session, NC_SESSION_TERM_CLOSED);
-					} else {
-						ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Reload hello failed due to channel establishment");
-					}
-				} else {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Invalid session identifier."));
-					break;
-				}
-				/* do NOT insert "break" here, we want to give new info back */;
+				reply = handle_op_reloadhello(server, pool, request, netconf_sessions_list, session_key);
+				break;
 			case MSG_INFO:
-				if (operation != MSG_INFO) {
-					if (locked_session->hello_message != NULL) {
-						json_object_put(reply);
-						reply = locked_session->hello_message;
-					} else {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("Invalid session identifier."));
-					}
-				} else {
-					ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: get info about session %s", session_key);
-
-					locked_session = (struct session_with_mutex *)apr_hash_get(netconf_sessions_list, session_key, APR_HASH_KEY_STRING);
-					if (locked_session != NULL) {
-						if (locked_session->hello_message != NULL) {
-							json_object_put(reply);
-							reply = locked_session->hello_message;
-						} else {
-							json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-							json_object_object_add(reply, "error-message", json_object_new_string("Invalid session identifier."));
-						}
-					} else {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("Invalid session identifier."));
-					}
-				}
+				reply = handle_op_info(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			case MSG_GENERIC:
-				ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Request: generic request for session %s", session_key);
-
-				config = json_object_get_string(json_object_object_get(request, "content"));
-
-				if (config == NULL) {
-					json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-					json_object_object_add(reply, "error-message", json_object_new_string("Missing content parameter."));
-					break;
-				}
-
-				if (netconf_generic(server, netconf_sessions_list, session_key, config, &data) != EXIT_SUCCESS) {
-					if (err_reply == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-						json_object_object_add(reply, "error-message", json_object_new_string("kill-session failed."));
-					} else {
-						/* use filled err_reply from libnetconf's callback */
-						json_object_put(reply);
-						reply = err_reply;
-					}
-				} else {
-					if (data == NULL) {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_OK));
-					} else {
-						json_object_object_add(reply, "type", json_object_new_int(REPLY_DATA));
-						json_object_object_add(reply, "data", json_object_new_string(data));
-					}
-				}
+				reply = handle_op_generic(server, pool, request, netconf_sessions_list, session_key);
 				break;
 			default:
 				ap_log_error(APLOG_MARK, APLOG_ERR, 0, server, "Unknown mod_netconf operation requested (%d)", operation);
-				json_object_object_add(reply, "type", json_object_new_int(REPLY_ERROR));
-				json_object_object_add(reply, "error-message", json_object_new_string("Operation not supported."));
+				reply = create_error("Operation not supported.");
 				break;
 			}
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Clean request json object.");
 			json_object_put(request);
 
+			ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, server, "Send reply json object.");
 			/* send reply to caller */
 			if (reply != NULL) {
 				msgtext = json_object_to_json_string(reply);