public function get_address_book($id, $writeable = false)
    {
        $contacts    = null;
        $ldap_config = (array)$this->config->get('ldap_public');

        // 'sql' is the alias for '0' used by autocomplete
        if ($id == 'sql')
            $id = '0';
        else if ($id == -1) {
            $id = $this->config->get('default_addressbook');
            $default = true;
        }

        // use existing instance
        if (isset($this->address_books[$id]) && ($this->address_books[$id] instanceof rcube_addressbook)) {
            $contacts = $this->address_books[$id];
        }
        else if ($id && $ldap_config[$id]) {
            $domain   = $this->config->mail_domain($_SESSION['storage_host']);
            $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $domain);
        }
        else if ($id === '0') {
            $contacts = new rcube_contacts($this->db, $this->get_user_id());
        }
        else {
            $plugin = $this->plugins->exec_hook('addressbook_get', array('id' => $id, 'writeable' => $writeable));

            // plugin returned instance of a rcube_addressbook
            if ($plugin['instance'] instanceof rcube_addressbook) {
                $contacts = $plugin['instance'];
            }
        }

        // when user requested default writeable addressbook
        // we need to check if default is writeable, if not we
        // will return first writeable book (if any exist)
        if ($contacts && $default && $contacts->readonly && $writeable) {
            $contacts = null;
        }

        // Get first addressbook from the list if configured default doesn't exist
        // This can happen when user deleted the addressbook (e.g. Kolab folder)
        if (!$contacts && (!$id || $default)) {
            $source = reset($this->get_address_sources($writeable, !$default));
            if (!empty($source)) {
                $contacts = $this->get_address_book($source['id']);
                if ($contacts) {
                    $id = $source['id'];
                }
            }
        }

        if (!$contacts) {
            // there's no default, just return
            if ($default) {
                return null;
            }

            self::raise_error(array(
                    'code'    => 700,
                    'file'    => __FILE__,
                    'line'    => __LINE__,
                    'message' => "Addressbook source ($id) not found!"
                ),
                true, true);
        }

        // add to the 'books' array for shutdown function
        $this->address_books[$id] = $contacts;

        if ($writeable && $contacts->readonly) {
            return null;
        }

        // set configured sort order
        if ($sort_col = $this->config->get('addressbook_sort_col')) {
            $contacts->set_sort_order($sort_col);
        }

        return $contacts;
    }