Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F4690499
rcube_imap_generic.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
58 KB
Referenced Files
None
Subscribers
None
rcube_imap_generic.php
View Options
<?php
/*
+-----------------------------------------------------------------------+
| program/include/rcube_imap_generic.php |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2010, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Provide alternative IMAP library that doesn't rely on the standard |
| C-Client based version. This allows to function regardless |
| of whether or not the PHP build it's running on has IMAP |
| functionality built-in. |
| |
| Based on Iloha IMAP Library. See http://ilohamail.org/ for details |
| |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
| Author: Ryo Chijiiwa <Ryo@IlohaMail.org> |
+-----------------------------------------------------------------------+
$Id$
*/
/**
* Struct representing an e-mail message header
*
* @package Mail
* @author Aleksander Machniak <alec@alec.pl>
*/
class
rcube_mail_header
{
public
$id
;
public
$uid
;
public
$subject
;
public
$from
;
public
$to
;
public
$cc
;
public
$replyto
;
public
$in_reply_to
;
public
$date
;
public
$messageID
;
public
$size
;
public
$encoding
;
public
$charset
;
public
$ctype
;
public
$flags
;
public
$timestamp
;
public
$f
;
public
$body_structure
;
public
$internaldate
;
public
$references
;
public
$priority
;
public
$mdn_to
;
public
$mdn_sent
=
false
;
public
$is_draft
=
false
;
public
$seen
=
false
;
public
$deleted
=
false
;
public
$recent
=
false
;
public
$answered
=
false
;
public
$forwarded
=
false
;
public
$junk
=
false
;
public
$flagged
=
false
;
public
$has_children
=
false
;
public
$depth
=
0
;
public
$unread_children
=
0
;
public
$others
=
array
();
}
// For backward compatibility with cached messages (#1486602)
class
iilBasicHeader
extends
rcube_mail_header
{
}
/**
* PHP based wrapper class to connect to an IMAP server
*
* @package Mail
* @author Aleksander Machniak <alec@alec.pl>
*/
class
rcube_imap_generic
{
public
$error
;
public
$errornum
;
public
$message
;
public
$rootdir
;
public
$delimiter
;
public
$permanentflags
=
array
();
public
$flags
=
array
(
'SEEN'
=>
'
\\
Seen'
,
'DELETED'
=>
'
\\
Deleted'
,
'RECENT'
=>
'
\\
Recent'
,
'ANSWERED'
=>
'
\\
Answered'
,
'DRAFT'
=>
'
\\
Draft'
,
'FLAGGED'
=>
'
\\
Flagged'
,
'FORWARDED'
=>
'$Forwarded'
,
'MDNSENT'
=>
'$MDNSent'
,
'*'
=>
'
\\
*'
,
);
private
$exists
;
private
$recent
;
private
$selected
;
private
$fp
;
private
$host
;
private
$logged
=
false
;
private
$capability
=
array
();
private
$capability_readed
=
false
;
private
$prefs
;
/**
* Object constructor
*/
function
__construct
()
{
}
private
function
putLine
(
$string
,
$endln
=
true
)
{
if
(!
$this
->
fp
)
return
false
;
if
(!
empty
(
$this
->
prefs
[
'debug_mode'
]))
{
write_log
(
'imap'
,
'C: '
.
rtrim
(
$string
));
}
return
fputs
(
$this
->
fp
,
$string
.
(
$endln
?
"
\r\n
"
:
''
));
}
// $this->putLine replacement with Command Continuation Requests (RFC3501 7.5) support
private
function
putLineC
(
$string
,
$endln
=
true
)
{
if
(!
$this
->
fp
)
return
NULL
;
if
(
$endln
)
$string
.=
"
\r\n
"
;
$res
=
0
;
if
(
$parts
=
preg_split
(
'/(
\{
[0-9]+
\}\r\n
)/m'
,
$string
,
-
1
,
PREG_SPLIT_DELIM_CAPTURE
))
{
for
(
$i
=
0
,
$cnt
=
count
(
$parts
);
$i
<
$cnt
;
$i
++)
{
if
(
preg_match
(
'/^
\{
[0-9]+
\}\r\n
$/'
,
$parts
[
$i
+
1
]))
{
$bytes
=
$this
->
putLine
(
$parts
[
$i
].
$parts
[
$i
+
1
],
false
);
if
(
$bytes
===
false
)
return
false
;
$res
+=
$bytes
;
$line
=
$this
->
readLine
(
1000
);
// handle error in command
if
(
$line
[
0
]
!=
'+'
)
return
false
;
$i
++;
}
else
{
$bytes
=
$this
->
putLine
(
$parts
[
$i
],
false
);
if
(
$bytes
===
false
)
return
false
;
$res
+=
$bytes
;
}
}
}
return
$res
;
}
private
function
readLine
(
$size
=
1024
)
{
$line
=
''
;
if
(!
$this
->
fp
)
{
return
NULL
;
}
if
(!
$size
)
{
$size
=
1024
;
}
do
{
if
(
feof
(
$this
->
fp
))
{
return
$line
?
$line
:
NULL
;
}
$buffer
=
fgets
(
$this
->
fp
,
$size
);
if
(
$buffer
===
false
)
{
@
fclose
(
$this
->
fp
);
$this
->
fp
=
null
;
break
;
}
if
(!
empty
(
$this
->
prefs
[
'debug_mode'
]))
{
write_log
(
'imap'
,
'S: '
.
chop
(
$buffer
));
}
$line
.=
$buffer
;
}
while
(
$buffer
[
strlen
(
$buffer
)-
1
]
!=
"
\n
"
);
return
$line
;
}
private
function
multLine
(
$line
,
$escape
=
false
)
{
$line
=
chop
(
$line
);
if
(
preg_match
(
'/
\{
[0-9]+
\}
$/'
,
$line
))
{
$out
=
''
;
preg_match_all
(
'/(.*)
\{
([0-9]+)
\}
$/'
,
$line
,
$a
);
$bytes
=
$a
[
2
][
0
];
while
(
strlen
(
$out
)
<
$bytes
)
{
$line
=
$this
->
readBytes
(
$bytes
);
if
(
$line
===
NULL
)
break
;
$out
.=
$line
;
}
$line
=
$a
[
1
][
0
]
.
'"'
.
(
$escape
?
$this
->
Escape
(
$out
)
:
$out
)
.
'"'
;
}
return
$line
;
}
private
function
readBytes
(
$bytes
)
{
$data
=
''
;
$len
=
0
;
while
(
$len
<
$bytes
&&
!
feof
(
$this
->
fp
))
{
$d
=
fread
(
$this
->
fp
,
$bytes
-
$len
);
if
(!
empty
(
$this
->
prefs
[
'debug_mode'
]))
{
write_log
(
'imap'
,
'S: '
.
$d
);
}
$data
.=
$d
;
$data_len
=
strlen
(
$data
);
if
(
$len
==
$data_len
)
{
break
;
// nothing was read -> exit to avoid apache lockups
}
$len
=
$data_len
;
}
return
$data
;
}
// don't use it in loops, until you exactly know what you're doing
private
function
readReply
(&
$untagged
=
null
)
{
do
{
$line
=
trim
(
$this
->
readLine
(
1024
));
// store untagged response lines
if
(
$line
[
0
]
==
'*'
)
$untagged
[]
=
$line
;
}
while
(
$line
[
0
]
==
'*'
);
if
(
$untagged
)
$untagged
=
join
(
"
\n
"
,
$untagged
);
return
$line
;
}
private
function
parseResult
(
$string
)
{
$a
=
explode
(
' '
,
trim
(
$string
));
if
(
count
(
$a
)
>=
2
)
{
$res
=
strtoupper
(
$a
[
1
]);
if
(
$res
==
'OK'
)
{
return
0
;
}
else
if
(
$res
==
'NO'
)
{
return
-
1
;
}
else
if
(
$res
==
'BAD'
)
{
return
-
2
;
}
else
if
(
$res
==
'BYE'
)
{
@
fclose
(
$this
->
fp
);
$this
->
fp
=
null
;
return
-
3
;
}
}
return
-
4
;
}
// check if $string starts with $match (or * BYE/BAD)
private
function
startsWith
(
$string
,
$match
,
$error
=
false
,
$nonempty
=
false
)
{
$len
=
strlen
(
$match
);
if
(
$len
==
0
)
{
return
false
;
}
if
(!
$this
->
fp
)
{
return
true
;
}
if
(
strncmp
(
$string
,
$match
,
$len
)
==
0
)
{
return
true
;
}
if
(
$error
&&
preg_match
(
'/^
\*
(BYE|BAD) /i'
,
$string
,
$m
))
{
if
(
strtoupper
(
$m
[
1
])
==
'BYE'
)
{
@
fclose
(
$this
->
fp
);
$this
->
fp
=
null
;
}
return
true
;
}
if
(
$nonempty
&&
!
strlen
(
$string
))
{
return
true
;
}
return
false
;
}
private
function
startsWithI
(
$string
,
$match
,
$error
=
false
,
$nonempty
=
false
)
{
$len
=
strlen
(
$match
);
if
(
$len
==
0
)
{
return
false
;
}
if
(!
$this
->
fp
)
{
return
true
;
}
if
(
strncasecmp
(
$string
,
$match
,
$len
)
==
0
)
{
return
true
;
}
if
(
$error
&&
preg_match
(
'/^
\*
(BYE|BAD) /i'
,
$string
,
$m
))
{
if
(
strtoupper
(
$m
[
1
])
==
'BYE'
)
{
@
fclose
(
$this
->
fp
);
$this
->
fp
=
null
;
}
return
true
;
}
if
(
$nonempty
&&
!
strlen
(
$string
))
{
return
true
;
}
return
false
;
}
function
getCapability
(
$name
)
{
if
(
in_array
(
$name
,
$this
->
capability
))
{
return
true
;
}
else
if
(
$this
->
capability_readed
)
{
return
false
;
}
// get capabilities (only once) because initial
// optional CAPABILITY response may differ
$this
->
capability
=
array
();
if
(!
$this
->
putLine
(
"cp01 CAPABILITY"
))
{
return
false
;
}
do
{
$line
=
trim
(
$this
->
readLine
(
1024
));
$a
=
explode
(
' '
,
$line
);
if
(
$line
[
0
]
==
'*'
)
{
while
(
list
(
$k
,
$w
)
=
each
(
$a
))
{
if
(
$w
!=
'*'
&&
$w
!=
'CAPABILITY'
)
$this
->
capability
[]
=
strtoupper
(
$w
);
}
}
}
while
(
$a
[
0
]
!=
'cp01'
);
$this
->
capability_readed
=
true
;
if
(
in_array
(
$name
,
$this
->
capability
))
{
return
true
;
}
return
false
;
}
function
clearCapability
()
{
$this
->
capability
=
array
();
$this
->
capability_readed
=
false
;
}
function
authenticate
(
$user
,
$pass
,
$encChallenge
)
{
$ipad
=
''
;
$opad
=
''
;
// initialize ipad, opad
for
(
$i
=
0
;
$i
<
64
;
$i
++)
{
$ipad
.=
chr
(
0x36
);
$opad
.=
chr
(
0x5C
);
}
// pad $pass so it's 64 bytes
$padLen
=
64
-
strlen
(
$pass
);
for
(
$i
=
0
;
$i
<
$padLen
;
$i
++)
{
$pass
.=
chr
(
0
);
}
// generate hash
$hash
=
md5
(
$this
->
_xor
(
$pass
,
$opad
)
.
pack
(
"H*"
,
md5
(
$this
->
_xor
(
$pass
,
$ipad
)
.
base64_decode
(
$encChallenge
))));
// generate reply
$reply
=
base64_encode
(
$user
.
' '
.
$hash
);
// send result, get reply
$this
->
putLine
(
$reply
);
$line
=
$this
->
readLine
(
1024
);
// process result
$result
=
$this
->
parseResult
(
$line
);
if
(
$result
==
0
)
{
$this
->
errornum
=
0
;
return
$this
->
fp
;
}
$this
->
error
=
"Authentication for $user failed (AUTH): $line"
;
$this
->
errornum
=
$result
;
return
$result
;
}
function
login
(
$user
,
$password
)
{
$this
->
putLine
(
'a001 LOGIN "'
.
$this
->
escape
(
$user
).
'" "'
.
$this
->
escape
(
$password
).
'"'
);
$line
=
$this
->
readReply
(
$untagged
);
// re-set capabilities list if untagged CAPABILITY response provided
if
(
preg_match
(
'/
\*
CAPABILITY (.+)/i'
,
$untagged
,
$matches
))
{
$this
->
capability
=
explode
(
' '
,
strtoupper
(
$matches
[
1
]));
}
// process result
$result
=
$this
->
parseResult
(
$line
);
if
(
$result
==
0
)
{
$this
->
errornum
=
0
;
return
$this
->
fp
;
}
@
fclose
(
$this
->
fp
);
$this
->
fp
=
false
;
$this
->
error
=
"Authentication for $user failed (LOGIN): $line"
;
$this
->
errornum
=
$result
;
return
$result
;
}
function
getNamespace
()
{
if
(
isset
(
$this
->
prefs
[
'rootdir'
])
&&
is_string
(
$this
->
prefs
[
'rootdir'
]))
{
$this
->
rootdir
=
$this
->
prefs
[
'rootdir'
];
return
true
;
}
if
(!
$this
->
getCapability
(
'NAMESPACE'
))
{
return
false
;
}
if
(!
$this
->
putLine
(
"ns1 NAMESPACE"
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
(
1024
);
if
(
$this
->
startsWith
(
$line
,
'* NAMESPACE'
))
{
$i
=
0
;
$line
=
$this
->
unEscape
(
$line
);
$data
=
$this
->
parseNamespace
(
substr
(
$line
,
11
),
$i
,
0
,
0
);
}
}
while
(!
$this
->
startsWith
(
$line
,
'ns1'
,
true
,
true
));
if
(!
is_array
(
$data
))
{
return
false
;
}
$user_space_data
=
$data
[
0
];
if
(!
is_array
(
$user_space_data
))
{
return
false
;
}
$first_userspace
=
$user_space_data
[
0
];
if
(
count
(
$first_userspace
)!=
2
)
{
return
false
;
}
$this
->
rootdir
=
$first_userspace
[
0
];
$this
->
delimiter
=
$first_userspace
[
1
];
$this
->
prefs
[
'rootdir'
]
=
substr
(
$this
->
rootdir
,
0
,
-
1
);
$this
->
prefs
[
'delimiter'
]
=
$this
->
delimiter
;
return
true
;
}
/**
* Gets the delimiter, for example:
* INBOX.foo -> .
* INBOX/foo -> /
* INBOX\foo -> \
*
* @return mixed A delimiter (string), or false.
* @see connect()
*/
function
getHierarchyDelimiter
()
{
if
(
$this
->
delimiter
)
{
return
$this
->
delimiter
;
}
if
(!
empty
(
$this
->
prefs
[
'delimiter'
]))
{
return
(
$this
->
delimiter
=
$this
->
prefs
[
'delimiter'
]);
}
$delimiter
=
false
;
// try (LIST "" ""), should return delimiter (RFC2060 Sec 6.3.8)
if
(!
$this
->
putLine
(
'ghd LIST "" ""'
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
(
500
);
if
(
$line
[
0
]
==
'*'
)
{
$line
=
rtrim
(
$line
);
$a
=
rcube_explode_quoted_string
(
' '
,
$this
->
unEscape
(
$line
));
if
(
$a
[
0
]
==
'*'
)
{
$delimiter
=
str_replace
(
'"'
,
''
,
$a
[
count
(
$a
)-
2
]);
}
}
}
while
(!
$this
->
startsWith
(
$line
,
'ghd'
,
true
,
true
));
if
(
strlen
(
$delimiter
)>
0
)
{
return
$delimiter
;
}
// if that fails, try namespace extension
// try to fetch namespace data
if
(!
$this
->
putLine
(
"ns1 NAMESPACE"
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
(
1024
);
if
(
$this
->
startsWith
(
$line
,
'* NAMESPACE'
))
{
$i
=
0
;
$line
=
$this
->
unEscape
(
$line
);
$data
=
$this
->
parseNamespace
(
substr
(
$line
,
11
),
$i
,
0
,
0
);
}
}
while
(!
$this
->
startsWith
(
$line
,
'ns1'
,
true
,
true
));
if
(!
is_array
(
$data
))
{
return
false
;
}
// extract user space data (opposed to global/shared space)
$user_space_data
=
$data
[
0
];
if
(!
is_array
(
$user_space_data
))
{
return
false
;
}
// get first element
$first_userspace
=
$user_space_data
[
0
];
if
(!
is_array
(
$first_userspace
))
{
return
false
;
}
// extract delimiter
$delimiter
=
$first_userspace
[
1
];
return
$delimiter
;
}
function
connect
(
$host
,
$user
,
$password
,
$options
=
null
)
{
// set options
if
(
is_array
(
$options
))
{
$this
->
prefs
=
$options
;
}
// set auth method
if
(!
empty
(
$this
->
prefs
[
'auth_method'
]))
{
$auth_method
=
strtoupper
(
$this
->
prefs
[
'auth_method'
]);
}
else
{
$auth_method
=
'CHECK'
;
}
$message
=
"INITIAL: $auth_method
\n
"
;
$result
=
false
;
// initialize connection
$this
->
error
=
''
;
$this
->
errornum
=
0
;
$this
->
selected
=
''
;
$this
->
user
=
$user
;
$this
->
host
=
$host
;
$this
->
logged
=
false
;
// check input
if
(
empty
(
$host
))
{
$this
->
error
=
"Empty host"
;
$this
->
errornum
=
-
2
;
return
false
;
}
if
(
empty
(
$user
))
{
$this
->
error
=
"Empty user"
;
$this
->
errornum
=
-
1
;
return
false
;
}
if
(
empty
(
$password
))
{
$this
->
error
=
"Empty password"
;
$this
->
errornum
=
-
1
;
return
false
;
}
if
(!
$this
->
prefs
[
'port'
])
{
$this
->
prefs
[
'port'
]
=
143
;
}
// check for SSL
if
(
$this
->
prefs
[
'ssl_mode'
]
&&
$this
->
prefs
[
'ssl_mode'
]
!=
'tls'
)
{
$host
=
$this
->
prefs
[
'ssl_mode'
]
.
'://'
.
$host
;
}
$this
->
fp
=
@
fsockopen
(
$host
,
$this
->
prefs
[
'port'
],
$errno
,
$errstr
,
10
);
if
(!
$this
->
fp
)
{
$this
->
error
=
sprintf
(
"Could not connect to %s:%d: %s"
,
$host
,
$this
->
prefs
[
'port'
],
$errstr
);
$this
->
errornum
=
-
2
;
return
false
;
}
stream_set_timeout
(
$this
->
fp
,
10
);
$line
=
trim
(
fgets
(
$this
->
fp
,
8192
));
if
(
$this
->
prefs
[
'debug_mode'
]
&&
$line
)
{
write_log
(
'imap'
,
'S: '
.
$line
);
}
// Connected to wrong port or connection error?
if
(!
preg_match
(
'/^
\*
(OK|PREAUTH)/i'
,
$line
))
{
if
(
$line
)
$this
->
error
=
sprintf
(
"Wrong startup greeting (%s:%d): %s"
,
$host
,
$this
->
prefs
[
'port'
],
$line
);
else
$this
->
error
=
sprintf
(
"Empty startup greeting (%s:%d)"
,
$host
,
$this
->
prefs
[
'port'
]);
$this
->
errornum
=
-
2
;
return
false
;
}
// RFC3501 [7.1] optional CAPABILITY response
if
(
preg_match
(
'/
\[
CAPABILITY ([^]]+)
\]
/i'
,
$line
,
$matches
))
{
$this
->
capability
=
explode
(
' '
,
strtoupper
(
$matches
[
1
]));
}
$this
->
message
.=
$line
;
// TLS connection
if
(
$this
->
prefs
[
'ssl_mode'
]
==
'tls'
&&
$this
->
getCapability
(
'STARTTLS'
))
{
if
(
version_compare
(
PHP_VERSION
,
'5.1.0'
,
'>='
))
{
$this
->
putLine
(
"tls0 STARTTLS"
);
$line
=
$this
->
readLine
(
4096
);
if
(!
$this
->
startsWith
(
$line
,
"tls0 OK"
))
{
$this
->
error
=
"Server responded to STARTTLS with: $line"
;
$this
->
errornum
=
-
2
;
return
false
;
}
if
(!
stream_socket_enable_crypto
(
$this
->
fp
,
true
,
STREAM_CRYPTO_METHOD_TLS_CLIENT
))
{
$this
->
error
=
"Unable to negotiate TLS"
;
$this
->
errornum
=
-
2
;
return
false
;
}
// Now we're authenticated, capabilities need to be reread
$this
->
clearCapability
();
}
}
$orig_method
=
$auth_method
;
if
(
$auth_method
==
'CHECK'
)
{
// check for supported auth methods
if
(
$this
->
getCapability
(
'AUTH=CRAM-MD5'
)
||
$this
->
getCapability
(
'AUTH=CRAM_MD5'
))
{
$auth_method
=
'AUTH'
;
}
else
{
// default to plain text auth
$auth_method
=
'PLAIN'
;
}
}
if
(
$auth_method
==
'AUTH'
)
{
// do CRAM-MD5 authentication
$this
->
putLine
(
"a000 AUTHENTICATE CRAM-MD5"
);
$line
=
trim
(
$this
->
readLine
(
1024
));
if
(
$line
[
0
]
==
'+'
)
{
// got a challenge string, try CRAM-MD5
$result
=
$this
->
authenticate
(
$user
,
$password
,
substr
(
$line
,
2
));
// stop if server sent BYE response
if
(
$result
==
-
3
)
{
return
false
;
}
}
if
(!
is_resource
(
$result
)
&&
$orig_method
==
'CHECK'
)
{
$auth_method
=
'PLAIN'
;
}
}
if
(
$auth_method
==
'PLAIN'
)
{
// do plain text auth
$result
=
$this
->
login
(
$user
,
$password
);
}
if
(
is_resource
(
$result
))
{
if
(
$this
->
prefs
[
'force_caps'
])
{
$this
->
clearCapability
();
}
$this
->
getNamespace
();
$this
->
logged
=
true
;
return
true
;
}
else
{
return
false
;
}
}
function
connected
()
{
return
(
$this
->
fp
&&
$this
->
logged
)
?
true
:
false
;
}
function
close
()
{
if
(
$this
->
putLine
(
"I LOGOUT"
))
{
if
(!
feof
(
$this
->
fp
))
fgets
(
$this
->
fp
,
1024
);
}
@
fclose
(
$this
->
fp
);
$this
->
fp
=
false
;
}
function
select
(
$mailbox
)
{
if
(
empty
(
$mailbox
))
{
return
false
;
}
if
(
$this
->
selected
==
$mailbox
)
{
return
true
;
}
if
(
$this
->
putLine
(
"sel1 SELECT
\"
"
.
$this
->
escape
(
$mailbox
).
'"'
))
{
do
{
$line
=
chop
(
$this
->
readLine
(
300
));
$a
=
explode
(
' '
,
$line
);
if
(
count
(
$a
)
==
3
)
{
$token
=
strtoupper
(
$a
[
2
]);
if
(
$token
==
'EXISTS'
)
{
$this
->
exists
=
(
int
)
$a
[
1
];
}
else
if
(
$token
==
'RECENT'
)
{
$this
->
recent
=
(
int
)
$a
[
1
];
}
}
else
if
(
preg_match
(
'/
\[
?PERMANENTFLAGS
\s
+
\(
([^
\)
]+)
\)\]
/U'
,
$line
,
$match
))
{
$this
->
permanentflags
=
explode
(
' '
,
$match
[
1
]);
}
}
while
(!
$this
->
startsWith
(
$line
,
'sel1'
,
true
,
true
));
if
(
strcasecmp
(
$a
[
1
],
'OK'
)
==
0
)
{
$this
->
selected
=
$mailbox
;
return
true
;
}
else
{
$this
->
error
=
"Couldn't select $mailbox"
;
}
}
return
false
;
}
function
checkForRecent
(
$mailbox
)
{
if
(
empty
(
$mailbox
))
{
$mailbox
=
'INBOX'
;
}
$this
->
select
(
$mailbox
);
if
(
$this
->
selected
==
$mailbox
)
{
return
$this
->
recent
;
}
return
false
;
}
function
countMessages
(
$mailbox
,
$refresh
=
false
)
{
if
(
$refresh
)
{
$this
->
selected
=
''
;
}
$this
->
select
(
$mailbox
);
if
(
$this
->
selected
==
$mailbox
)
{
return
$this
->
exists
;
}
return
false
;
}
function
sort
(
$mailbox
,
$field
,
$add
=
''
,
$is_uid
=
FALSE
,
$encoding
=
'US-ASCII'
)
{
$field
=
strtoupper
(
$field
);
if
(
$field
==
'INTERNALDATE'
)
{
$field
=
'ARRIVAL'
;
}
$fields
=
array
(
'ARRIVAL'
=>
1
,
'CC'
=>
1
,
'DATE'
=>
1
,
'FROM'
=>
1
,
'SIZE'
=>
1
,
'SUBJECT'
=>
1
,
'TO'
=>
1
);
if
(!
$fields
[
$field
])
{
return
false
;
}
/* Do "SELECT" command */
if
(!
$this
->
select
(
$mailbox
))
{
return
false
;
}
$is_uid
=
$is_uid
?
'UID '
:
''
;
// message IDs
if
(
is_array
(
$add
))
$add
=
$this
->
compressMessageSet
(
join
(
','
,
$add
));
$command
=
"s "
.
$is_uid
.
"SORT ($field) $encoding ALL"
;
$line
=
$data
=
''
;
if
(!
empty
(
$add
))
$command
.=
' '
.
$add
;
if
(!
$this
->
putLineC
(
$command
))
{
return
false
;
}
do
{
$line
=
chop
(
$this
->
readLine
());
if
(
$this
->
startsWith
(
$line
,
'* SORT'
))
{
$data
.=
substr
(
$line
,
7
);
}
else
if
(
preg_match
(
'/^[0-9 ]+$/'
,
$line
))
{
$data
.=
$line
;
}
}
while
(!
$this
->
startsWith
(
$line
,
's '
,
true
,
true
));
$result_code
=
$this
->
parseResult
(
$line
);
if
(
$result_code
!=
0
)
{
$this
->
error
=
"Sort: $line"
;
return
false
;
}
return
preg_split
(
'/
\s
+/'
,
$data
,
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
function
fetchHeaderIndex
(
$mailbox
,
$message_set
,
$index_field
=
''
,
$skip_deleted
=
true
,
$uidfetch
=
false
)
{
if
(
is_array
(
$message_set
))
{
if
(!(
$message_set
=
$this
->
compressMessageSet
(
join
(
','
,
$message_set
))))
return
false
;
}
else
{
list
(
$from_idx
,
$to_idx
)
=
explode
(
':'
,
$message_set
);
if
(
empty
(
$message_set
)
||
(
isset
(
$to_idx
)
&&
$to_idx
!=
'*'
&&
(
int
)
$from_idx
>
(
int
)
$to_idx
))
{
return
false
;
}
}
$index_field
=
empty
(
$index_field
)
?
'DATE'
:
strtoupper
(
$index_field
);
$fields_a
[
'DATE'
]
=
1
;
$fields_a
[
'INTERNALDATE'
]
=
4
;
$fields_a
[
'ARRIVAL'
]
=
4
;
$fields_a
[
'FROM'
]
=
1
;
$fields_a
[
'REPLY-TO'
]
=
1
;
$fields_a
[
'SENDER'
]
=
1
;
$fields_a
[
'TO'
]
=
1
;
$fields_a
[
'CC'
]
=
1
;
$fields_a
[
'SUBJECT'
]
=
1
;
$fields_a
[
'UID'
]
=
2
;
$fields_a
[
'SIZE'
]
=
2
;
$fields_a
[
'SEEN'
]
=
3
;
$fields_a
[
'RECENT'
]
=
3
;
$fields_a
[
'DELETED'
]
=
3
;
if
(!(
$mode
=
$fields_a
[
$index_field
]))
{
return
false
;
}
/* Do "SELECT" command */
if
(!
$this
->
select
(
$mailbox
))
{
return
false
;
}
// build FETCH command string
$key
=
'fhi0'
;
$cmd
=
$uidfetch
?
'UID FETCH'
:
'FETCH'
;
$deleted
=
$skip_deleted
?
' FLAGS'
:
''
;
if
(
$mode
==
1
&&
$index_field
==
'DATE'
)
$request
=
" $cmd $message_set (INTERNALDATE BODY.PEEK[HEADER.FIELDS (DATE)]$deleted)"
;
else
if
(
$mode
==
1
)
$request
=
" $cmd $message_set (BODY.PEEK[HEADER.FIELDS ($index_field)]$deleted)"
;
else
if
(
$mode
==
2
)
{
if
(
$index_field
==
'SIZE'
)
$request
=
" $cmd $message_set (RFC822.SIZE$deleted)"
;
else
$request
=
" $cmd $message_set ($index_field$deleted)"
;
}
else
if
(
$mode
==
3
)
$request
=
" $cmd $message_set (FLAGS)"
;
else
// 4
$request
=
" $cmd $message_set (INTERNALDATE$deleted)"
;
$request
=
$key
.
$request
;
if
(!
$this
->
putLine
(
$request
))
{
return
false
;
}
$result
=
array
();
do
{
$line
=
chop
(
$this
->
readLine
(
200
));
$line
=
$this
->
multLine
(
$line
);
if
(
preg_match
(
'/^
\*
([0-9]+) FETCH/'
,
$line
,
$m
))
{
$id
=
$m
[
1
];
$flags
=
NULL
;
if
(
$skip_deleted
&&
preg_match
(
'/FLAGS
\(
([^)]+)
\)
/'
,
$line
,
$matches
))
{
$flags
=
explode
(
' '
,
strtoupper
(
$matches
[
1
]));
if
(
in_array
(
'
\\
DELETED'
,
$flags
))
{
$deleted
[
$id
]
=
$id
;
continue
;
}
}
if
(
$mode
==
1
&&
$index_field
==
'DATE'
)
{
if
(
preg_match
(
'/BODY
\[
HEADER
\.
FIELDS
\(
"*DATE"*
\)\]
(.*)/'
,
$line
,
$matches
))
{
$value
=
preg_replace
(
array
(
'/^"*[a-z]+:/i'
),
''
,
$matches
[
1
]);
$value
=
trim
(
$value
);
$result
[
$id
]
=
$this
->
strToTime
(
$value
);
}
// non-existent/empty Date: header, use INTERNALDATE
if
(
empty
(
$result
[
$id
]))
{
if
(
preg_match
(
'/INTERNALDATE "([^"]+)"/'
,
$line
,
$matches
))
$result
[
$id
]
=
$this
->
strToTime
(
$matches
[
1
]);
else
$result
[
$id
]
=
0
;
}
}
else
if
(
$mode
==
1
)
{
if
(
preg_match
(
'/BODY
\[
HEADER
\.
FIELDS
\(
"?(FROM|REPLY-TO|SENDER|TO|SUBJECT)"?
\)\]
(.*)/'
,
$line
,
$matches
))
{
$value
=
preg_replace
(
array
(
'/^"*[a-z]+:/i'
,
'/
\s
+$/sm'
),
array
(
''
,
''
),
$matches
[
2
]);
$result
[
$id
]
=
trim
(
$value
);
}
else
{
$result
[
$id
]
=
''
;
}
}
else
if
(
$mode
==
2
)
{
if
(
preg_match
(
'/
\(
(UID|RFC822
\.
SIZE) ([0-9]+)/'
,
$line
,
$matches
))
{
$result
[
$id
]
=
trim
(
$matches
[
2
]);
}
else
{
$result
[
$id
]
=
0
;
}
}
else
if
(
$mode
==
3
)
{
if
(!
$flags
&&
preg_match
(
'/FLAGS
\(
([^)]+)
\)
/'
,
$line
,
$matches
))
{
$flags
=
explode
(
' '
,
$matches
[
1
]);
}
$result
[
$id
]
=
in_array
(
'
\\
'
.
$index_field
,
$flags
)
?
1
:
0
;
}
else
if
(
$mode
==
4
)
{
if
(
preg_match
(
'/INTERNALDATE "([^"]+)"/'
,
$line
,
$matches
))
{
$result
[
$id
]
=
$this
->
strToTime
(
$matches
[
1
]);
}
else
{
$result
[
$id
]
=
0
;
}
}
}
}
while
(!
$this
->
startsWith
(
$line
,
$key
,
true
,
true
));
return
$result
;
}
private
function
compressMessageSet
(
$message_set
)
{
// given a comma delimited list of independent mid's,
// compresses by grouping sequences together
// if less than 255 bytes long, let's not bother
if
(
strlen
(
$message_set
)<
255
)
{
return
$message_set
;
}
// see if it's already been compress
if
(
strpos
(
$message_set
,
':'
)
!==
false
)
{
return
$message_set
;
}
// separate, then sort
$ids
=
explode
(
','
,
$message_set
);
sort
(
$ids
);
$result
=
array
();
$start
=
$prev
=
$ids
[
0
];
foreach
(
$ids
as
$id
)
{
$incr
=
$id
-
$prev
;
if
(
$incr
>
1
)
{
//found a gap
if
(
$start
==
$prev
)
{
$result
[]
=
$prev
;
//push single id
}
else
{
$result
[]
=
$start
.
':'
.
$prev
;
//push sequence as start_id:end_id
}
$start
=
$id
;
//start of new sequence
}
$prev
=
$id
;
}
// handle the last sequence/id
if
(
$start
==
$prev
)
{
$result
[]
=
$prev
;
}
else
{
$result
[]
=
$start
.
':'
.
$prev
;
}
// return as comma separated string
return
implode
(
','
,
$result
);
}
function
UID2ID
(
$folder
,
$uid
)
{
if
(
$uid
>
0
)
{
$id_a
=
$this
->
search
(
$folder
,
"UID $uid"
);
if
(
is_array
(
$id_a
)
&&
count
(
$id_a
)
==
1
)
{
return
$id_a
[
0
];
}
}
return
false
;
}
function
ID2UID
(
$folder
,
$id
)
{
if
(
empty
(
$id
))
{
return
-
1
;
}
if
(!
$this
->
select
(
$folder
))
{
return
-
1
;
}
$result
=
-
1
;
if
(
$this
->
putLine
(
"fuid FETCH $id (UID)"
))
{
do
{
$line
=
chop
(
$this
->
readLine
(
1024
));
if
(
preg_match
(
"/^
\*
$id FETCH
\(
UID (.*)
\)
/i"
,
$line
,
$r
))
{
$result
=
$r
[
1
];
}
}
while
(!
$this
->
startsWith
(
$line
,
'fuid'
,
true
,
true
));
}
return
$result
;
}
function
fetchUIDs
(
$mailbox
,
$message_set
=
null
)
{
if
(
is_array
(
$message_set
))
$message_set
=
join
(
','
,
$message_set
);
else
if
(
empty
(
$message_set
))
$message_set
=
'1:*'
;
return
$this
->
fetchHeaderIndex
(
$mailbox
,
$message_set
,
'UID'
,
false
);
}
function
fetchHeaders
(
$mailbox
,
$message_set
,
$uidfetch
=
false
,
$bodystr
=
false
,
$add
=
''
)
{
$result
=
array
();
if
(!
$this
->
select
(
$mailbox
))
{
return
false
;
}
if
(
is_array
(
$message_set
))
$message_set
=
join
(
','
,
$message_set
);
$message_set
=
$this
->
compressMessageSet
(
$message_set
);
if
(
$add
)
$add
=
' '
.
strtoupper
(
trim
(
$add
));
/* FETCH uid, size, flags and headers */
$key
=
'FH12'
;
$request
=
$key
.
(
$uidfetch
?
' UID'
:
''
)
.
" FETCH $message_set "
;
$request
.=
"(UID RFC822.SIZE FLAGS INTERNALDATE "
;
if
(
$bodystr
)
$request
.=
"BODYSTRUCTURE "
;
$request
.=
"BODY.PEEK[HEADER.FIELDS "
;
$request
.=
"(DATE FROM TO SUBJECT REPLY-TO IN-REPLY-TO CC BCC "
;
$request
.=
"CONTENT-TRANSFER-ENCODING CONTENT-TYPE MESSAGE-ID "
;
$request
.=
"REFERENCES DISPOSITION-NOTIFICATION-TO X-PRIORITY "
;
$request
.=
"X-DRAFT-INFO"
.
$add
.
")])"
;
if
(!
$this
->
putLine
(
$request
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
(
1024
);
$line
=
$this
->
multLine
(
$line
);
if
(!
$line
)
break
;
$a
=
explode
(
' '
,
$line
);
if
((
$line
[
0
]
==
'*'
)
&&
(
$a
[
2
]
==
'FETCH'
))
{
$id
=
$a
[
1
];
$result
[
$id
]
=
new
rcube_mail_header
;
$result
[
$id
]->
id
=
$id
;
$result
[
$id
]->
subject
=
''
;
$result
[
$id
]->
messageID
=
'mid:'
.
$id
;
$lines
=
array
();
$ln
=
0
;
// Sample reply line:
// * 321 FETCH (UID 2417 RFC822.SIZE 2730 FLAGS (\Seen)
// INTERNALDATE "16-Nov-2008 21:08:46 +0100" BODYSTRUCTURE (...)
// BODY[HEADER.FIELDS ...
if
(
preg_match
(
'/^
\*
[0-9]+ FETCH
\(
(.*) BODY/s'
,
$line
,
$matches
))
{
$str
=
$matches
[
1
];
// swap parents with quotes, then explode
$str
=
preg_replace
(
'/[()]/'
,
'"'
,
$str
);
$a
=
rcube_explode_quoted_string
(
' '
,
$str
);
// did we get the right number of replies?
$parts_count
=
count
(
$a
);
if
(
$parts_count
>=
6
)
{
for
(
$i
=
0
;
$i
<
$parts_count
;
$i
=
$i
+
2
)
{
if
(
$a
[
$i
]
==
'UID'
)
$result
[
$id
]->
uid
=
$a
[
$i
+
1
];
else
if
(
$a
[
$i
]
==
'RFC822.SIZE'
)
$result
[
$id
]->
size
=
$a
[
$i
+
1
];
else
if
(
$a
[
$i
]
==
'INTERNALDATE'
)
$time_str
=
$a
[
$i
+
1
];
else
if
(
$a
[
$i
]
==
'FLAGS'
)
$flags_str
=
$a
[
$i
+
1
];
}
$time_str
=
str_replace
(
'"'
,
''
,
$time_str
);
// if time is gmt...
$time_str
=
str_replace
(
'GMT'
,
'+0000'
,
$time_str
);
$result
[
$id
]->
internaldate
=
$time_str
;
$result
[
$id
]->
timestamp
=
$this
->
StrToTime
(
$time_str
);
$result
[
$id
]->
date
=
$time_str
;
}
// BODYSTRUCTURE
if
(
$bodystr
)
{
while
(!
preg_match
(
'/ BODYSTRUCTURE (.*) BODY
\[
HEADER.FIELDS/s'
,
$line
,
$m
))
{
$line2
=
$this
->
readLine
(
1024
);
$line
.=
$this
->
multLine
(
$line2
,
true
);
}
$result
[
$id
]->
body_structure
=
$m
[
1
];
}
// the rest of the result
preg_match
(
'/ BODY
\[
HEADER.FIELDS
\(
.*?
\)\]\s
*(.*)$/s'
,
$line
,
$m
);
$reslines
=
explode
(
"
\n
"
,
trim
(
$m
[
1
],
'"'
));
// re-parse (see below)
foreach
(
$reslines
as
$resln
)
{
if
(
ord
(
$resln
[
0
])<=
32
)
{
$lines
[
$ln
]
.=
(
empty
(
$lines
[
$ln
])?
''
:
"
\n
"
).
trim
(
$resln
);
}
else
{
$lines
[++
$ln
]
=
trim
(
$resln
);
}
}
}
// Start parsing headers. The problem is, some header "lines" take up multiple lines.
// So, we'll read ahead, and if the one we're reading now is a valid header, we'll
// process the previous line. Otherwise, we'll keep adding the strings until we come
// to the next valid header line.
do
{
$line
=
chop
(
$this
->
readLine
(
300
),
"
\r\n
"
);
// The preg_match below works around communigate imap, which outputs " UID <number>)".
// Without this, the while statement continues on and gets the "FH0 OK completed" message.
// If this loop gets the ending message, then the outer loop does not receive it from radline on line 1249.
// This in causes the if statement on line 1278 to never be true, which causes the headers to end up missing
// If the if statement was changed to pick up the fh0 from this loop, then it causes the outer loop to spin
// An alternative might be:
// if (!preg_match("/:/",$line) && preg_match("/\)$/",$line)) break;
// however, unsure how well this would work with all imap clients.
if
(
preg_match
(
"/^
\s
*UID [0-9]+
\)
$/"
,
$line
))
{
break
;
}
// handle FLAGS reply after headers (AOL, Zimbra?)
if
(
preg_match
(
'/
\s
+FLAGS
\(
(.*)
\)\)
$/'
,
$line
,
$matches
))
{
$flags_str
=
$matches
[
1
];
break
;
}
if
(
ord
(
$line
[
0
])<=
32
)
{
$lines
[
$ln
]
.=
(
empty
(
$lines
[
$ln
])?
''
:
"
\n
"
).
trim
(
$line
);
}
else
{
$lines
[++
$ln
]
=
trim
(
$line
);
}
// patch from "Maksim Rubis" <siburny@hotmail.com>
}
while
(
$line
[
0
]
!=
')'
&&
!
$this
->
startsWith
(
$line
,
$key
,
true
));
if
(
strncmp
(
$line
,
$key
,
strlen
(
$key
)))
{
// process header, fill rcube_mail_header obj.
// initialize
if
(
is_array
(
$headers
))
{
reset
(
$headers
);
while
(
list
(
$k
,
$bar
)
=
each
(
$headers
))
{
$headers
[
$k
]
=
''
;
}
}
// create array with header field:data
while
(
list
(
$lines_key
,
$str
)
=
each
(
$lines
)
)
{
list
(
$field
,
$string
)
=
$this
->
splitHeaderLine
(
$str
);
$field
=
strtolower
(
$field
);
$string
=
preg_replace
(
'/
\n\s
*/'
,
' '
,
$string
);
switch
(
$field
)
{
case
'date'
;
$result
[
$id
]->
date
=
$string
;
$result
[
$id
]->
timestamp
=
$this
->
strToTime
(
$string
);
break
;
case
'from'
:
$result
[
$id
]->
from
=
$string
;
break
;
case
'to'
:
$result
[
$id
]->
to
=
preg_replace
(
'/undisclosed-recipients:[;,]*/'
,
''
,
$string
);
break
;
case
'subject'
:
$result
[
$id
]->
subject
=
$string
;
break
;
case
'reply-to'
:
$result
[
$id
]->
replyto
=
$string
;
break
;
case
'cc'
:
$result
[
$id
]->
cc
=
$string
;
break
;
case
'bcc'
:
$result
[
$id
]->
bcc
=
$string
;
break
;
case
'content-transfer-encoding'
:
$result
[
$id
]->
encoding
=
$string
;
break
;
case
'content-type'
:
$ctype_parts
=
preg_split
(
'/[; ]/'
,
$string
);
$result
[
$id
]->
ctype
=
array_shift
(
$ctype_parts
);
if
(
preg_match
(
'/charset
\s
*=
\s
*"?([a-z0-9
\-\.\_
]+)"?/i'
,
$string
,
$regs
))
{
$result
[
$id
]->
charset
=
$regs
[
1
];
}
break
;
case
'in-reply-to'
:
$result
[
$id
]->
in_reply_to
=
preg_replace
(
'/[
\n
<>]/'
,
''
,
$string
);
break
;
case
'references'
:
$result
[
$id
]->
references
=
$string
;
break
;
case
'return-receipt-to'
:
case
'disposition-notification-to'
:
case
'x-confirm-reading-to'
:
$result
[
$id
]->
mdn_to
=
$string
;
break
;
case
'message-id'
:
$result
[
$id
]->
messageID
=
$string
;
break
;
case
'x-priority'
:
if
(
preg_match
(
'/^(
\d
+)/'
,
$string
,
$matches
))
$result
[
$id
]->
priority
=
intval
(
$matches
[
1
]);
break
;
default
:
if
(
strlen
(
$field
)
>
2
)
$result
[
$id
]->
others
[
$field
]
=
$string
;
break
;
}
// end switch ()
}
// end while ()
}
else
{
$a
=
explode
(
' '
,
$line
);
}
// process flags
if
(!
empty
(
$flags_str
))
{
$flags_str
=
preg_replace
(
'/[
\\\"
]/'
,
''
,
$flags_str
);
$flags_a
=
explode
(
' '
,
$flags_str
);
if
(
is_array
(
$flags_a
))
{
// reset($flags_a);
foreach
(
$flags_a
as
$flag
)
{
$flag
=
strtoupper
(
$flag
);
if
(
$flag
==
'SEEN'
)
{
$result
[
$id
]->
seen
=
true
;
}
else
if
(
$flag
==
'DELETED'
)
{
$result
[
$id
]->
deleted
=
true
;
}
else
if
(
$flag
==
'RECENT'
)
{
$result
[
$id
]->
recent
=
true
;
}
else
if
(
$flag
==
'ANSWERED'
)
{
$result
[
$id
]->
answered
=
true
;
}
else
if
(
$flag
==
'$FORWARDED'
)
{
$result
[
$id
]->
forwarded
=
true
;
}
else
if
(
$flag
==
'DRAFT'
)
{
$result
[
$id
]->
is_draft
=
true
;
}
else
if
(
$flag
==
'$MDNSENT'
)
{
$result
[
$id
]->
mdn_sent
=
true
;
}
else
if
(
$flag
==
'FLAGGED'
)
{
$result
[
$id
]->
flagged
=
true
;
}
}
$result
[
$id
]->
flags
=
$flags_a
;
}
}
}
}
while
(!
$this
->
startsWith
(
$line
,
$key
,
true
));
return
$result
;
}
function
fetchHeader
(
$mailbox
,
$id
,
$uidfetch
=
false
,
$bodystr
=
false
,
$add
=
''
)
{
$a
=
$this
->
fetchHeaders
(
$mailbox
,
$id
,
$uidfetch
,
$bodystr
,
$add
);
if
(
is_array
(
$a
))
{
return
array_shift
(
$a
);
}
return
false
;
}
function
sortHeaders
(
$a
,
$field
,
$flag
)
{
if
(
empty
(
$field
))
{
$field
=
'uid'
;
}
else
{
$field
=
strtolower
(
$field
);
}
if
(
$field
==
'date'
||
$field
==
'internaldate'
)
{
$field
=
'timestamp'
;
}
if
(
empty
(
$flag
))
{
$flag
=
'ASC'
;
}
else
{
$flag
=
strtoupper
(
$flag
);
}
$stripArr
=
(
$field
==
'subject'
)
?
array
(
'Re: '
,
'Fwd: '
,
'Fw: '
,
'"'
)
:
array
(
'"'
);
$c
=
count
(
$a
);
if
(
$c
>
0
)
{
// Strategy:
// First, we'll create an "index" array.
// Then, we'll use sort() on that array,
// and use that to sort the main array.
// create "index" array
$index
=
array
();
reset
(
$a
);
while
(
list
(
$key
,
$val
)
=
each
(
$a
))
{
if
(
$field
==
'timestamp'
)
{
$data
=
$this
->
strToTime
(
$val
->
date
);
if
(!
$data
)
{
$data
=
$val
->
timestamp
;
}
}
else
{
$data
=
$val
->
$field
;
if
(
is_string
(
$data
))
{
$data
=
strtoupper
(
str_replace
(
$stripArr
,
''
,
$data
));
}
}
$index
[
$key
]=
$data
;
}
// sort index
$i
=
0
;
if
(
$flag
==
'ASC'
)
{
asort
(
$index
);
}
else
{
arsort
(
$index
);
}
// form new array based on index
$result
=
array
();
reset
(
$index
);
while
(
list
(
$key
,
$val
)
=
each
(
$index
))
{
$result
[
$key
]=
$a
[
$key
];
$i
++;
}
}
return
$result
;
}
function
expunge
(
$mailbox
,
$messages
=
NULL
)
{
if
(!
$this
->
select
(
$mailbox
))
{
return
-
1
;
}
$c
=
0
;
$command
=
$messages
?
"UID EXPUNGE $messages"
:
"EXPUNGE"
;
if
(!
$this
->
putLine
(
"exp1 $command"
))
{
return
-
1
;
}
do
{
$line
=
$this
->
readLine
(
100
);
if
(
$line
[
0
]
==
'*'
)
{
$c
++;
}
}
while
(!
$this
->
startsWith
(
$line
,
'exp1'
,
true
,
true
));
if
(
$this
->
parseResult
(
$line
)
==
0
)
{
$this
->
selected
=
''
;
// state has changed, need to reselect
return
$c
;
}
$this
->
error
=
$line
;
return
-
1
;
}
function
modFlag
(
$mailbox
,
$messages
,
$flag
,
$mod
)
{
if
(
$mod
!=
'+'
&&
$mod
!=
'-'
)
{
return
-
1
;
}
$flag
=
$this
->
flags
[
strtoupper
(
$flag
)];
if
(!
$this
->
select
(
$mailbox
))
{
return
-
1
;
}
$c
=
0
;
if
(!
$this
->
putLine
(
"flg UID STORE $messages {$mod}FLAGS ($flag)"
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
(
1000
);
if
(
$line
[
0
]
==
'*'
)
{
$c
++;
}
}
while
(!
$this
->
startsWith
(
$line
,
'flg'
,
true
,
true
));
if
(
$this
->
parseResult
(
$line
)
==
0
)
{
return
$c
;
}
$this
->
error
=
$line
;
return
-
1
;
}
function
flag
(
$mailbox
,
$messages
,
$flag
)
{
return
$this
->
modFlag
(
$mailbox
,
$messages
,
$flag
,
'+'
);
}
function
unflag
(
$mailbox
,
$messages
,
$flag
)
{
return
$this
->
modFlag
(
$mailbox
,
$messages
,
$flag
,
'-'
);
}
function
delete
(
$mailbox
,
$messages
)
{
return
$this
->
modFlag
(
$mailbox
,
$messages
,
'DELETED'
,
'+'
);
}
function
copy
(
$messages
,
$from
,
$to
)
{
if
(
empty
(
$from
)
||
empty
(
$to
))
{
return
-
1
;
}
if
(!
$this
->
select
(
$from
))
{
return
-
1
;
}
$this
->
putLine
(
"cpy1 UID COPY $messages
\"
"
.
$this
->
escape
(
$to
).
"
\"
"
);
$line
=
$this
->
readReply
();
return
$this
->
parseResult
(
$line
);
}
function
countUnseen
(
$folder
)
{
$index
=
$this
->
search
(
$folder
,
'ALL UNSEEN'
);
if
(
is_array
(
$index
))
return
count
(
$index
);
return
false
;
}
// Don't be tempted to change $str to pass by reference to speed this up - it will slow it down by about
// 7 times instead :-) See comments on http://uk2.php.net/references and this article:
// http://derickrethans.nl/files/phparch-php-variables-article.pdf
private
function
parseThread
(
$str
,
$begin
,
$end
,
$root
,
$parent
,
$depth
,
&
$depthmap
,
&
$haschildren
)
{
$node
=
array
();
if
(
$str
[
$begin
]
!=
'('
)
{
$stop
=
$begin
+
strspn
(
$str
,
"1234567890"
,
$begin
,
$end
-
$begin
);
$msg
=
substr
(
$str
,
$begin
,
$stop
-
$begin
);
if
(
$msg
==
0
)
return
$node
;
if
(
is_null
(
$root
))
$root
=
$msg
;
$depthmap
[
$msg
]
=
$depth
;
$haschildren
[
$msg
]
=
false
;
if
(!
is_null
(
$parent
))
$haschildren
[
$parent
]
=
true
;
if
(
$stop
+
1
<
$end
)
$node
[
$msg
]
=
$this
->
parseThread
(
$str
,
$stop
+
1
,
$end
,
$root
,
$msg
,
$depth
+
1
,
$depthmap
,
$haschildren
);
else
$node
[
$msg
]
=
array
();
}
else
{
$off
=
$begin
;
while
(
$off
<
$end
)
{
$start
=
$off
;
$off
++;
$n
=
1
;
while
(
$n
>
0
)
{
$p
=
strpos
(
$str
,
')'
,
$off
);
if
(
$p
===
false
)
{
error_log
(
'Mismatched brackets parsing IMAP THREAD response:'
);
error_log
(
substr
(
$str
,
(
$begin
<
10
)
?
0
:
(
$begin
-
10
),
$end
-
$begin
+
20
));
error_log
(
str_repeat
(
' '
,
$off
-
((
$begin
<
10
)
?
0
:
(
$begin
-
10
))));
return
$node
;
}
$p1
=
strpos
(
$str
,
'('
,
$off
);
if
(
$p1
!==
false
&&
$p1
<
$p
)
{
$off
=
$p1
+
1
;
$n
++;
}
else
{
$off
=
$p
+
1
;
$n
--;
}
}
$node
+=
$this
->
parseThread
(
$str
,
$start
+
1
,
$off
-
1
,
$root
,
$parent
,
$depth
,
$depthmap
,
$haschildren
);
}
}
return
$node
;
}
function
thread
(
$folder
,
$algorithm
=
'REFERENCES'
,
$criteria
=
''
,
$encoding
=
'US-ASCII'
)
{
if
(!
$this
->
select
(
$folder
))
{
return
false
;
}
$encoding
=
$encoding
?
trim
(
$encoding
)
:
'US-ASCII'
;
$algorithm
=
$algorithm
?
trim
(
$algorithm
)
:
'REFERENCES'
;
$criteria
=
$criteria
?
'ALL '
.
trim
(
$criteria
)
:
'ALL'
;
if
(!
$this
->
putLineC
(
"thrd1 THREAD $algorithm $encoding $criteria"
))
{
return
false
;
}
do
{
$line
=
trim
(
$this
->
readLine
(
10000
));
if
(
preg_match
(
'/^
\*
THREAD/'
,
$line
))
{
$str
=
trim
(
substr
(
$line
,
8
));
$depthmap
=
array
();
$haschildren
=
array
();
$tree
=
$this
->
parseThread
(
$str
,
0
,
strlen
(
$str
),
null
,
null
,
0
,
$depthmap
,
$haschildren
);
}
}
while
(!
$this
->
startsWith
(
$line
,
'thrd1'
,
true
,
true
));
$result_code
=
$this
->
parseResult
(
$line
);
if
(
$result_code
==
0
)
{
return
array
(
$tree
,
$depthmap
,
$haschildren
);
}
$this
->
error
=
"Thread: $line"
;
return
false
;
}
function
search
(
$folder
,
$criteria
,
$return_uid
=
false
)
{
if
(!
$this
->
select
(
$folder
))
{
return
false
;
}
$data
=
''
;
$query
=
'srch1 '
.
(
$return_uid
?
'UID '
:
''
)
.
'SEARCH '
.
chop
(
$criteria
);
if
(!
$this
->
putLineC
(
$query
))
{
return
false
;
}
do
{
$line
=
trim
(
$this
->
readLine
());
if
(
$this
->
startsWith
(
$line
,
'* SEARCH'
))
{
$data
.=
substr
(
$line
,
8
);
}
else
if
(
preg_match
(
'/^[0-9 ]+$/'
,
$line
))
{
$data
.=
$line
;
}
}
while
(!
$this
->
startsWith
(
$line
,
'srch1'
,
true
,
true
));
$result_code
=
$this
->
parseResult
(
$line
);
if
(
$result_code
==
0
)
{
return
preg_split
(
'/
\s
+/'
,
$data
,
-
1
,
PREG_SPLIT_NO_EMPTY
);
}
$this
->
error
=
"Search: $line"
;
return
false
;
}
function
move
(
$messages
,
$from
,
$to
)
{
if
(!
$from
||
!
$to
)
{
return
-
1
;
}
$r
=
$this
->
copy
(
$messages
,
$from
,
$to
);
if
(
$r
==
0
)
{
return
$this
->
delete
(
$from
,
$messages
);
}
return
$r
;
}
function
listMailboxes
(
$ref
,
$mailbox
)
{
return
$this
->
_listMailboxes
(
$ref
,
$mailbox
,
false
);
}
function
listSubscribed
(
$ref
,
$mailbox
)
{
return
$this
->
_listMailboxes
(
$ref
,
$mailbox
,
true
);
}
private
function
_listMailboxes
(
$ref
,
$mailbox
,
$subscribed
=
false
)
{
if
(
empty
(
$mailbox
))
{
$mailbox
=
'*'
;
}
if
(
empty
(
$ref
)
&&
$this
->
rootdir
)
{
$ref
=
$this
->
rootdir
;
}
if
(
$subscribed
)
{
$key
=
'lsb'
;
$command
=
'LSUB'
;
}
else
{
$key
=
'lmb'
;
$command
=
'LIST'
;
}
// send command
if
(!
$this
->
putLine
(
$key
.
" "
.
$command
.
"
\"
"
.
$this
->
escape
(
$ref
)
.
"
\"
\"
"
.
$this
->
escape
(
$mailbox
)
.
"
\"
"
))
{
$this
->
error
=
"Couldn't send $command command"
;
return
false
;
}
// get folder list
do
{
$line
=
$this
->
readLine
(
500
);
$line
=
$this
->
multLine
(
$line
,
true
);
$a
=
explode
(
' '
,
$line
);
if
((
$line
[
0
]
==
'*'
)
&&
(
$a
[
1
]
==
$command
))
{
$line
=
rtrim
(
$line
);
// split one line
$a
=
rcube_explode_quoted_string
(
' '
,
$line
);
// last string is folder name
$folders
[]
=
preg_replace
(
array
(
'/^"/'
,
'/"$/'
),
''
,
$this
->
unEscape
(
$a
[
count
(
$a
)-
1
]));
// second from last is delimiter
$delim
=
trim
(
$a
[
count
(
$a
)-
2
],
'"'
);
}
}
while
(!
$this
->
startsWith
(
$line
,
$key
,
true
));
if
(
is_array
(
$folders
))
{
return
$folders
;
}
else
if
(
$this
->
parseResult
(
$line
)
==
0
)
{
return
array
();
}
$this
->
error
=
$line
;
return
false
;
}
function
fetchMIMEHeaders
(
$mailbox
,
$id
,
$parts
,
$mime
=
true
)
{
if
(!
$this
->
select
(
$mailbox
))
{
return
false
;
}
$result
=
false
;
$parts
=
(
array
)
$parts
;
$key
=
'fmh0'
;
$peeks
=
''
;
$idx
=
0
;
$type
=
$mime
?
'MIME'
:
'HEADER'
;
// format request
foreach
(
$parts
as
$part
)
$peeks
[]
=
"BODY.PEEK[$part.$type]"
;
$request
=
"$key FETCH $id ("
.
implode
(
' '
,
$peeks
)
.
')'
;
// send request
if
(!
$this
->
putLine
(
$request
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
(
1000
);
$line
=
$this
->
multLine
(
$line
);
if
(
preg_match
(
'/BODY
\[
([0-9
\.
]+)
\.
'
.
$type
.
'
\]
/'
,
$line
,
$matches
))
{
$idx
=
$matches
[
1
];
$result
[
$idx
]
=
preg_replace
(
'/^(
\*
'
.
$id
.
' FETCH
\(
)?
\s
*BODY
\[
'
.
$idx
.
'
\.
'
.
$type
.
'
\]\s
+/'
,
''
,
$line
);
$result
[
$idx
]
=
trim
(
$result
[
$idx
],
'"'
);
$result
[
$idx
]
=
rtrim
(
$result
[
$idx
],
"
\t\r\n\0\x
0B"
);
}
}
while
(!
$this
->
startsWith
(
$line
,
$key
,
true
));
return
$result
;
}
function
fetchPartHeader
(
$mailbox
,
$id
,
$is_uid
=
false
,
$part
=
NULL
)
{
$part
=
empty
(
$part
)
?
'HEADER'
:
$part
.
'.MIME'
;
return
$this
->
handlePartBody
(
$mailbox
,
$id
,
$is_uid
,
$part
);
}
function
handlePartBody
(
$mailbox
,
$id
,
$is_uid
=
false
,
$part
=
''
,
$encoding
=
NULL
,
$print
=
NULL
,
$file
=
NULL
)
{
if
(!
$this
->
select
(
$mailbox
))
{
return
false
;
}
switch
(
$encoding
)
{
case
'base64'
:
$mode
=
1
;
break
;
case
'quoted-printable'
:
$mode
=
2
;
break
;
case
'x-uuencode'
:
case
'x-uue'
:
case
'uue'
:
case
'uuencode'
:
$mode
=
3
;
break
;
default
:
$mode
=
0
;
}
$reply_key
=
'* '
.
$id
;
$result
=
false
;
// format request
$key
=
'ftch0'
;
$request
=
$key
.
(
$is_uid
?
' UID'
:
''
)
.
" FETCH $id (BODY.PEEK[$part])"
;
// send request
if
(!
$this
->
putLine
(
$request
))
{
return
false
;
}
// receive reply line
do
{
$line
=
chop
(
$this
->
readLine
(
1000
));
$a
=
explode
(
' '
,
$line
);
}
while
(!(
$end
=
$this
->
startsWith
(
$line
,
$key
,
true
))
&&
$a
[
2
]
!=
'FETCH'
);
$len
=
strlen
(
$line
);
// handle empty "* X FETCH ()" response
if
(
$line
[
$len
-
1
]
==
')'
&&
$line
[
$len
-
2
]
!=
'('
)
{
// one line response, get everything between first and last quotes
if
(
substr
(
$line
,
-
4
,
3
)
==
'NIL'
)
{
// NIL response
$result
=
''
;
}
else
{
$from
=
strpos
(
$line
,
'"'
)
+
1
;
$to
=
strrpos
(
$line
,
'"'
);
$len
=
$to
-
$from
;
$result
=
substr
(
$line
,
$from
,
$len
);
}
if
(
$mode
==
1
)
$result
=
base64_decode
(
$result
);
else
if
(
$mode
==
2
)
$result
=
quoted_printable_decode
(
$result
);
else
if
(
$mode
==
3
)
$result
=
convert_uudecode
(
$result
);
}
else
if
(
$line
[
$len
-
1
]
==
'}'
)
{
// multi-line request, find sizes of content and receive that many bytes
$from
=
strpos
(
$line
,
'{'
)
+
1
;
$to
=
strrpos
(
$line
,
'}'
);
$len
=
$to
-
$from
;
$sizeStr
=
substr
(
$line
,
$from
,
$len
);
$bytes
=
(
int
)
$sizeStr
;
$prev
=
''
;
while
(
$bytes
>
0
)
{
$line
=
$this
->
readLine
(
1024
);
$len
=
strlen
(
$line
);
if
(
$len
>
$bytes
)
{
$line
=
substr
(
$line
,
0
,
$bytes
);
$len
=
strlen
(
$line
);
}
$bytes
-=
$len
;
if
(
$mode
==
1
)
{
$line
=
rtrim
(
$line
,
"
\t\r\n\0\x
0B"
);
// create chunks with proper length for base64 decoding
$line
=
$prev
.
$line
;
$length
=
strlen
(
$line
);
if
(
$length
%
4
)
{
$length
=
floor
(
$length
/
4
)
*
4
;
$prev
=
substr
(
$line
,
$length
);
$line
=
substr
(
$line
,
0
,
$length
);
}
else
$prev
=
''
;
if
(
$file
)
fwrite
(
$file
,
base64_decode
(
$line
));
else
if
(
$print
)
echo
base64_decode
(
$line
);
else
$result
.=
base64_decode
(
$line
);
}
else
if
(
$mode
==
2
)
{
$line
=
rtrim
(
$line
,
"
\t\r\0\x
0B"
);
if
(
$file
)
fwrite
(
$file
,
quoted_printable_decode
(
$line
));
else
if
(
$print
)
echo
quoted_printable_decode
(
$line
);
else
$result
.=
quoted_printable_decode
(
$line
);
}
else
if
(
$mode
==
3
)
{
$line
=
rtrim
(
$line
,
"
\t\r\n\0\x
0B"
);
if
(
$line
==
'end'
||
preg_match
(
'/^begin
\s
+[0-7]+
\s
+.+$/'
,
$line
))
continue
;
if
(
$file
)
fwrite
(
$file
,
convert_uudecode
(
$line
));
else
if
(
$print
)
echo
convert_uudecode
(
$line
);
else
$result
.=
convert_uudecode
(
$line
);
}
else
{
$line
=
rtrim
(
$line
,
"
\t\r\n\0\x
0B"
);
if
(
$file
)
fwrite
(
$file
,
$line
.
"
\n
"
);
else
if
(
$print
)
echo
$line
.
"
\n
"
;
else
$result
.=
$line
.
"
\n
"
;
}
}
}
// read in anything up until last line
if
(!
$end
)
do
{
$line
=
$this
->
readLine
(
1024
);
}
while
(!
$this
->
startsWith
(
$line
,
$key
,
true
));
if
(
$result
)
{
if
(
$file
)
{
fwrite
(
$file
,
$result
);
}
else
if
(
$print
)
{
echo
$result
;
}
else
return
$result
;
return
true
;
}
return
false
;
}
function
createFolder
(
$folder
)
{
if
(
$this
->
putLine
(
'c CREATE "'
.
$this
->
escape
(
$folder
)
.
'"'
))
{
do
{
$line
=
$this
->
readLine
(
300
);
}
while
(!
$this
->
startsWith
(
$line
,
'c '
,
true
,
true
));
return
(
$this
->
parseResult
(
$line
)
==
0
);
}
return
false
;
}
function
renameFolder
(
$from
,
$to
)
{
if
(
$this
->
putLine
(
'r RENAME "'
.
$this
->
escape
(
$from
)
.
'" "'
.
$this
->
escape
(
$to
)
.
'"'
))
{
do
{
$line
=
$this
->
readLine
(
300
);
}
while
(!
$this
->
startsWith
(
$line
,
'r '
,
true
,
true
));
return
(
$this
->
parseResult
(
$line
)
==
0
);
}
return
false
;
}
function
deleteFolder
(
$folder
)
{
if
(
$this
->
putLine
(
'd DELETE "'
.
$this
->
escape
(
$folder
).
'"'
))
{
do
{
$line
=
$this
->
readLine
(
300
);
}
while
(!
$this
->
startsWith
(
$line
,
'd '
,
true
,
true
));
return
(
$this
->
parseResult
(
$line
)
==
0
);
}
return
false
;
}
function
clearFolder
(
$folder
)
{
$num_in_trash
=
$this
->
countMessages
(
$folder
);
if
(
$num_in_trash
>
0
)
{
$this
->
delete
(
$folder
,
'1:*'
);
}
return
(
$this
->
expunge
(
$folder
)
>=
0
);
}
function
subscribe
(
$folder
)
{
$query
=
'sub1 SUBSCRIBE "'
.
$this
->
escape
(
$folder
).
'"'
;
$this
->
putLine
(
$query
);
$line
=
trim
(
$this
->
readLine
(
512
));
return
(
$this
->
parseResult
(
$line
)
==
0
);
}
function
unsubscribe
(
$folder
)
{
$query
=
'usub1 UNSUBSCRIBE "'
.
$this
->
escape
(
$folder
)
.
'"'
;
$this
->
putLine
(
$query
);
$line
=
trim
(
$this
->
readLine
(
512
));
return
(
$this
->
parseResult
(
$line
)
==
0
);
}
function
append
(
$folder
,
&
$message
)
{
if
(!
$folder
)
{
return
false
;
}
$message
=
str_replace
(
"
\r
"
,
''
,
$message
);
$message
=
str_replace
(
"
\n
"
,
"
\r\n
"
,
$message
);
$len
=
strlen
(
$message
);
if
(!
$len
)
{
return
false
;
}
$request
=
'a APPEND "'
.
$this
->
escape
(
$folder
)
.
'" (
\\
Seen) {'
.
$len
.
'}'
;
if
(
$this
->
putLine
(
$request
))
{
$line
=
$this
->
readLine
(
512
);
if
(
$line
[
0
]
!=
'+'
)
{
// $errornum = $this->parseResult($line);
$this
->
error
=
"Cannot write to folder: $line"
;
return
false
;
}
if
(!
$this
->
putLine
(
$message
))
{
return
false
;
}
do
{
$line
=
$this
->
readLine
();
}
while
(!
$this
->
startsWith
(
$line
,
'a '
,
true
,
true
));
$result
=
(
$this
->
parseResult
(
$line
)
==
0
);
if
(!
$result
)
{
$this
->
error
=
$line
;
}
return
$result
;
}
$this
->
error
=
"Couldn't send command
\"
$request
\"
"
;
return
false
;
}
function
appendFromFile
(
$folder
,
$path
,
$headers
=
null
,
$separator
=
"
\n\n
"
)
{
if
(!
$folder
)
{
return
false
;
}
// open message file
$in_fp
=
false
;
if
(
file_exists
(
realpath
(
$path
)))
{
$in_fp
=
fopen
(
$path
,
'r'
);
}
if
(!
$in_fp
)
{
$this
->
error
=
"Couldn't open $path for reading"
;
return
false
;
}
$len
=
filesize
(
$path
);
if
(!
$len
)
{
return
false
;
}
if
(
$headers
)
{
$headers
=
preg_replace
(
'/[
\r\n
]+$/'
,
''
,
$headers
);
$len
+=
strlen
(
$headers
)
+
strlen
(
$separator
);
}
// send APPEND command
$request
=
'a APPEND "'
.
$this
->
escape
(
$folder
)
.
'" (
\\
Seen) {'
.
$len
.
'}'
;
if
(
$this
->
putLine
(
$request
))
{
$line
=
$this
->
readLine
(
512
);
if
(
$line
[
0
]
!=
'+'
)
{
//$errornum = $this->parseResult($line);
$this
->
error
=
"Cannot write to folder: $line"
;
return
false
;
}
// send headers with body separator
if
(
$headers
)
{
$this
->
putLine
(
$headers
.
$separator
,
false
);
}
// send file
while
(!
feof
(
$in_fp
)
&&
$this
->
fp
)
{
$buffer
=
fgets
(
$in_fp
,
4096
);
$this
->
putLine
(
$buffer
,
false
);
}
fclose
(
$in_fp
);
if
(!
$this
->
putLine
(
''
))
{
// \r\n
return
false
;
}
// read response
do
{
$line
=
$this
->
readLine
();
}
while
(!
$this
->
startsWith
(
$line
,
'a '
,
true
,
true
));
$result
=
(
$this
->
parseResult
(
$line
)
==
0
);
if
(!
$result
)
{
$this
->
error
=
$line
;
}
return
$result
;
}
$this
->
error
=
"Couldn't send command
\"
$request
\"
"
;
return
false
;
}
function
fetchStructureString
(
$folder
,
$id
,
$is_uid
=
false
)
{
if
(!
$this
->
select
(
$folder
))
{
return
false
;
}
$key
=
'F1247'
;
$result
=
false
;
if
(
$this
->
putLine
(
$key
.
(
$is_uid
?
' UID'
:
''
)
.
" FETCH $id (BODYSTRUCTURE)"
))
{
do
{
$line
=
$this
->
readLine
(
5000
);
$line
=
$this
->
multLine
(
$line
,
true
);
if
(!
preg_match
(
"/^$key/"
,
$line
))
$result
.=
$line
;
}
while
(!
$this
->
startsWith
(
$line
,
$key
,
true
,
true
));
$result
=
trim
(
substr
(
$result
,
strpos
(
$result
,
'BODYSTRUCTURE'
)+
13
,
-
1
));
}
return
$result
;
}
function
getQuota
()
{
/*
* GETQUOTAROOT "INBOX"
* QUOTAROOT INBOX user/rchijiiwa1
* QUOTA user/rchijiiwa1 (STORAGE 654 9765)
* OK Completed
*/
$result
=
false
;
$quota_lines
=
array
();
// get line(s) containing quota info
if
(
$this
->
putLine
(
'QUOT1 GETQUOTAROOT "INBOX"'
))
{
do
{
$line
=
chop
(
$this
->
readLine
(
5000
));
if
(
$this
->
startsWith
(
$line
,
'* QUOTA '
))
{
$quota_lines
[]
=
$line
;
}
}
while
(!
$this
->
startsWith
(
$line
,
'QUOT1'
,
true
,
true
));
}
// return false if not found, parse if found
$min_free
=
PHP_INT_MAX
;
foreach
(
$quota_lines
as
$key
=>
$quota_line
)
{
$quota_line
=
preg_replace
(
'/[()]/'
,
''
,
$quota_line
);
$parts
=
explode
(
' '
,
$quota_line
);
$storage_part
=
array_search
(
'STORAGE'
,
$parts
);
if
(!
$storage_part
)
continue
;
$used
=
intval
(
$parts
[
$storage_part
+
1
]);
$total
=
intval
(
$parts
[
$storage_part
+
2
]);
$free
=
$total
-
$used
;
// return lowest available space from all quotas
if
(
$free
<
$min_free
)
{
$min_free
=
$free
;
$result
[
'used'
]
=
$used
;
$result
[
'total'
]
=
$total
;
$result
[
'percent'
]
=
min
(
100
,
round
((
$used
/
max
(
1
,
$total
))*
100
));
$result
[
'free'
]
=
100
-
$result
[
'percent'
];
}
}
return
$result
;
}
private
function
_xor
(
$string
,
$string2
)
{
$result
=
''
;
$size
=
strlen
(
$string
);
for
(
$i
=
0
;
$i
<
$size
;
$i
++)
{
$result
.=
chr
(
ord
(
$string
[
$i
])
^
ord
(
$string2
[
$i
]));
}
return
$result
;
}
private
function
strToTime
(
$date
)
{
// support non-standard "GMTXXXX" literal
$date
=
preg_replace
(
'/GMT
\s
*([+-][0-9]+)/'
,
'
\\
1'
,
$date
);
// if date parsing fails, we have a date in non-rfc format.
// remove token from the end and try again
while
(((
$ts
=
@
strtotime
(
$date
))===
false
)
||
(
$ts
<
0
))
{
$d
=
explode
(
' '
,
$date
);
array_pop
(
$d
);
if
(!
$d
)
break
;
$date
=
implode
(
' '
,
$d
);
}
$ts
=
(
int
)
$ts
;
return
$ts
<
0
?
0
:
$ts
;
}
private
function
SplitHeaderLine
(
$string
)
{
$pos
=
strpos
(
$string
,
':'
);
if
(
$pos
>
0
)
{
$res
[
0
]
=
substr
(
$string
,
0
,
$pos
);
$res
[
1
]
=
trim
(
substr
(
$string
,
$pos
+
1
));
return
$res
;
}
return
$string
;
}
private
function
parseNamespace
(
$str
,
&
$i
,
$len
=
0
,
$l
)
{
if
(!
$l
)
{
$str
=
str_replace
(
'NIL'
,
'()'
,
$str
);
}
if
(!
$len
)
{
$len
=
strlen
(
$str
);
}
$data
=
array
();
$in_quotes
=
false
;
$elem
=
0
;
for
(
$i
;
$i
<
$len
;
$i
++)
{
$c
=
(
string
)
$str
[
$i
];
if
(
$c
==
'('
&&
!
$in_quotes
)
{
$i
++;
$data
[
$elem
]
=
$this
->
parseNamespace
(
$str
,
$i
,
$len
,
$l
++);
$elem
++;
}
else
if
(
$c
==
')'
&&
!
$in_quotes
)
{
return
$data
;
}
else
if
(
$c
==
'
\\
'
)
{
$i
++;
if
(
$in_quotes
)
{
$data
[
$elem
]
.=
$c
.
$str
[
$i
];
}
}
else
if
(
$c
==
'"'
)
{
$in_quotes
=
!
$in_quotes
;
if
(!
$in_quotes
)
{
$elem
++;
}
}
else
if
(
$in_quotes
)
{
$data
[
$elem
].=
$c
;
}
}
return
$data
;
}
private
function
escape
(
$string
)
{
return
strtr
(
$string
,
array
(
'"'
=>
'
\\
"'
,
'
\\
'
=>
'
\\\\
'
));
}
private
function
unEscape
(
$string
)
{
return
strtr
(
$string
,
array
(
'
\\
"'
=>
'"'
,
'
\\\\
'
=>
'
\\
'
));
}
}
?>
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Fri, May 1, 5:01 PM (13 m, 46 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
593764
Default Alt Text
rcube_imap_generic.php (58 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment