Source for file mailbox_display.php

Documentation is available at mailbox_display.php

  1. <?php
  2.  
  3. /**
  4.  * mailbox_display.php
  5.  *
  6.  * This contains functions that display mailbox information, such as the
  7.  * table row that has sender, date, subject, etc...
  8.  *
  9.  * @copyright &copy; 1999-2006 The SquirrelMail Project Team
  10.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  11.  * @version $Id: mailbox_display.php,v 1.465 2006/07/15 12:00:45 tokul Exp $
  12.  * @package squirrelmail
  13.  */
  14.  
  15.  
  16. /**
  17.  * Selects a mailbox for header retrieval.
  18.  * Cache control for message headers is embedded.
  19.  *
  20.  * @param resource $imapConnection imap socket handle
  21.  * @param string   $mailbox mailbox to select and retrieve message headers from
  22.  * @param array    $aConfig array with system config settings and incoming vars
  23.  * @param array    $aProps mailbox specific properties
  24.  * @return array   $aMailbox mailbox array with all relevant information
  25.  * @since 1.5.1
  26.  * @author Marc Groot Koerkamp
  27.  */
  28. function sqm_api_mailbox_select($imapConnection,$account,$mailbox,$aConfig,$aProps{
  29.  
  30.     /**
  31.      * NB: retrieve this from the session before accessing this function
  32.      * and make sure you write it back at the end of the script after
  33.      * the aMailbox var is added so that the headers are added to the cache
  34.      */
  35.     global $mailbox_cache;
  36.  
  37.     $aDefaultConfigProps array(
  38. //                'charset'           => 'US-ASCII',
  39.                 'user'              => false/* no pref storage if false */
  40.                 'setindex'          => 0,
  41. //                'search'            => 'ALL',
  42.                 'max_cache_size'    => SQM_MAX_MBX_IN_CACHE
  43.                 );
  44.  
  45.     $aConfig array_merge($aDefaultConfigProps,$aConfig);
  46.  
  47.     $iSetIndx $aConfig['setindex'];
  48.  
  49.     $aMbxResponse sqimap_mailbox_select($imapConnection$mailbox);
  50.  
  51.     if ($mailbox_cache{
  52.         if (isset($mailbox_cache[$account.'_'.$mailbox])) {
  53.             $aCachedMailbox $mailbox_cache[$account.'_'.$mailbox];
  54.         else {
  55.             $aCachedMailbox false;
  56.         }
  57.             /* cleanup cache */
  58.         if (count($mailbox_cache$aConfig['max_cache_size'-1{
  59.             $aTime array();
  60.             foreach($mailbox_cache as $cachedmailbox => $aVal{
  61.                 $aTime[$aVal['TIMESTAMP']] $cachedmailbox;
  62.             }
  63.             if (ksort($aTime,SORT_NUMERIC)) {
  64.                 for ($i=0,$iCnt=count($mailbox_cache);$i<($iCnt-$aConfig['max_cache_size']);++$i{
  65.                     $sOldestMbx array_shift($aTime);
  66.                     /**
  67.                      * Remove only the UIDSET and MSG_HEADERS from cache because those can
  68.                      * contain large amounts of data.
  69.                      */
  70.                     if (isset($mailbox_cache[$sOldestMbx]['UIDSET'])) {
  71.                         $mailbox_cache[$sOldestMbx]['UIDSET']false;
  72.                     }
  73.                     if (isset($mailbox_cache[$sOldestMbx]['MSG_HEADERS'])) {
  74.                         $mailbox_cache[$sOldestMbx]['MSG_HEADERS'false;
  75.                     }
  76.                 }
  77.             }
  78.         }
  79.  
  80.     else {
  81.         $aCachedMailbox false;
  82.     }
  83.  
  84.     /**
  85.      * Deal with imap servers that do not return the required UIDNEXT or
  86.      * UIDVALIDITY response
  87.      * from a SELECT call (since rfc 3501 it's required).
  88.      */
  89.     if (!isset($aMbxResponse['UIDNEXT']|| !isset($aMbxResponse['UIDVALIDITY'])) {
  90.         $aStatus sqimap_status_messages($imapConnection,$mailbox,
  91.                                         array('UIDNEXT','UIDVALIDITY'));
  92.         $aMbxResponse['UIDNEXT'$aStatus['UIDNEXT'];
  93.         $aMbxResponse['UIDVALIDTY'$aStatus['UIDVALIDITY'];
  94.     }
  95.  
  96.     $aMailbox['ACCOUNT'$account;
  97.     $aMailbox['UIDSET'][$iSetIndxfalse;
  98.     $aMailbox['ID'false;
  99.     $aMailbox['SETINDEX'$iSetIndx;
  100.     $aMailbox['MSG_HEADERS'false;
  101.  
  102.     if ($aCachedMailbox{
  103.         /**
  104.          * Validate integrity of cached data
  105.          */
  106.         if ($aCachedMailbox['EXISTS'== $aMbxResponse['EXISTS'&&
  107.             $aMbxResponse['EXISTS'&&
  108.             $aCachedMailbox['UIDVALIDITY'== $aMbxResponse['UIDVALIDITY'&&
  109.             $aCachedMailbox['UIDNEXT']  == $aMbxResponse['UIDNEXT'&&
  110.             isset($aCachedMailbox['SEARCH'][$iSetIndx]&&
  111.             (!isset($aConfig['search']|| /* always set search from the searchpage */
  112.              $aCachedMailbox['SEARCH'][$iSetIndx== $aConfig['search'])) {
  113.             if (isset($aCachedMailbox['MSG_HEADERS'])) {
  114.                 $aMailbox['MSG_HEADERS'$aCachedMailbox['MSG_HEADERS'];
  115.             }
  116.             $aMailbox['ID'=  $aCachedMailbox['ID'];
  117.             if (isset($aCachedMailbox['UIDSET'][$iSetIndx]&& $aCachedMailbox['UIDSET'][$iSetIndx]{
  118.                 if (isset($aProps[MBX_PREF_SORT]&&  $aProps[MBX_PREF_SORT!= $aCachedMailbox['SORT'{
  119.                     $newsort $aProps[MBX_PREF_SORT];
  120.                     $oldsort $aCachedMailbox['SORT'];
  121.                     /**
  122.                      * If it concerns a reverse sort we do not need to invalidate
  123.                      * the cached sorted UIDSET, a reverse is sufficient.
  124.                      */
  125.                     if ((($newsort 2&& ($newsort == $oldsort)) ||
  126.                         (!($newsort 2&& ($newsort == $oldsort))) {
  127.                         $aMailbox['UIDSET'][$iSetIndxarray_reverse($aCachedMailbox['UIDSET'][$iSetIndx]);
  128.                     else {
  129.                         $server_sort_array false;
  130.                         $aMailbox['MSG_HEADERS'false;
  131.                         $aMailbox['ID'false;
  132.                     }
  133.                     // store the new sort value in the mailbox pref
  134.                     if ($aConfig['user']{
  135.                         // FIXME, in ideal situation, we write back the
  136.                         // prefs at the end of the script
  137.                         setUserPref($aConfig['user'],'pref_'.$account.'_'.$mailbox,serialize($aProps));
  138.                     }
  139.                 else {
  140.                     $aMailbox['UIDSET'][$iSetIndx$aCachedMailbox['UIDSET'][$iSetIndx];
  141.                 }
  142.             }
  143.         }
  144.     }
  145.     /**
  146.      * Restore the offset in the paginator if no new offset is provided.
  147.      */
  148.     if (isset($aMailbox['UIDSET'][$iSetIndx]&& !isset($aConfig['offset']&& $aCachedMailbox['OFFSET']{
  149.         $aMailbox['OFFSET'=  $aCachedMailbox['OFFSET'];
  150.         $aMailbox['PAGEOFFSET'=  $aCachedMailbox['PAGEOFFSET'];
  151.     else {
  152.         $aMailbox['OFFSET'(isset($aConfig['offset']&& $aConfig['offset']$aConfig['offset'-0;
  153.         $aMailbox['PAGEOFFSET'(isset($aConfig['offset']&& $aConfig['offset']$aConfig['offset'1;
  154.     }
  155.     /**
  156.      * Restore the number of messages in the result set
  157.      */
  158.     if (isset($aCachedMailbox['TOTAL'][$iSetIndx]&& $aCachedMailbox['TOTAL'][$iSetIndx]{
  159.         $aMailbox['TOTAL'][$iSetIndx=  $aCachedMailbox['TOTAL'][$iSetIndx];
  160.     }
  161.  
  162.     /**
  163.      * Restore the showall value no new showall value is provided.
  164.      */
  165.     if (isset($aMailbox['UIDSET'][$iSetIndx]&& !isset($aConfig['showall']&&
  166.         isset($aCachedMailbox['SHOWALL'][$iSetIndx]&& $aCachedMailbox['SHOWALL'][$iSetIndx]{
  167.         $aMailbox['SHOWALL'][$iSetIndx=  $aCachedMailbox['SHOWALL'][$iSetIndx];
  168.     else {
  169.         $aMailbox['SHOWALL'][$iSetIndx(isset($aConfig['showall']&& $aConfig['showall']0;
  170.     }
  171.  
  172.     /**
  173.      * Restore the sort order if no new sort order is provided.
  174.      */
  175.     if (!isset($aProps[MBX_PREF_SORT]&& isset($aCachedMailbox['SORT'])) {
  176.         $aMailbox['SORT'$aCachedMailbox['SORT'];
  177.     else {
  178.         $aMailbox['SORT'=  (isset($aProps[MBX_PREF_SORT])) $aProps[MBX_PREF_SORT0;
  179.     }
  180.  
  181.     /**
  182.      * Restore the number of message to show per page when no new limit is provided
  183.      */
  184.     if (!isset($aProps[MBX_PREF_LIMIT]&& isset($aCachedMailbox['LIMIT'])) {
  185.         $aMailbox['LIMIT'$aCachedMailbox['LIMIT'];
  186.     else {
  187.         $aMailbox['LIMIT'=  (isset($aProps[MBX_PREF_LIMIT])) $aProps[MBX_PREF_LIMIT15;
  188.     }
  189.  
  190.     /**
  191.      * Restore the ordered columns to show when no new ordered columns are provided
  192.      */
  193.     if (!isset($aProps[MBX_PREF_COLUMNS]&& isset($aCachedMailbox['COLUMNS'])) {
  194.         $aMailbox['COLUMNS'$aCachedMailbox['COLUMNS'];
  195.     else {
  196.         $aMailbox['COLUMNS'=  (isset($aProps[MBX_PREF_COLUMNS])) $aProps[MBX_PREF_COLUMNS:
  197.             array(SQM_COL_FLAGS,SQM_COL_FROMSQM_COL_SUBJSQM_COL_FLAGS);
  198.     }
  199.  
  200.     /**
  201.      * Restore the headers we fetch the last time. Saves intitialisation stuff in read_body.
  202.      */
  203.     $aMailbox['FETCHHEADERS'(isset($aCachedMailbox['FETCHHEADERS'])) $aCachedMailbox['FETCHHEADERS'null;
  204.  
  205.     if (!isset($aProps[MBX_PREF_AUTO_EXPUNGE]&& isset($aCachedMailbox['AUTO_EXPUNGE'])) {
  206.         $aMailbox['AUTO_EXPUNGE'$aCachedMailbox['AUTO_EXPUNGE'];
  207.     else {
  208.         $aMailbox['AUTO_EXPUNGE'=  (isset($aProps[MBX_PREF_AUTO_EXPUNGE])) $aProps[MBX_PREF_AUTO_EXPUNGEfalse;
  209.     }
  210.     if (!isset($aConfig['search']&& isset($aCachedMailbox['SEARCH'][$iSetIndx])) {
  211.         $aMailbox['SEARCH'][$iSetIndx$aCachedMailbox['SEARCH'][$iSetIndx];
  212.     else if (isset($aConfig['search']&& isset($aCachedMailbox['SEARCH'][$iSetIndx]&&
  213.         $aConfig['search'!= $aCachedMailbox['SEARCH'][$iSetIndx]{
  214.         // reset the pageindex
  215.         $aMailbox['SEARCH'][$iSetIndx$aConfig['search'];
  216.         $aMailbox['OFFSET'0;
  217.         $aMailbox['PAGEOFFSET'1;
  218.     else {
  219.         $aMailbox['SEARCH'][$iSetIndx=  (isset($aConfig['search'])) $aConfig['search''ALL';
  220.     }
  221.     if (!isset($aConfig['charset']&& isset($aCachedMailbox['CHARSET'][$iSetIndx])) {
  222.         $aMailbox['CHARSET'][$iSetIndx$aCachedMailbox['CHARSET'][$iSetIndx];
  223.     else {
  224.         $aMailbox['CHARSET'][$iSetIndx=  (isset($aConfig['charset'])) $aConfig['charset''US-ASCII';
  225.     }
  226.  
  227.     $aMailbox['NAME'$mailbox;
  228.     $aMailbox['EXISTS'$aMbxResponse['EXISTS'];
  229.     $aMailbox['SEEN'(isset($aMbxResponse['SEEN'])) $aMbxResponse['SEEN'$aMbxResponse['EXISTS'];
  230.     $aMailbox['RECENT'(isset($aMbxResponse['RECENT'])) $aMbxResponse['RECENT'0;
  231.     $aMailbox['UIDVALIDITY'$aMbxResponse['UIDVALIDITY'];
  232.     $aMailbox['UIDNEXT'$aMbxResponse['UIDNEXT'];
  233.     $aMailbox['PERMANENTFLAGS'$aMbxResponse['PERMANENTFLAGS'];
  234.     $aMailbox['RIGHTS'$aMbxResponse['RIGHTS'];
  235.  
  236.     /* decide if we are thread sorting or not */
  237.     if ($aMailbox['SORT'SQSORT_THREAD{
  238.         if (!sqimap_capability($imapConnection,'THREAD')) {
  239.             $aMailbox['SORT'^= SQSORT_THREAD;
  240.         else {
  241.             $aMailbox['THREAD_INDENT'$aCachedMailbox['THREAD_INDENT'];
  242.         }
  243.     else {
  244.         $aMailbox['THREAD_INDENT'false;
  245.     }
  246.  
  247.     /* set a timestamp for cachecontrol */
  248.     $aMailbox['TIMESTAMP'time();
  249.     return $aMailbox;
  250. }
  251.  
  252. /**
  253.  * Fetch the message headers for a mailbox. Settings are part of the aMailbox
  254.  * array. Dependent of the mailbox settings it deals with sort, thread and search
  255.  * If server sort is supported then SORT is also used for retrieving sorted search results
  256.  *
  257.  * @param resource $imapConnection imap socket handle
  258.  * @param array    $aMailbox (reference) mailbox retrieved from sqm_api_mailbox_select
  259.  * @return error   $error error number
  260.  * @since 1.5.1
  261.  * @author Marc Groot Koerkamp
  262.  */
  263. function fetchMessageHeaders($imapConnection&$aMailbox{
  264.  
  265.     /* FIX ME, this function is kind of big, maybe we can split it up in
  266.        a couple of functions. Make sure the functions are private and starts with _
  267.        Also make sure that the error codes are propagated */
  268.  
  269.     /**
  270.      * Retrieve the UIDSET.
  271.      * Setindex is used to be able to store multiple uid sets. That will make it
  272.      * possible to display the mailbox multiple times in different sort order
  273.      * or to store serach results separate from normal mailbox view.
  274.      */
  275.     $iSetIndx =  (isset($aMailbox['SETINDEX'])) $aMailbox['SETINDEX'0;
  276.  
  277.     $iLimit ($aMailbox['SHOWALL'][$iSetIndx]$aMailbox['EXISTS'$aMailbox['LIMIT'];
  278.     /**
  279.      * Adjust the start_msg
  280.      */
  281.     $start_msg $aMailbox['PAGEOFFSET'];
  282.     if($aMailbox['PAGEOFFSET'$aMailbox['EXISTS']{
  283.         $start_msg -= $aMailbox['LIMIT'];
  284.         if($start_msg 1{
  285.             $start_msg 1;
  286.         }
  287.     }
  288.  
  289.     if (is_array($aMailbox['UIDSET'])) {
  290.         $aUid =$aMailbox['UIDSET'][$iSetIndx];
  291.     else {
  292.         $aUid false;
  293.     }
  294.     $aFetchHeaders $aMailbox['FETCHHEADERS'];
  295.  
  296.     $iError 0;
  297.     $aFetchItems $aHeaderItems array();
  298.     // initialize the fields we want to retrieve:
  299.     $aHeaderFields array();
  300.     foreach ($aFetchHeaders as $v{
  301.       switch ($v{
  302.         case SQM_COL_DATE:       $aHeaderFields['Date';         break;
  303.         case SQM_COL_TO:         $aHeaderFields['To';           break;
  304.         case SQM_COL_CC:         $aHeaderFields['Cc';           break;
  305.         case SQM_COL_FROM:       $aHeaderFields['From';         break;
  306.         case SQM_COL_SUBJ:       $aHeaderFields['Subject';      break;
  307.         case SQM_COL_PRIO:       $aHeaderFields['X-Priority';   break;
  308.         case SQM_COL_ATTACHMENT$aHeaderFields['Content-Type'break;
  309.         case SQM_COL_INT_DATE:   $aFetchItems[]   'INTERNALDATE'break;
  310.         case SQM_COL_FLAGS:      $aFetchItems[]   'FLAGS';        break;
  311.         case SQM_COL_SIZE:       $aFetchItems[]   'RFC822.SIZE';  break;
  312.         defaultbreak;
  313.       }
  314.     }
  315.  
  316.     /**
  317.      * A uidset with sorted uid's is available. We can use the cache
  318.      */
  319.     if (isset($aUid&& $aUid {
  320.         // limit the cache to SQM_MAX_PAGES_IN_CACHE
  321.         if (!$aMailbox['SHOWALL'][$iSetIndx&& isset($aMailbox['MSG_HEADERS'])) {
  322.             $iMaxMsgs $iLimit SQM_MAX_PAGES_IN_CACHE;
  323.             $iCacheSize count($aMailbox['MSG_HEADERS']);
  324.             if ($iCacheSize $iMaxMsgs{
  325.                 $iReduce $iCacheSize $iMaxMsgs;
  326.                 foreach ($aMailbox['MSG_HEADERS'as $iUid => $value{
  327.                     if ($iReduce{
  328.                         unset($aMailbox['MSG_HEADERS'][$iUid]);
  329.                     else {
  330.                         break;
  331.                     }
  332.                     --$iReduce;
  333.                 }
  334.             }
  335.         }
  336.  
  337.         $id_slice array_slice($aUid,$start_msg-1,$iLimit);
  338.         /* do some funky cache checks */
  339.         if (isset($aMailbox['MSG_HEADERS']&& is_array($aMailbox['MSG_HEADERS'])) {
  340.             // temp code, read_body del / next links fo not update fields.
  341.             foreach ($aMailbox['MSG_HEADERS'as $iUid => $aValue{
  342.                 if (!isset($aValue['UID'])) {
  343.                     unset($aMailbox['MSG_HEADERS'][$iUid]);
  344.                 }
  345.             }
  346.             $aUidCached array_keys($aMailbox['MSG_HEADERS']);
  347.         else {
  348.             $aMailbox['MSG_HEADERS'array();
  349.             $aUidCached array();
  350.         }
  351.         $aUidNotCached array_values(array_diff($id_slice,$aUidCached));
  352.  
  353.         /**
  354.          * $aUidNotCached contains an array with UID's which need to be fetched to
  355.          * complete the needed message headers.
  356.          */
  357.         if (count($aUidNotCached)) {
  358.             $aMsgs sqimap_get_small_header_list($imapConnection,$aUidNotCached,
  359.                                                     $aHeaderFields,$aFetchItems);
  360.             // append the msgs to the existend headers
  361.             $aMailbox['MSG_HEADERS'+= $aMsgs;
  362.         }
  363.     else {
  364.         /**
  365.          * Initialize the sorted UID list or initiate a UID list with search
  366.          * results and fetch the visible message headers
  367.          */
  368.  
  369.         if ($aMailbox['SEARCH'][$iSetIndx!= 'ALL'// in case of a search request
  370.  
  371.             if ($aMailbox['SEARCH'][$iSetIndx&& $aMailbox['SORT'== 0{
  372.                 $aUid sqimap_run_search($imapConnection$aMailbox['SEARCH'][$iSetIndx]$aMailbox['CHARSET'][$iSetIndx]);
  373.             else {
  374.  
  375.                 $iError 0;
  376.                 $iError _get_sorted_msgs_list($imapConnection,$aMailbox,$iError);
  377.                 $aUid $aMailbox['UIDSET'][$iSetIndx];
  378.             }
  379.             if (!$iError{
  380.                 /**
  381.                  * Number of messages is the resultset
  382.                  */
  383.                 $aMailbox['TOTAL'][$iSetIndxcount($aUid);
  384.                 $id_slice array_slice($aUid,$aMailbox['OFFSET']$iLimit);
  385.                 if (count($id_slice)) {
  386.                     $aMailbox['MSG_HEADERS'sqimap_get_small_header_list($imapConnection,$id_slice,
  387.                         $aHeaderFields,$aFetchItems);
  388.                 else {
  389.                     $iError 1// FIX ME, define an error code
  390.                 }
  391.             }
  392.         else //
  393.             $iError 0;
  394.             $iError _get_sorted_msgs_list($imapConnection,$aMailbox,$iError);
  395.             $aUid $aMailbox['UIDSET'][$iSetIndx];
  396.  
  397.             if (!$iError{
  398.                 /**
  399.                  * Number of messages is the resultset
  400.                  */
  401.                 $aMailbox['TOTAL'][$iSetIndxcount($aUid);
  402.                 $id_slice array_slice($aUid,$aMailbox['OFFSET']$iLimit);
  403.                 if (count($id_slice)) {
  404.                     $aMailbox['MSG_HEADERS'sqimap_get_small_header_list($imapConnection,$id_slice,
  405.                         $aHeaderFields,$aFetchItems);
  406.                 else {
  407.                     $iError 1// FIX ME, define an error code
  408.    &nb