/*
 * Copyright 2014 Cloud Linux Zug GmbH
 *
 * Licensed under CLOUD LINUX LICENSE AGREEMENT
 * http://cloudlinux.com/docs/LICENSE.TXT
 *
 * The part the support library for lsapi & proxy_lsapi Apache modules
 * author Alexander Demeshko <ademeshko@cloudlinux.com>
 *
 */
 
#include <lscapi_util.h>

#include <unistd.h>

#include <mod_core.h>

#include <apr_strings.h>

const char* lscapi_php_value_handler(cmd_parms* cmd, void *cfg,
                                    const char *name, const char *value,
                                    int isAdmin) {
    php_param_t *eptr = apr_palloc(cmd->pool, sizeof(php_param_t));

    if(!strncasecmp(value, "none", 4)) {
        value = "";
    }

    eptr->valueLen = strlen(value);
    eptr->value = apr_pmemdup(cmd->pool, value, eptr->valueLen+1);
    eptr->isAdmin = isAdmin;
	eptr->htaccess = ((cmd->override & (RSRC_CONF|ACCESS_CONF)) == 0);

	//ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, cmd->server, LSCAPI_APLOGNO
    //             "LSCAPI_PhpValueHandler: (%s)->(%s) isAdmin:%d", name, eptr->value, eptr->isAdmin);
    apr_hash_t* phpParams = ((lsapi_dir_conf_t*)cfg)->phpParams;

    apr_hash_set(phpParams, name, APR_HASH_KEY_STRING, eptr);

    return NULL;
}

const char *lscapi_php_flag_handler(cmd_parms *cmd, void *cfg,
                                    const char *name, const char *value, int isAdmin) {
    char boolVal[2];

    boolVal[0] = ( (strcasecmp(value, "On") == 0) || (value[0] == '1' && value[1] == '\0')) ? '1' : '0';
	boolVal[1] = '\0';
    return lscapi_php_value_handler(cmd, cfg, name, boolVal, isAdmin);
}

void *lscapi_create_dir_config(apr_pool_t *pool, char *x) {
    lsapi_dir_conf_t *cfg = apr_pcalloc(pool, sizeof(lsapi_dir_conf_t));
    cfg->phpParams = apr_hash_make(pool);
    return cfg;
}

void *lscapi_merge_dir_config(apr_pool_t *pool, void *BASE, void *CUR) {
    lsapi_dir_conf_t *base = BASE;
    lsapi_dir_conf_t *cur = CUR;
    apr_hash_t *curH = cur->phpParams;
    apr_hash_t *baseH = base->phpParams;

    // initially lets create new config as a copy of the base one
    apr_hash_t *newH = apr_hash_copy(pool, baseH);

    // iterate over current config to check its values against values of the base config
    for(apr_hash_index_t *hi = apr_hash_first(pool, curH); hi; hi = apr_hash_next(hi)) {
        const char *key;
        apr_ssize_t keyLen;
        php_param_t *curVal;
        apr_hash_this(hi, (const void**)(&key), &keyLen, (void**)(&curVal));

        if(curVal->isAdmin) { // new admin value will beat even old admin one
            apr_hash_set(newH, key, keyLen, curVal);
            continue;
        }

        php_param_t *baseVal = apr_hash_get(baseH, key, keyLen);
        if(!baseVal                  // there is no such key in the base config
           || !baseVal->isAdmin)  {  // old value is not admin so new one will beat it

            apr_hash_set(newH, key, keyLen, curVal);
        }

    } // for


    lsapi_dir_conf_t *cfg = apr_pcalloc(pool, sizeof(lsapi_dir_conf_t));
    cfg->phpParams = newH;

#ifdef LSCAPI_DEBUG_UID_GID
    for(int i = 0; i < base->lsapi_uid_num; i++) {
        cfg->lsapi_uids[i] = base->lsapi_uids[i];
        cfg->lsapi_gids[i] = base->lsapi_gids[i];
    }
    cfg->lsapi_uid_num = base->lsapi_uid_num;
    for(int i = 0; i < cur->lsapi_uid_num; i++) {
        cfg->lsapi_uids[cfg->lsapi_uid_num+i] = cur->lsapi_uids[i];
        cfg->lsapi_gids[cfg->lsapi_uid_num+i] = cur->lsapi_gids[i];
    }
    cfg->lsapi_uid_num += cur->lsapi_uid_num;

    for(int i = 0; i < base->suphp_uid_num; i++) {
        cfg->suphp_uids[i] = base->suphp_uids[i];
        cfg->suphp_gids[i] = base->suphp_gids[i];
    }
    cfg->suphp_uid_num = base->suphp_uid_num;
    for(int i = 0; i < cur->suphp_uid_num; i++) {
        cfg->suphp_uids[cfg->suphp_uid_num+i] = cur->suphp_uids[i];
        cfg->suphp_gids[cfg->suphp_uid_num+i] = cur->suphp_gids[i];
    }
    cfg->suphp_uid_num += cur->suphp_uid_num;

    for(int i = 0; i < base->ruid_num; i++) {
        cfg->ruids[i] = base->ruids[i];
        cfg->rgids[i] = base->rgids[i];
    }
    cfg->ruid_num = base->ruid_num;
    for(int i = 0; i < cur->ruid_num; i++) {
        cfg->ruids[cfg->ruid_num+i] = cur->ruids[i];
        cfg->rgids[cfg->ruid_num+i] = cur->rgids[i];
    }
    cfg->ruid_num += cur->ruid_num;

    for(int i = 0; i < base->itk_uid_num; i++) {
        cfg->itk_uids[i] = base->itk_uids[i];
        cfg->itk_gids[i] = base->itk_gids[i];
    }
    cfg->itk_uid_num = base->itk_uid_num;
    for(int i = 0; i < cur->itk_uid_num; i++) {
        cfg->itk_uids[cfg->itk_uid_num+i] = cur->itk_uids[i];
        cfg->itk_gids[cfg->itk_uid_num+i] = cur->itk_gids[i];
    }
    cfg->itk_uid_num += cur->itk_uid_num;
#else
    if(cur->lsapi_uid > 0) {
        cfg->lsapi_uid = cur->lsapi_uid;
        cfg->lsapi_gid = cur->lsapi_gid;
    } else if(base->lsapi_uid > 0) {
        cfg->lsapi_uid = base->lsapi_uid;
        cfg->lsapi_gid = base->lsapi_gid;
    }

    if(cur->suphp_uid > 0) {
        cfg->suphp_uid = cur->suphp_uid;
        cfg->suphp_gid = cur->suphp_gid;
    } else if(base->suphp_uid > 0) {
        cfg->suphp_uid = base->suphp_uid;
        cfg->suphp_gid = base->suphp_gid;
    }

    if(cur->ruid > 0) {
        cfg->ruid = cur->ruid;
        cfg->rgid = cur->rgid;
    } else if(base->ruid > 0) {
        cfg->ruid = base->ruid;
        cfg->rgid = base->rgid;
    }

    if(cur->itk_uid > 0) {
        cfg->itk_uid = cur->itk_uid;
        cfg->itk_gid = cur->itk_gid;
    } else  if(base->itk_uid > 0) {
        cfg->itk_uid = base->itk_uid;
        cfg->itk_gid = base->itk_gid;
    }
#endif //LSCAPI_DEBUG_UID_GID
    return cfg;
}

void *lscapi_create_svr_config(apr_pool_t *pool, server_rec *s) {
    //ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, LSCAPI_APLOGNO
    //                  "entering lsapi_create_svr_config" );
    lsapi_svr_conf_t *cfg = apr_pcalloc(pool, sizeof(lsapi_svr_conf_t));
#if MODULE_MAGIC_NUMBER_MAJOR > 20081212
    cfg->default_uid = ap_unixd_config.user_id;
    cfg->default_gid = ap_unixd_config.group_id;
#else
    cfg->default_uid = unixd_config.user_id;
    cfg->default_gid = unixd_config.group_id;
#endif
    cfg->terminate_backends_on_exit = 1;
    cfg->selfstarter = 1;
    
    lscapi_init_backend_info(&cfg->backend_info);

    if (!s->is_virtual) {
        if(!s->error_fname || s->error_fname[0] == '|' || !strcmp(s->error_fname, "syslog") ) {

            cfg->selfstarter_socket_path = ap_server_root_relative(pool, "lsapisock");

        } else {
            char *relname = apr_pstrcat(pool, ap_make_dirstr_parent(pool, s->error_fname), 
                                        "lsapisock", NULL);
            cfg->selfstarter_socket_path = ap_server_root_relative(pool, relname);
        }
    }

    return cfg;
}

void *lscapi_merge_svr_config(apr_pool_t *pool, void *BASE, void *CUR) {
    lsapi_svr_conf_t *base = BASE;
    lsapi_svr_conf_t *cur = CUR;

    lsapi_svr_conf_t *cfg = apr_palloc(pool, sizeof(lsapi_svr_conf_t));
    cfg->default_uid = cur->default_uid;
    cfg->default_gid = cur->default_gid;

    if(cur->socket_path) {
        cfg->socket_path = cur->socket_path;
    } else {
        cfg->socket_path = base->socket_path;
    }

    if(cur->terminate_backends_was_set) {
        cfg->terminate_backends_on_exit = cur->terminate_backends_on_exit;
    } else if(base->terminate_backends_was_set) {
        cfg->terminate_backends_on_exit = base->terminate_backends_on_exit;
    }
    
    if(cur->debug_enabled_was_set) {
        cfg->debug_enabled = cur->debug_enabled;
    } else if(base->debug_enabled_was_set) {
        cfg->debug_enabled = base->debug_enabled;
    }
    
    if(cur->check_target_perm_was_set) {
        cfg->check_target_perm = cur->check_target_perm;
    } else if(base->check_target_perm_was_set) {
        cfg->check_target_perm = base->check_target_perm;
    }
    
    if(cur->use_default_uid_was_set) {
        cfg->use_default_uid = cur->use_default_uid;
    } else if(base->use_default_uid_was_set) {
        cfg->use_default_uid = base->use_default_uid;
    }
    
    if(cur->selfstarter_was_set) {
        cfg->selfstarter = cur->selfstarter;
    } else if(base->selfstarter_was_set) {
        cfg->selfstarter = base->selfstarter;
    }
    
    if(cur->backend_coredump_was_set) {
        cfg->backend_coredump = cur->backend_coredump;
    } else if(base->backend_coredump_was_set) {
        cfg->backend_coredump = base->backend_coredump;
    }
    
    if(cur->hostname_on_debug) {
        cfg->hostname_on_debug = cur->hostname_on_debug;
    } else if(base->hostname_on_debug) {
        cfg->hostname_on_debug = base->hostname_on_debug;
    }
    
    cfg->phprc = cur->phprc ? cur->phprc : base->phprc;

    if(base->selfstarter_socket_path) {
        cfg->selfstarter_socket_path = base->selfstarter_socket_path;
    } else if(cur->selfstarter_socket_path) {
        cfg->selfstarter_socket_path = cur->selfstarter_socket_path;
    }

    lscapi_merge_backend_info(&base->backend_info, &cur->backend_info, &cfg->backend_info);

    return cfg;
}
