imap_general.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <?php
  2. /**
  3. * imap.php
  4. *
  5. * Copyright (c) 1999-2002 The SquirrelMail Project Team
  6. * Licensed under the GNU GPL. For full terms see the file COPYING.
  7. *
  8. * This implements all functions that do general imap functions.
  9. *
  10. * $Id$
  11. */
  12. require_once('../functions/page_header.php');
  13. require_once('../functions/display_messages.php');
  14. /**
  15. * Unique SessionId
  16. *
  17. * Sets an unique session id in order to avoid simultanous sessions crash.
  18. *
  19. * @return string a 4 chars unique string
  20. */
  21. global $sqimap_session_id;
  22. $sqimap_session_id = 1;
  23. function sqimap_session_id() {
  24. global $data_dir, $username, $sqimap_session_id;
  25. return( sprintf("A%03d", $sqimap_session_id++) );
  26. }
  27. /******************************************************************************
  28. ** Both send a command and accept the result from the command. This is
  29. ** to allow proper session number handling.
  30. ******************************************************************************/
  31. function sqimap_run_command_list ($imap_stream, $query, $handle_errors, &$response, &$message) {
  32. $sid = sqimap_session_id();
  33. fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
  34. $read = sqimap_read_data_list ($imap_stream, $sid, $handle_errors, $response, $message);
  35. return $read;
  36. }
  37. function sqimap_run_command ($imap_stream, $query, $handle_errors, &$response, &$message) {
  38. $sid = sqimap_session_id();
  39. fputs ($imap_stream, $sid . ' ' . $query . "\r\n");
  40. $read = sqimap_read_data ($imap_stream, $sid, $handle_errors, $response, $message);
  41. return $read;
  42. }
  43. /******************************************************************************
  44. ** Reads the output from the IMAP stream. If handle_errors is set to true,
  45. ** this will also handle all errors that are received. If it is not set,
  46. ** the errors will be sent back through $response and $message
  47. ******************************************************************************/
  48. function sqimap_read_data_list ($imap_stream, $pre, $handle_errors,
  49. &$response, &$message) {
  50. global $color, $squirrelmail_language;
  51. $read = '';
  52. $resultlist = array();
  53. $more_msgs = true;
  54. while ($more_msgs) {
  55. $data = array();
  56. $total_size = 0;
  57. while (strpos($read, "\n") === false) {
  58. if(!($read .= fgets($imap_stream, 9096))) {
  59. break;
  60. }
  61. }
  62. if (ereg("^\\* [0-9]+ FETCH.*\\{([0-9]+)\\}", $read, $regs)) {
  63. $size = $regs[1];
  64. } else if (ereg("^\\* [0-9]+ FETCH", $read, $regs)) {
  65. // Sizeless response, probably single-line
  66. $size = -1;
  67. $data[] = $read;
  68. $read = fgets($imap_stream, 9096);
  69. } else {
  70. $size = -1;
  71. }
  72. while (1) {
  73. while (strpos($read, "\n") === false) {
  74. if(!($read .= fgets($imap_stream, 9096))) {
  75. break;
  76. }
  77. }
  78. // If we know the size, no need to look at the end parameters
  79. if ($size > 0) {
  80. if ($total_size == $size) {
  81. // We've reached the end of this 'message', switch to the next one.
  82. $data[] = $read;
  83. break;
  84. } else if ($total_size > $size) {
  85. $difference = $total_size - $size;
  86. $total_size = $total_size - strlen($read);
  87. $data[] = substr ($read, 0, strlen($read)-$difference);
  88. $read = substr ($read, strlen($read)-$difference, strlen($read));
  89. break;
  90. } else {
  91. $data[] = $read;
  92. $read = fgets($imap_stream, 9096);
  93. while (strpos($read, "\n") === false) {
  94. $read .= fgets($imap_stream, 9096);
  95. }
  96. }
  97. $total_size += strlen($read);
  98. } else {
  99. if (ereg("^$pre (OK|BAD|NO)(.*)", $read, $regs) ||
  100. (($size == -1) && ereg("^\\* [0-9]+ FETCH.*", $read, $regs))) {
  101. break;
  102. } else {
  103. $data[] = $read;
  104. $read = fgets ($imap_stream, 9096);
  105. }
  106. }
  107. }
  108. while (($more_msgs = !ereg("^$pre (OK|BAD|NO)(.*)$", $read, $regs)) &&
  109. !ereg("^\\* [0-9]+ FETCH.*", $read, $regs)) {
  110. $read = fgets($imap_stream, 9096);
  111. }
  112. $resultlist[] = $data;
  113. }
  114. $response = $regs[1];
  115. $message = trim($regs[2]);
  116. if ($handle_errors == false) { return $resultlist; }
  117. if ($response == 'NO') {
  118. // ignore this error from m$ exchange, it is not fatal (aka bug)
  119. if (strstr($message, 'command resulted in') === false) {
  120. set_up_language($squirrelmail_language);
  121. echo "<br><b><font color=$color[2]>\n" .
  122. _("ERROR : Could not complete request.") .
  123. "</b><br>\n" .
  124. _("Reason Given: ") .
  125. $message . "</font><br>\n";
  126. exit;
  127. }
  128. } else if ($response == 'BAD') {
  129. set_up_language($squirrelmail_language);
  130. echo "<br><b><font color=$color[2]>\n" .
  131. _("ERROR : Bad or malformed request.") .
  132. "</b><br>\n" .
  133. _("Server responded: ") .
  134. $message . "</font><br>\n";
  135. exit;
  136. }
  137. return $resultlist;
  138. }
  139. function sqimap_read_data ($imap_stream, $pre, $handle_errors, &$response, &$message) {
  140. $res = sqimap_read_data_list($imap_stream, $pre, $handle_errors, $response, $message);
  141. return $res[0];
  142. }
  143. /******************************************************************************
  144. ** Logs the user into the imap server. If $hide is set, no error messages
  145. ** will be displayed. This function returns the imap connection handle.
  146. ******************************************************************************/
  147. function sqimap_login ($username, $password, $imap_server_address, $imap_port, $hide) {
  148. global $color, $squirrelmail_language, $HTTP_ACCEPT_LANGUAGE, $onetimepad;
  149. $imap_stream = fsockopen ( $imap_server_address, $imap_port,
  150. $error_number, $error_string, 15);
  151. if ( !$imap_stream ) {
  152. return FALSE;
  153. }
  154. $server_info = fgets ($imap_stream, 1024);
  155. // Decrypt the password
  156. $password = OneTimePadDecrypt($password, $onetimepad);
  157. /** Do some error correction **/
  158. if (!$imap_stream) {
  159. if (!$hide) {
  160. set_up_language($squirrelmail_language, true);
  161. printf (_("Error connecting to IMAP server: %s.")."<br>\r\n", $imap_server_address);
  162. echo "$error_number : $error_string<br>\r\n";
  163. }
  164. exit;
  165. }
  166. $query = 'LOGIN "' . quoteIMAP($username) . '" "' . quoteIMAP($password) . '"';
  167. $read = sqimap_run_command ($imap_stream, $query, false, $response, $message);
  168. /** If the connection was not successful, lets see why **/
  169. if ($response != 'OK') {
  170. if (!$hide) {
  171. if ($response != 'NO') {
  172. // "BAD" and anything else gets reported here.
  173. set_up_language($squirrelmail_language, true);
  174. if ($response == 'BAD') {
  175. printf (_("Bad request: %s")."<br>\r\n", $message);
  176. } else {
  177. printf (_("Unknown error: %s") . "<br>\n", $message);
  178. }
  179. echo '<br>' . _("Read data:") . "<br>\n";
  180. if (is_array($read)) {
  181. foreach ($read as $line) {
  182. echo htmlspecialchars($line) . "<br>\n";
  183. }
  184. }
  185. exit;
  186. } else {
  187. /* If the user does not log in with the correct
  188. * username and password it is not possible to get the
  189. * correct locale from the user's preferences.
  190. * Therefore, apply the same hack as on the login
  191. * screen.
  192. */
  193. /* $squirrelmail_language is set by a cookie when
  194. * the user selects language and logs out
  195. */
  196. set_up_language($squirrelmail_language, true);
  197. displayHtmlHeader( _("Unknown user or password incorrect.") );
  198. echo "<body bgcolor=\"#ffffff\">\n";
  199. error_username_password_incorrect();
  200. session_destroy();
  201. exit;
  202. }
  203. } else {
  204. exit;
  205. }
  206. }
  207. return $imap_stream;
  208. }
  209. /*
  210. * Simply logs out the imap session
  211. */
  212. function sqimap_logout ($imap_stream) {
  213. /* Logout is not valid until the server returns 'BYE' */
  214. sqimap_run_command($imap_stream, 'LOGOUT', false, $response, $message);
  215. }
  216. function sqimap_capability($imap_stream, $capability) {
  217. global $sqimap_capabilities;
  218. if (!is_array($sqimap_capabilities)) {
  219. $read = sqimap_run_command($imap_stream, 'CAPABILITY', true, $a, $b);
  220. $c = explode(' ', $read[0]);
  221. for ($i=2; $i < count($c); $i++) {
  222. $cap_list = explode('=', $c[$i]);
  223. if (isset($cap_list[1]))
  224. $sqimap_capabilities[$cap_list[0]] = $cap_list[1];
  225. else
  226. $sqimap_capabilities[$cap_list[0]] = TRUE;
  227. }
  228. }
  229. if (! isset($sqimap_capabilities[$capability])) {
  230. return false;
  231. } else {
  232. return $sqimap_capabilities[$capability];
  233. }
  234. }
  235. /******************************************************************************
  236. ** Returns the delimeter between mailboxes: INBOX/Test, or INBOX.Test...
  237. ******************************************************************************/
  238. function sqimap_get_delimiter ($imap_stream = false) {
  239. global $sqimap_delimiter;
  240. global $optional_delimiter;
  241. /* Use configured delimiter if set */
  242. if((!empty($optional_delimiter)) && $optional_delimiter != 'detect') {
  243. return $optional_delimiter;
  244. }
  245. /* Do some caching here */
  246. if (!$sqimap_delimiter) {
  247. if (sqimap_capability($imap_stream, 'NAMESPACE')) {
  248. /* According to something that I can't find, this is supposed to work on all systems
  249. OS: This won't work in Courier IMAP.
  250. OS: According to rfc2342 response from NAMESPACE command is:
  251. OS: * NAMESPACE (PERSONAL NAMESPACES) (OTHER_USERS NAMESPACE) (SHARED NAMESPACES)
  252. OS: We want to lookup all personal NAMESPACES...
  253. */
  254. $read = sqimap_run_command($imap_stream, 'NAMESPACE', true, $a, $b);
  255. if (eregi('\\* NAMESPACE +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL) +(\\( *\\(.+\\) *\\)|NIL)', $read[0], $data)) {
  256. if (eregi('^\\( *\\((.*)\\) *\\)', $data[1], $data2)) {
  257. $pn = $data2[1];
  258. }
  259. $pna = explode(')(', $pn);
  260. while (list($k, $v) = each($pna)) {
  261. $lst = explode('"', $v);
  262. if (isset($lst[3])) {
  263. $pn[$lst[1]] = $lst[3];
  264. } else {
  265. $pn[$lst[1]] = '';
  266. }
  267. }
  268. }
  269. $sqimap_delimiter = $pn[0];
  270. } else {
  271. fputs ($imap_stream, ". LIST \"INBOX\" \"\"\r\n");
  272. $read = sqimap_read_data($imap_stream, '.', true, $a, $b);
  273. $quote_position = strpos ($read[0], '"');
  274. $sqimap_delimiter = substr ($read[0], $quote_position+1, 1);
  275. }
  276. }
  277. return $sqimap_delimiter;
  278. }
  279. /*
  280. * Gets the number of messages in the current mailbox.
  281. */
  282. function sqimap_get_num_messages ($imap_stream, $mailbox) {
  283. $read_ary = sqimap_run_command ($imap_stream, "EXAMINE \"$mailbox\"", true, $result, $message);
  284. for ($i = 0; $i < count($read_ary); $i++) {
  285. if (ereg("[^ ]+ +([^ ]+) +EXISTS", $read_ary[$i], $regs)) {
  286. return $regs[1];
  287. }
  288. }
  289. return sprintf( "BUG! Couldn't get number of messages in %s!", $mailbox );
  290. }
  291. /*
  292. * Returns a displayable email address
  293. */
  294. function sqimap_find_email ($string) {
  295. /** Luke Ehresman <lehresma@css.tayloru.edu>
  296. ** <lehresma@css.tayloru.edu>
  297. ** lehresma@css.tayloru.edu
  298. **
  299. ** What about
  300. ** lehresma@css.tayloru.edu (Luke Ehresman)
  301. **/
  302. if (ereg("<([^>]+)>", $string, $regs)) {
  303. $string = $regs[1];
  304. }
  305. return trim($string);
  306. }
  307. /*
  308. * Takes the From: field, and creates a displayable name.
  309. * Luke Ehresman <lkehresman@yahoo.com>
  310. * "Luke Ehresman" <lkehresman@yahoo.com>
  311. * lkehresman@yahoo.com (Luke Ehresman)
  312. * becomes: Luke Ehresman
  313. * <lkehresman@yahoo.com>
  314. * becomes: lkehresman@yahoo.com
  315. */
  316. function sqimap_find_displayable_name ($string) {
  317. $string = trim($string);
  318. if ( ereg('^(.+)<.*>', $string, $regs) ) {
  319. $orig_string = $string;
  320. $string = str_replace ('"', '', $regs[1] );
  321. if (trim($string) == '') {
  322. $string = sqimap_find_email($orig_string);
  323. }
  324. if( $string == '' || $string == ' ' ){
  325. $string = '&nbsp';
  326. }
  327. }
  328. elseif ( ereg('\((.*)\)', $string, $regs) ) {
  329. if( ( $regs[1] == '' ) || ( $regs[1] == ' ' ) ){
  330. if ( ereg('^(.+) \(', $string, $regs) ) {
  331. $string = ereg_replace( ' \(\)$', '', $string );
  332. } else {
  333. $string = '&nbsp';
  334. }
  335. } else {
  336. $string = $regs[1];
  337. }
  338. }
  339. else {
  340. $string = str_replace ('"', '', sqimap_find_email($string));
  341. }
  342. return trim($string);
  343. }
  344. /*
  345. * Returns the number of unseen messages in this folder
  346. */
  347. function sqimap_unseen_messages ($imap_stream, $mailbox) {
  348. //fputs ($imap_stream, sqimap_session_id() . " SEARCH UNSEEN NOT DELETED\r\n");
  349. $read_ary = sqimap_run_command ($imap_stream, "STATUS \"$mailbox\" (UNSEEN)", true, $result, $message);
  350. ereg("UNSEEN ([0-9]+)", $read_ary[0], $regs);
  351. return $regs[1];
  352. }
  353. /*
  354. * Saves a message to a given folder -- used for saving sent messages
  355. */
  356. function sqimap_append ($imap_stream, $sent_folder, $length) {
  357. fputs ($imap_stream, sqimap_session_id() . " APPEND \"$sent_folder\" (\\Seen) \{$length}\r\n");
  358. $tmp = fgets ($imap_stream, 1024);
  359. }
  360. function sqimap_append_done ($imap_stream) {
  361. fputs ($imap_stream, "\r\n");
  362. $tmp = fgets ($imap_stream, 1024);
  363. }
  364. ?>