function opf_save()
{
    global $database;
    $types = opf_get_types();
    // get values
    $id = opf_fetch_post('id', 0, 'int');
    // id is set from opf_edit_filter() only
    $type = opf_fetch_post('type', '', 'unchanged');
    $name = opf_fetch_post('name', '', 'unchanged');
    $func = opf_fetch_post('func', '', 'unchanged');
    $funcname = opf_fetch_post('funcname', '', 'unchanged');
    $desc = opf_fetch_post('desc', '', 'unchanged');
    $active = opf_fetch_post('active', 0, 'int');
    $modules = opf_fetch_post('modules', array(), 'unchanged');
    //$pages  = opf_fetch_post( 'pages', array(), 'unchanged');
    $pages_parent = opf_fetch_post('pages_parent', array(), 'unchanged');
    $searchres = opf_fetch_post('searchresult', FALSE, 'exists');
    $backend = opf_fetch_post('backend', FALSE, 'exists');
    if ($searchres !== FALSE) {
        $pages_parent[] = '0';
    }
    if ($backend !== FALSE) {
        $pages_parent[] = 'backend';
    }
    // cleanup
    $desc = trim($desc);
    $func = trim($func);
    $name = trim($name);
    $funcname = trim($funcname);
    $type = array_key_exists($type, $types) ? $type : key($types);
    $file = '';
    $additional_values = serialize('');
    // move single-page values from $pages_parent to $pages
    $tmp_pages_parent = $tmp_pages = array();
    foreach ($pages_parent as $pid) {
        if (strpos($pid, 's') === 0) {
            $tmp_pages[] = substr($pid, 1);
        } else {
            $tmp_pages_parent[] = $pid;
        }
    }
    $pages_parent = $tmp_pages_parent;
    $pages = $tmp_pages;
    // add additional data
    $filter_old = array();
    if ($id > 0 && opf_db_query_vars("SELECT TRUE FROM " . TABLE_PREFIX . "mod_outputfilter_dashboard" . " WHERE `id`=%d", $id)) {
        // comes from edit, so fetch old data from DB
        $filter_old = opf_db_query("SELECT *" . " FROM " . TABLE_PREFIX . "mod_outputfilter_dashboard" . " WHERE `id`=%d", $id);
        if (!empty($filter_old)) {
            $filter_old = $filter_old[0];
            $userfunc = $filter_old['userfunc'];
            $plugin = $filter_old['plugin'];
            $allowedit = $filter_old['allowedit'];
            $allowedittarget = $filter_old['allowedittarget'];
            $configurl = $filter_old['configurl'];
            $helppath = unserialize($filter_old['helppath']);
            $csspath = $filter_old['csspath'];
            $file = $filter_old['file'];
        }
    } else {
        // comes from add, add default values for inline-filters
        $userfunc = 1;
        $plugin = '';
        $allowedit = 1;
        $allowedittarget = 1;
        $configurl = '';
        $csspath = '';
        $helppath = array();
    }
    // do we have to handle additional data?
    if ($id > 0 && !empty($filter_old)) {
        // comes from edit, so check additional_fields
        $additional_fields = unserialize($filter_old['additional_fields']);
        if (!empty($additional_fields)) {
            $additional_values = array();
            foreach ($additional_fields as $field) {
                if (isset($_POST[$field['name']])) {
                    if (($field['type'] == 'textarea' || $field['type'] == 'editarea') && is_array($field['value'])) {
                        $a = array();
                        preg_match_all("~^\\s*'(.*?)'\\s*=>\\s*'(.*?)'\\s*,?\\s*\$~ms", opf_fetch_post($field['name'], '', 'unchanged'), $matches, PREG_SET_ORDER);
                        if (isset($matches) && $matches) {
                            foreach ($matches as $match) {
                                $a[$match[1]] = $match[2];
                            }
                        }
                        $additional_values[$field['variable']] = $a;
                    } elseif ($field['type'] == 'array') {
                        $a = array();
                        $i = 0;
                        while (isset($_POST[$field['name']]['k'][$i])) {
                            // we can't use opf_fetch_post() because we need to read from $_POST[$field['name']]['k'][$i]
                            $a[opf_fetch_clean($_POST[$field['name']]['k'][$i], '', 'unchanged', FALSE, TRUE)] = opf_fetch_clean($_POST[$field['name']]['v'][$i], '', 'unchanged', FALSE, TRUE);
                            $i++;
                        }
                        $additional_values[$field['variable']] = $a;
                    } else {
                        $additional_values[$field['variable']] = opf_fetch_post($field['name'], '', 'unchanged');
                    }
                } else {
                    $additional_values[$field['variable']] = FALSE;
                }
            }
        }
    }
    // use old values if we come from edit and allowedit is 0
    if ($id > 0 && !empty($filter_old)) {
        if ($allowedit == 0) {
            $name = $filter_old['name'];
            $funcname = $filter_old['funcname'];
            $func = $filter_old['func'];
            $type = $filter_old['type'];
            $desc = unserialize($filter_old['desc']);
            if ($allowedittarget == 0) {
                $modules = unserialize($filter_old['modules']);
                $pages = unserialize($filter_old['pages']);
                $pages_parent = unserialize($filter_old['pages_parent']);
            }
        }
    }
    // prevent inline-filters from overwriting a different filter with same name
    if ($id == 0) {
        // we come from add-filter
        while (opf_is_registered($name)) {
            $name .= mt_rand(0, 9);
        }
    } else {
        // we come from edit-filter: allow to overwrite old one (same $id)
        if (opf_check_name($id) != $name) {
            while (opf_is_registered($name)) {
                $name .= mt_rand(0, 9);
            }
        }
    }
    // register or update filter
    $res = opf_register_filter(array('id' => $id, 'type' => $type, 'name' => $name, 'func' => $func, 'file' => $file, 'funcname' => $funcname, 'modules' => $modules, 'pages' => $pages, 'pages_parent' => $pages_parent, 'desc' => $desc, 'userfunc' => $userfunc, 'plugin' => $plugin, 'active' => $active, 'allowedit' => $allowedit, 'allowedittarget' => $allowedittarget, 'configurl' => $configurl, 'csspath' => $csspath, 'helppath' => $helppath, 'force' => TRUE, 'filter_installed' => FALSE, 'additional_values' => $additional_values));
    if ($res) {
        if ($id == 0) {
            return $database->getLastInsertId();
        } else {
            return $id;
        }
    }
    return $res;
}
function opf_unregister_filter($name)
{
    if (!function_exists('opf_unregister_call_uninstall')) {
        function opf_unregister_call_uninstall($file)
        {
            include $file;
        }
    }
    static $old_name = FALSE;
    $now = time();
    $name = opf_check_name($name);
    if (!$name) {
        return FALSE;
    }
    if ($old_name == $name) {
        return FALSE;
    }
    // prevent usage of opf_unregister_filter() in plugin_uninstall.php
    $old_name = $name;
    // check whether $name is in DB
    if (opf_is_registered($name)) {
        $pos = opf_get_position($name);
        $type = opf_get_type($name);
        // delete plugin-dir if present
        if ($plugin_dir = opf_db_query_vars("SELECT `plugin` FROM `" . TABLE_PREFIX . "mod_outputfilter_dashboard` WHERE `name`='%s'", $name)) {
            if ($plugin_dir && file_exists(WB_PATH . '/modules/outputfilter_dashboard/plugins/' . $plugin_dir)) {
                // uninstall.php present? include it
                if (file_exists(WB_PATH . '/modules/outputfilter_dashboard/plugins/' . $plugin_dir . '/plugin_uninstall.php')) {
                    opf_unregister_call_uninstall(WB_PATH . '/modules/outputfilter_dashboard/plugins/' . $plugin_dir . '/plugin_uninstall.php');
                }
                opf_io_rmdir(WB_PATH . '/modules/outputfilter_dashboard/plugins/' . $plugin_dir);
            }
        }
        $res = opf_db_run_query("DELETE FROM `" . TABLE_PREFIX . "mod_outputfilter_dashboard` WHERE `name`='%s'", $name);
        if ($res) {
            if (opf_db_run_query("UPDATE `" . TABLE_PREFIX . "mod_outputfilter_dashboard` SET `position`=`position`-1\n                      WHERE `type`='%s' AND `position`>%d", $type, $pos)) {
                return TRUE;
            }
        }
    }
    return FALSE;
}