示例#1
0
/**
 * This function shows the address book sort button.
 *
 * @param integer $abook_sort_order Current sort value
 * @param string  $alt_tag          The alt tag value (string
 *                                  visible to text only browsers)
 * @param integer $Down             Sort value when list is sorted
 *                                  ascending
 * @param integer $Up               Sort value when list is sorted
 *                                  descending
 * @param array   $uri_extra        Any additional parameters to add
 *                                  to the button's link, as an
 *                                  associative array of key/value pairs
 *                                  (OPTIONAL; default none)
 *
 * @return string html code with sorting images and urls
 *
 */
function show_abook_sort_button($abook_sort_order, $alt_tag, $Down, $Up, $uri_extra = array())
{
    global $form_url, $icon_theme_path;
    /* Figure out which image we want to use. */
    if ($abook_sort_order != $Up && $abook_sort_order != $Down) {
        $img = 'sort_none.png';
        $text_icon = '◻';
        // U+25FB WHITE MEDIUM SQUARE
        $which = $Up;
    } elseif ($abook_sort_order == $Up) {
        $img = 'up_pointer.png';
        $text_icon = '⇧';
        // U+21E7 UPWARDS WHITE ARROW
        $which = $Down;
    } else {
        $img = 'down_pointer.png';
        $text_icon = '⇩';
        // U+21E9 DOWNWARDS WHITE ARROW
        $which = 8;
    }
    $uri_extra['abook_sort_order'] = $which;
    $uri = set_uri_vars($form_url, $uri_extra, FALSE);
    /* Now that we have everything figured out, show the actual button. */
    return create_hyperlink($uri, getIcon($icon_theme_path, $img, $text_icon, $alt_tag), '', '', '', '', '', array('style' => 'text-decoration:none', 'title' => $alt_tag), FALSE);
}
示例#2
0
/**
 * This function computes the paginator string.
 *
 * @param string  $box               mailbox name
 * @param integer $iOffset           offset in total number of messages
 * @param integer $iTotal            total number of messages
 * @param integer $iLimit            maximum number of messages to show on a page
 * @param bool    $bShowAll          whether or not to show all messages at once 
 *                                   ("show all" == non paginate mode)
 * @param bool    $page_selector     whether or not to show the page selection widget
 * @param integer $page_selector_max maximum number of pages to show on the screen
 *
 * @return string $result   paginate string with links to pages
 *
 */
function get_paginator_str($box, $iOffset, $iTotal, $iLimit, $bShowAll, $page_selector, $page_selector_max)
{
    static $accesskeys_constructed = FALSE;
    /* This will be used as a space. */
    global $oTemplate, $nbsp;
    sqgetGlobalVar('PHP_SELF', $php_self, SQ_SERVER);
    /* Initialize paginator string chunks. */
    $prv_str = '';
    $nxt_str = '';
    $pg_str = '';
    $all_str = '';
    $box = urlencode($box);
    /* Create simple strings that will be creating the paginator. */
    /* This will be used as a seperator. */
    $sep = '|';
    /* Make sure that our start message number is not too big. */
    $iOffset = min($iOffset, $iTotal);
    /* Compute the starting message of the previous and next page group. */
    $next_grp = $iOffset + $iLimit;
    $prev_grp = $iOffset - $iLimit;
    if (!$bShowAll) {
        /* Compute the basic previous and next strings. */
        global $accesskey_mailbox_previous, $accesskey_mailbox_next;
        if ($next_grp <= $iTotal && $prev_grp >= 0) {
            $prv_str = get_paginator_link($box, $prev_grp, _("Previous"), $accesskeys_constructed ? 'NONE' : $accesskey_mailbox_previous);
            $nxt_str = get_paginator_link($box, $next_grp, _("Next"), $accesskeys_constructed ? 'NONE' : $accesskey_mailbox_next);
        } else {
            if ($next_grp > $iTotal && $prev_grp >= 0) {
                $prv_str = get_paginator_link($box, $prev_grp, _("Previous"), $accesskeys_constructed ? 'NONE' : $accesskey_mailbox_previous);
                $nxt_str = _("Next");
            } else {
                if ($next_grp <= $iTotal && $prev_grp < 0) {
                    $prv_str = _("Previous");
                    $nxt_str = get_paginator_link($box, $next_grp, _("Next"), $accesskeys_constructed ? 'NONE' : $accesskey_mailbox_next);
                }
            }
        }
        /* Page selector block. Following code computes page links. */
        if ($iLimit != 0 && $page_selector && $iTotal > $iLimit) {
            /* Most importantly, what is the current page!!! */
            $cur_pg = intval($iOffset / $iLimit) + 1;
            /* Compute total # of pages and # of paginator page links. */
            $tot_pgs = ceil($iTotal / $iLimit);
            /* Total number of Pages */
            $vis_pgs = min($page_selector_max, $tot_pgs - 1);
            /* Visible Pages    */
            /* Compute the size of the four quarters of the page links. */
            /* If we can, just show all the pages. */
            if ($tot_pgs - 1 <= $page_selector_max) {
                $q1_pgs = $cur_pg - 1;
                $q2_pgs = $q3_pgs = 0;
                $q4_pgs = $tot_pgs - $cur_pg;
                /* Otherwise, compute some magic to choose the four quarters. */
            } else {
                /*
                 * Compute the magic base values. Added together,
                 * these values will always equal to the $pag_pgs.
                 * NOTE: These are DEFAULT values and do not take
                 * the current page into account. That is below.
                 */
                $q1_pgs = floor($vis_pgs / 4);
                $q2_pgs = round($vis_pgs / 4, 0);
                $q3_pgs = ceil($vis_pgs / 4);
                $q4_pgs = round(($vis_pgs - $q2_pgs) / 3, 0);
                /* Adjust if the first quarter contains the current page. */
                if ($cur_pg - $q1_pgs < 1) {
                    $extra_pgs = $q1_pgs - ($cur_pg - 1) + $q2_pgs;
                    $q1_pgs = $cur_pg - 1;
                    $q2_pgs = 0;
                    $q3_pgs += ceil($extra_pgs / 2);
                    $q4_pgs += floor($extra_pgs / 2);
                    /* Adjust if the first and second quarters intersect. */
                } else {
                    if ($cur_pg - $q2_pgs - ceil($q2_pgs / 3) <= $q1_pgs) {
                        $extra_pgs = $q2_pgs;
                        $extra_pgs -= ceil(($cur_pg - $q1_pgs - 1) * 3 / 4);
                        $q2_pgs = ceil(($cur_pg - $q1_pgs - 1) * 3 / 4);
                        $q3_pgs += ceil($extra_pgs / 2);
                        $q4_pgs += floor($extra_pgs / 2);
                        /* Adjust if the fourth quarter contains the current page. */
                    } else {
                        if ($cur_pg + $q4_pgs >= $tot_pgs) {
                            $extra_pgs = $q4_pgs - ($tot_pgs - $cur_pg) + $q3_pgs;
                            $q3_pgs = 0;
                            $q4_pgs = $tot_pgs - $cur_pg;
                            $q1_pgs += floor($extra_pgs / 2);
                            $q2_pgs += ceil($extra_pgs / 2);
                            /* Adjust if the third and fourth quarter intersect. */
                        } else {
                            if ($cur_pg + $q3_pgs + 1 >= $tot_pgs - $q4_pgs + 1) {
                                $extra_pgs = $q3_pgs;
                                $extra_pgs -= ceil(($tot_pgs - $cur_pg - $q4_pgs) * 3 / 4);
                                $q3_pgs = ceil(($tot_pgs - $cur_pg - $q4_pgs) * 3 / 4);
                                $q1_pgs += floor($extra_pgs / 2);
                                $q2_pgs += ceil($extra_pgs / 2);
                            }
                        }
                    }
                }
            }
            /*
             * I am leaving this debug code here, commented out, because
             * it is a really nice way to see what the above code is doing.
             * echo "qts =  $q1_pgs/$q2_pgs/$q3_pgs/$q4_pgs = "
             *    . ($q1_pgs + $q2_pgs + $q3_pgs + $q4_pgs) . '<br />';
             */
            /* Print out the page links from the compute page quarters. */
            /* Start with the first quarter. */
            if ($q1_pgs == 0 && $cur_pg > 1) {
                $pg_str .= "...{$nbsp}";
            } else {
                for ($pg = 1; $pg <= $q1_pgs; ++$pg) {
                    $start = ($pg - 1) * $iLimit + 1;
                    $pg_str .= get_paginator_link($box, $start, $pg) . $nbsp;
                }
                if ($cur_pg - $q2_pgs - $q1_pgs > 1) {
                    $pg_str .= "...{$nbsp}";
                }
            }
            /* Continue with the second quarter. */
            for ($pg = $cur_pg - $q2_pgs; $pg < $cur_pg; ++$pg) {
                $start = ($pg - 1) * $iLimit + 1;
                $pg_str .= get_paginator_link($box, $start, $pg) . $nbsp;
            }
            /* Now print the current page. */
            $pg_str .= $cur_pg . $nbsp;
            /* Next comes the third quarter. */
            for ($pg = $cur_pg + 1; $pg <= $cur_pg + $q3_pgs; ++$pg) {
                $start = ($pg - 1) * $iLimit + 1;
                $pg_str .= get_paginator_link($box, $start, $pg) . $nbsp;
            }
            /* And last, print the forth quarter page links. */
            if ($q4_pgs == 0 && $cur_pg < $tot_pgs) {
                $pg_str .= "...{$nbsp}";
            } else {
                if ($tot_pgs - $q4_pgs > $cur_pg + $q3_pgs) {
                    $pg_str .= "...{$nbsp}";
                }
                for ($pg = $tot_pgs - $q4_pgs + 1; $pg <= $tot_pgs; ++$pg) {
                    $start = ($pg - 1) * $iLimit + 1;
                    $pg_str .= get_paginator_link($box, $start, $pg) . $nbsp;
                }
            }
            $last_grp = ($tot_pgs - 1) * $iLimit + 1;
        }
    } else {
        global $accesskey_mailbox_all_paginate;
        $pg_str = create_hyperlink("{$php_self}?showall=0&amp;startMessage=1&amp;mailbox={$box}" . (strpos($php_self, 'src/search.php') ? '&amp;smtoken=' . sm_generate_security_token() : ''), _("Paginate"), '', '', '', '', '', $accesskeys_constructed ? array() : array('accesskey' => $accesskey_mailbox_all_paginate));
    }
    /* Put all the pieces of the paginator string together. */
    /**
     * Hairy code... But let's leave it like it is since I am not certain
     * a different approach would be any easier to read. ;)
     */
    $result = '';
    if ($prv_str || $nxt_str) {
        /* Compute the 'show all' string. */
        global $accesskey_mailbox_all_paginate;
        $all_str = create_hyperlink("{$php_self}?showall=1&amp;startMessage=1&amp;mailbox={$box}" . (strpos($php_self, 'src/search.php') ? '&amp;smtoken=' . sm_generate_security_token() : ''), _("Show All"), '', '', '', '', '', $accesskeys_constructed ? array() : array('accesskey' => $accesskey_mailbox_all_paginate));
        $result .= '[';
        $result .= $prv_str != '' ? $prv_str . $nbsp . $sep . $nbsp : '';
        $result .= $nxt_str != '' ? $nxt_str : '';
        $result .= ']' . $nbsp;
    }
    $result .= $pg_str != '' ? $nbsp . '[' . $nbsp . $pg_str . ']' . $nbsp : '';
    $result .= $all_str != '' ? $nbsp . '[' . $all_str . ']' . $nbsp . $nbsp : '';
    /* If the resulting string is blank, return a non-breaking space. */
    if ($result == '') {
        $result = $nbsp;
    }
    $accesskeys_constructed = TRUE;
    /* Return our final magical compact paginator string. */
    return $result;
}
示例#3
0
/**
 * Create compose link
 *
 * Returns a link to the compose-page, taking in consideration
 * the compose_in_new and javascript settings.
 *
 * @param string $url       The URL to the compose page
 * @param string $text      The link text, default "Compose"
 * @param string $target    URL target, if any (since 1.4.3)
 * @param string $accesskey The access key to be used, if any
 *
 * @return string a link to the compose page
 *
 * @since 1.4.2
 */
function makeComposeLink($url, $text = null, $target = '', $accesskey = 'NONE')
{
    global $compose_new_win, $compose_width, $compose_height, $oTemplate;
    if (!$text) {
        $text = _("Compose");
    }
    // if not using "compose in new window", make
    // regular link and be done with it
    if ($compose_new_win != '1') {
        return makeInternalLink($url, $text, $target, $accesskey);
    }
    // build the compose in new window link...
    // if javascript is on, use onclick event to handle it
    if (checkForJavascript()) {
        sqgetGlobalVar('base_uri', $base_uri, SQ_SESSION);
        $compuri = SM_BASE_URI . $url;
        return create_hyperlink('javascript:void(0)', $text, '', "comp_in_new('{$compuri}','{$compose_width}','{$compose_height}')", '', '', '', $accesskey == 'NONE' ? array() : array('accesskey' => $accesskey));
    }
    // otherwise, just open new window using regular HTML
    return makeInternalLink($url, $text, '_blank', $accesskey);
}
示例#4
0
/**
 * This returns a parsed string called $body. That string can then
 * be displayed as the actual message in the HTML. It contains
 * everything needed, including HTML Tags, Attachments at the
 * bottom, etc.
 *
 * Since 1.2.0 function uses message_body hook.
 * Till 1.3.0 function included output of formatAttachments().
 *
 * @param resource $imap_stream imap connection resource
 * @param object $message squirrelmail message object
 * @param array $color squirrelmail color theme array
 * @param integer $wrap_at number of characters per line
 * @param string $ent_num (since 1.3.0) message part id
 * @param integer $id (since 1.3.0) message id
 * @param string $mailbox (since 1.3.0) imap folder name
 * @return string html formated message text
 */
function formatBody($imap_stream, $message, $color, $wrap_at, $ent_num, $id, $mailbox = 'INBOX')
{
    /* This if statement checks for the entity to show as the
     * primary message. To add more of them, just put them in the
     * order that is their priority.
     */
    global $startMessage, $languages, $squirrelmail_language, $show_html_default, $sort, $has_unsafe_images, $passed_ent_id, $use_iframe, $iframe_height, $download_and_unsafe_link, $download_href, $unsafe_image_toggle_href, $unsafe_image_toggle_text, $oTemplate, $nbsp;
    // workaround for not updated config.php
    if (!isset($use_iframe)) {
        $use_iframe = false;
    }
    // If there's no "view_unsafe_images" variable in the URL, turn unsafe
    // images off by default.
    sqgetGlobalVar('view_unsafe_images', $view_unsafe_images, SQ_GET, FALSE);
    $body = '';
    $urlmailbox = urlencode($mailbox);
    $body_message = getEntity($message, $ent_num);
    if ($body_message->header->type0 == 'text' || $body_message->header->type0 == 'rfc822') {
        $body = mime_fetch_body($imap_stream, $id, $ent_num);
        $body = decodeBody($body, $body_message->header->encoding);
        if (isset($languages[$squirrelmail_language]['XTRA_CODE']) && function_exists($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode')) {
            if (mb_detect_encoding($body) != 'ASCII') {
                $body = call_user_func($languages[$squirrelmail_language]['XTRA_CODE'] . '_decode', $body);
            }
        }
        /* As of 1.5.2, $body is passed (and modified) by reference */
        do_hook('message_body', $body);
        /* If there are other types that shouldn't be formatted, add
         * them here.
         */
        if ($body_message->header->type1 == 'html') {
            if ($show_html_default != 1) {
                $entity_conv = array('&nbsp;' => ' ', '<p>' => "\n", '<P>' => "\n", '<br>' => "\n", '<BR>' => "\n", '<br />' => "\n", '<BR />' => "\n", '&gt;' => '>', '&lt;' => '<');
                $body = strtr($body, $entity_conv);
                $body = strip_tags($body);
                $body = trim($body);
                translateText($body, $wrap_at, $body_message->header->getParameter('charset'));
            } elseif ($use_iframe) {
                /**
                 * If we don't add html message between iframe tags,
                 * we must detect unsafe images and modify $has_unsafe_images.
                 */
                $html_body = magicHTML($body, $id, $message, $mailbox);
                // Convert character set in order to display html mails in different character set
                $html_body = charset_decode($body_message->header->getParameter('charset'), $html_body, false, true);
                // creating iframe url
                $iframeurl = sqm_baseuri() . 'src/view_html.php?' . 'mailbox=' . $urlmailbox . '&amp;passed_id=' . $id . '&amp;ent_id=' . $ent_num . '&amp;view_unsafe_images=' . (int) $view_unsafe_images;
                global $oTemplate;
                $oTemplate->assign('iframe_url', $iframeurl);
                $oTemplate->assign('iframe_height', $iframe_height);
                $oTemplate->assign('html_body', $html_body);
                $body = $oTemplate->fetch('read_html_iframe.tpl');
            } else {
                // old way of html rendering
                /**
                 * convert character set. charset_decode does not remove html special chars
                 * applied by magicHTML functions and does not sanitize them second time if
                 * fourth argument is true.
                 */
                $charset = $body_message->header->getParameter('charset');
                if (!empty($charset)) {
                    $body = charset_decode($charset, $body, false, true);
                }
                $body = magicHTML($body, $id, $message, $mailbox);
            }
        } else {
            translateText($body, $wrap_at, $body_message->header->getParameter('charset'));
        }
        /*
         * Previously the links for downloading and unsafe images were printed
         * under the mail. By putting the links in a global variable we can
         * print it in the toolbar where it belongs. Since the original code was
         * in this place it's left here. It might be possible to move it to some
         * other place if that makes sense. The possibility to do so has not
         * been evaluated yet.
         */
        // Initialize the global variable to an empty string.
        // FIXME: To have $download_and_unsafe_link as a global variable might not be needed since the use of separate variables ($download_href, $unsafe_image_toggle_href, and $unsafe_image_toggle_text) for the templates was introduced.
        $download_and_unsafe_link = '';
        // Prepare and build a link for downloading the mail.
        $link = 'passed_id=' . $id . '&amp;ent_id=' . $ent_num . '&amp;mailbox=' . $urlmailbox . '&amp;sort=' . $sort . '&amp;startMessage=' . $startMessage . '&amp;show_more=0';
        if (isset($passed_ent_id)) {
            $link .= '&amp;passed_ent_id=' . $passed_ent_id;
        }
        $download_href = SM_PATH . 'src/download.php?absolute_dl=true&amp;' . $link;
        // Always add the link for downloading the mail as a file to the global
        // variable.
        $download_and_unsafe_link .= "{$nbsp}|{$nbsp}" . create_hyperlink($download_href, _("Download this as a file"));
        // Find out the right text to use in the link depending on the
        // circumstances. If the unsafe images are displayed the link should
        // hide them, if they aren't displayed the link should only appear if
        // the mail really contains unsafe images.
        if ($view_unsafe_images) {
            $text = _("Hide Unsafe Images");
        } else {
            if (isset($has_unsafe_images) && $has_unsafe_images) {
                $link .= '&amp;view_unsafe_images=1';
                $text = _("View Unsafe Images");
            } else {
                $text = '';
            }
        }
        // Only create a link for unsafe images if there's need for one. If so:
        // add it to the global variable.
        if ($text != '') {
            $unsafe_image_toggle_href = SM_PATH . 'src/read_body.php?' . $link;
            $unsafe_image_toggle_text = $text;
            $download_and_unsafe_link .= "{$nbsp}|{$nbsp}" . create_hyperlink($unsafe_image_toggle_href, $text);
        }
    }
    return $body;
}
示例#5
0
/**
 * internal function that builds mailing list links
 */
function plugin_listcommands_menu_do()
{
    global $passed_id, $passed_ent_id, $mailbox, $message, $startMessage, $oTemplate, $listcommands_allow_non_rfc_list_management;
    @(include_once SM_PATH . 'plugins/listcommands/config.php');
    /**
     * Array of commands we can deal with from the header. The Reply option
     * is added later because we generate it using the Post information.
     */
    $fieldsdescr = listcommands_fieldsdescr();
    $links = array();
    foreach ($message->rfc822_header->mlist as $cmd => $actions) {
        /* I don't know this action... skip it */
        if (!array_key_exists($cmd, $fieldsdescr)) {
            continue;
        }
        /* proto = {mailto,href} */
        $aActions = array_keys($actions);
        // note that we only use the first cmd/action, ignore the rest
        $proto = array_shift($aActions);
        $act = array_shift($actions);
        if ($proto == 'mailto') {
            $identity = '';
            if ($cmd == 'post' || $cmd == 'owner') {
                $url = 'src/compose.php?' . (isset($startMessage) ? 'startMessage=' . $startMessage . '&amp;' : '');
            } else {
                $url = "plugins/listcommands/mailout.php?action={$cmd}&amp;";
                // try to find which identity the mail should come from
                include_once SM_PATH . 'functions/identity.php';
                $idents = get_identities();
                // ripped from src/compose.php
                $identities = array();
                if (count($idents) > 1) {
                    foreach ($idents as $nr => $data) {
                        $enc_from_name = '"' . $data['full_name'] . '" <' . $data['email_address'] . '>';
                        $identities[] = $enc_from_name;
                    }
                    $identity_match = $message->rfc822_header->findAddress($identities);
                    if ($identity_match !== FALSE) {
                        $identity = $identity_match;
                    }
                }
            }
            // if things like subject are given, peel them off and give
            // them to src/compose.php as is (not encoded)
            if (strpos($act, '?') > 0) {
                list($act, $parameters) = explode('?', $act, 2);
                $parameters = '&amp;identity=' . $identity . '&amp;' . $parameters;
            } else {
                $parameters = '&amp;identity=' . $identity;
            }
            $url .= 'send_to=' . urlencode($act) . $parameters;
            $links[$cmd] = makeComposeLink($url, $fieldsdescr[$cmd]);
            if ($cmd == 'post') {
                if (!isset($mailbox)) {
                    $mailbox = 'INBOX';
                }
                $url .= '&amp;passed_id=' . $passed_id . '&amp;mailbox=' . urlencode($mailbox) . (isset($passed_ent_id) ? '&amp;passed_ent_id=' . $passed_ent_id : '');
                $url .= '&amp;smaction=reply';
                $links['reply'] = makeComposeLink($url, $fieldsdescr['reply']);
            }
        } else {
            if ($proto == 'href') {
                $links[$cmd] = create_hyperlink($act, $fieldsdescr[$cmd], '_blank');
            }
        }
    }
    // allow non-rfc reply link if admin allows and message is from
    // non-rfc list the user has configured
    //
    if ($listcommands_allow_non_rfc_list_management) {
        $non_rfc_lists = get_non_rfc_lists();
        $recipients = formatRecipientString($message->rfc822_header->to, "to") . ' ' . formatRecipientString($message->rfc822_header->cc, "cc") . ' ' . formatRecipientString($message->rfc822_header->bcc, "bcc");
        if (!in_array('post', array_keys($links))) {
            foreach ($non_rfc_lists as $non_rfc_list) {
                if (preg_match('/(^|,|<|\\s)' . preg_quote($non_rfc_list) . '($|,|>|\\s)/', $recipients)) {
                    $url = 'src/compose.php?' . (isset($startMessage) ? 'startMessage=' . $startMessage . '&amp;' : '') . 'send_to=' . str_replace('?', '&amp;', $non_rfc_list);
                    $links['post'] = makeComposeLink($url, $fieldsdescr['post']);
                    break;
                }
            }
        }
        if (!in_array('reply', array_keys($links))) {
            foreach ($non_rfc_lists as $non_rfc_list) {
                if (preg_match('/(^|,|\\s)' . preg_quote($non_rfc_list) . '($|,|\\s)/', $recipients)) {
                    if (!isset($mailbox)) {
                        $mailbox = 'INBOX';
                    }
                    $url = 'src/compose.php?' . (isset($startMessage) ? 'startMessage=' . $startMessage . '&amp;' : '') . 'send_to=' . str_replace('?', '&amp;', $non_rfc_list) . '&amp;passed_id=' . $passed_id . '&amp;mailbox=' . urlencode($mailbox) . (isset($passed_ent_id) ? '&amp;passed_ent_id=' . $passed_ent_id : '') . '&amp;smaction=reply';
                    $links['reply'] = makeComposeLink($url, $fieldsdescr['reply']);
                    break;
                }
            }
        }
    }
    if (count($links) > 0) {
        $oTemplate->assign('links', $links);
        $output = $oTemplate->fetch('plugins/listcommands/read_body_header.tpl');
        return array('read_body_header' => $output);
    }
}
function track_relative_path($trackid)
{
    $filename = get_mp3path($trackid);
    return create_hyperlink($filename);
}
示例#7
0
/**
 * Build a page (pagination) link for use with the address book list page
 *
 * @param int    $page_number       The page number for the link
 * @param string $text              The link text
 * @param array  $current_page_args All known query string arguments
 *                                  for the current page request; structured
 *                                  as an associative array of key/value pairs
 *
 */
function make_abook_paginator_link($page_number, $text, $current_page_args)
{
    $uri = sqm_baseuri() . 'src/addressbook.php';
    $current_page_args['page_number'] = $page_number;
    $uri = set_uri_vars($uri, $current_page_args, FALSE);
    return create_hyperlink($uri, $text);
}