* @param bool $reverse Reverse order search
* @return array $id sorted uid list
*/
-function sqimap_get_sort_order ($imap_stream, $sSortField = 'UID',$reverse) {
+function sqimap_get_sort_order ($imap_stream, $sSortField,$reverse) {
global $default_charset,
$sent_folder;
$sort_test = array();
$sort_query = '';
- if ($sSortField == 'UID') {
- $query = "SEARCH UID 1:*";
- $uids = sqimap_run_command ($imap_stream, $query, true, $response, $message, true);
- if (isset($uids[0])) {
- if (preg_match("/^\* SEARCH (.+)$/", $uids[0], $regs)) {
- $id = preg_split("/ /", trim($regs[1]));
- }
- }
- if (!preg_match("/OK/", $response)) {
- $id = false;
- }
- $id = array_reverse($id);
- return $id;
- }
if ($sSortField) {
if ($reverse) {
$sSortField = 'REVERSE '.$sSortField;
* @param resource $imap_stream IMAP socket connection
* @param string $sSortField Field to sort on
* @param bool $reverse Reverse order search
-* @param mixed $key UNDOCUMENTED
-* @return array $id sorted uid list
+* @return array $aUid sorted uid list
*/
function get_squirrel_sort ($imap_stream, $sSortField, $reverse = false) {
-
- if ($sSortField == 'UID') {
- $query = "SEARCH UID 1:*";
- $uids = sqimap_run_command ($imap_stream, $query, true, $response, $message, true);
- if (isset($uids[0])) {
- if (preg_match("/^\* SEARCH (.+)$/", $uids[0], $regs)) {
- $msgs = preg_split("/ /", trim($regs[1]));
- }
- }
- if (!preg_match("/OK/", $response)) {
- $msgs = false;
- }
- } else if ($sSortField != 'RFC822.SIZE' && $sSortField != 'INTERNALDATE') {
+ if ($sSortField != 'RFC822.SIZE' && $sSortField != 'INTERNALDATE') {
$msgs = sqimap_get_small_header_list($imap_stream, false, '*',
- array($sSortField), array('UID'));
+ array($sSortField), array());
} else {
$msgs = sqimap_get_small_header_list($imap_stream, false, '*',
- array(), array('UID', $sSortField));
+ array(), array($sSortField));
}
+ $aUid = array();
+ $walk = false;
switch ($sSortField) {
+ // natcasesort section
case 'FROM':
- array_walk($msgs, create_function('&$v,&$k',
- '$from = parseAddress($v["FROM"]);
- $v["FROM"] = ($from[0][1]) ? decodeHeader($from[0][1]):$from[0][0];'));
- foreach ($msgs as $item) {
- $msort["$item[ID]"] = (isset($item['FROM'])) ? $item['FROM'] : '';
- }
-
- natcasesort($msort);
- $msort = array_keys($msort);
- if ($reverse) {
- array_reverse($msort);
- }
- break;
case 'TO':
- array_walk($msgs, create_function('&$v,&$k',
- '$from = parseAddress($v["TO"]);
- $v["TO"] = ($from[0][1]) ? decodeHeader($from[0][1]):$from[0][0];'));
- foreach ($msgs as $item) {
- $msort["$item[ID]"] = (isset($item['TO'])) ? $item['TO'] : '';
- }
-
- natcasesort($msort);
- $msort = array_keys($msort);
- if ($reverse) {
- array_reverse($msort);
- }
- break;
-
+ case 'CC':
+ if(!$walk) {
+ array_walk($msgs, create_function('&$v,&$k,$f',
+ '$v[$f] = (isset($v[$f])) ? $v[$f] : "";
+ $addr = parseAddress($v[$f]);
+ $v[$f] = ($addr[0][1]) ? decodeHeader($addr[0][1]):$addr[0][0];'),$sSortField);
+ $walk = true;
+ }
+ // nobreak
case 'SUBJECT':
- array_walk($msgs, create_function('&$v,&$k',
- '$v["SUBJECT"] = strtolower(decodeHeader(trim($v["SUBJECT"])));
- $v["SUBJECT"] = (preg_match("/^(vedr|sv|re|aw):\s*(.*)$/si", $v["SUBJECT"], $matches)) ?
- $matches[2] : $v["SUBJECT"];'));
+ if(!$walk) {
+ array_walk($msgs, create_function('&$v,&$k,$f',
+ '$v[$f] = (isset($v[$f])) ? $v[$f] : "";
+ $v[$f] = strtolower(decodeHeader(trim($v[$f])));
+ $v[$f] = (preg_match("/^(vedr|sv|re|aw|\[\w\]):\s*(.*)$/si", $v[$f], $matches)) ?
+ $matches[2] : $v[$f];'),$sSortField);
+ $walk = true;
+ }
foreach ($msgs as $item) {
- $msort["$item[ID]"] = $item['SUBJECT'];
+ $aUid[$item['ID']] = $item[$sSortField];
}
- natcasesort($msort);
- $msort = array_keys($msort);
+ natcasesort($aUid);
+ $aUid = array_keys($aUid);
if ($reverse) {
- array_reverse($msort);
+ $aUid = array_reverse($aUid);
}
break;
+ // \natcasesort section
+ // sort_numeric section
case 'DATE':
- array_walk($msgs, create_function('&$v,$k',
- '$v["DATE"] = getTimeStamp(explode(" ",$v["DATE"]));'));
- foreach ($msgs as $item) {
- $msort[$item['ID']] = $item['DATE'];
- }
- if ($reverse) {
- arsort($msort,SORT_NUMERIC);
- } else {
- asort( $msort, SORT_NUMERIC);
+ case 'INTERNALDATE':
+ if(!$walk) {
+ array_walk($msgs, create_function('&$v,$k,$f',
+ '$v[$f] = (isset($v[$f])) ? $v[$f] : "";
+ $v[$f] = getTimeStamp(explode(" ",$v[$f]));'),$sSortField);
+ $walk = true;
}
- $msort = array_keys($msort);
- break;
+ // nobreak;
case 'RFC822.SIZE':
- case 'INTERNALDATE':
- //array_walk($msgs, create_function('&$v,$k',
- // '$v["RFC822.SIZE"] = getTimeStamp(explode(" ",$v["RFC822.SIZE"]));'));
+ if(!$walk) {
+ // redefine $sSortField to maintain the same namespace between
+ // server-side sorting and squirrelmail sorting
+ $sSortField = 'SIZE';
+ }
foreach ($msgs as $item) {
- $msort[$item['ID']] = $item['SIZE'];
+ $aUid[$item['ID']] = (isset($item[$sSortField])) ? $item[$sSortField] : 0;
}
if ($reverse) {
- arsort($msort,SORT_NUMERIC);
+ arsort($aUid,SORT_NUMERIC);
} else {
- asort($msort, SORT_NUMERIC);
+ asort($aUid, SORT_NUMERIC);
}
- $msort = array_keys($msort);
+ $aUid = array_keys($aUid);
break;
+ // \sort_numeric section
case 'UID':
- $msort = array_reverse($msgs);
+ $aUid = array_reverse($msgs);
break;
}
- return $msort;
+ return $aUid;
}
/**
* This represents the amount of indent needed (value),
* for this message number (key)
*/
+
+/*
+ * Notes for future work:
+ * indent_array should contain: indent_level, parent and flags,
+ * sibling notes ..
+ * To achieve that we need to define the following flags:
+ * 0: hasnochildren
+ * 1: haschildren
+ * 2: is first
+ * 4: is last
+ * a node has sibling nodes if it's not the last node
+ * a node has no sibling nodes if it's the last node
+ * By using binary comparations we can store the flag in one var
+ *
+ * example:
+ * -1 par = 0, level = 0, flag = 1 + 2 + 4 = 7 (haschildren, isfirst, islast)
+ * \-2 par = 1, level = 1, flag = 0 + 2 = 2 (hasnochildren, isfirst)
+ * |-3 par = 1, level = 1, flag = 1 + 4 = 5 (haschildren, islast)
+ * \-4 par = 3, level = 2, flag = 1 + 2 + 4 = 7 (haschildren, isfirst, islast)
+ * \-5 par = 4, level = 3, flag = 0 + 2 + 4 = 6 (hasnochildren, isfirst, islast)
+ */
function get_parent_level ($thread_new) {
$parent = '';
$child = '';
$cutoff = 0;
- /* loop through the threads and take unwanted characters out
- of the thread string then chop it up
- */
+ /*
+ * loop through the threads and take unwanted characters out
+ * of the thread string then chop it up
+ */
for ($i=0;$i<count($thread_new);$i++) {
$thread_new[$i] = preg_replace("/\s\(/", "(", $thread_new[$i]);
$thread_new[$i] = preg_replace("/(\d+)/", "$1|", $thread_new[$i]);
$thread_new[$i] = preg_split("/\|/", $thread_new[$i], -1, PREG_SPLIT_NO_EMPTY);
}
$indent_array = array();
- if (!$thread_new) {
- $thread_new = array();
- }
+ if (!$thread_new) {
+ $thread_new = array();
+ }
/* looping through the parts of one message thread */
for ($i=0;$i<count($thread_new);$i++) {
- /* first grab the parent, it does not indent */
+ /* first grab the parent, it does not indent */
if (isset($thread_new[$i][0])) {
if (preg_match("/(\d+)/", $thread_new[$i][0], $regs)) {
}
$indent_array[$parent] = 0;
- /* now the children, checking each thread portion for
- ),(, and space, adjusting the level and space values
- to get the indent level
- */
+ /*
+ * now the children, checking each thread portion for
+ * ),(, and space, adjusting the level and space values
+ * to get the indent level
+ */
$level = 0;
$spaces = array();
$spaces_total = 0;
$indent = 0;
$fake = FALSE;
- for ($k=1;$k<(count($thread_new[$i]))-1;$k++) {
+ for ($k=1,$iCnt=count($thread_new[$i])-1;$k<$iCnt;++$k) {
$chars = count_chars($thread_new[$i][$k], 1);
if (isset($chars['40'])) { /* testing for ( */
- $level = $level + $chars['40'];
+ $level += $chars['40'];
}
if (isset($chars['41'])) { /* testing for ) */
- $level = $level - $chars['41'];
+ $level -= $chars['41'];
$spaces[$level] = 0;
/* if we were faking lets stop, this portion
- of the thread is over
- */
+ * of the thread is over
+ */
if ($level == $cutoff) {
$fake = FALSE;
}
if (!isset($spaces[$level])) {
$spaces[$level] = 0;
}
- $spaces[$level] = $spaces[$level] + $chars['32'];
+ $spaces[$level] += $chars['32'];
}
for ($x=0;$x<=$level;$x++) {
if (isset($spaces[$x])) {
- $spaces_total = $spaces_total + $spaces[$x];
+ $spaces_total += $spaces[$x];
}
}
$indent = $level + $spaces_total;
/* must have run into a message that broke the thread
- so we are adjusting for that portion
- */
+ * so we are adjusting for that portion
+ */
if ($fake == TRUE) {
$indent = $indent +1;
}
$child = $regs[1];
}
/* the thread must be broken if $indent == 0
- so indent the message once and start faking it
- */
+ * so indent the message once and start faking it
+ */
if ($indent == 0) {
$indent = 1;
$fake = TRUE;
$cutoff = $level;
}
/* dont need abs but if indent was negative
- errors would occur
- */
- $indent_array[$child] = abs($indent);
+ * errors would occur
+ */
+ $indent_array[$child] = ($indent < 0) ? 0 : $indent;
$spaces_total = 0;
}
}
$thread_temp = array ();
if ($sort_by_ref == 1) {
$sort_type = 'REFERENCES';
- }
- else {
+ } else {
$sort_type = 'ORDEREDSUBJECT';
}
$query = "THREAD $sort_type ".strtoupper($default_charset)." ALL";
$thread_test = sqimap_run_command ($imap_stream, $query, true, $response, $message, TRUE);
if (isset($thread_test[0])) {
for ($i=0,$iCnt=count($thread_test);$i<$iCnt;++$i) {
- if (preg_match("/^\* THREAD (.+)$/", $thread_test[$i], $regs)) {
- $thread_list = trim($regs[1]);
- break;
- }
+ if (preg_match("/^\* THREAD (.+)$/", $thread_test[$i], $regs)) {
+ $thread_list = trim($regs[1]);
+ break;
+ }
}
- }
- else {
- $thread_list = "";
+ } else {
+ $thread_list = "";
}
if (!preg_match("/OK/", $response)) {
- $server_sort_array = 'no';
- return $server_sort_array;
+ $server_sort_array = 'no';
+ return $server_sort_array;
}
if (isset($thread_list)) {
$thread_temp = preg_split("//", $thread_list, -1, PREG_SPLIT_NO_EMPTY);
}
+
$char_count = count($thread_temp);
$counter = 0;
$thread_new = array();
$k = 0;
$thread_new[0] = "";
- for ($i=0;$i<$char_count;$i++) {
+ /*
+ * parse the thread response into separate threads
+ *
+ * example:
+ * [0] => (540)
+ * [1] => (1386)
+ * [2] => (1599 759 959 37)
+ * [3] => (492 1787)
+ * [4] => ((933)(1891))
+ * [5] => (1030 (1497)(845)(1637))
+ */
+ for ($i=0,$iCnt=count($thread_temp);$i<$iCnt;$i++) {
if ($thread_temp[$i] != ')' && $thread_temp[$i] != '(') {
$thread_new[$k] = $thread_new[$k] . $thread_temp[$i];
- }
- elseif ($thread_temp[$i] == '(') {
+ } elseif ($thread_temp[$i] == '(') {
$thread_new[$k] .= $thread_temp[$i];
$counter++;
- }
- elseif ($thread_temp[$i] == ')') {
- if ($counter > 1) {
- $thread_new[$k] .= $thread_temp[$i];
- $counter = $counter - 1;
- }
- else {
- $thread_new[$k] .= $thread_temp[$i];
- $k++;
- $thread_new[$k] = "";
- $counter = $counter - 1;
- }
+ } elseif ($thread_temp[$i] == ')') {
+ if ($counter > 1) {
+ $thread_new[$k] .= $thread_temp[$i];
+ $counter = $counter - 1;
+ } else {
+ $thread_new[$k] .= $thread_temp[$i];
+ $k++;
+ $thread_new[$k] = "";
+ $counter = $counter - 1;
+ }
}
}
sqsession_register($thread_new, 'thread_new');
$thread_new = array_reverse($thread_new);
+ /* place the threads after each other in one string */
$thread_list = implode(" ", $thread_new);
$thread_list = str_replace("(", " ", $thread_list);
$thread_list = str_replace(")", " ", $thread_list);
function sqimap_get_small_header_list ($imap_stream, $msg_list, $show_num=false,
$aHeaderFields = array('Date', 'To', 'Cc', 'From', 'Subject', 'X-Priority', 'Content-Type'),
- $aFetchItems = array('FLAGS', 'UID', 'RFC822.SIZE', 'INTERNALDATE')) {
-
- global $squirrelmail_language, $color, $data_dir, $username, $imap_server_type;
- global $allow_server_sort;
+ $aFetchItems = array('FLAGS', 'RFC822.SIZE', 'INTERNALDATE')) {
$messages = array();
$read_list = array();
+ if (array_search('UID',$aFetchItems,true) !== false) {
+ $bUidFetch = false;
+ } else {
+ $bUidFetch = true;
+ }
+
/* Get the small headers for each message in $msg_list */
if ($show_num != '999999' && $show_num != '*' ) {
$msgs_str = sqimap_message_list_squisher($msg_list);
* in $msg_list, but IMAP servers are free to return responses in
* whatever order they wish... So we need to re-sort manually
*/
- for ($i = 0; $i < sizeof($msg_list); $i++) {
- $messages["$msg_list[$i]"] = array();
+ if ($bUidFetch) {
+ for ($i = 0; $i < sizeof($msg_list); $i++) {
+ $messages["$msg_list[$i]"] = array();
+ }
}
} else {
$msgs_str = '1:*';
* Create the query
*/
- $internaldate = getPref($data_dir, $username, 'internal_date_sort');
- if (($i = array_search('INTERNALDATE',$aFetchItems,true)) !== false && $internaldate == false) {
- unset($aFetchItems[$i]);
- }
$sFetchItems = '';
$query = "FETCH $msgs_str (";
if (count($aFetchItems)) {
$sFetchItems .= ' BODY.PEEK[HEADER.FIELDS ('.$sHeaderFields.')]';
}
$query .= trim($sFetchItems) . ')';
- $read_list = sqimap_run_command_list ($imap_stream, $query, true, $response, $message, TRUE);
+
+ $read_list = sqimap_run_command_list ($imap_stream, $query, true, $response, $message, $bUidFetch);
$i = 0;
foreach ($read_list as $r) {
$id = substr($read,2,$i_space-2);
$fetch = substr($read,$i_space+1,5);
if (!is_numeric($id) && $fetch !== 'FETCH') {
- set_up_language($squirrelmail_language);
- echo '<br><b><font color=$color[2]>' .
- _("ERROR : Could not complete request.") .
- '</b><br>' .
- _("Unknown response from IMAP server: ") . ' 1.' .
- htmlspecialchars($read) . "</font><br>\n";
- break;
+ $msg['ERROR'] = $read; // htmlspecialchars should be done just before display. this is backend code
+ break;
}
$i = strpos($read,'(',$i_space+5);
$read = substr($read,$i+1);
break 3;
}
+ break;
+ case 'ENVELOPE':
+ break; // to be implemented, moving imap code out of the nessages class
+ sqimap_parse_address($read,$i,$msg);
+ break; // to be implemented, moving imap code out of the nessages class
+ case 'BODYSTRUCTURE':
break;
case 'INTERNALDATE':
- $msg['INTERNALDATE'] = parseString($read,$i);
+ $msg['INTERNALDATE'] = str_replace(' ', ' ',parseString($read,$i));
break;
case 'BODY.PEEK[HEADER.FIELDS':
case 'BODY[HEADER.FIELDS':
/* Now we can make a new header array with */
/* each element representing a headerline */
$hdr = explode("\n" , $hdr);
+ $aReceived = array();
foreach ($hdr as $line) {
$pos = strpos($line, ':');
if ($pos > 0) {
$msg['TYPE1'] = 'plain';
}
break;
+ case 'received':
+ $aReceived[] = $value;
+ break;
default: break;
}
}
}
}
+ if (count($aReceived)) {
+ $msg['RECEIVED'] = $aReceived;
+ }
break;
default:
++$i;
return $messages;
}
+function sqimap_parse_envelope($read, &$i, &$msg) {
+ $arg_no = 0;
+ $arg_a = array();
+ ++$i;
+ for ($cnt = strlen($read); ($i < $cnt) && ($read{$i} != ')'); ++$i) {
+ $char = strtoupper($read{$i});
+ switch ($char) {
+ case '{':
+ case '"':
+ $arg_a[] = parseString($read,$i);
+ ++$arg_no;
+ break;
+ case 'N':
+ /* probably NIL argument */
+ if (strtoupper(substr($read, $i, 3)) == 'NIL') {
+ $arg_a[] = '';
+ ++$arg_no;
+ $i += 2;
+ }
+ break;
+ case '(':
+ /* Address structure (with group support)
+ * Note: Group support is useless on SMTP connections
+ * because the protocol doesn't support it
+ */
+ $addr_a = array();
+ $group = '';
+ $a=0;
+ for (; $i < $cnt && $read{$i} != ')'; ++$i) {
+ if ($read{$i} == '(') {
+ $addr = sqimap_parse_address($read, $i);
+ if (($addr[3] == '') && ($addr[2] != '')) {
+ /* start of group */
+ $group = $addr[2];
+ $group_addr = $addr;
+ $j = $a;
+ } else if ($group && ($addr[3] == '') && ($addr[2] == '')) {
+ /* end group */
+ if ($a == ($j+1)) { /* no group members */
+ $group_addr[4] = $group;
+ $group_addr[2] = '';
+ $group_addr[0] = "$group: Undisclosed recipients;";
+ $addr_a[] = $group_addr;
+ $group ='';
+ }
+ } else {
+ $addr[4] = $group;
+ $addr_a[] = $addr;
+ }
+ ++$a;
+ }
+ }
+ $arg_a[] = $addr_a;
+ break;
+ default: break;
+ }
+ }
+
+ if (count($arg_a) > 9) {
+ $d = strtr($arg_a[0], array(' ' => ' '));
+ $d = explode(' ', $d);
+ if (!$arg_a[1]) $arg_1[1] = '';
+ $msg['DATE'] = $d; /* argument 1: date */
+ $msg['SUBJECT'] = $arg_a[1]; /* argument 2: subject */
+ $msg['FROM'] = is_array($arg_a[2]) ? $arg_a[2][0] : ''; /* argument 3: from */
+ $msg['SENDER'] = is_array($arg_a[3]) ? $arg_a[3][0] : ''; /* argument 4: sender */
+ $msg['REPLY-TO'] = is_array($arg_a[4]) ? $arg_a[4][0] : ''; /* argument 5: reply-to */
+ $msg['TO'] = $arg_a[5]; /* argument 6: to */
+ $msg['CC'] = $arg_a[6]; /* argument 7: cc */
+ $msg['BCC'] = $arg_a[7]; /* argument 8: bcc */
+ $msg['IN-REPLY-TO'] = $arg_a[8]; /* argument 9: in-reply-to */
+ $msg['MESSAGE-ID'] = $arg_a[9]; /* argument 10: message-id */
+ }
+}
+
+function sqimap_parse_address($read, &$i) {
+ $arg_a = array();
+ for (; $read{$i} != ')'; ++$i) {
+ $char = strtoupper($read{$i});
+ switch ($char) {
+ case '{':
+ case '"': $arg_a[] = parseString($read,$i); break;
+ case 'n':
+ case 'N':
+ if (strtoupper(substr($read, $i, 3)) == 'NIL') {
+ $arg_a[] = '';
+ $i += 2;
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (count($arg_a) == 4) {
+ return $arg_a;
+
+// $adr = new AddressStructure();
+// $adr->personal = $arg_a[0];
+// $adr->adl = $arg_a[1];
+// $adr->mailbox = $arg_a[2];
+// $adr->host = $arg_a[3];
+ } else {
+ $adr = '';
+ }
+ return $adr;
+}
+
/**
* Returns a message array with all the information about a message.
* See the documentation folder for more information about this array.