messages CHANGE split to 3 groups of functions
diff --git a/src/messages_server.c b/src/messages_server.c
new file mode 100644
index 0000000..0467483
--- /dev/null
+++ b/src/messages_server.c
@@ -0,0 +1,494 @@
+/**
+ * \file messages_server.c
+ * \author Michal Vasko <mvasko@cesnet.cz>
+ * \brief libnetconf2 - server NETCONF messages functions
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ *    may be used to endorse or promote products derived from this
+ *    software without specific prior written permission.
+ *
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include <libyang/libyang.h>
+
+#include "libnetconf.h"
+#include "messages_p.h"
+
+API struct nc_server_reply *
+nc_server_reply_ok(void)
+{
+    struct nc_server_reply *ret;
+
+    ret = malloc(sizeof *ret);
+    if (!ret) {
+        ERRMEM;
+        return NULL;
+    }
+
+    ret->type = NC_RPL_OK;
+    return ret;
+}
+
+API struct nc_server_reply *
+nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype)
+{
+    struct nc_server_reply_data *ret;
+
+    if (!data) {
+        ERRARG;
+        return NULL;
+    }
+
+    ret = malloc(sizeof *ret);
+    if (!ret) {
+        ERRMEM;
+        return NULL;
+    }
+
+    ret->type = NC_RPL_DATA;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        ret->data = lyd_dup(data, 1);
+    } else {
+        ret->data = data;
+    }
+    if (paramtype != NC_PARAMTYPE_CONST) {
+        ret->free = 1;
+    } else {
+        ret->free = 0;
+    }
+    return (struct nc_server_reply *)ret;
+}
+
+API struct nc_server_reply *
+nc_server_reply_err(struct ly_ctx *ctx, struct nc_server_error *err)
+{
+    struct nc_server_reply_error *ret;
+
+    if (!ctx || !err) {
+        ERRARG;
+        return NULL;
+    }
+
+    ret = malloc(sizeof *ret);
+    if (!ret) {
+        ERRMEM;
+        return NULL;
+    }
+
+    ret->type = NC_RPL_ERROR;
+    ret->ctx = ctx;
+    ret->err = malloc(sizeof *ret->err);
+    ret->err[0] = err;
+    ret->count = 1;
+    return (struct nc_server_reply *)ret;
+}
+
+API int
+nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err)
+{
+    struct nc_server_reply_error *err_rpl;
+
+    if (!reply || (reply->type != NC_RPL_ERROR) || !err) {
+        ERRARG;
+        return -1;
+    }
+
+    err_rpl = (struct nc_server_reply_error *)reply;
+    ++err_rpl->count;
+    err_rpl->err = realloc(err_rpl->err, err_rpl->count * sizeof *err_rpl->err);
+    err_rpl->err[err_rpl->count - 1] = err;
+    return 0;
+}
+
+API struct nc_server_error *
+nc_err(struct ly_ctx *ctx, NC_ERR tag, ...)
+{
+    va_list ap;
+    struct nc_server_error *ret;
+    NC_ERR_TYPE type;
+    const char *arg1, *arg2;
+    uint32_t sid;
+
+    if (!ctx || !tag) {
+        ERRARG;
+        return NULL;
+    }
+
+    ret = calloc(1, sizeof *ret);
+    if (!ret) {
+        ERRMEM;
+        return NULL;
+    }
+
+    va_start(ap, tag);
+
+    switch (tag) {
+    case NC_ERR_IN_USE:
+    case NC_ERR_INVALID_VALUE:
+    case NC_ERR_ACCESS_DENIED:
+    case NC_ERR_ROLLBACK_FAILED:
+    case NC_ERR_OP_NOT_SUPPORTED:
+        type = va_arg(ap, NC_ERR_TYPE);
+        if ((type != NC_ERR_TYPE_PROT) && (type == NC_ERR_TYPE_APP)) {
+            goto fail;
+        }
+        break;
+
+    case NC_ERR_TOO_BIG:
+    case NC_ERR_RES_DENIED:
+        type = va_arg(ap, NC_ERR_TYPE);
+        /* nothing to check */
+        break;
+
+    case NC_ERR_MISSING_ATTR:
+    case NC_ERR_BAD_ATTR:
+    case NC_ERR_UNKNOWN_ATTR:
+        type = va_arg(ap, NC_ERR_TYPE);
+        arg1 = va_arg(ap, const char *);
+        arg2 = va_arg(ap, const char *);
+
+        if (type == NC_ERR_TYPE_TRAN) {
+            goto fail;
+        }
+        nc_err_add_bad_attr(ctx, ret, arg1);
+        nc_err_add_bad_elem(ctx, ret, arg2);
+        break;
+
+    case NC_ERR_MISSING_ELEM:
+    case NC_ERR_BAD_ELEM:
+    case NC_ERR_UNKNOWN_ELEM:
+        type = va_arg(ap, NC_ERR_TYPE);
+        arg1 = va_arg(ap, const char *);
+
+        if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
+            goto fail;
+        }
+        nc_err_add_bad_elem(ctx, ret, arg1);
+        break;
+
+    case NC_ERR_UNKNOWN_NS:
+        type = va_arg(ap, NC_ERR_TYPE);
+        arg1 = va_arg(ap, const char *);
+        arg2 = va_arg(ap, const char *);
+
+        if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
+            goto fail;
+        }
+        nc_err_add_bad_elem(ctx, ret, arg1);
+        nc_err_add_bad_ns(ctx, ret, arg2);
+        break;
+
+    case NC_ERR_LOCK_DENIED:
+        sid = va_arg(ap, uint32_t);
+
+        type = NC_ERR_TYPE_PROT;
+        nc_err_set_sid(ret, sid);
+        break;
+
+    case NC_ERR_DATA_EXISTS:
+    case NC_ERR_DATA_MISSING:
+        type = NC_ERR_TYPE_APP;
+        break;
+
+    case NC_ERR_OP_FAILED:
+        type = va_arg(ap, NC_ERR_TYPE);
+
+        if (type == NC_ERR_TYPE_TRAN) {
+            goto fail;
+        }
+        break;
+
+    case NC_ERR_MALFORMED_MSG:
+        type = NC_ERR_TYPE_RPC;
+        break;
+
+    default:
+        goto fail;
+    }
+
+    switch (tag) {
+    case NC_ERR_IN_USE:
+        nc_err_set_msg(ctx, ret, "The request requires a resource that already is in use.", "en");
+        break;
+    case NC_ERR_INVALID_VALUE:
+        nc_err_set_msg(ctx, ret, "The request specifies an unacceptable value for one or more parameters.", "en");
+        break;
+    case NC_ERR_TOO_BIG:
+        nc_err_set_msg(ctx, ret, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
+        break;
+    case NC_ERR_MISSING_ATTR:
+        nc_err_set_msg(ctx, ret, "An expected attribute is missing.", "en");
+        break;
+    case NC_ERR_BAD_ATTR:
+        nc_err_set_msg(ctx, ret, "An attribute value is not correct.", "en");
+        break;
+    case NC_ERR_UNKNOWN_ATTR:
+        nc_err_set_msg(ctx, ret, "An unexpected attribute is present.", "en");
+        break;
+    case NC_ERR_MISSING_ELEM:
+        nc_err_set_msg(ctx, ret, "An expected element is missing.", "en");
+        break;
+    case NC_ERR_BAD_ELEM:
+        nc_err_set_msg(ctx, ret, "An element value is not correct.", "en");
+        break;
+    case NC_ERR_UNKNOWN_ELEM:
+        nc_err_set_msg(ctx, ret, "An unexpected element is present.", "en");
+        break;
+    case NC_ERR_UNKNOWN_NS:
+        nc_err_set_msg(ctx, ret, "An unexpected namespace is present.", "en");
+        break;
+    case NC_ERR_ACCESS_DENIED:
+        nc_err_set_msg(ctx, ret, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
+        break;
+    case NC_ERR_LOCK_DENIED:
+        nc_err_set_msg(ctx, ret, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
+        break;
+    case NC_ERR_RES_DENIED:
+        nc_err_set_msg(ctx, ret, "Request could not be completed because of insufficient resources.", "en");
+        break;
+    case NC_ERR_ROLLBACK_FAILED:
+        nc_err_set_msg(ctx, ret, "Request to roll back some configuration change was not completed for some reason.", "en");
+        break;
+    case NC_ERR_DATA_EXISTS:
+        nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content already exists.", "en");
+        break;
+    case NC_ERR_DATA_MISSING:
+        nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content does not exist.", "en");
+        break;
+    case NC_ERR_OP_NOT_SUPPORTED:
+        nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
+        break;
+    case NC_ERR_OP_FAILED:
+        nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
+        break;
+    case NC_ERR_MALFORMED_MSG:
+        nc_err_set_msg(ctx, ret, "A message could not be handled because it failed to be parsed correctly.", "en");
+        break;
+    default:
+        goto fail;
+    }
+
+    va_end(ap);
+
+    ret->type = type;
+    ret->tag = tag;
+    return ret;
+
+fail:
+    ERRARG;
+    free(ret);
+    return NULL;
+}
+
+API int
+nc_err_set_app_tag(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_app_tag)
+{
+    if (!ctx || !err || !error_app_tag) {
+        ERRARG;
+        return -1;
+    }
+
+    if (err->apptag) {
+        lydict_remove(ctx, err->apptag);
+    }
+    err->apptag = lydict_insert(ctx, error_app_tag, 0);
+    return 0;
+}
+
+API int
+nc_err_set_path(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_path)
+{
+    if (!ctx || !err || !error_path) {
+        ERRARG;
+        return -1;
+    }
+
+    if (err->path) {
+        lydict_remove(ctx, err->path);
+    }
+    err->path = lydict_insert(ctx, error_path, 0);
+    return 0;
+}
+
+API int
+nc_err_set_msg(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_message, const char *lang)
+{
+    if (!ctx || !err || !error_message) {
+        ERRARG;
+        return -1;
+    }
+
+    if (err->message) {
+        lydict_remove(ctx, err->apptag);
+    }
+    err->message = lydict_insert(ctx, error_message, 0);
+
+    if (err->message_lang) {
+        lydict_remove(ctx, err->message_lang);
+    }
+    if (lang) {
+        err->message_lang = lydict_insert(ctx, lang, 0);
+    } else {
+        lang = NULL;
+    }
+    return 0;
+}
+
+API int
+nc_err_set_sid(struct nc_server_error *err, uint32_t session_id)
+{
+    if (!err || !session_id) {
+        ERRARG;
+        return -1;
+    }
+
+    err->sid = session_id;
+    return 0;
+}
+
+API int
+nc_err_add_bad_attr(struct ly_ctx *ctx, struct nc_server_error *err, const char *attr_name)
+{
+    if (!ctx || !err || !attr_name) {
+        ERRARG;
+        return -1;
+    }
+
+    ++err->attr_count;
+    err->attr = realloc(err->attr, err->attr_count * sizeof *err->attr);
+    err->attr[err->attr_count - 1] = lydict_insert(ctx, attr_name, 0);
+    return 0;
+}
+
+API int
+nc_err_add_bad_elem(struct ly_ctx *ctx, struct nc_server_error *err, const char *elem_name)
+{
+    if (!ctx || !err || !elem_name) {
+        ERRARG;
+        return -1;
+    }
+
+    ++err->elem_count;
+    err->elem = realloc(err->elem, err->elem_count * sizeof *err->elem);
+    err->elem[err->elem_count - 1] = lydict_insert(ctx, elem_name, 0);
+    return 0;
+}
+
+API int
+nc_err_add_bad_ns(struct ly_ctx *ctx, struct nc_server_error *err, const char *ns_name)
+{
+    if (!ctx || !err || !ns_name) {
+        ERRARG;
+        return -1;
+    }
+
+    ++err->ns_count;
+    err->ns = realloc(err->ns, err->ns_count * sizeof *err->ns);
+    err->ns[err->ns_count - 1] = lydict_insert(ctx, ns_name, 0);
+    return 0;
+}
+
+API int
+nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other)
+{
+    if (!err || !other) {
+        ERRARG;
+        return -1;
+    }
+
+    ++err->other_count;
+    err->other = realloc(err->other, err->other_count * sizeof *err->other);
+    err->other[err->other_count - 1] = other;
+    return 0;
+}
+
+void
+nc_server_rpc_free(struct nc_server_rpc *rpc)
+{
+    lyxml_free(rpc->tree->schema->module->ctx, rpc->root);
+    lyd_free(rpc->tree);
+    free(rpc);
+}
+
+API void
+nc_server_reply_free(struct nc_server_reply *reply)
+{
+    uint32_t i;
+    struct nc_server_reply_data *data_rpl;
+    struct nc_server_reply_error *error_rpl;
+
+    if (!reply) {
+        return;
+    }
+
+    switch (reply->type) {
+    case NC_RPL_DATA:
+        data_rpl = (struct nc_server_reply_data *)reply;
+        if (data_rpl->free) {
+            lyd_free_withsiblings(data_rpl->data);
+        }
+        break;
+    case NC_RPL_OK:
+        /* nothing to free */
+        break;
+    case NC_RPL_ERROR:
+        error_rpl = (struct nc_server_reply_error *)reply;
+        for (i = 0; i < error_rpl->count; ++i) {
+            nc_err_free(error_rpl->ctx, error_rpl->err[i]);
+        }
+        free(error_rpl->err);
+        break;
+    default:
+        break;
+    }
+    free(reply);
+}
+
+API void
+nc_err_free(struct ly_ctx *ctx, struct nc_server_error *err)
+{
+    uint32_t i;
+
+    if (!err) {
+        ERRARG;
+        return;
+    }
+
+    lydict_remove(ctx, err->apptag);
+    lydict_remove(ctx, err->path);
+    lydict_remove(ctx, err->message);
+    lydict_remove(ctx, err->message_lang);
+    for (i = 0; i < err->attr_count; ++i) {
+        lydict_remove(ctx, err->attr[i]);
+    }
+    free(err->attr);
+    for (i = 0; i < err->elem_count; ++i) {
+        lydict_remove(ctx, err->elem[i]);
+    }
+    free(err->elem);
+    for (i = 0; i < err->ns_count; ++i) {
+        lydict_remove(ctx, err->ns[i]);
+    }
+    free(err->ns);
+    for (i = 0; i < err->other_count; ++i) {
+        lyxml_free(ctx, err->other[i]);
+    }
+    free(err->other);
+    free(err);
+}