/** * Returns sorted mailbox lists in several different ways. * See comment on sqimap_mailbox_parse() for info about the returned array. */ function sqimap_mailbox_list($imap_stream, $force = false) { global $default_folder_prefix; if (!sqgetGlobalVar('boxesnew', $boxesnew, SQ_SESSION) || $force) { global $data_dir, $username, $list_special_folders_first, $folder_prefix, $trash_folder, $sent_folder, $draft_folder, $move_to_trash, $move_to_sent, $save_as_draft, $delimiter, $noselect_fix_enable; $inbox_in_list = false; $inbox_subscribed = false; require_once SM_PATH . 'include/load_prefs.php'; if ($noselect_fix_enable) { $lsub_args = "LSUB \"{$folder_prefix}\" \"*%\""; } else { $lsub_args = "LSUB \"{$folder_prefix}\" \"*\""; } /* LSUB array */ $lsub_ary = sqimap_run_command($imap_stream, $lsub_args, true, $response, $message); $sorted_lsub_ary = array(); for ($i = 0, $cnt = count($lsub_ary); $i < $cnt; $i++) { /* * Workaround for mailboxes returned as literal * Doesn't work if the mailbox name is multiple lines * (larger then fgets buffer) */ if (isset($lsub_ary[$i + 1]) && substr($lsub_ary[$i], -3) == "}\r\n") { if (ereg("^(\\* [A-Z]+.*)\\{[0-9]+\\}([ \n\r\t]*)\$", $lsub_ary[$i], $regs)) { $i++; $lsub_ary[$i] = $regs[1] . '"' . addslashes(trim($lsub_ary[$i])) . '"' . $regs[2]; } } $temp_mailbox_name = find_mailbox_name($lsub_ary[$i]); $sorted_lsub_ary[] = $temp_mailbox_name; if (!$inbox_subscribed && strtoupper($temp_mailbox_name) == 'INBOX') { $inbox_subscribed = true; } } /* remove duplicates */ $sorted_lsub_ary = array_unique($sorted_lsub_ary); /* natural sort mailboxes */ if (isset($sorted_lsub_ary)) { mailtree_sort($sorted_lsub_ary); } /* * The LSUB response doesn't provide us information about \Noselect * mail boxes. The LIST response does, that's why we need to do a LIST * call to retrieve the flags for the mailbox * Note: according RFC2060 an imap server may provide \NoSelect flags in the LSUB response. * in other words, we cannot rely on it. */ $sorted_list_ary = array(); for ($i = 0; $i < count($sorted_lsub_ary); $i++) { if (substr($sorted_lsub_ary[$i], -1) == $delimiter) { $mbx = substr($sorted_lsub_ary[$i], 0, strlen($sorted_lsub_ary[$i]) - 1); } else { $mbx = $sorted_lsub_ary[$i]; } $read = sqimap_run_command($imap_stream, "LIST \"\" \"{$mbx}\"", true, $response, $message); /* Another workaround for literals */ if (isset($read[1]) && substr($read[1], -3) == "}\r\n") { if (ereg("^(\\* [A-Z]+.*)\\{[0-9]+\\}([ \n\r\t]*)\$", $read[0], $regs)) { $read[0] = $regs[1] . '"' . addslashes(trim($read[1])) . '"' . $regs[2]; } } if (isset($read[0])) { $sorted_list_ary[$i] = $read[0]; } else { $sorted_list_ary[$i] = ''; } } /* * Just in case they're not subscribed to their inbox, * we'll get it for them anyway */ if (!$inbox_subscribed) { $inbox_ary = sqimap_run_command($imap_stream, "LIST \"\" \"INBOX\"", true, $response, $message); /* Another workaround for literals */ if (isset($inbox_ary[1]) && substr($inbox_ary[0], -3) == "}\r\n") { if (ereg("^(\\* [A-Z]+.*)\\{[0-9]+\\}([ \n\r\t]*)\$", $inbox_ary[0], $regs)) { $inbox_ary[0] = $regs[1] . '"' . addslashes(trim($inbox_ary[1])) . '"' . $regs[2]; } } $sorted_list_ary[] = $inbox_ary[0]; $sorted_lsub_ary[] = find_mailbox_name($inbox_ary[0]); } $boxesall = sqimap_mailbox_parse($sorted_list_ary, $sorted_lsub_ary); /* Now, lets sort for special folders */ $boxesnew = $used = array(); /* Find INBOX */ $cnt = count($boxesall); $used = array_pad($used, $cnt, false); for ($k = 0; $k < $cnt; ++$k) { if (strtolower($boxesall[$k]['unformatted']) == 'inbox') { $boxesnew[] = $boxesall[$k]; $used[$k] = true; break; } } /* List special folders and their subfolders, if requested. */ if ($list_special_folders_first) { for ($k = 0; $k < $cnt; ++$k) { if (!$used[$k] && isSpecialMailbox($boxesall[$k]['unformatted'])) { $boxesnew[] = $boxesall[$k]; $used[$k] = true; } } } /* Find INBOX's children */ for ($k = 0; $k < $cnt; ++$k) { if (!$used[$k] && isBoxBelow(strtolower($boxesall[$k]['unformatted']), 'inbox') && strtolower($boxesall[$k]['unformatted']) != 'inbox') { $boxesnew[] = $boxesall[$k]; $used[$k] = true; } } /* Rest of the folders */ for ($k = 0; $k < $cnt; $k++) { if (!$used[$k]) { $boxesnew[] = $boxesall[$k]; } } sqsession_register($boxesnew, 'boxesnew'); } return $boxesnew; }
function isDraftMailbox($box) { global $draft_folder, $save_as_draft; return $save_as_draft && ($box == $draft_folder || isBoxBelow($box, $draft_folder)); }
/** * @param string $cur_mailbox unformatted mailbox name * @param array $boxes_unformatted selectable mailbox unformatted names array (reference) * @return array sub mailboxes unformatted names */ function sqimap_asearch_get_sub_mailboxes($cur_mailbox, &$mboxes_array) { $sub_mboxes_array = array(); $boxcount = count($mboxes_array); for ($boxnum = 0; $boxnum < $boxcount; $boxnum++) { if (isBoxBelow($mboxes_array[$boxnum], $cur_mailbox)) { $sub_mboxes_array[] = $mboxes_array[$boxnum]; } } return $sub_mboxes_array; }
/** * Gets the list of mailboxes for sqimap_maolbox_tree and sqimap_mailbox_list * * This is because both of those functions had duplicated logic, but with slightly different * implementations. This will make both use the same implementation, which should make it * easier to maintain and easier to modify in the future * @param stream $imap_stream imap connection resource * @param bool $force force a reload and ignore cache * @param bool $show_only_subscribed controls listing of visible or all folders * @param bool $session_register controls registration of retrieved data in session. * @return object boxesnew - array of mailboxes and their attributes * @since 1.5.1 */ function sqimap_get_mailboxes($imap_stream, $force = false, $show_only_subscribed = true, $session_register = true) { global $show_only_subscribed_folders, $noselect_fix_enable, $folder_prefix, $list_special_folders_first, $imap_server_type; $inbox_subscribed = false; $listsubscribed = sqimap_capability($imap_stream, 'LIST-SUBSCRIBED'); if ($show_only_subscribed) { $show_only_subscribed = $show_only_subscribed_folders; } //require_once(SM_PATH . 'include/load_prefs.php'); /** * There are three main listing commands we can use in IMAP: * LSUB shows just the list of subscribed folders * may include flags, but these are not necessarily accurate or authoratative * \NoSelect has special meaning: the folder does not exist -OR- it means this * folder is not subscribed but children may be * [RFC-2060] * LIST this shows every mailbox on the system * flags are always included and are accurate and authoratative * \NoSelect means folder should not be selected * [RFC-2060] * LIST (SUBSCRIBED) implemented with LIST-SUBSCRIBED extension * this is like list but returns only subscribed folders * flag meanings are like LIST, not LSUB * \NonExistent means mailbox doesn't exist * \PlaceHolder means parent is not valid (selectable), but one or more children are * \NoSelect indeed means that the folder should not be selected * IMAPEXT-LIST-EXTENSIONS-04 August 2003 B. Leiba */ if (!$show_only_subscribed) { $lsub = 'LIST'; $sub_cache_name = 'list_cache'; } elseif ($listsubscribed) { $lsub = 'LIST (SUBSCRIBED)'; $sub_cache_name = 'listsub_cache'; } else { $lsub = 'LSUB'; $sub_cache_name = 'lsub_cache'; } // Some IMAP servers allow subfolders to exist even if the parent folders do not // This fixes some problems with the folder list when this is the case, causing the // NoSelect folders to be displayed if ($noselect_fix_enable) { $lsub_args = "{$lsub} \"{$folder_prefix}\" \"*%\""; $list_args = "LIST \"{$folder_prefix}\" \"*%\""; } else { $lsub_args = "{$lsub} \"{$folder_prefix}\" \"*\""; $list_args = "LIST \"{$folder_prefix}\" \"*\""; } // get subscribed mailbox list from cache (session) // if not there, then get it from the imap server and store in cache if (!$force) { sqgetGlobalVar($sub_cache_name, $lsub_cache, SQ_SESSION); } $lsub_assoc_ary = array(); if (!empty($lsub_cache)) { $lsub_assoc_ary = $lsub_cache; } else { $lsub_ary = sqimap_run_command($imap_stream, $lsub_args, true, $response, $message); $lsub_ary = compact_mailboxes_response($lsub_ary); if (!empty($lsub_ary)) { foreach ($lsub_ary as $rawline) { $temp_mailbox_name = find_mailbox_name($rawline); $lsub_assoc_ary[$temp_mailbox_name] = $rawline; } unset($lsub_ary); sqsession_register($lsub_assoc_ary, $sub_cache_name); } } // Now to get the mailbox flags // The LSUB response may return \NoSelect flags, etc. but it is optional // according to RFC3501, and even when returned it may not be accurate // or authoratative. LIST will always return accurate results. if ($lsub == 'LIST' || $lsub == 'LIST (SUBSCRIBED)') { // we've already done a LIST or LIST (SUBSCRIBED) // and NOT a LSUB, so no need to do it again $list_assoc_ary = $lsub_assoc_ary; } else { // we did a LSUB so now we need to do a LIST // first see if it is in cache $list_cache_name = 'list_cache'; if (!$force) { sqgetGlobalVar($list_cache_name, $list_cache, SQ_SESSION); } if (!empty($list_cache)) { $list_assoc_ary = $list_cache; // we could store this in list_cache_name but not necessary } else { // not in cache so we need to go get it from the imap server $list_assoc_ary = array(); $list_ary = sqimap_run_command($imap_stream, $list_args, true, $response, $message); $list_ary = compact_mailboxes_response($list_ary); if (!empty($list_ary)) { foreach ($list_ary as $rawline) { $temp_mailbox_name = find_mailbox_name($rawline); $list_assoc_ary[$temp_mailbox_name] = $rawline; } unset($list_ary); sqsession_register($list_assoc_ary, $list_cache_name); } } } // If they aren't subscribed to the inbox, then add it anyway (if its in LIST) $inbox_subscribed = false; if (!empty($lsub_assoc_ary)) { foreach ($lsub_assoc_ary as $temp_mailbox_name => $rawline) { if (strtoupper($temp_mailbox_name) == 'INBOX') { $inbox_subscribed = true; } } } if (!$inbox_subscribed) { if (!empty($list_assoc_ary)) { foreach ($list_assoc_ary as $temp_mailbox_name => $rawline) { if (strtoupper($temp_mailbox_name) == 'INBOX') { $lsub_assoc_ary[$temp_mailbox_name] = $rawline; } } } } // Now we have the raw output, we need to create an array of mailbox names we will return if (!$show_only_subscribed) { $final_folders_assoc_ary = $list_assoc_ary; } else { /** * only show subscribed folders * we need to merge the folders here... we can't trust the flags, etc. from the lsub_assoc_array * so we use the lsub_assoc_array as the list of folders and the values come from list_assoc_array */ if (!empty($lsub_assoc_ary)) { foreach ($lsub_assoc_ary as $temp_mailbox_name => $rawline) { if (!empty($list_assoc_ary[$temp_mailbox_name])) { $final_folders_assoc_ary[$temp_mailbox_name] = $list_assoc_ary[$temp_mailbox_name]; } } } } // Now produce a flat, sorted list if (!empty($final_folders_assoc_ary)) { uksort($final_folders_assoc_ary, 'strnatcasecmp'); foreach ($final_folders_assoc_ary as $temp_mailbox_name => $rawline) { $final_folders_ary[] = $rawline; } } // this will put it into an array we can use later // containing: // raw - Raw LIST/LSUB response from the IMAP server // formatted - formatted folder name // unformatted - unformatted, but with the delimiter at the end removed // unformated-dm - folder name as it appears in raw response // unformatted-disp - unformatted without $folder_prefix // id - the array element number (0, 1, 2, etc.) // flags - mailbox flags if (!empty($final_folders_ary)) { $boxesall = sqimap_mailbox_parse($final_folders_ary); } else { // they have no mailboxes $boxesall = array(); } /* Now, lets sort for special folders */ $boxesnew = $used = array(); /* Find INBOX */ $cnt = count($boxesall); $used = array_pad($used, $cnt, false); $has_inbox = false; for ($k = 0; $k < $cnt; ++$k) { if (strtoupper($boxesall[$k]['unformatted']) == 'INBOX') { $boxesnew[] = $boxesall[$k]; $used[$k] = true; $has_inbox = true; break; } } if ($has_inbox == false) { // do a list request for inbox because we should always show // inbox even if the user isn't subscribed to it. $inbox_ary = sqimap_run_command($imap_stream, 'LIST "" "INBOX"', true, $response, $message); $inbox_ary = compact_mailboxes_response($inbox_ary); if (count($inbox_ary)) { $inbox_entry = sqimap_mailbox_parse($inbox_ary); // add it on top of the list if (!empty($boxesnew)) { array_unshift($boxesnew, $inbox_entry[0]); } else { $boxesnew[] = $inbox_entry[0]; } /* array_unshift($used,true); */ } } /* List special folders and their subfolders, if requested. */ if ($list_special_folders_first) { for ($k = 0; $k < $cnt; ++$k) { if (!$used[$k] && isSpecialMailbox($boxesall[$k]['unformatted'])) { $boxesnew[] = $boxesall[$k]; $used[$k] = true; } } } /* Find INBOX's children */ for ($k = 0; $k < $cnt; ++$k) { $isboxbelow = isBoxBelow(strtoupper($boxesall[$k]['unformatted']), 'INBOX'); if (strtoupper($boxesall[$k]['unformatted']) == 'INBOX') { $is_inbox = 1; } else { $is_inbox = 0; } if (!$used[$k] && $isboxbelow && $is_inbox) { $boxesnew[] = $boxesall[$k]; $used[$k] = true; } } /* Rest of the folders */ for ($k = 0; $k < $cnt; $k++) { if (!$used[$k]) { $boxesnew[] = $boxesall[$k]; } } /** * Don't register boxes in session, if $session_register is set to false * Prevents registration of sqimap_mailbox_list_all() results. */ if ($session_register) { sqsession_register($boxesnew, 'boxesnew'); } return $boxesnew; }