xref: /PHP-7.0/ext/imap/php_imap.c (revision 7edc639b)
1 /*
2    +----------------------------------------------------------------------+
3    | PHP Version 7                                                        |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1997-2017 The PHP Group                                |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 3.01 of the PHP license,      |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.php.net/license/3_01.txt                                  |
11    | If you did not receive a copy of the PHP license and are unable to   |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@php.net so we can mail you a copy immediately.               |
14    +----------------------------------------------------------------------+
15    | Authors: Rex Logan           <veebert@dimensional.com>               |
16    |          Mark Musone         <musone@afterfive.com>                  |
17    |          Brian Wang          <brian@vividnet.com>                    |
18    |          Kaj-Michael Lang    <milang@tal.org>                        |
19    |          Antoni Pamies Olive <toni@readysoft.net>                    |
20    |          Rasmus Lerdorf      <rasmus@php.net>                        |
21    |          Chuck Hagenbuch     <chuck@horde.org>                       |
22    |          Andrew Skalski      <askalski@chekinc.com>                  |
23    |          Hartmut Holzgraefe  <hholzgra@php.net>                      |
24    |          Jani Taskinen       <jani.taskinen@iki.fi>                  |
25    |          Daniel R. Kalowsky  <kalowsky@php.net>                      |
26    | PHP 4.0 updates:  Zeev Suraski <zeev@zend.com>                       |
27    +----------------------------------------------------------------------+
28  */
29 /* $Id$ */
30 
31 #define IMAP41
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "php.h"
38 #include "php_ini.h"
39 #include "php_streams.h"
40 #include "ext/standard/php_string.h"
41 #include "ext/standard/info.h"
42 #include "ext/standard/file.h"
43 #include "zend_smart_str.h"
44 #include "ext/pcre/php_pcre.h"
45 
46 #ifdef ERROR
47 #undef ERROR
48 #endif
49 #include "php_imap.h"
50 
51 #include <time.h>
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <signal.h>
55 
56 #ifdef PHP_WIN32
57 #include <winsock2.h>
58 #include <stdlib.h>
59 #include "win32/sendmail.h"
60 MAILSTREAM DEFAULTPROTO;
61 #endif
62 
63 #define CRLF	"\015\012"
64 #define CRLF_LEN sizeof("\015\012") - 1
65 #define PHP_EXPUNGE 32768
66 #define PHP_IMAP_ADDRESS_SIZE_BUF 10
67 #ifndef SENDBUFLEN
68 #define SENDBUFLEN 16385
69 #endif
70 
71 #if defined(__GNUC__) && __GNUC__ >= 4
72 # define PHP_IMAP_EXPORT __attribute__ ((visibility("default")))
73 #else
74 # define PHP_IMAP_EXPORT
75 #endif
76 
77 static void _php_make_header_object(zval *myzvalue, ENVELOPE *en);
78 static void _php_imap_add_body(zval *arg, BODY *body);
79 static zend_string* _php_imap_parse_address(ADDRESS *addresslist, zval *paddress);
80 static zend_string* _php_rfc822_write_address(ADDRESS *addresslist);
81 
82 /* the gets we use */
83 static char *php_mail_gets(readfn_t f, void *stream, unsigned long size, GETS_DATA *md);
84 
85 /* These function declarations are missing from the IMAP header files... */
86 void rfc822_date(char *date);
87 char *cpystr(const char *str);
88 char *cpytxt(SIZEDTEXT *dst, char *text, unsigned long size);
89 #ifndef HAVE_NEW_MIME2TEXT
90 long utf8_mime2text(SIZEDTEXT *src, SIZEDTEXT *dst);
91 #else
92 long utf8_mime2text (SIZEDTEXT *src, SIZEDTEXT *dst, long flags);
93 #endif
94 unsigned long find_rightmost_bit(unsigned long *valptr);
95 void fs_give(void **block);
96 void *fs_get(size_t size);
97 
98 ZEND_DECLARE_MODULE_GLOBALS(imap)
99 static PHP_GINIT_FUNCTION(imap);
100 
101 /* {{{ arginfo */
102 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_open, 0, 0, 3)
103 	ZEND_ARG_INFO(0, mailbox)
104 	ZEND_ARG_INFO(0, user)
105 	ZEND_ARG_INFO(0, password)
106 	ZEND_ARG_INFO(0, options)
107 	ZEND_ARG_INFO(0, n_retries)
108 	ZEND_ARG_INFO(0, params)
109 ZEND_END_ARG_INFO()
110 
111 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_reopen, 0, 0, 2)
112 	ZEND_ARG_INFO(0, stream_id)
113 	ZEND_ARG_INFO(0, mailbox)
114 	ZEND_ARG_INFO(0, options)
115 	ZEND_ARG_INFO(0, n_retries)
116 ZEND_END_ARG_INFO()
117 
118 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_append, 0, 0, 3)
119 	ZEND_ARG_INFO(0, stream_id)
120 	ZEND_ARG_INFO(0, folder)
121 	ZEND_ARG_INFO(0, message)
122 	ZEND_ARG_INFO(0, options)
123 	ZEND_ARG_INFO(0, date)
124 ZEND_END_ARG_INFO()
125 
126 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_num_msg, 0, 0, 1)
127 	ZEND_ARG_INFO(0, stream_id)
128 ZEND_END_ARG_INFO()
129 
130 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_ping, 0, 0, 1)
131 	ZEND_ARG_INFO(0, stream_id)
132 ZEND_END_ARG_INFO()
133 
134 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_num_recent, 0, 0, 1)
135 	ZEND_ARG_INFO(0, stream_id)
136 ZEND_END_ARG_INFO()
137 
138 #if defined(HAVE_IMAP2000) || defined(HAVE_IMAP2001)
139 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_get_quota, 0, 0, 2)
140 	ZEND_ARG_INFO(0, stream_id)
141 	ZEND_ARG_INFO(0, qroot)
142 ZEND_END_ARG_INFO()
143 
144 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_get_quotaroot, 0, 0, 2)
145 	ZEND_ARG_INFO(0, stream_id)
146 	ZEND_ARG_INFO(0, mbox)
147 ZEND_END_ARG_INFO()
148 
149 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_set_quota, 0, 0, 3)
150 	ZEND_ARG_INFO(0, stream_id)
151 	ZEND_ARG_INFO(0, qroot)
152 	ZEND_ARG_INFO(0, mailbox_size)
153 ZEND_END_ARG_INFO()
154 
155 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_setacl, 0, 0, 4)
156 	ZEND_ARG_INFO(0, stream_id)
157 	ZEND_ARG_INFO(0, mailbox)
158 	ZEND_ARG_INFO(0, id)
159 	ZEND_ARG_INFO(0, rights)
160 ZEND_END_ARG_INFO()
161 
162 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_getacl, 0, 0, 2)
163 	ZEND_ARG_INFO(0, stream_id)
164 	ZEND_ARG_INFO(0, mailbox)
165 ZEND_END_ARG_INFO()
166 #endif
167 
168 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_expunge, 0, 0, 1)
169 	ZEND_ARG_INFO(0, stream_id)
170 ZEND_END_ARG_INFO()
171 
172 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_gc, 0, 0, 1)
173 	ZEND_ARG_INFO(0, stream_id)
174 	ZEND_ARG_INFO(0, flags)
175 ZEND_END_ARG_INFO()
176 
177 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_close, 0, 0, 1)
178 	ZEND_ARG_INFO(0, stream_id)
179 	ZEND_ARG_INFO(0, options)
180 ZEND_END_ARG_INFO()
181 
182 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_headers, 0, 0, 1)
183 	ZEND_ARG_INFO(0, stream_id)
184 ZEND_END_ARG_INFO()
185 
186 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_body, 0, 0, 2)
187 	ZEND_ARG_INFO(0, stream_id)
188 	ZEND_ARG_INFO(0, msg_no)
189 	ZEND_ARG_INFO(0, options)
190 ZEND_END_ARG_INFO()
191 
192 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mail_copy, 0, 0, 3)
193 	ZEND_ARG_INFO(0, stream_id)
194 	ZEND_ARG_INFO(0, msglist)
195 	ZEND_ARG_INFO(0, mailbox)
196 	ZEND_ARG_INFO(0, options)
197 ZEND_END_ARG_INFO()
198 
199 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mail_move, 0, 0, 3)
200 	ZEND_ARG_INFO(0, stream_id)
201 	ZEND_ARG_INFO(0, sequence)
202 	ZEND_ARG_INFO(0, mailbox)
203 	ZEND_ARG_INFO(0, options)
204 ZEND_END_ARG_INFO()
205 
206 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_createmailbox, 0, 0, 2)
207 	ZEND_ARG_INFO(0, stream_id)
208 	ZEND_ARG_INFO(0, mailbox)
209 ZEND_END_ARG_INFO()
210 
211 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_renamemailbox, 0, 0, 3)
212 	ZEND_ARG_INFO(0, stream_id)
213 	ZEND_ARG_INFO(0, old_name)
214 	ZEND_ARG_INFO(0, new_name)
215 ZEND_END_ARG_INFO()
216 
217 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_deletemailbox, 0, 0, 2)
218 	ZEND_ARG_INFO(0, stream_id)
219 	ZEND_ARG_INFO(0, mailbox)
220 ZEND_END_ARG_INFO()
221 
222 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_list, 0, 0, 3)
223 	ZEND_ARG_INFO(0, stream_id)
224 	ZEND_ARG_INFO(0, ref)
225 	ZEND_ARG_INFO(0, pattern)
226 ZEND_END_ARG_INFO()
227 
228 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_getmailboxes, 0, 0, 3)
229 	ZEND_ARG_INFO(0, stream_id)
230 	ZEND_ARG_INFO(0, ref)
231 	ZEND_ARG_INFO(0, pattern)
232 ZEND_END_ARG_INFO()
233 
234 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_listscan, 0, 0, 4)
235 	ZEND_ARG_INFO(0, stream_id)
236 	ZEND_ARG_INFO(0, ref)
237 	ZEND_ARG_INFO(0, pattern)
238 	ZEND_ARG_INFO(0, content)
239 ZEND_END_ARG_INFO()
240 
241 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_check, 0, 0, 1)
242 	ZEND_ARG_INFO(0, stream_id)
243 ZEND_END_ARG_INFO()
244 
245 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_delete, 0, 0, 2)
246 	ZEND_ARG_INFO(0, stream_id)
247 	ZEND_ARG_INFO(0, msg_no)
248 	ZEND_ARG_INFO(0, options)
249 ZEND_END_ARG_INFO()
250 
251 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_undelete, 0, 0, 2)
252 	ZEND_ARG_INFO(0, stream_id)
253 	ZEND_ARG_INFO(0, msg_no)
254 	ZEND_ARG_INFO(0, flags)
255 ZEND_END_ARG_INFO()
256 
257 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_headerinfo, 0, 0, 2)
258 	ZEND_ARG_INFO(0, stream_id)
259 	ZEND_ARG_INFO(0, msg_no)
260 	ZEND_ARG_INFO(0, from_length)
261 	ZEND_ARG_INFO(0, subject_length)
262 	ZEND_ARG_INFO(0, default_host)
263 ZEND_END_ARG_INFO()
264 
265 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_rfc822_parse_headers, 0, 0, 1)
266 	ZEND_ARG_INFO(0, headers)
267 	ZEND_ARG_INFO(0, default_host)
268 ZEND_END_ARG_INFO()
269 
270 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_lsub, 0, 0, 3)
271 	ZEND_ARG_INFO(0, stream_id)
272 	ZEND_ARG_INFO(0, ref)
273 	ZEND_ARG_INFO(0, pattern)
274 ZEND_END_ARG_INFO()
275 
276 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_getsubscribed, 0, 0, 3)
277 	ZEND_ARG_INFO(0, stream_id)
278 	ZEND_ARG_INFO(0, ref)
279 	ZEND_ARG_INFO(0, pattern)
280 ZEND_END_ARG_INFO()
281 
282 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_subscribe, 0, 0, 2)
283 	ZEND_ARG_INFO(0, stream_id)
284 	ZEND_ARG_INFO(0, mailbox)
285 ZEND_END_ARG_INFO()
286 
287 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_unsubscribe, 0, 0, 2)
288 	ZEND_ARG_INFO(0, stream_id)
289 	ZEND_ARG_INFO(0, mailbox)
290 ZEND_END_ARG_INFO()
291 
292 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_fetchstructure, 0, 0, 2)
293 	ZEND_ARG_INFO(0, stream_id)
294 	ZEND_ARG_INFO(0, msg_no)
295 	ZEND_ARG_INFO(0, options)
296 ZEND_END_ARG_INFO()
297 
298 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_fetchbody, 0, 0, 3)
299 	ZEND_ARG_INFO(0, stream_id)
300 	ZEND_ARG_INFO(0, msg_no)
301 	ZEND_ARG_INFO(0, section)
302 	ZEND_ARG_INFO(0, options)
303 ZEND_END_ARG_INFO()
304 
305 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_savebody, 0, 0, 3)
306 	ZEND_ARG_INFO(0, stream_id)
307 	ZEND_ARG_INFO(0, file)
308 	ZEND_ARG_INFO(0, msg_no)
309 	ZEND_ARG_INFO(0, section)
310 	ZEND_ARG_INFO(0, options)
311 ZEND_END_ARG_INFO()
312 
313 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_base64, 0, 0, 1)
314 	ZEND_ARG_INFO(0, text)
315 ZEND_END_ARG_INFO()
316 
317 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_qprint, 0, 0, 1)
318 	ZEND_ARG_INFO(0, text)
319 ZEND_END_ARG_INFO()
320 
321 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_8bit, 0, 0, 1)
322 	ZEND_ARG_INFO(0, text)
323 ZEND_END_ARG_INFO()
324 
325 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_binary, 0, 0, 1)
326 	ZEND_ARG_INFO(0, text)
327 ZEND_END_ARG_INFO()
328 
329 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mailboxmsginfo, 0, 0, 1)
330 	ZEND_ARG_INFO(0, stream_id)
331 ZEND_END_ARG_INFO()
332 
333 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_rfc822_write_address, 0, 0, 3)
334 	ZEND_ARG_INFO(0, mailbox)
335 	ZEND_ARG_INFO(0, host)
336 	ZEND_ARG_INFO(0, personal)
337 ZEND_END_ARG_INFO()
338 
339 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_rfc822_parse_adrlist, 0, 0, 2)
340 	ZEND_ARG_INFO(0, address_string)
341 	ZEND_ARG_INFO(0, default_host)
342 ZEND_END_ARG_INFO()
343 
344 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_utf8, 0, 0, 1)
345 	ZEND_ARG_INFO(0, mime_encoded_text)
346 ZEND_END_ARG_INFO()
347 
348 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_utf7_decode, 0, 0, 1)
349 	ZEND_ARG_INFO(0, buf)
350 ZEND_END_ARG_INFO()
351 
352 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_utf7_encode, 0, 0, 1)
353 	ZEND_ARG_INFO(0, buf)
354 ZEND_END_ARG_INFO()
355 
356 #ifdef HAVE_IMAP_MUTF7
357 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_utf8_to_mutf7, 0, 0, 1)
358 	ZEND_ARG_INFO(0, in)
359 ZEND_END_ARG_INFO()
360 
361 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mutf7_to_utf8, 0, 0, 1)
362 	ZEND_ARG_INFO(0, in)
363 ZEND_END_ARG_INFO()
364 #endif
365 
366 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_setflag_full, 0, 0, 3)
367 	ZEND_ARG_INFO(0, stream_id)
368 	ZEND_ARG_INFO(0, sequence)
369 	ZEND_ARG_INFO(0, flag)
370 	ZEND_ARG_INFO(0, options)
371 ZEND_END_ARG_INFO()
372 
373 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_clearflag_full, 0, 0, 3)
374 	ZEND_ARG_INFO(0, stream_id)
375 	ZEND_ARG_INFO(0, sequence)
376 	ZEND_ARG_INFO(0, flag)
377 	ZEND_ARG_INFO(0, options)
378 ZEND_END_ARG_INFO()
379 
380 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_sort, 0, 0, 3)
381 	ZEND_ARG_INFO(0, stream_id)
382 	ZEND_ARG_INFO(0, criteria)
383 	ZEND_ARG_INFO(0, reverse)
384 	ZEND_ARG_INFO(0, options)
385 	ZEND_ARG_INFO(0, search_criteria)
386 	ZEND_ARG_INFO(0, charset)
387 ZEND_END_ARG_INFO()
388 
389 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_fetchheader, 0, 0, 2)
390 	ZEND_ARG_INFO(0, stream_id)
391 	ZEND_ARG_INFO(0, msg_no)
392 	ZEND_ARG_INFO(0, options)
393 ZEND_END_ARG_INFO()
394 
395 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_uid, 0, 0, 2)
396 	ZEND_ARG_INFO(0, stream_id)
397 	ZEND_ARG_INFO(0, msg_no)
398 ZEND_END_ARG_INFO()
399 
400 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_msgno, 0, 0, 2)
401 	ZEND_ARG_INFO(0, stream_id)
402 	ZEND_ARG_INFO(0, unique_msg_id)
403 ZEND_END_ARG_INFO()
404 
405 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_status, 0, 0, 3)
406 	ZEND_ARG_INFO(0, stream_id)
407 	ZEND_ARG_INFO(0, mailbox)
408 	ZEND_ARG_INFO(0, options)
409 ZEND_END_ARG_INFO()
410 
411 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_bodystruct, 0, 0, 3)
412 	ZEND_ARG_INFO(0, stream_id)
413 	ZEND_ARG_INFO(0, msg_no)
414 	ZEND_ARG_INFO(0, section)
415 ZEND_END_ARG_INFO()
416 
417 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_fetch_overview, 0, 0, 2)
418 	ZEND_ARG_INFO(0, stream_id)
419 	ZEND_ARG_INFO(0, sequence)
420 	ZEND_ARG_INFO(0, options)
421 ZEND_END_ARG_INFO()
422 
423 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mail_compose, 0, 0, 2)
424 	ZEND_ARG_INFO(0, envelope)
425 	ZEND_ARG_INFO(0, body)
426 ZEND_END_ARG_INFO()
427 
428 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mail, 0, 0, 3)
429 	ZEND_ARG_INFO(0, to)
430 	ZEND_ARG_INFO(0, subject)
431 	ZEND_ARG_INFO(0, message)
432 	ZEND_ARG_INFO(0, additional_headers)
433 	ZEND_ARG_INFO(0, cc)
434 	ZEND_ARG_INFO(0, bcc)
435 	ZEND_ARG_INFO(0, rpath)
436 ZEND_END_ARG_INFO()
437 
438 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_search, 0, 0, 2)
439 	ZEND_ARG_INFO(0, stream_id)
440 	ZEND_ARG_INFO(0, criteria)
441 	ZEND_ARG_INFO(0, options)
442 	ZEND_ARG_INFO(0, charset)
443 ZEND_END_ARG_INFO()
444 
445 ZEND_BEGIN_ARG_INFO(arginfo_imap_alerts, 0)
446 ZEND_END_ARG_INFO()
447 
448 ZEND_BEGIN_ARG_INFO(arginfo_imap_errors, 0)
449 ZEND_END_ARG_INFO()
450 
451 ZEND_BEGIN_ARG_INFO(arginfo_imap_last_error, 0)
452 ZEND_END_ARG_INFO()
453 
454 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_mime_header_decode, 0, 0, 1)
455 	ZEND_ARG_INFO(0, str)
456 ZEND_END_ARG_INFO()
457 
458 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_thread, 0, 0, 1)
459 	ZEND_ARG_INFO(0, stream_id)
460 	ZEND_ARG_INFO(0, options)
461 ZEND_END_ARG_INFO()
462 
463 ZEND_BEGIN_ARG_INFO_EX(arginfo_imap_timeout, 0, 0, 1)
464 	ZEND_ARG_INFO(0, timeout_type)
465 	ZEND_ARG_INFO(0, timeout)
466 ZEND_END_ARG_INFO()
467 /* }}} */
468 
469 /* {{{ imap_functions[]
470  */
471 const zend_function_entry imap_functions[] = {
472 	PHP_FE(imap_open,								arginfo_imap_open)
473 	PHP_FE(imap_reopen,								arginfo_imap_reopen)
474 	PHP_FE(imap_close,								arginfo_imap_close)
475 	PHP_FE(imap_num_msg,							arginfo_imap_num_msg)
476 	PHP_FE(imap_num_recent,							arginfo_imap_num_recent)
477 	PHP_FE(imap_headers,							arginfo_imap_headers)
478 	PHP_FE(imap_headerinfo,							arginfo_imap_headerinfo)
479 	PHP_FE(imap_rfc822_parse_headers,				arginfo_imap_rfc822_parse_headers)
480 	PHP_FE(imap_rfc822_write_address,				arginfo_imap_rfc822_write_address)
481 	PHP_FE(imap_rfc822_parse_adrlist,				arginfo_imap_rfc822_parse_adrlist)
482 	PHP_FE(imap_body,								arginfo_imap_body)
483 	PHP_FE(imap_bodystruct,							arginfo_imap_bodystruct)
484 	PHP_FE(imap_fetchbody,							arginfo_imap_fetchbody)
485 	PHP_FE(imap_fetchmime,							arginfo_imap_fetchbody)
486 	PHP_FE(imap_savebody,							arginfo_imap_savebody)
487 	PHP_FE(imap_fetchheader,						arginfo_imap_fetchheader)
488 	PHP_FE(imap_fetchstructure,						arginfo_imap_fetchstructure)
489 	PHP_FE(imap_gc,										arginfo_imap_gc)
490 	PHP_FE(imap_expunge,							arginfo_imap_expunge)
491 	PHP_FE(imap_delete,								arginfo_imap_delete)
492 	PHP_FE(imap_undelete,							arginfo_imap_undelete)
493 	PHP_FE(imap_check,								arginfo_imap_check)
494 	PHP_FE(imap_listscan,							arginfo_imap_listscan)
495 	PHP_FE(imap_mail_copy,							arginfo_imap_mail_copy)
496 	PHP_FE(imap_mail_move,							arginfo_imap_mail_move)
497 	PHP_FE(imap_mail_compose,						arginfo_imap_mail_compose)
498 	PHP_FE(imap_createmailbox,						arginfo_imap_createmailbox)
499 	PHP_FE(imap_renamemailbox,						arginfo_imap_renamemailbox)
500 	PHP_FE(imap_deletemailbox,						arginfo_imap_deletemailbox)
501 	PHP_FE(imap_subscribe,							arginfo_imap_subscribe)
502 	PHP_FE(imap_unsubscribe,						arginfo_imap_unsubscribe)
503 	PHP_FE(imap_append,								arginfo_imap_append)
504 	PHP_FE(imap_ping,								arginfo_imap_ping)
505 	PHP_FE(imap_base64,								arginfo_imap_base64)
506 	PHP_FE(imap_qprint,								arginfo_imap_qprint)
507 	PHP_FE(imap_8bit,								arginfo_imap_8bit)
508 	PHP_FE(imap_binary,								arginfo_imap_binary)
509 	PHP_FE(imap_utf8,								arginfo_imap_utf8)
510 	PHP_FE(imap_status,								arginfo_imap_status)
511 	PHP_FE(imap_mailboxmsginfo,						arginfo_imap_mailboxmsginfo)
512 	PHP_FE(imap_setflag_full,						arginfo_imap_setflag_full)
513 	PHP_FE(imap_clearflag_full,						arginfo_imap_clearflag_full)
514 	PHP_FE(imap_sort,								arginfo_imap_sort)
515 	PHP_FE(imap_uid,								arginfo_imap_uid)
516 	PHP_FE(imap_msgno,								arginfo_imap_msgno)
517 	PHP_FE(imap_list,								arginfo_imap_list)
518 	PHP_FE(imap_lsub,								arginfo_imap_lsub)
519 	PHP_FE(imap_fetch_overview,						arginfo_imap_fetch_overview)
520 	PHP_FE(imap_alerts,								arginfo_imap_alerts)
521 	PHP_FE(imap_errors,								arginfo_imap_errors)
522 	PHP_FE(imap_last_error,							arginfo_imap_last_error)
523 	PHP_FE(imap_search,								arginfo_imap_search)
524 	PHP_FE(imap_utf7_decode,						arginfo_imap_utf7_decode)
525 	PHP_FE(imap_utf7_encode,						arginfo_imap_utf7_encode)
526 #ifdef HAVE_IMAP_MUTF7
527 	PHP_FE(imap_utf8_to_mutf7,						arginfo_imap_utf8_to_mutf7)
528 	PHP_FE(imap_mutf7_to_utf8,						arginfo_imap_mutf7_to_utf8)
529 #endif
530 	PHP_FE(imap_mime_header_decode,					arginfo_imap_mime_header_decode)
531 	PHP_FE(imap_thread,								arginfo_imap_thread)
532 	PHP_FE(imap_timeout,								arginfo_imap_timeout)
533 
534 #if defined(HAVE_IMAP2000) || defined(HAVE_IMAP2001)
535 	PHP_FE(imap_get_quota,							arginfo_imap_get_quota)
536 	PHP_FE(imap_get_quotaroot,						arginfo_imap_get_quotaroot)
537 	PHP_FE(imap_set_quota,							arginfo_imap_set_quota)
538 	PHP_FE(imap_setacl,								arginfo_imap_setacl)
539 	PHP_FE(imap_getacl,								arginfo_imap_getacl)
540 #endif
541 
542 	PHP_FE(imap_mail,								arginfo_imap_mail)
543 
544 	PHP_FALIAS(imap_header,			imap_headerinfo,	arginfo_imap_headerinfo)
545 	PHP_FALIAS(imap_listmailbox,	imap_list,			arginfo_imap_list)
546 	PHP_FALIAS(imap_getmailboxes,	imap_list_full,		arginfo_imap_getmailboxes)
547 	PHP_FALIAS(imap_scanmailbox,	imap_listscan,		arginfo_imap_listscan)
548 	PHP_FALIAS(imap_listsubscribed,	imap_lsub,			arginfo_imap_lsub)
549 	PHP_FALIAS(imap_getsubscribed,	imap_lsub_full,		arginfo_imap_getsubscribed)
550 	PHP_FALIAS(imap_fetchtext,		imap_body,			arginfo_imap_body)
551 	PHP_FALIAS(imap_scan,			imap_listscan,		arginfo_imap_listscan)
552 	PHP_FALIAS(imap_create,			imap_createmailbox,	arginfo_imap_createmailbox)
553 	PHP_FALIAS(imap_rename,			imap_renamemailbox,	arginfo_imap_renamemailbox)
554 	PHP_FE_END
555 };
556 /* }}} */
557 
558 /* {{{ imap dependencies */
559 static const zend_module_dep imap_deps[] = {
560 	ZEND_MOD_REQUIRED("standard")
561 	ZEND_MOD_END
562 };
563 /* }}} */
564 
565 
566 /* {{{ PHP_INI
567  */
568 PHP_INI_BEGIN()
569 STD_PHP_INI_BOOLEAN("imap.enable_insecure_rsh", "0", PHP_INI_SYSTEM, OnUpdateBool, enable_rsh, zend_imap_globals, imap_globals)
570 PHP_INI_END()
571 /* }}} */
572 
573 
574 /* {{{ imap_module_entry
575  */
576 zend_module_entry imap_module_entry = {
577 	STANDARD_MODULE_HEADER_EX, NULL,
578 	imap_deps,
579 	"imap",
580 	imap_functions,
581 	PHP_MINIT(imap),
582 	NULL,
583 	PHP_RINIT(imap),
584 	PHP_RSHUTDOWN(imap),
585 	PHP_MINFO(imap),
586 	PHP_IMAP_VERSION,
587 	PHP_MODULE_GLOBALS(imap),
588 	PHP_GINIT(imap),
589 	NULL,
590 	NULL,
591 	STANDARD_MODULE_PROPERTIES_EX
592 };
593 /* }}} */
594 
595 #ifdef COMPILE_DL_IMAP
ZEND_GET_MODULE(imap)596 ZEND_GET_MODULE(imap)
597 #endif
598 
599 /* True globals, no need for thread safety */
600 static int le_imap;
601 
602 #define PHP_IMAP_CHECK_MSGNO(msgindex)	\
603 	if ((msgindex < 1) || ((unsigned) msgindex > imap_le_struct->imap_stream->nmsgs)) {	\
604 		php_error_docref(NULL, E_WARNING, "Bad message number");	\
605 		RETURN_FALSE;	\
606 	}	\
607 
608 /* {{{ mail_close_it
609  */
610 static void mail_close_it(zend_resource *rsrc)
611 {
612 	pils *imap_le_struct = (pils *)rsrc->ptr;
613 
614 	/* Do not try to close prototype streams */
615 	if (!(imap_le_struct->flags & OP_PROTOTYPE)) {
616 		mail_close_full(imap_le_struct->imap_stream, imap_le_struct->flags);
617 	}
618 
619 	if (IMAPG(imap_user)) {
620 		efree(IMAPG(imap_user));
621 		IMAPG(imap_user) = 0;
622 	}
623 	if (IMAPG(imap_password)) {
624 		efree(IMAPG(imap_password));
625 		IMAPG(imap_password) = 0;
626 	}
627 
628 	efree(imap_le_struct);
629 }
630 /* }}} */
631 
632 /* {{{ add_assoc_object
633  */
add_assoc_object(zval * arg,char * key,zval * tmp)634 static zval *add_assoc_object(zval *arg, char *key, zval *tmp)
635 {
636 	HashTable *symtable;
637 
638 	if (Z_TYPE_P(arg) == IS_OBJECT) {
639 		symtable = Z_OBJPROP_P(arg);
640 	} else {
641 		symtable = Z_ARRVAL_P(arg);
642 	}
643 	return zend_hash_str_update(symtable, key, strlen(key), tmp);
644 }
645 /* }}} */
646 
647 /* {{{ add_next_index_object
648  */
add_next_index_object(zval * arg,zval * tmp)649 static inline zval *add_next_index_object(zval *arg, zval *tmp)
650 {
651 	HashTable *symtable;
652 
653 	if (Z_TYPE_P(arg) == IS_OBJECT) {
654 		symtable = Z_OBJPROP_P(arg);
655 	} else {
656 		symtable = Z_ARRVAL_P(arg);
657 	}
658 
659 	return zend_hash_next_index_insert(symtable, tmp);
660 }
661 /* }}} */
662 
663 /* {{{ mail_newfolderobjectlist
664  *
665  * Mail instantiate FOBJECTLIST
666  * Returns: new FOBJECTLIST list
667  * Author: CJH
668  */
mail_newfolderobjectlist(void)669 FOBJECTLIST *mail_newfolderobjectlist(void)
670 {
671 	return (FOBJECTLIST *) memset(fs_get(sizeof(FOBJECTLIST)), 0, sizeof(FOBJECTLIST));
672 }
673 /* }}} */
674 
675 /* {{{ mail_free_foblist
676  *
677  * Mail garbage collect FOBJECTLIST
678  * Accepts: pointer to FOBJECTLIST pointer
679  * Author: CJH
680  */
mail_free_foblist(FOBJECTLIST ** foblist,FOBJECTLIST ** tail)681 void mail_free_foblist(FOBJECTLIST **foblist, FOBJECTLIST **tail)
682 {
683 	FOBJECTLIST *cur, *next;
684 
685 	for (cur=*foblist, next=cur->next; cur; cur=next) {
686 		next = cur->next;
687 
688 		if(cur->text.data)
689 			fs_give((void **)&(cur->text.data));
690 
691 		fs_give((void **)&cur);
692 	}
693 
694 	*tail = NIL;
695 	*foblist = NIL;
696 }
697 /* }}} */
698 
699 /* {{{ mail_newerrorlist
700  *
701  * Mail instantiate ERRORLIST
702  * Returns: new ERRORLIST list
703  * Author: CJH
704  */
mail_newerrorlist(void)705 ERRORLIST *mail_newerrorlist(void)
706 {
707 	return (ERRORLIST *) memset(fs_get(sizeof(ERRORLIST)), 0, sizeof(ERRORLIST));
708 }
709 /* }}} */
710 
711 /* {{{ mail_free_errorlist
712  *
713  * Mail garbage collect FOBJECTLIST
714  * Accepts: pointer to FOBJECTLIST pointer
715  * Author: CJH
716  */
mail_free_errorlist(ERRORLIST ** errlist)717 void mail_free_errorlist(ERRORLIST **errlist)
718 {
719 	if (*errlist) {		/* only free if exists */
720 		if ((*errlist)->text.data) {
721 			fs_give((void **) &(*errlist)->text.data);
722 		}
723 		mail_free_errorlist (&(*errlist)->next);
724 		fs_give((void **) errlist);	/* return string to free storage */
725 	}
726 }
727 /* }}} */
728 
729 /* {{{ mail_newmessagelist
730  *
731  * Mail instantiate MESSAGELIST
732  * Returns: new MESSAGELIST list
733  * Author: CJH
734  */
mail_newmessagelist(void)735 MESSAGELIST *mail_newmessagelist(void)
736 {
737 	return (MESSAGELIST *) memset(fs_get(sizeof(MESSAGELIST)), 0, sizeof(MESSAGELIST));
738 }
739 /* }}} */
740 
741 /* {{{ mail_free_messagelist
742  *
743  * Mail garbage collect MESSAGELIST
744  * Accepts: pointer to MESSAGELIST pointer
745  * Author: CJH
746  */
mail_free_messagelist(MESSAGELIST ** msglist,MESSAGELIST ** tail)747 void mail_free_messagelist(MESSAGELIST **msglist, MESSAGELIST **tail)
748 {
749 	MESSAGELIST *cur, *next;
750 
751 	for (cur = *msglist, next = cur->next; cur; cur = next) {
752 		next = cur->next;
753 		fs_give((void **)&cur);
754 	}
755 
756 	*tail = NIL;
757 	*msglist = NIL;
758 }
759 /* }}} */
760 
761 #if defined(HAVE_IMAP2000) || defined(HAVE_IMAP2001)
762 /* {{{ mail_getquota
763  *
764  * Mail GET_QUOTA callback
765  * Called via the mail_parameter function in c-client:src/c-client/mail.c
766  * Author DRK
767  */
768 
mail_getquota(MAILSTREAM * stream,char * qroot,QUOTALIST * qlist)769 void mail_getquota(MAILSTREAM *stream, char *qroot, QUOTALIST *qlist)
770 {
771 	zval t_map, *return_value;
772 
773 	return_value = *IMAPG(quota_return);
774 
775 /* put parsing code here */
776 	for(; qlist; qlist = qlist->next) {
777 		array_init(&t_map);
778 		if (strncmp(qlist->name, "STORAGE", 7) == 0)
779 		{
780 			/* this is to add backwards compatibility */
781 			add_assoc_long_ex(return_value, "usage", sizeof("usage") - 1, qlist->usage);
782 			add_assoc_long_ex(return_value, "limit", sizeof("limit") - 1, qlist->limit);
783 		}
784 
785 		add_assoc_long_ex(&t_map, "usage", sizeof("usage") - 1, qlist->usage);
786 		add_assoc_long_ex(&t_map, "limit", sizeof("limit") - 1, qlist->limit);
787 		add_assoc_zval_ex(return_value, qlist->name, strlen(qlist->name), &t_map);
788 	}
789 }
790 /* }}} */
791 
792 /* {{{ mail_getquota
793  *
794  * Mail GET_ACL callback
795  * Called via the mail_parameter function in c-client:src/c-client/mail.c
796  */
mail_getacl(MAILSTREAM * stream,char * mailbox,ACLLIST * alist)797 void mail_getacl(MAILSTREAM *stream, char *mailbox, ACLLIST *alist)
798 {
799 
800 	/* walk through the ACLLIST */
801 	for(; alist; alist = alist->next) {
802 		add_assoc_stringl(IMAPG(imap_acl_list), alist->identifier, alist->rights, strlen(alist->rights));
803 	}
804 }
805 /* }}} */
806 #endif
807 
808 /* {{{ PHP_GINIT_FUNCTION
809  */
PHP_GINIT_FUNCTION(imap)810 static PHP_GINIT_FUNCTION(imap)
811 {
812 	imap_globals->imap_user = NIL;
813 	imap_globals->imap_password = NIL;
814 
815 	imap_globals->imap_alertstack = NIL;
816 	imap_globals->imap_errorstack = NIL;
817 
818 	imap_globals->imap_folders = NIL;
819 	imap_globals->imap_folders_tail = NIL;
820 	imap_globals->imap_sfolders = NIL;
821 	imap_globals->imap_sfolders_tail = NIL;
822 	imap_globals->imap_messages = NIL;
823 	imap_globals->imap_messages_tail = NIL;
824 	imap_globals->imap_folder_objects = NIL;
825 	imap_globals->imap_folder_objects_tail = NIL;
826 	imap_globals->imap_sfolder_objects = NIL;
827 	imap_globals->imap_sfolder_objects_tail = NIL;
828 
829 	imap_globals->folderlist_style = FLIST_ARRAY;
830 #if defined(HAVE_IMAP2000) || defined(HAVE_IMAP2001)
831 	imap_globals->quota_return = NIL;
832 	imap_globals->imap_acl_list = NIL;
833 #endif
834 	imap_globals->gets_stream = NIL;
835 }
836 /* }}} */
837 
838 /* {{{ PHP_MINIT_FUNCTION
839  */
PHP_MINIT_FUNCTION(imap)840 PHP_MINIT_FUNCTION(imap)
841 {
842 	unsigned long sa_all =	SA_MESSAGES | SA_RECENT | SA_UNSEEN | SA_UIDNEXT | SA_UIDVALIDITY;
843 
844 	REGISTER_INI_ENTRIES();
845 
846 #ifndef PHP_WIN32
847 	mail_link(&unixdriver);		/* link in the unix driver */
848 	mail_link(&mhdriver);		/* link in the mh driver */
849 	/* mail_link(&mxdriver); */	/* According to c-client docs (internal.txt) this shouldn't be used. */
850 	mail_link(&mmdfdriver);		/* link in the mmdf driver */
851 	mail_link(&newsdriver);		/* link in the news driver */
852 	mail_link(&philedriver);	/* link in the phile driver */
853 #endif
854 	mail_link(&imapdriver);		/* link in the imap driver */
855 	mail_link(&nntpdriver);		/* link in the nntp driver */
856 	mail_link(&pop3driver);		/* link in the pop3 driver */
857 	mail_link(&mbxdriver);		/* link in the mbx driver */
858 	mail_link(&tenexdriver);	/* link in the tenex driver */
859 	mail_link(&mtxdriver);		/* link in the mtx driver */
860 	mail_link(&dummydriver);	/* link in the dummy driver */
861 
862 #ifndef PHP_WIN32
863 	auth_link(&auth_log);		/* link in the log authenticator */
864 	auth_link(&auth_md5);		/* link in the cram-md5 authenticator */
865 #if HAVE_IMAP_KRB && defined(HAVE_IMAP_AUTH_GSS)
866 	auth_link(&auth_gss);		/* link in the gss authenticator */
867 #endif
868 	auth_link(&auth_pla);		/* link in the plain authenticator */
869 #endif
870 
871 #ifdef HAVE_IMAP_SSL
872 	ssl_onceonlyinit ();
873 #endif
874 
875 	/* lets allow NIL */
876 	REGISTER_LONG_CONSTANT("NIL", NIL, CONST_PERSISTENT | CONST_CS);
877 
878 	/* plug in our gets */
879 	mail_parameters(NIL, SET_GETS, (void *) NIL);
880 
881 	/* set default timeout values */
882 	mail_parameters(NIL, SET_OPENTIMEOUT, (void *) FG(default_socket_timeout));
883 	mail_parameters(NIL, SET_READTIMEOUT, (void *) FG(default_socket_timeout));
884 	mail_parameters(NIL, SET_WRITETIMEOUT, (void *) FG(default_socket_timeout));
885 	mail_parameters(NIL, SET_CLOSETIMEOUT, (void *) FG(default_socket_timeout));
886 
887 	/* timeout constants */
888 	REGISTER_LONG_CONSTANT("IMAP_OPENTIMEOUT", 1, CONST_PERSISTENT | CONST_CS);
889 	REGISTER_LONG_CONSTANT("IMAP_READTIMEOUT", 2, CONST_PERSISTENT | CONST_CS);
890 	REGISTER_LONG_CONSTANT("IMAP_WRITETIMEOUT", 3, CONST_PERSISTENT | CONST_CS);
891 	REGISTER_LONG_CONSTANT("IMAP_CLOSETIMEOUT", 4, CONST_PERSISTENT | CONST_CS);
892 
893 	/* Open Options */
894 
895 	REGISTER_LONG_CONSTANT("OP_DEBUG", OP_DEBUG, CONST_PERSISTENT | CONST_CS);
896 	/* debug protocol negotiations */
897 	REGISTER_LONG_CONSTANT("OP_READONLY", OP_READONLY, CONST_PERSISTENT | CONST_CS);
898 	/* read-only open */
899 	REGISTER_LONG_CONSTANT("OP_ANONYMOUS", OP_ANONYMOUS, CONST_PERSISTENT | CONST_CS);
900 	/* anonymous open of newsgroup */
901 	REGISTER_LONG_CONSTANT("OP_SHORTCACHE", OP_SHORTCACHE, CONST_PERSISTENT | CONST_CS);
902 	/* short (elt-only) caching */
903 	REGISTER_LONG_CONSTANT("OP_SILENT", OP_SILENT, CONST_PERSISTENT | CONST_CS);
904 	/* don't pass up events (internal use) */
905 	REGISTER_LONG_CONSTANT("OP_PROTOTYPE", OP_PROTOTYPE, CONST_PERSISTENT | CONST_CS);
906 	/* return driver prototype */
907 	REGISTER_LONG_CONSTANT("OP_HALFOPEN", OP_HALFOPEN, CONST_PERSISTENT | CONST_CS);
908 	/* half-open (IMAP connect but no select) */
909 	REGISTER_LONG_CONSTANT("OP_EXPUNGE", OP_EXPUNGE, CONST_PERSISTENT | CONST_CS);
910 	/* silently expunge recycle stream */
911 	REGISTER_LONG_CONSTANT("OP_SECURE", OP_SECURE, CONST_PERSISTENT | CONST_CS);
912 	/* don't do non-secure authentication */
913 
914 	/*
915 	PHP re-assigns CL_EXPUNGE a custom value that can be used as part of the imap_open() bitfield
916 	because it seems like a good idea to be able to indicate that the mailbox should be
917 	automatically expunged during imap_open in case the script get interrupted and it doesn't get
918 	to the imap_close() where this option is normally placed.  If the c-client library adds other
919 	options and the value for this one conflicts, simply make PHP_EXPUNGE higher at the top of
920 	this file
921 	*/
922 	REGISTER_LONG_CONSTANT("CL_EXPUNGE", PHP_EXPUNGE, CONST_PERSISTENT | CONST_CS);
923 	/* expunge silently */
924 
925 	/* Fetch options */
926 
927 	REGISTER_LONG_CONSTANT("FT_UID", FT_UID, CONST_PERSISTENT | CONST_CS);
928 	/* argument is a UID */
929 	REGISTER_LONG_CONSTANT("FT_PEEK", FT_PEEK, CONST_PERSISTENT | CONST_CS);
930 	/* peek at data */
931 	REGISTER_LONG_CONSTANT("FT_NOT", FT_NOT, CONST_PERSISTENT | CONST_CS);
932 	/* NOT flag for header lines fetch */
933 	REGISTER_LONG_CONSTANT("FT_INTERNAL", FT_INTERNAL, CONST_PERSISTENT | CONST_CS);
934 	/* text can be internal strings */
935 	REGISTER_LONG_CONSTANT("FT_PREFETCHTEXT", FT_PREFETCHTEXT, CONST_PERSISTENT | CONST_CS);
936 	/* IMAP prefetch text when fetching header */
937 
938 	/* Flagging options */
939 
940 	REGISTER_LONG_CONSTANT("ST_UID", ST_UID, CONST_PERSISTENT | CONST_CS);
941 	/* argument is a UID sequence */
942 	REGISTER_LONG_CONSTANT("ST_SILENT", ST_SILENT, CONST_PERSISTENT | CONST_CS);
943 	/* don't return results */
944 	REGISTER_LONG_CONSTANT("ST_SET", ST_SET, CONST_PERSISTENT | CONST_CS);
945 	/* set vs. clear */
946 
947 	/* Copy options */
948 
949 	REGISTER_LONG_CONSTANT("CP_UID", CP_UID, CONST_PERSISTENT | CONST_CS);
950 	/* argument is a UID sequence */
951 	REGISTER_LONG_CONSTANT("CP_MOVE", CP_MOVE, CONST_PERSISTENT | CONST_CS);
952 	/* delete from source after copying */
953 
954 	/* Search/sort options */
955 
956 	REGISTER_LONG_CONSTANT("SE_UID", SE_UID, CONST_PERSISTENT | CONST_CS);
957 	/* return UID */
958 	REGISTER_LONG_CONSTANT("SE_FREE", SE_FREE, CONST_PERSISTENT | CONST_CS);
959 	/* free search program after finished */
960 	REGISTER_LONG_CONSTANT("SE_NOPREFETCH", SE_NOPREFETCH, CONST_PERSISTENT | CONST_CS);
961 	/* no search prefetching */
962 	REGISTER_LONG_CONSTANT("SO_FREE", SO_FREE, CONST_PERSISTENT | CONST_CS);
963 	/* free sort program after finished */
964 	REGISTER_LONG_CONSTANT("SO_NOSERVER", SO_NOSERVER, CONST_PERSISTENT | CONST_CS);
965 	/* don't do server-based sort */
966 
967 	/* Status options */
968 
969 	REGISTER_LONG_CONSTANT("SA_MESSAGES", SA_MESSAGES , CONST_PERSISTENT | CONST_CS);
970 	/* number of messages */
971 	REGISTER_LONG_CONSTANT("SA_RECENT", SA_RECENT, CONST_PERSISTENT | CONST_CS);
972 	/* number of recent messages */
973 	REGISTER_LONG_CONSTANT("SA_UNSEEN", SA_UNSEEN , CONST_PERSISTENT | CONST_CS);
974 	/* number of unseen messages */
975 	REGISTER_LONG_CONSTANT("SA_UIDNEXT", SA_UIDNEXT, CONST_PERSISTENT | CONST_CS);
976 	/* next UID to be assigned */
977 	REGISTER_LONG_CONSTANT("SA_UIDVALIDITY", SA_UIDVALIDITY , CONST_PERSISTENT | CONST_CS);
978 	/* UID validity value */
979 	REGISTER_LONG_CONSTANT("SA_ALL", sa_all, CONST_PERSISTENT | CONST_CS);
980 	/* get all status information */
981 
982 	/* Bits for mm_list() and mm_lsub() */
983 
984 	REGISTER_LONG_CONSTANT("LATT_NOINFERIORS", LATT_NOINFERIORS , CONST_PERSISTENT | CONST_CS);
985 	REGISTER_LONG_CONSTANT("LATT_NOSELECT", LATT_NOSELECT, CONST_PERSISTENT | CONST_CS);
986 	REGISTER_LONG_CONSTANT("LATT_MARKED", LATT_MARKED, CONST_PERSISTENT | CONST_CS);
987 	REGISTER_LONG_CONSTANT("LATT_UNMARKED", LATT_UNMARKED , CONST_PERSISTENT | CONST_CS);
988 
989 #ifdef LATT_REFERRAL
990 	REGISTER_LONG_CONSTANT("LATT_REFERRAL", LATT_REFERRAL, CONST_PERSISTENT | CONST_CS);
991 #endif
992 
993 #ifdef LATT_HASCHILDREN
994 	REGISTER_LONG_CONSTANT("LATT_HASCHILDREN", LATT_HASCHILDREN, CONST_PERSISTENT | CONST_CS);
995 #endif
996 
997 #ifdef LATT_HASNOCHILDREN
998 	REGISTER_LONG_CONSTANT("LATT_HASNOCHILDREN", LATT_HASNOCHILDREN, CONST_PERSISTENT | CONST_CS);
999 #endif
1000 
1001 	/* Sort functions */
1002 
1003 	REGISTER_LONG_CONSTANT("SORTDATE", SORTDATE , CONST_PERSISTENT | CONST_CS);
1004 	/* date */
1005 	REGISTER_LONG_CONSTANT("SORTARRIVAL", SORTARRIVAL , CONST_PERSISTENT | CONST_CS);
1006 	/* arrival date */
1007 	REGISTER_LONG_CONSTANT("SORTFROM", SORTFROM , CONST_PERSISTENT | CONST_CS);
1008 	/* from */
1009 	REGISTER_LONG_CONSTANT("SORTSUBJECT", SORTSUBJECT , CONST_PERSISTENT | CONST_CS);
1010 	/* subject */
1011 	REGISTER_LONG_CONSTANT("SORTTO", SORTTO , CONST_PERSISTENT | CONST_CS);
1012 	/* to */
1013 	REGISTER_LONG_CONSTANT("SORTCC", SORTCC , CONST_PERSISTENT | CONST_CS);
1014 	/* cc */
1015 	REGISTER_LONG_CONSTANT("SORTSIZE", SORTSIZE , CONST_PERSISTENT | CONST_CS);
1016 	/* size */
1017 
1018 	REGISTER_LONG_CONSTANT("TYPETEXT", TYPETEXT , CONST_PERSISTENT | CONST_CS);
1019 	REGISTER_LONG_CONSTANT("TYPEMULTIPART", TYPEMULTIPART , CONST_PERSISTENT | CONST_CS);
1020 	REGISTER_LONG_CONSTANT("TYPEMESSAGE", TYPEMESSAGE , CONST_PERSISTENT | CONST_CS);
1021 	REGISTER_LONG_CONSTANT("TYPEAPPLICATION", TYPEAPPLICATION , CONST_PERSISTENT | CONST_CS);
1022 	REGISTER_LONG_CONSTANT("TYPEAUDIO", TYPEAUDIO , CONST_PERSISTENT | CONST_CS);
1023 	REGISTER_LONG_CONSTANT("TYPEIMAGE", TYPEIMAGE , CONST_PERSISTENT | CONST_CS);
1024 	REGISTER_LONG_CONSTANT("TYPEVIDEO", TYPEVIDEO , CONST_PERSISTENT | CONST_CS);
1025 	REGISTER_LONG_CONSTANT("TYPEMODEL", TYPEMODEL , CONST_PERSISTENT | CONST_CS);
1026 	REGISTER_LONG_CONSTANT("TYPEOTHER", TYPEOTHER , CONST_PERSISTENT | CONST_CS);
1027 	/*
1028 	TYPETEXT                unformatted text
1029 	TYPEMULTIPART           multiple part
1030 	TYPEMESSAGE             encapsulated message
1031 	TYPEAPPLICATION         application data
1032 	TYPEAUDIO               audio
1033 	TYPEIMAGE               static image (GIF, JPEG, etc.)
1034 	TYPEVIDEO               video
1035 	TYPEMODEL               model
1036 	TYPEOTHER               unknown
1037 	*/
1038 
1039 	REGISTER_LONG_CONSTANT("ENC7BIT", ENC7BIT , CONST_PERSISTENT | CONST_CS);
1040 	REGISTER_LONG_CONSTANT("ENC8BIT", ENC8BIT , CONST_PERSISTENT | CONST_CS);
1041 	REGISTER_LONG_CONSTANT("ENCBINARY", ENCBINARY , CONST_PERSISTENT | CONST_CS);
1042 	REGISTER_LONG_CONSTANT("ENCBASE64", ENCBASE64, CONST_PERSISTENT | CONST_CS);
1043 	REGISTER_LONG_CONSTANT("ENCQUOTEDPRINTABLE", ENCQUOTEDPRINTABLE , CONST_PERSISTENT | CONST_CS);
1044 	REGISTER_LONG_CONSTANT("ENCOTHER", ENCOTHER , CONST_PERSISTENT | CONST_CS);
1045 	/*
1046 	ENC7BIT                 7 bit SMTP semantic data
1047 	ENC8BIT                 8 bit SMTP semantic data
1048 	ENCBINARY               8 bit binary data
1049 	ENCBASE64               base-64 encoded data
1050 	ENCQUOTEDPRINTABLE      human-readable 8-as-7 bit data
1051 	ENCOTHER                unknown
1052 	*/
1053 
1054 	REGISTER_LONG_CONSTANT("IMAP_GC_ELT", GC_ELT , CONST_PERSISTENT | CONST_CS);
1055 	REGISTER_LONG_CONSTANT("IMAP_GC_ENV", GC_ENV , CONST_PERSISTENT | CONST_CS);
1056 	REGISTER_LONG_CONSTANT("IMAP_GC_TEXTS", GC_TEXTS , CONST_PERSISTENT | CONST_CS);
1057 	/*
1058 	GC_ELT                 message cache elements
1059 	GC_ENV                 ENVELOPEs and BODYs
1060 	GC_TEXTS               texts
1061 	*/
1062 
1063 	if (!IMAPG(enable_rsh)) {
1064 		/* disable SSH and RSH, see https://bugs.php.net/bug.php?id=77153 */
1065 		mail_parameters (NIL, SET_RSHTIMEOUT, 0);
1066 		mail_parameters (NIL, SET_SSHTIMEOUT, 0);
1067 	}
1068 
1069 	le_imap = zend_register_list_destructors_ex(mail_close_it, NULL, "imap", module_number);
1070 	return SUCCESS;
1071 }
1072 /* }}} */
1073 
1074 /* {{{ PHP_RINIT_FUNCTION
1075  */
PHP_RINIT_FUNCTION(imap)1076 PHP_RINIT_FUNCTION(imap)
1077 {
1078 	IMAPG(imap_errorstack) = NIL;
1079 	IMAPG(imap_alertstack) = NIL;
1080 	IMAPG(gets_stream) = NIL;
1081 	return SUCCESS;
1082 }
1083 /* }}} */
1084 
1085 /* {{{ PHP_RSHUTDOWN_FUNCTION
1086  */
PHP_RSHUTDOWN_FUNCTION(imap)1087 PHP_RSHUTDOWN_FUNCTION(imap)
1088 {
1089 	ERRORLIST *ecur = NIL;
1090 	STRINGLIST *acur = NIL;
1091 
1092 	if (IMAPG(imap_errorstack) != NIL) {
1093 		/* output any remaining errors at their original error level */
1094 		if (EG(error_reporting) & E_NOTICE) {
1095 			ecur = IMAPG(imap_errorstack);
1096 			while (ecur != NIL) {
1097 				php_error_docref(NULL, E_NOTICE, "%s (errflg=%ld)", ecur->LTEXT, ecur->errflg);
1098 				ecur = ecur->next;
1099 			}
1100 		}
1101 		mail_free_errorlist(&IMAPG(imap_errorstack));
1102 	}
1103 
1104 	if (IMAPG(imap_alertstack) != NIL) {
1105 		/* output any remaining alerts at E_NOTICE level */
1106 		if (EG(error_reporting) & E_NOTICE) {
1107 			acur = IMAPG(imap_alertstack);
1108 			while (acur != NIL) {
1109 				php_error_docref(NULL, E_NOTICE, "%s", acur->LTEXT);
1110 				acur = acur->next;
1111 			}
1112 		}
1113 		mail_free_stringlist(&IMAPG(imap_alertstack));
1114 		IMAPG(imap_alertstack) = NIL;
1115 	}
1116 	return SUCCESS;
1117 }
1118 /* }}} */
1119 
1120 #if !defined(CCLIENTVERSION)
1121 #if HAVE_IMAP2007e
1122 #define CCLIENTVERSION "2007e"
1123 #elif HAVE_IMAP2007d
1124 #define CCLIENTVERSION "2007d"
1125 #elif HAVE_IMAP2007b
1126 #define CCLIENTVERSION "2007b"
1127 #elif HAVE_IMAP2007a
1128 #define CCLIENTVERSION "2007a"
1129 #elif HAVE_IMAP2004
1130 #define CCLIENTVERSION "2004"
1131 #elif HAVE_IMAP2001
1132 #define CCLIENTVERSION "2001"
1133 #elif HAVE_IMAP2000
1134 #define CCLIENTVERSION "2000"
1135 #elif defined(IMAP41)
1136 #define CCLIENTVERSION "4.1"
1137 #else
1138 #define CCLIENTVERSION "4.0"
1139 #endif
1140 #endif
1141 
1142 /* {{{ PHP_MINFO_FUNCTION
1143  */
PHP_MINFO_FUNCTION(imap)1144 PHP_MINFO_FUNCTION(imap)
1145 {
1146 	php_info_print_table_start();
1147 	php_info_print_table_row(2, "IMAP c-Client Version", CCLIENTVERSION);
1148 #if HAVE_IMAP_SSL
1149 	php_info_print_table_row(2, "SSL Support", "enabled");
1150 #endif
1151 #if HAVE_IMAP_KRB && HAVE_IMAP_AUTH_GSS
1152 	php_info_print_table_row(2, "Kerberos Support", "enabled");
1153 #endif
1154 	php_info_print_table_end();
1155 
1156 	DISPLAY_INI_ENTRIES();
1157 }
1158 /* }}} */
1159 
1160 /* {{{ imap_do_open
1161  */
php_imap_do_open(INTERNAL_FUNCTION_PARAMETERS,int persistent)1162 static void php_imap_do_open(INTERNAL_FUNCTION_PARAMETERS, int persistent)
1163 {
1164 	zend_string *mailbox, *user, *passwd;
1165 	zend_long retries = 0, flags = NIL, cl_flags = NIL;
1166 	MAILSTREAM *imap_stream;
1167 	pils *imap_le_struct;
1168 	zval *params = NULL;
1169 	int argc = ZEND_NUM_ARGS();
1170 
1171 	if (zend_parse_parameters(argc, "PSS|lla", &mailbox, &user,
1172 		&passwd, &flags, &retries, &params) == FAILURE) {
1173 		return;
1174 	}
1175 
1176 	if (argc >= 4) {
1177 		if (flags & PHP_EXPUNGE) {
1178 			cl_flags = CL_EXPUNGE;
1179 			flags ^= PHP_EXPUNGE;
1180 		}
1181 		if (flags & OP_PROTOTYPE) {
1182 			cl_flags |= OP_PROTOTYPE;
1183 		}
1184 	}
1185 
1186 	if (params) {
1187 		zval *disabled_auth_method;
1188 
1189 		if ((disabled_auth_method = zend_hash_str_find(Z_ARRVAL_P(params), "DISABLE_AUTHENTICATOR", sizeof("DISABLE_AUTHENTICATOR") - 1)) != NULL) {
1190 			switch (Z_TYPE_P(disabled_auth_method)) {
1191 				case IS_STRING:
1192 					if (Z_STRLEN_P(disabled_auth_method) > 1) {
1193 						mail_parameters(NIL, DISABLE_AUTHENTICATOR, (void *)Z_STRVAL_P(disabled_auth_method));
1194 					}
1195 					break;
1196 				case IS_ARRAY:
1197 					{
1198 						zval *z_auth_method;
1199 						int i;
1200 						int nelems = zend_hash_num_elements(Z_ARRVAL_P(disabled_auth_method));
1201 
1202 						if (nelems == 0 ) {
1203 							break;
1204 						}
1205 						for (i = 0; i < nelems; i++) {
1206 							if ((z_auth_method = zend_hash_index_find(Z_ARRVAL_P(disabled_auth_method), i)) != NULL) {
1207 								if (Z_TYPE_P(z_auth_method) == IS_STRING) {
1208 									if (Z_STRLEN_P(z_auth_method) > 1) {
1209 										mail_parameters(NIL, DISABLE_AUTHENTICATOR, (void *)Z_STRVAL_P(z_auth_method));
1210 									}
1211 								} else {
1212 									php_error_docref(NULL, E_WARNING, "Invalid argument, expect string or array of strings");
1213 								}
1214 							}
1215 						}
1216 					}
1217 					break;
1218 				case IS_LONG:
1219 				default:
1220 					php_error_docref(NULL, E_WARNING, "Invalid argument, expect string or array of strings");
1221 					break;
1222 			}
1223 		}
1224 	}
1225 
1226 	if (IMAPG(imap_user)) {
1227 		efree(IMAPG(imap_user));
1228 		IMAPG(imap_user) = 0;
1229 	}
1230 
1231 	if (IMAPG(imap_password)) {
1232 		efree(IMAPG(imap_password));
1233 		IMAPG(imap_password) = 0;
1234 	}
1235 
1236 	/* local filename, need to perform open_basedir check */
1237 	if (ZSTR_VAL(mailbox)[0] != '{' && php_check_open_basedir(ZSTR_VAL(mailbox))) {
1238 		RETURN_FALSE;
1239 	}
1240 
1241 	IMAPG(imap_user)     = estrndup(ZSTR_VAL(user), ZSTR_LEN(user));
1242 	IMAPG(imap_password) = estrndup(ZSTR_VAL(passwd), ZSTR_LEN(passwd));
1243 
1244 #ifdef SET_MAXLOGINTRIALS
1245 	if (argc >= 5) {
1246 		if (retries < 0) {
1247 			php_error_docref(NULL, E_WARNING ,"Retries must be greater or equal to 0");
1248 		} else {
1249 			mail_parameters(NIL, SET_MAXLOGINTRIALS, (void *) retries);
1250 		}
1251 	}
1252 #endif
1253 
1254 	imap_stream = mail_open(NIL, ZSTR_VAL(mailbox), flags);
1255 
1256 	if (imap_stream == NIL) {
1257 		php_error_docref(NULL, E_WARNING, "Couldn't open stream %s", ZSTR_VAL(mailbox));
1258 		efree(IMAPG(imap_user)); IMAPG(imap_user) = 0;
1259 		efree(IMAPG(imap_password)); IMAPG(imap_password) = 0;
1260 		RETURN_FALSE;
1261 	}
1262 
1263 	imap_le_struct = emalloc(sizeof(pils));
1264 	imap_le_struct->imap_stream = imap_stream;
1265 	imap_le_struct->flags = cl_flags;
1266 
1267 	RETURN_RES(zend_register_resource(imap_le_struct, le_imap));
1268 }
1269 /* }}} */
1270 
1271 /* {{{ proto resource imap_open(string mailbox, string user, string password [, int options [, int n_retries]])
1272    Open an IMAP stream to a mailbox */
PHP_FUNCTION(imap_open)1273 PHP_FUNCTION(imap_open)
1274 {
1275 	php_imap_do_open(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1276 }
1277 /* }}} */
1278 
1279 /* {{{ proto bool imap_reopen(resource stream_id, string mailbox [, int options [, int n_retries]])
1280    Reopen an IMAP stream to a new mailbox */
PHP_FUNCTION(imap_reopen)1281 PHP_FUNCTION(imap_reopen)
1282 {
1283 	zval *streamind;
1284 	zend_string *mailbox;
1285 	zend_long options = 0, retries = 0;
1286 	pils *imap_le_struct;
1287 	long flags=NIL;
1288 	long cl_flags=NIL;
1289 
1290 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS|ll", &streamind, &mailbox, &options, &retries) == FAILURE) {
1291 		return;
1292 	}
1293 
1294 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1295 		RETURN_FALSE;
1296 	}
1297 
1298 	if (options) {
1299 		flags = options;
1300 		if (flags & PHP_EXPUNGE) {
1301 			cl_flags = CL_EXPUNGE;
1302 			flags ^= PHP_EXPUNGE;
1303 		}
1304 		imap_le_struct->flags = cl_flags;
1305 	}
1306 #ifdef SET_MAXLOGINTRIALS
1307 	if (retries) {
1308 		mail_parameters(NIL, SET_MAXLOGINTRIALS, (void *) retries);
1309 	}
1310 #endif
1311 	/* local filename, need to perform open_basedir check */
1312 	if (ZSTR_VAL(mailbox)[0] != '{' && php_check_open_basedir(ZSTR_VAL(mailbox))) {
1313 		RETURN_FALSE;
1314 	}
1315 
1316 	imap_le_struct->imap_stream = mail_open(imap_le_struct->imap_stream, ZSTR_VAL(mailbox), flags);
1317 	if (imap_le_struct->imap_stream == NIL) {
1318 		zend_list_delete(Z_RES_P(streamind));
1319 		php_error_docref(NULL, E_WARNING, "Couldn't re-open stream");
1320 		RETURN_FALSE;
1321 	}
1322 	RETURN_TRUE;
1323 }
1324 /* }}} */
1325 
1326 /* {{{ proto bool imap_append(resource stream_id, string folder, string message [, string options [, string internal_date]])
1327    Append a new message to a specified mailbox */
PHP_FUNCTION(imap_append)1328 PHP_FUNCTION(imap_append)
1329 {
1330 	zval *streamind;
1331 	zend_string *folder, *message, *internal_date = NULL, *flags = NULL;
1332 	pils *imap_le_struct;
1333 	STRING st;
1334 	zend_string* regex;
1335 	pcre_cache_entry *pce;				/* Compiled regex */
1336 	zval *subpats = NULL;				/* Parts (not used) */
1337 	int global = 0;
1338 
1339 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS|SS", &streamind, &folder, &message, &flags, &internal_date) == FAILURE) {
1340 		return;
1341 	}
1342 
1343 	regex  = zend_string_init("/[0-3][0-9]-((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))-[0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] [+-][0-9]{4}/", sizeof("/[0-3][0-9]-((Jan)|(Feb)|(Mar)|(Apr)|(May)|(Jun)|(Jul)|(Aug)|(Sep)|(Oct)|(Nov)|(Dec))-[0-9]{4} [0-2][0-9]:[0-5][0-9]:[0-5][0-9] [+-][0-9]{4}/") - 1, 0);
1344 
1345 	if (internal_date) {
1346 		/* Make sure the given internal_date string matches the RFC specifiedformat */
1347 		if ((pce = pcre_get_compiled_regex_cache(regex))== NULL) {
1348 			zend_string_free(regex);
1349 			RETURN_FALSE;
1350 		}
1351 
1352 		zend_string_free(regex);
1353 		php_pcre_match_impl(pce, ZSTR_VAL(internal_date), ZSTR_LEN(internal_date), return_value, subpats, global,
1354 			0, Z_L(0), Z_L(0));
1355 
1356 		if (!Z_LVAL_P(return_value)) {
1357 			php_error_docref(NULL, E_WARNING, "internal date not correctly formatted");
1358 			internal_date = NULL;
1359 		}
1360 	}
1361 
1362 	zend_string_free(regex);
1363 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1364 		RETURN_FALSE;
1365 	}
1366 
1367 	INIT (&st, mail_string, (void *) ZSTR_VAL(message), ZSTR_LEN(message));
1368 
1369 	if (mail_append_full(imap_le_struct->imap_stream, ZSTR_VAL(folder), (flags ? ZSTR_VAL(flags) : NIL), (internal_date ? ZSTR_VAL(internal_date) : NIL), &st)) {
1370 		RETURN_TRUE;
1371 	} else {
1372 		RETURN_FALSE;
1373 	}
1374 }
1375 /* }}} */
1376 
1377 /* {{{ proto int imap_num_msg(resource stream_id)
1378    Gives the number of messages in the current mailbox */
PHP_FUNCTION(imap_num_msg)1379 PHP_FUNCTION(imap_num_msg)
1380 {
1381 	zval *streamind;
1382 	pils *imap_le_struct;
1383 
1384 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1385 		return;
1386 	}
1387 
1388 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1389 		RETURN_FALSE;
1390 	}
1391 
1392 	RETURN_LONG(imap_le_struct->imap_stream->nmsgs);
1393 }
1394 /* }}} */
1395 
1396 /* {{{ proto bool imap_ping(resource stream_id)
1397    Check if the IMAP stream is still active */
PHP_FUNCTION(imap_ping)1398 PHP_FUNCTION(imap_ping)
1399 {
1400 	zval *streamind;
1401 	pils *imap_le_struct;
1402 
1403 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1404 		return;
1405 	}
1406 
1407 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1408 		RETURN_FALSE;
1409 	}
1410 
1411 	RETURN_BOOL(mail_ping(imap_le_struct->imap_stream));
1412 }
1413 /* }}} */
1414 
1415 /* {{{ proto int imap_num_recent(resource stream_id)
1416    Gives the number of recent messages in current mailbox */
PHP_FUNCTION(imap_num_recent)1417 PHP_FUNCTION(imap_num_recent)
1418 {
1419 	zval *streamind;
1420 	pils *imap_le_struct;
1421 
1422 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1423 		return;
1424 	}
1425 
1426 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1427 		RETURN_FALSE;
1428 	}
1429 
1430 	RETURN_LONG(imap_le_struct->imap_stream->recent);
1431 }
1432 /* }}} */
1433 
1434 #if defined(HAVE_IMAP2000) || defined(HAVE_IMAP2001)
1435 /* {{{ proto array imap_get_quota(resource stream_id, string qroot)
1436 	Returns the quota set to the mailbox account qroot */
PHP_FUNCTION(imap_get_quota)1437 PHP_FUNCTION(imap_get_quota)
1438 {
1439 	zval *streamind;
1440 	zend_string *qroot;
1441 	pils *imap_le_struct;
1442 
1443 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &qroot) == FAILURE) {
1444 		return;
1445 	}
1446 
1447 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1448 		RETURN_FALSE;
1449 	}
1450 
1451 	array_init(return_value);
1452 	IMAPG(quota_return) = &return_value;
1453 
1454 	/* set the callback for the GET_QUOTA function */
1455 	mail_parameters(NIL, SET_QUOTA, (void *) mail_getquota);
1456 	if (!imap_getquota(imap_le_struct->imap_stream, ZSTR_VAL(qroot))) {
1457 		php_error_docref(NULL, E_WARNING, "c-client imap_getquota failed");
1458 		zval_dtor(return_value);
1459 		RETURN_FALSE;
1460 	}
1461 }
1462 /* }}} */
1463 
1464 /* {{{ proto array imap_get_quotaroot(resource stream_id, string mbox)
1465 	Returns the quota set to the mailbox account mbox */
PHP_FUNCTION(imap_get_quotaroot)1466 PHP_FUNCTION(imap_get_quotaroot)
1467 {
1468 	zval *streamind;
1469 	zend_string *mbox;
1470 	pils *imap_le_struct;
1471 
1472 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &mbox) == FAILURE) {
1473 		return;
1474 	}
1475 
1476 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1477 		RETURN_FALSE;
1478 	}
1479 
1480 	array_init(return_value);
1481 	IMAPG(quota_return) = &return_value;
1482 
1483 	/* set the callback for the GET_QUOTAROOT function */
1484 	mail_parameters(NIL, SET_QUOTA, (void *) mail_getquota);
1485 	if (!imap_getquotaroot(imap_le_struct->imap_stream, ZSTR_VAL(mbox))) {
1486 		php_error_docref(NULL, E_WARNING, "c-client imap_getquotaroot failed");
1487 		zval_dtor(return_value);
1488 		RETURN_FALSE;
1489 	}
1490 }
1491 /* }}} */
1492 
1493 /* {{{ proto bool imap_set_quota(resource stream_id, string qroot, int mailbox_size)
1494    Will set the quota for qroot mailbox */
PHP_FUNCTION(imap_set_quota)1495 PHP_FUNCTION(imap_set_quota)
1496 {
1497 	zval *streamind;
1498 	zend_string *qroot;
1499 	zend_long mailbox_size;
1500 	pils *imap_le_struct;
1501 	STRINGLIST	limits;
1502 
1503 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSl", &streamind, &qroot, &mailbox_size) == FAILURE) {
1504 		return;
1505 	}
1506 
1507 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1508 		RETURN_FALSE;
1509 	}
1510 
1511 	limits.text.data = (unsigned char*)"STORAGE";
1512 	limits.text.size = mailbox_size;
1513 	limits.next = NIL;
1514 
1515 	RETURN_BOOL(imap_setquota(imap_le_struct->imap_stream, ZSTR_VAL(qroot), &limits));
1516 }
1517 /* }}} */
1518 
1519 /* {{{ proto bool imap_setacl(resource stream_id, string mailbox, string id, string rights)
1520 	Sets the ACL for a given mailbox */
PHP_FUNCTION(imap_setacl)1521 PHP_FUNCTION(imap_setacl)
1522 {
1523 	zval *streamind;
1524 	zend_string *mailbox, *id, *rights;
1525 	pils *imap_le_struct;
1526 
1527 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSSS", &streamind, &mailbox, &id, &rights) == FAILURE) {
1528 		return;
1529 	}
1530 
1531 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1532 		RETURN_FALSE;
1533 	}
1534 
1535 	RETURN_BOOL(imap_setacl(imap_le_struct->imap_stream, ZSTR_VAL(mailbox), ZSTR_VAL(id), ZSTR_VAL(rights)));
1536 }
1537 /* }}} */
1538 
1539 /* {{{ proto array imap_getacl(resource stream_id, string mailbox)
1540 	Gets the ACL for a given mailbox */
PHP_FUNCTION(imap_getacl)1541 PHP_FUNCTION(imap_getacl)
1542 {
1543 	zval *streamind;
1544 	zend_string *mailbox;
1545 	pils *imap_le_struct;
1546 
1547 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &mailbox) == FAILURE) {
1548 		return;
1549 	}
1550 
1551 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1552 		RETURN_FALSE;
1553 	}
1554 
1555 	/* initializing the special array for the return values */
1556 	array_init(return_value);
1557 
1558 	IMAPG(imap_acl_list) = return_value;
1559 
1560 	/* set the callback for the GET_ACL function */
1561 	mail_parameters(NIL, SET_ACL, (void *) mail_getacl);
1562 	if (!imap_getacl(imap_le_struct->imap_stream, ZSTR_VAL(mailbox))) {
1563 		php_error(E_WARNING, "c-client imap_getacl failed");
1564 		zval_dtor(return_value);
1565 		RETURN_FALSE;
1566 	}
1567 
1568 	IMAPG(imap_acl_list) = NIL;
1569 }
1570 /* }}} */
1571 #endif /* HAVE_IMAP2000 || HAVE_IMAP2001 */
1572 
1573 /* {{{ proto bool imap_expunge(resource stream_id)
1574    Permanently delete all messages marked for deletion */
PHP_FUNCTION(imap_expunge)1575 PHP_FUNCTION(imap_expunge)
1576 {
1577 	zval *streamind;
1578 	pils *imap_le_struct;
1579 
1580 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1581 		return;
1582 	}
1583 
1584 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1585 		RETURN_FALSE;
1586 	}
1587 
1588 	mail_expunge (imap_le_struct->imap_stream);
1589 
1590 	RETURN_TRUE;
1591 }
1592 /* }}} */
1593 
1594 /* {{{ proto bool imap_gc(resource stream_id, int flags)
1595    This function garbage collects (purges) the cache of entries of a specific type. */
PHP_FUNCTION(imap_gc)1596 PHP_FUNCTION(imap_gc)
1597 {
1598 	zval *streamind;
1599 	pils *imap_le_struct;
1600 	zend_long flags;
1601 
1602 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &streamind, &flags) == FAILURE) {
1603 		return;
1604 	}
1605 
1606 	if (flags && ((flags & ~(GC_TEXTS | GC_ELT | GC_ENV)) != 0)) {
1607 		php_error_docref(NULL, E_WARNING, "invalid value for the flags parameter");
1608 		RETURN_FALSE;
1609 	}
1610 
1611 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1612 		RETURN_FALSE;
1613 	}
1614 
1615 	mail_gc(imap_le_struct->imap_stream, flags);
1616 
1617 	RETURN_TRUE;
1618 }
1619 /* }}} */
1620 
1621 /* {{{ proto bool imap_close(resource stream_id [, int options])
1622    Close an IMAP stream */
PHP_FUNCTION(imap_close)1623 PHP_FUNCTION(imap_close)
1624 {
1625 	zval *streamind;
1626 	pils *imap_le_struct=NULL;
1627 	zend_long options = 0, flags = NIL;
1628 	int argc = ZEND_NUM_ARGS();
1629 
1630 	if (zend_parse_parameters(argc, "r|l", &streamind, &options) == FAILURE) {
1631 		return;
1632 	}
1633 
1634 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1635 		RETURN_FALSE;
1636 	}
1637 
1638 	if (argc == 2) {
1639 		flags = options;
1640 
1641 		/* Check that flags is exactly equal to PHP_EXPUNGE or zero */
1642 		if (flags && ((flags & ~PHP_EXPUNGE) != 0)) {
1643 			php_error_docref(NULL, E_WARNING, "invalid value for the flags parameter");
1644 			RETURN_FALSE;
1645 		}
1646 
1647 		/* Do the translation from PHP's internal PHP_EXPUNGE define to c-client's CL_EXPUNGE */
1648 		if (flags & PHP_EXPUNGE) {
1649 			flags ^= PHP_EXPUNGE;
1650 			flags |= CL_EXPUNGE;
1651 		}
1652 		imap_le_struct->flags = flags;
1653 	}
1654 
1655 	zend_list_close(Z_RES_P(streamind));
1656 
1657 	RETURN_TRUE;
1658 }
1659 /* }}} */
1660 
1661 /* {{{ proto array imap_headers(resource stream_id)
1662    Returns headers for all messages in a mailbox */
PHP_FUNCTION(imap_headers)1663 PHP_FUNCTION(imap_headers)
1664 {
1665 	zval *streamind;
1666 	pils *imap_le_struct;
1667 	unsigned long i;
1668 	char *t;
1669 	unsigned int msgno;
1670 	char tmp[MAILTMPLEN];
1671 
1672 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1673 		return;
1674 	}
1675 
1676 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1677 		RETURN_FALSE;
1678 	}
1679 
1680 	/* Initialize return array */
1681 	array_init(return_value);
1682 
1683 	for (msgno = 1; msgno <= imap_le_struct->imap_stream->nmsgs; msgno++) {
1684 		MESSAGECACHE * cache = mail_elt (imap_le_struct->imap_stream, msgno);
1685 		mail_fetchstructure(imap_le_struct->imap_stream, msgno, NIL);
1686 		tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
1687 		tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
1688 		tmp[2] = cache->flagged ? 'F' : ' ';
1689 		tmp[3] = cache->answered ? 'A' : ' ';
1690 		tmp[4] = cache->deleted ? 'D' : ' ';
1691 		tmp[5] = cache->draft ? 'X' : ' ';
1692 		snprintf(tmp + 6, sizeof(tmp) - 6, "%4ld) ", cache->msgno);
1693 		mail_date(tmp+11, cache);
1694 		tmp[22] = ' ';
1695 		tmp[23] = '\0';
1696 		mail_fetchfrom(tmp+23, imap_le_struct->imap_stream, msgno, (long)20);
1697 		strcat(tmp, " ");
1698 		if ((i = cache->user_flags)) {
1699 			strcat(tmp, "{");
1700 			while (i) {
1701 				strlcat(tmp, imap_le_struct->imap_stream->user_flags[find_rightmost_bit (&i)], sizeof(tmp));
1702 				if (i) strlcat(tmp, " ", sizeof(tmp));
1703 			}
1704 			strlcat(tmp, "} ", sizeof(tmp));
1705 		}
1706 		mail_fetchsubject(t = tmp + strlen(tmp), imap_le_struct->imap_stream, msgno, (long)25);
1707 		snprintf(t += strlen(t), sizeof(tmp) - strlen(tmp), " (%ld chars)", cache->rfc822_size);
1708 		add_next_index_string(return_value, tmp);
1709 	}
1710 }
1711 /* }}} */
1712 
1713 /* {{{ proto string imap_body(resource stream_id, int msg_no [, int options])
1714    Read the message body */
PHP_FUNCTION(imap_body)1715 PHP_FUNCTION(imap_body)
1716 {
1717 	zval *streamind;
1718 	zend_long msgno, flags = 0;
1719 	pils *imap_le_struct;
1720 	int msgindex, argc = ZEND_NUM_ARGS();
1721 	char *body;
1722 	unsigned long body_len = 0;
1723 
1724 	if (zend_parse_parameters(argc, "rl|l", &streamind, &msgno, &flags) == FAILURE) {
1725 		return;
1726 	}
1727 
1728 	if (flags && ((flags & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
1729 		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
1730 		RETURN_FALSE;
1731 	}
1732 
1733 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1734 		RETURN_FALSE;
1735 	}
1736 
1737 	if ((argc == 3) && (flags & FT_UID)) {
1738 		/* This should be cached; if it causes an extra RTT to the
1739 		   IMAP server, then that's the price we pay for making
1740 		   sure we don't crash. */
1741 		msgindex = mail_msgno(imap_le_struct->imap_stream, msgno);
1742 	} else {
1743 		msgindex = msgno;
1744 	}
1745 	if ((msgindex < 1) || ((unsigned) msgindex > imap_le_struct->imap_stream->nmsgs)) {
1746 		php_error_docref(NULL, E_WARNING, "Bad message number");
1747 		RETURN_FALSE;
1748 	}
1749 
1750 	body = mail_fetchtext_full (imap_le_struct->imap_stream, msgno, &body_len, (argc == 3 ? flags : NIL));
1751 	if (body_len == 0) {
1752 		RETVAL_EMPTY_STRING();
1753 	} else {
1754 		RETVAL_STRINGL(body, body_len);
1755 	}
1756 }
1757 /* }}} */
1758 
1759 /* {{{ proto bool imap_mail_copy(resource stream_id, string msglist, string mailbox [, int options])
1760    Copy specified message to a mailbox */
PHP_FUNCTION(imap_mail_copy)1761 PHP_FUNCTION(imap_mail_copy)
1762 {
1763 	zval *streamind;
1764 	zend_long options = 0;
1765 	zend_string *seq, *folder;
1766 	int argc = ZEND_NUM_ARGS();
1767 	pils *imap_le_struct;
1768 
1769 	if (zend_parse_parameters(argc, "rSS|l", &streamind, &seq, &folder, &options) == FAILURE) {
1770 		return;
1771 	}
1772 
1773 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1774 		RETURN_FALSE;
1775 	}
1776 
1777 	if (mail_copy_full(imap_le_struct->imap_stream, ZSTR_VAL(seq), ZSTR_VAL(folder), (argc == 4 ? options : NIL)) == T) {
1778 		RETURN_TRUE;
1779 	} else {
1780 		RETURN_FALSE;
1781 	}
1782 }
1783 /* }}} */
1784 
1785 /* {{{ proto bool imap_mail_move(resource stream_id, string sequence, string mailbox [, int options])
1786    Move specified message to a mailbox */
PHP_FUNCTION(imap_mail_move)1787 PHP_FUNCTION(imap_mail_move)
1788 {
1789 	zval *streamind;
1790 	zend_string *seq, *folder;
1791 	zend_long options = 0;
1792 	pils *imap_le_struct;
1793 	int argc = ZEND_NUM_ARGS();
1794 
1795 	if (zend_parse_parameters(argc, "rSS|l", &streamind, &seq, &folder, &options) == FAILURE) {
1796 		return;
1797 	}
1798 
1799 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1800 		RETURN_FALSE;
1801 	}
1802 
1803 	if (mail_copy_full(imap_le_struct->imap_stream, ZSTR_VAL(seq), ZSTR_VAL(folder), (argc == 4 ? (options | CP_MOVE) : CP_MOVE)) == T) {
1804 		RETURN_TRUE;
1805 	} else {
1806 		RETURN_FALSE;
1807 	}
1808 }
1809 /* }}} */
1810 
1811 /* {{{ proto bool imap_createmailbox(resource stream_id, string mailbox)
1812    Create a new mailbox */
PHP_FUNCTION(imap_createmailbox)1813 PHP_FUNCTION(imap_createmailbox)
1814 {
1815 	zval *streamind;
1816 	zend_string *folder;
1817 	pils *imap_le_struct;
1818 
1819 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
1820 		return;
1821 	}
1822 
1823 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1824 		RETURN_FALSE;
1825 	}
1826 
1827 	if (mail_create(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
1828 		RETURN_TRUE;
1829 	} else {
1830 		RETURN_FALSE;
1831 	}
1832 }
1833 /* }}} */
1834 
1835 /* {{{ proto bool imap_renamemailbox(resource stream_id, string old_name, string new_name)
1836    Rename a mailbox */
PHP_FUNCTION(imap_renamemailbox)1837 PHP_FUNCTION(imap_renamemailbox)
1838 {
1839 	zval *streamind;
1840 	zend_string *old_mailbox, *new_mailbox;
1841 	pils *imap_le_struct;
1842 
1843 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &old_mailbox, &new_mailbox) == FAILURE) {
1844 		return;
1845 	}
1846 
1847 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1848 		RETURN_FALSE;
1849 	}
1850 
1851 	if (mail_rename(imap_le_struct->imap_stream, ZSTR_VAL(old_mailbox), ZSTR_VAL(new_mailbox)) == T) {
1852 		RETURN_TRUE;
1853 	} else {
1854 		RETURN_FALSE;
1855 	}
1856 }
1857 /* }}} */
1858 
1859 /* {{{ proto bool imap_deletemailbox(resource stream_id, string mailbox)
1860    Delete a mailbox */
PHP_FUNCTION(imap_deletemailbox)1861 PHP_FUNCTION(imap_deletemailbox)
1862 {
1863 	zval *streamind;
1864 	zend_string *folder;
1865 	pils *imap_le_struct;
1866 
1867 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
1868 		return;
1869 	}
1870 
1871 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1872 		RETURN_FALSE;
1873 	}
1874 
1875 	if (mail_delete(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
1876 		RETURN_TRUE;
1877 	} else {
1878 		RETURN_FALSE;
1879 	}
1880 }
1881 /* }}} */
1882 
1883 /* {{{ proto array imap_list(resource stream_id, string ref, string pattern)
1884    Read the list of mailboxes */
PHP_FUNCTION(imap_list)1885 PHP_FUNCTION(imap_list)
1886 {
1887 	zval *streamind;
1888 	zend_string *ref, *pat;
1889 	pils *imap_le_struct;
1890 	STRINGLIST *cur=NIL;
1891 
1892 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
1893 		return;
1894 	}
1895 
1896 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1897 		RETURN_FALSE;
1898 	}
1899 
1900 	/* set flag for normal, old mailbox list */
1901 	IMAPG(folderlist_style) = FLIST_ARRAY;
1902 
1903 	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
1904 	mail_list(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
1905 	if (IMAPG(imap_folders) == NIL) {
1906 		RETURN_FALSE;
1907 	}
1908 
1909 	array_init(return_value);
1910 	cur=IMAPG(imap_folders);
1911 	while (cur != NIL) {
1912 		add_next_index_string(return_value, (char*)cur->LTEXT);
1913 		cur=cur->next;
1914 	}
1915 	mail_free_stringlist (&IMAPG(imap_folders));
1916 	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
1917 }
1918 
1919 /* }}} */
1920 
1921 /* {{{ proto array imap_getmailboxes(resource stream_id, string ref, string pattern)
1922    Reads the list of mailboxes and returns a full array of objects containing name, attributes, and delimiter */
1923 /* Author: CJH */
PHP_FUNCTION(imap_list_full)1924 PHP_FUNCTION(imap_list_full)
1925 {
1926 	zval *streamind, mboxob;
1927 	zend_string *ref, *pat;
1928 	pils *imap_le_struct;
1929 	FOBJECTLIST *cur=NIL;
1930 	char *delim=NIL;
1931 
1932 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
1933 		return;
1934 	}
1935 
1936 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1937 		RETURN_FALSE;
1938 	}
1939 
1940 	/* set flag for new, improved array of objects mailbox list */
1941 	IMAPG(folderlist_style) = FLIST_OBJECT;
1942 
1943 	IMAPG(imap_folder_objects) = IMAPG(imap_folder_objects_tail) = NIL;
1944 	mail_list(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
1945 	if (IMAPG(imap_folder_objects) == NIL) {
1946 		RETURN_FALSE;
1947 	}
1948 
1949 	array_init(return_value);
1950 	delim = safe_emalloc(2, sizeof(char), 0);
1951 	cur=IMAPG(imap_folder_objects);
1952 	while (cur != NIL) {
1953 		object_init(&mboxob);
1954 		add_property_string(&mboxob, "name", (char*)cur->LTEXT);
1955 		add_property_long(&mboxob, "attributes", cur->attributes);
1956 #ifdef IMAP41
1957 		delim[0] = (char)cur->delimiter;
1958 		delim[1] = 0;
1959 		add_property_string(&mboxob, "delimiter", delim);
1960 #else
1961 		add_property_string(&mboxob, "delimiter", cur->delimiter);
1962 #endif
1963 		add_next_index_object(return_value, &mboxob);
1964 		cur=cur->next;
1965 	}
1966 	mail_free_foblist(&IMAPG(imap_folder_objects), &IMAPG(imap_folder_objects_tail));
1967 	efree(delim);
1968 	IMAPG(folderlist_style) = FLIST_ARRAY;		/* reset to default */
1969 }
1970 /* }}} */
1971 
1972 /* {{{ proto array imap_listscan(resource stream_id, string ref, string pattern, string content)
1973    Read list of mailboxes containing a certain string */
PHP_FUNCTION(imap_listscan)1974 PHP_FUNCTION(imap_listscan)
1975 {
1976 	zval *streamind;
1977 	zend_string *ref, *pat, *content;
1978 	pils *imap_le_struct;
1979 	STRINGLIST *cur=NIL;
1980 
1981 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSSS", &streamind, &ref, &pat, &content) == FAILURE) {
1982 		return;
1983 	}
1984 
1985 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1986 		RETURN_FALSE;
1987 	}
1988 
1989 	IMAPG(imap_folders) = NIL;
1990 	mail_scan(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat), ZSTR_VAL(content));
1991 	if (IMAPG(imap_folders) == NIL) {
1992 		RETURN_FALSE;
1993 	}
1994 
1995 	array_init(return_value);
1996 	cur=IMAPG(imap_folders);
1997 	while (cur != NIL) {
1998 		add_next_index_string(return_value, (char*)cur->LTEXT);
1999 		cur=cur->next;
2000 	}
2001 	mail_free_stringlist (&IMAPG(imap_folders));
2002 	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
2003 }
2004 
2005 /* }}} */
2006 
2007 /* {{{ proto object imap_check(resource stream_id)
2008    Get mailbox properties */
PHP_FUNCTION(imap_check)2009 PHP_FUNCTION(imap_check)
2010 {
2011 	zval *streamind;
2012 	pils *imap_le_struct;
2013 	char date[100];
2014 
2015 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
2016 		return;
2017 	}
2018 
2019 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2020 		RETURN_FALSE;
2021 	}
2022 
2023 	if (mail_ping (imap_le_struct->imap_stream) == NIL) {
2024 		RETURN_FALSE;
2025 	}
2026 
2027 	if (imap_le_struct->imap_stream && imap_le_struct->imap_stream->mailbox) {
2028 		rfc822_date(date);
2029 		object_init(return_value);
2030 		add_property_string(return_value, "Date", date);
2031 		add_property_string(return_value, "Driver", imap_le_struct->imap_stream->dtb->name);
2032 		add_property_string(return_value, "Mailbox", imap_le_struct->imap_stream->mailbox);
2033 		add_property_long(return_value, "Nmsgs", imap_le_struct->imap_stream->nmsgs);
2034 		add_property_long(return_value, "Recent", imap_le_struct->imap_stream->recent);
2035 	} else {
2036 		RETURN_FALSE;
2037 	}
2038 }
2039 /* }}} */
2040 
2041 /* {{{ proto bool imap_delete(resource stream_id, int msg_no [, int options])
2042    Mark a message for deletion */
PHP_FUNCTION(imap_delete)2043 PHP_FUNCTION(imap_delete)
2044 {
2045 	zval *streamind, *sequence;
2046 	pils *imap_le_struct;
2047 	zend_long flags = 0;
2048 	int argc = ZEND_NUM_ARGS();
2049 
2050 	if (zend_parse_parameters(argc, "rz|l", &streamind, &sequence, &flags) == FAILURE) {
2051 		return;
2052 	}
2053 
2054 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2055 		RETURN_FALSE;
2056 	}
2057 
2058 	convert_to_string_ex(sequence);
2059 
2060 	mail_setflag_full(imap_le_struct->imap_stream, Z_STRVAL_P(sequence), "\\DELETED", (argc == 3 ? flags : NIL));
2061 	RETVAL_TRUE;
2062 }
2063 /* }}} */
2064 
2065 /* {{{ proto bool imap_undelete(resource stream_id, int msg_no [, int flags])
2066    Remove the delete flag from a message */
PHP_FUNCTION(imap_undelete)2067 PHP_FUNCTION(imap_undelete)
2068 {
2069 	zval *streamind, *sequence;
2070 	zend_long flags = 0;
2071 	pils *imap_le_struct;
2072 	int argc = ZEND_NUM_ARGS();
2073 
2074 	if (zend_parse_parameters(argc, "rz|l", &streamind, &sequence, &flags) == FAILURE) {
2075 		return;
2076 	}
2077 
2078 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2079 		RETURN_FALSE;
2080 	}
2081 
2082 	convert_to_string_ex(sequence);
2083 
2084 	mail_clearflag_full(imap_le_struct->imap_stream, Z_STRVAL_P(sequence), "\\DELETED", (argc == 3 ? flags : NIL));
2085 	RETVAL_TRUE;
2086 }
2087 /* }}} */
2088 
2089 /* {{{ proto object imap_headerinfo(resource stream_id, int msg_no [, int from_length [, int subject_length [, string default_host]]])
2090    Read the headers of the message */
PHP_FUNCTION(imap_headerinfo)2091 PHP_FUNCTION(imap_headerinfo)
2092 {
2093 	zval *streamind;
2094 	zend_string *defaulthost = NULL;
2095 	int argc = ZEND_NUM_ARGS();
2096 	zend_long msgno, fromlength, subjectlength;
2097 	pils *imap_le_struct;
2098 	MESSAGECACHE *cache;
2099 	ENVELOPE *en;
2100 	char dummy[2000], fulladdress[MAILTMPLEN + 1];
2101 
2102 	if (zend_parse_parameters(argc, "rl|llS", &streamind, &msgno, &fromlength, &subjectlength, &defaulthost) == FAILURE) {
2103 		return;
2104 	}
2105 
2106 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2107 		RETURN_FALSE;
2108 	}
2109 
2110 	if (argc >= 3) {
2111 		if (fromlength < 0 || fromlength > MAILTMPLEN) {
2112 			php_error_docref(NULL, E_WARNING, "From length has to be between 0 and %d", MAILTMPLEN);
2113 			RETURN_FALSE;
2114 		}
2115 	} else {
2116 		fromlength = 0x00;
2117 	}
2118 	if (argc >= 4) {
2119 		if (subjectlength < 0 || subjectlength > MAILTMPLEN) {
2120 			php_error_docref(NULL, E_WARNING, "Subject length has to be between 0 and %d", MAILTMPLEN);
2121 			RETURN_FALSE;
2122 		}
2123 	} else {
2124 		subjectlength = 0x00;
2125 	}
2126 
2127 	PHP_IMAP_CHECK_MSGNO(msgno);
2128 
2129 	if (mail_fetchstructure(imap_le_struct->imap_stream, msgno, NIL)) {
2130 		cache = mail_elt(imap_le_struct->imap_stream, msgno);
2131 	} else {
2132 		RETURN_FALSE;
2133 	}
2134 
2135 	en = mail_fetchenvelope(imap_le_struct->imap_stream, msgno);
2136 
2137 	/* call a function to parse all the text, so that we can use the
2138 	   same function to parse text from other sources */
2139 	_php_make_header_object(return_value, en);
2140 
2141 	/* now run through properties that are only going to be returned
2142 	   from a server, not text headers */
2143 	add_property_string(return_value, "Recent", cache->recent ? (cache->seen ? "R": "N") : " ");
2144 	add_property_string(return_value, "Unseen", (cache->recent | cache->seen) ? " " : "U");
2145 	add_property_string(return_value, "Flagged", cache->flagged ? "F" : " ");
2146 	add_property_string(return_value, "Answered", cache->answered ? "A" : " ");
2147 	add_property_string(return_value, "Deleted", cache->deleted ? "D" : " ");
2148 	add_property_string(return_value, "Draft", cache->draft ? "X" : " ");
2149 
2150 	snprintf(dummy, sizeof(dummy), "%4ld", cache->msgno);
2151 	add_property_string(return_value, "Msgno", dummy);
2152 
2153 	mail_date(dummy, cache);
2154 	add_property_string(return_value, "MailDate", dummy);
2155 
2156 	snprintf(dummy, sizeof(dummy), "%ld", cache->rfc822_size);
2157 	add_property_string(return_value, "Size", dummy);
2158 
2159 	add_property_long(return_value, "udate", mail_longdate(cache));
2160 
2161 	if (en->from && fromlength) {
2162 		fulladdress[0] = 0x00;
2163 		mail_fetchfrom(fulladdress, imap_le_struct->imap_stream, msgno, fromlength);
2164 		add_property_string(return_value, "fetchfrom", fulladdress);
2165 	}
2166 	if (en->subject && subjectlength) {
2167 		fulladdress[0] = 0x00;
2168 		mail_fetchsubject(fulladdress, imap_le_struct->imap_stream, msgno, subjectlength);
2169 		add_property_string(return_value, "fetchsubject", fulladdress);
2170 	}
2171 }
2172 /* }}} */
2173 
2174 /* {{{ proto object imap_rfc822_parse_headers(string headers [, string default_host])
2175    Parse a set of mail headers contained in a string, and return an object similar to imap_headerinfo() */
PHP_FUNCTION(imap_rfc822_parse_headers)2176 PHP_FUNCTION(imap_rfc822_parse_headers)
2177 {
2178 	zend_string *headers, *defaulthost = NULL;
2179 	ENVELOPE *en;
2180 	int argc = ZEND_NUM_ARGS();
2181 
2182 	if (zend_parse_parameters(argc, "S|S", &headers, &defaulthost) == FAILURE) {
2183 		return;
2184 	}
2185 
2186 	if (argc == 2) {
2187 		rfc822_parse_msg(&en, NULL, ZSTR_VAL(headers), ZSTR_LEN(headers), NULL, ZSTR_VAL(defaulthost), NIL);
2188 	} else {
2189 		rfc822_parse_msg(&en, NULL, ZSTR_VAL(headers), ZSTR_LEN(headers), NULL, "UNKNOWN", NIL);
2190 	}
2191 
2192 	/* call a function to parse all the text, so that we can use the
2193 	   same function no matter where the headers are from */
2194 	_php_make_header_object(return_value, en);
2195 	mail_free_envelope(&en);
2196 }
2197 /* }}} */
2198 
2199 /* KMLANG */
2200 /* {{{ proto array imap_lsub(resource stream_id, string ref, string pattern)
2201    Return a list of subscribed mailboxes */
PHP_FUNCTION(imap_lsub)2202 PHP_FUNCTION(imap_lsub)
2203 {
2204 	zval *streamind;
2205 	zend_string *ref, *pat;
2206 	pils *imap_le_struct;
2207 	STRINGLIST *cur=NIL;
2208 
2209 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
2210 		return;
2211 	}
2212 
2213 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2214 		RETURN_FALSE;
2215 	}
2216 
2217 	/* set flag for normal, old mailbox list */
2218 	IMAPG(folderlist_style) = FLIST_ARRAY;
2219 
2220 	IMAPG(imap_sfolders) = NIL;
2221 	mail_lsub(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
2222 	if (IMAPG(imap_sfolders) == NIL) {
2223 		RETURN_FALSE;
2224 	}
2225 
2226 	array_init(return_value);
2227 	cur=IMAPG(imap_sfolders);
2228 	while (cur != NIL) {
2229 		add_next_index_string(return_value, (char*)cur->LTEXT);
2230 		cur=cur->next;
2231 	}
2232 	mail_free_stringlist (&IMAPG(imap_sfolders));
2233 	IMAPG(imap_sfolders) = IMAPG(imap_sfolders_tail) = NIL;
2234 }
2235 /* }}} */
2236 
2237 /* {{{ proto array imap_getsubscribed(resource stream_id, string ref, string pattern)
2238    Return a list of subscribed mailboxes, in the same format as imap_getmailboxes() */
2239 /* Author: CJH */
PHP_FUNCTION(imap_lsub_full)2240 PHP_FUNCTION(imap_lsub_full)
2241 {
2242 	zval *streamind, mboxob;
2243 	zend_string *ref, *pat;
2244 	pils *imap_le_struct;
2245 	FOBJECTLIST *cur=NIL;
2246 	char *delim=NIL;
2247 
2248 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
2249 		return;
2250 	}
2251 
2252 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2253 		RETURN_FALSE;
2254 	}
2255 
2256 	/* set flag for new, improved array of objects list */
2257 	IMAPG(folderlist_style) = FLIST_OBJECT;
2258 
2259 	IMAPG(imap_sfolder_objects) = IMAPG(imap_sfolder_objects_tail) = NIL;
2260 	mail_lsub(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
2261 	if (IMAPG(imap_sfolder_objects) == NIL) {
2262 		RETURN_FALSE;
2263 	}
2264 
2265 	array_init(return_value);
2266 	delim = safe_emalloc(2, sizeof(char), 0);
2267 	cur=IMAPG(imap_sfolder_objects);
2268 	while (cur != NIL) {
2269 		object_init(&mboxob);
2270 		add_property_string(&mboxob, "name", (char*)cur->LTEXT);
2271 		add_property_long(&mboxob, "attributes", cur->attributes);
2272 #ifdef IMAP41
2273 		delim[0] = (char)cur->delimiter;
2274 		delim[1] = 0;
2275 		add_property_string(&mboxob, "delimiter", delim);
2276 #else
2277 		add_property_string(&mboxob, "delimiter", cur->delimiter);
2278 #endif
2279 		add_next_index_object(return_value, &mboxob);
2280 		cur=cur->next;
2281 	}
2282 	mail_free_foblist (&IMAPG(imap_sfolder_objects), &IMAPG(imap_sfolder_objects_tail));
2283 	efree(delim);
2284 	IMAPG(folderlist_style) = FLIST_ARRAY; /* reset to default */
2285 }
2286 /* }}} */
2287 
2288 /* {{{ proto bool imap_subscribe(resource stream_id, string mailbox)
2289    Subscribe to a mailbox */
PHP_FUNCTION(imap_subscribe)2290 PHP_FUNCTION(imap_subscribe)
2291 {
2292 	zval *streamind;
2293 	zend_string *folder;
2294 	pils *imap_le_struct;
2295 
2296 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
2297 		return;
2298 	}
2299 
2300 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2301 		RETURN_FALSE;
2302 	}
2303 
2304 	if (mail_subscribe(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
2305 		RETURN_TRUE;
2306 	} else {
2307 		RETURN_FALSE;
2308 	}
2309 }
2310 /* }}} */
2311 
2312 /* {{{ proto bool imap_unsubscribe(resource stream_id, string mailbox)
2313    Unsubscribe from a mailbox */
PHP_FUNCTION(imap_unsubscribe)2314 PHP_FUNCTION(imap_unsubscribe)
2315 {
2316 	zval *streamind;
2317 	zend_string *folder;
2318 	pils *imap_le_struct;
2319 
2320 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
2321 		return;
2322 	}
2323 
2324 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2325 		RETURN_FALSE;
2326 	}
2327 
2328 	if (mail_unsubscribe(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
2329 		RETURN_TRUE;
2330 	} else {
2331 		RETURN_FALSE;
2332 	}
2333 }
2334 /* }}} */
2335 
2336 /* {{{ proto object imap_fetchstructure(resource stream_id, int msg_no [, int options])
2337    Read the full structure of a message */
PHP_FUNCTION(imap_fetchstructure)2338 PHP_FUNCTION(imap_fetchstructure)
2339 {
2340 	zval *streamind;
2341 	zend_long msgno, flags = 0;
2342 	pils *imap_le_struct;
2343 	BODY *body;
2344 	int msgindex, argc = ZEND_NUM_ARGS();
2345 
2346 	if (zend_parse_parameters(argc, "rl|l", &streamind, &msgno, &flags) == FAILURE) {
2347 		return;
2348 	}
2349 
2350 	if (flags && ((flags & ~FT_UID) != 0)) {
2351 		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
2352 		RETURN_FALSE;
2353 	}
2354 
2355 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2356 		RETURN_FALSE;
2357 	}
2358 
2359 	if (msgno < 1) {
2360 		RETURN_FALSE;
2361 	}
2362 
2363 	object_init(return_value);
2364 
2365 	if ((argc == 3) && (flags & FT_UID)) {
2366 		/* This should be cached; if it causes an extra RTT to the
2367 		   IMAP server, then that's the price we pay for making
2368 		   sure we don't crash. */
2369 		msgindex = mail_msgno(imap_le_struct->imap_stream, msgno);
2370 	} else {
2371 		msgindex = msgno;
2372 	}
2373 	PHP_IMAP_CHECK_MSGNO(msgindex);
2374 
2375 	mail_fetchstructure_full(imap_le_struct->imap_stream, msgno, &body , (argc == 3 ? flags : NIL));
2376 
2377 	if (!body) {
2378 		php_error_docref(NULL, E_WARNING, "No body information available");
2379 		RETURN_FALSE;
2380 	}
2381 
2382 	_php_imap_add_body(return_value, body);
2383 }
2384 /* }}} */
2385 
2386 /* {{{ proto string imap_fetchbody(resource stream_id, int msg_no, string section [, int options])
2387    Get a specific body section */
PHP_FUNCTION(imap_fetchbody)2388 PHP_FUNCTION(imap_fetchbody)
2389 {
2390 	zval *streamind;
2391 	zend_long msgno, flags = 0;
2392 	pils *imap_le_struct;
2393 	char *body;
2394 	zend_string *sec;
2395 	unsigned long len;
2396 	int argc = ZEND_NUM_ARGS();
2397 
2398 	if (zend_parse_parameters(argc, "rlS|l", &streamind, &msgno, &sec, &flags) == FAILURE) {
2399 		return;
2400 	}
2401 
2402 	if (flags && ((flags & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
2403 		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
2404 		RETURN_FALSE;
2405 	}
2406 
2407 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2408 		RETURN_FALSE;
2409 	}
2410 
2411 	if (argc < 4 || !(flags & FT_UID)) {
2412 		/* only perform the check if the msgno is a message number and not a UID */
2413 		PHP_IMAP_CHECK_MSGNO(msgno);
2414 	}
2415 
2416 	body = mail_fetchbody_full(imap_le_struct->imap_stream, msgno, ZSTR_VAL(sec), &len, (argc == 4 ? flags : NIL));
2417 
2418 	if (!body) {
2419 		php_error_docref(NULL, E_WARNING, "No body information available");
2420 		RETURN_FALSE;
2421 	}
2422 	RETVAL_STRINGL(body, len);
2423 }
2424 
2425 /* }}} */
2426 
2427 
2428 /* {{{ proto string imap_fetchmime(resource stream_id, int msg_no, string section [, int options])
2429    Get a specific body section's MIME headers */
PHP_FUNCTION(imap_fetchmime)2430 PHP_FUNCTION(imap_fetchmime)
2431 {
2432 	zval *streamind;
2433 	zend_long msgno, flags = 0;
2434 	pils *imap_le_struct;
2435 	char *body;
2436 	zend_string *sec;
2437 	unsigned long len;
2438 	int argc = ZEND_NUM_ARGS();
2439 
2440 	if (zend_parse_parameters(argc, "rlS|l", &streamind, &msgno, &sec, &flags) == FAILURE) {
2441 		return;
2442 	}
2443 
2444 	if (flags && ((flags & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
2445 		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
2446 		RETURN_FALSE;
2447 	}
2448 
2449 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2450 		RETURN_FALSE;
2451 	}
2452 
2453 	if (argc < 4 || !(flags & FT_UID)) {
2454 		/* only perform the check if the msgno is a message number and not a UID */
2455 		PHP_IMAP_CHECK_MSGNO(msgno);
2456 	}
2457 
2458 	body = mail_fetch_mime(imap_le_struct->imap_stream, msgno, ZSTR_VAL(sec), &len, (argc == 4 ? flags : NIL));
2459 
2460 	if (!body) {
2461 		php_error_docref(NULL, E_WARNING, "No body MIME information available");
2462 		RETURN_FALSE;
2463 	}
2464 	RETVAL_STRINGL(body, len);
2465 }
2466 
2467 /* }}} */
2468 
2469 /* {{{ proto bool imap_savebody(resource stream_id, string|resource file, int msg_no[, string section = ""[, int options = 0]])
2470 	Save a specific body section to a file */
PHP_FUNCTION(imap_savebody)2471 PHP_FUNCTION(imap_savebody)
2472 {
2473 	zval *stream, *out;
2474 	pils *imap_ptr = NULL;
2475 	php_stream *writer = NULL;
2476 	zend_string *section = NULL;
2477 	int close_stream = 1;
2478 	zend_long msgno, flags = 0;
2479 
2480 	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rzl|Sl", &stream, &out, &msgno, &section, &flags)) {
2481 		RETURN_FALSE;
2482 	}
2483 
2484 	if ((imap_ptr = (pils *)zend_fetch_resource(Z_RES_P(stream), "imap", le_imap)) == NULL) {
2485 		RETURN_FALSE;
2486 	}
2487 
2488 	if (!imap_ptr) {
2489 		RETURN_FALSE;
2490 	}
2491 
2492 	switch (Z_TYPE_P(out))
2493 	{
2494 		case IS_LONG:
2495 		case IS_RESOURCE:
2496 			close_stream = 0;
2497 			php_stream_from_zval(writer, out);
2498 		break;
2499 
2500 		default:
2501 			convert_to_string_ex(out);
2502 			writer = php_stream_open_wrapper(Z_STRVAL_P(out), "wb", REPORT_ERRORS, NULL);
2503 		break;
2504 	}
2505 
2506 	if (!writer) {
2507 		RETURN_FALSE;
2508 	}
2509 
2510 	IMAPG(gets_stream) = writer;
2511 	mail_parameters(NIL, SET_GETS, (void *) php_mail_gets);
2512 	mail_fetchbody_full(imap_ptr->imap_stream, msgno, section?ZSTR_VAL(section):"", NULL, flags);
2513 	mail_parameters(NIL, SET_GETS, (void *) NULL);
2514 	IMAPG(gets_stream) = NULL;
2515 
2516 	if (close_stream) {
2517 		php_stream_close(writer);
2518 	}
2519 
2520 	RETURN_TRUE;
2521 }
2522 /* }}} */
2523 
2524 /* {{{ proto string imap_base64(string text)
2525    Decode BASE64 encoded text */
PHP_FUNCTION(imap_base64)2526 PHP_FUNCTION(imap_base64)
2527 {
2528 	zend_string *text;
2529 	char *decode;
2530 	unsigned long newlength;
2531 
2532 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2533 		return;
2534 	}
2535 
2536 	decode = (char *) rfc822_base64((unsigned char *) ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2537 
2538 	if (decode == NULL) {
2539 		RETURN_FALSE;
2540 	}
2541 
2542 	RETVAL_STRINGL(decode, newlength);
2543 	fs_give((void**) &decode);
2544 }
2545 /* }}} */
2546 
2547 /* {{{ proto string imap_qprint(string text)
2548    Convert a quoted-printable string to an 8-bit string */
PHP_FUNCTION(imap_qprint)2549 PHP_FUNCTION(imap_qprint)
2550 {
2551 	zend_string *text;
2552 	char *decode;
2553 	unsigned long newlength;
2554 
2555 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2556 		return;
2557 	}
2558 
2559 	decode = (char *) rfc822_qprint((unsigned char *) ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2560 
2561 	if (decode == NULL) {
2562 		RETURN_FALSE;
2563 	}
2564 
2565 	RETVAL_STRINGL(decode, newlength);
2566 	fs_give((void**) &decode);
2567 }
2568 /* }}} */
2569 
2570 /* {{{ proto string imap_8bit(string text)
2571    Convert an 8-bit string to a quoted-printable string */
PHP_FUNCTION(imap_8bit)2572 PHP_FUNCTION(imap_8bit)
2573 {
2574 	zend_string *text;
2575 	char *decode;
2576 	unsigned long newlength;
2577 
2578 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2579 		return;
2580 	}
2581 
2582 	decode = (char *) rfc822_8bit((unsigned char *) ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2583 
2584 	if (decode == NULL) {
2585 		RETURN_FALSE;
2586 	}
2587 
2588 	RETVAL_STRINGL(decode, newlength);
2589 	fs_give((void**) &decode);
2590 }
2591 /* }}} */
2592 
2593 /* {{{ proto string imap_binary(string text)
2594    Convert an 8bit string to a base64 string */
PHP_FUNCTION(imap_binary)2595 PHP_FUNCTION(imap_binary)
2596 {
2597 	zend_string *text;
2598 	char *decode;
2599 	unsigned long newlength;
2600 
2601 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2602 		return;
2603 	}
2604 
2605 	decode = (char*)rfc822_binary(ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2606 
2607 	if (decode == NULL) {
2608 		RETURN_FALSE;
2609 	}
2610 
2611 	RETVAL_STRINGL(decode, newlength);
2612 	fs_give((void**) &decode);
2613 }
2614 /* }}} */
2615 
2616 /* {{{ proto object imap_mailboxmsginfo(resource stream_id)
2617    Returns info about the current mailbox */
PHP_FUNCTION(imap_mailboxmsginfo)2618 PHP_FUNCTION(imap_mailboxmsginfo)
2619 {
2620 	zval *streamind;
2621 	pils *imap_le_struct;
2622 	char date[100];
2623 	unsigned int msgno, unreadmsg, deletedmsg, msize;
2624 
2625 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
2626 		return;
2627 	}
2628 
2629 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2630 		RETURN_FALSE;
2631 	}
2632 
2633 	/* Initialize return object */
2634 	object_init(return_value);
2635 
2636 	unreadmsg = 0;
2637 	deletedmsg = 0;
2638 	msize = 0;
2639 
2640 	for (msgno = 1; msgno <= imap_le_struct->imap_stream->nmsgs; msgno++) {
2641 		MESSAGECACHE * cache = mail_elt (imap_le_struct->imap_stream, msgno);
2642 		mail_fetchstructure (imap_le_struct->imap_stream, msgno, NIL);
2643 
2644 		if (!cache->seen || cache->recent) {
2645 			unreadmsg++;
2646 		}
2647 
2648 		if (cache->deleted) {
2649 			deletedmsg++;
2650 		}
2651 		msize = msize + cache->rfc822_size;
2652 	}
2653 	add_property_long(return_value, "Unread", unreadmsg);
2654 	add_property_long(return_value, "Deleted", deletedmsg);
2655 	add_property_long(return_value, "Nmsgs", imap_le_struct->imap_stream->nmsgs);
2656 	add_property_long(return_value, "Size", msize);
2657 	rfc822_date(date);
2658 	add_property_string(return_value, "Date", date);
2659 	add_property_string(return_value, "Driver", imap_le_struct->imap_stream->dtb->name);
2660 	add_property_string(return_value, "Mailbox", imap_le_struct->imap_stream->mailbox);
2661 	add_property_long(return_value, "Recent", imap_le_struct->imap_stream->recent);
2662 }
2663 /* }}} */
2664 
2665 /* {{{ proto string imap_rfc822_write_address(string mailbox, string host, string personal)
2666    Returns a properly formatted email address given the mailbox, host, and personal info */
PHP_FUNCTION(imap_rfc822_write_address)2667 PHP_FUNCTION(imap_rfc822_write_address)
2668 {
2669 	zend_string *mailbox, *host, *personal;
2670 	ADDRESS *addr;
2671 	zend_string *string;
2672 
2673 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &mailbox, &host, &personal) == FAILURE) {
2674 		return;
2675 	}
2676 
2677 	addr=mail_newaddr();
2678 
2679 	if (mailbox) {
2680 		addr->mailbox = cpystr(ZSTR_VAL(mailbox));
2681 	}
2682 
2683 	if (host) {
2684 		addr->host = cpystr(ZSTR_VAL(host));
2685 	}
2686 
2687 	if (personal) {
2688 		addr->personal = cpystr(ZSTR_VAL(personal));
2689 	}
2690 
2691 	addr->next=NIL;
2692 	addr->error=NIL;
2693 	addr->adl=NIL;
2694 
2695 	string = _php_rfc822_write_address(addr);
2696 	if (string) {
2697 		RETVAL_STR(string);
2698 	} else {
2699 		RETURN_FALSE;
2700 	}
2701 }
2702 /* }}} */
2703 
2704 /* {{{ proto array imap_rfc822_parse_adrlist(string address_string, string default_host)
2705    Parses an address string */
PHP_FUNCTION(imap_rfc822_parse_adrlist)2706 PHP_FUNCTION(imap_rfc822_parse_adrlist)
2707 {
2708 	zval tovals;
2709 	zend_string *str, *defaulthost;
2710 	char *str_copy;
2711 	ADDRESS *addresstmp;
2712 	ENVELOPE *env;
2713 
2714 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &str, &defaulthost) == FAILURE) {
2715 		return;
2716 	}
2717 
2718 	env = mail_newenvelope();
2719 
2720 	/* rfc822_parse_adrlist() modifies passed string. Copy it. */
2721 	str_copy = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
2722 	rfc822_parse_adrlist(&env->to, str_copy, ZSTR_VAL(defaulthost));
2723 	efree(str_copy);
2724 
2725 	array_init(return_value);
2726 
2727 	addresstmp = env->to;
2728 
2729 	if (addresstmp) do {
2730 		object_init(&tovals);
2731 		if (addresstmp->mailbox) {
2732 			add_property_string(&tovals, "mailbox", addresstmp->mailbox);
2733 		}
2734 		if (addresstmp->host) {
2735 			add_property_string(&tovals, "host", addresstmp->host);
2736 		}
2737 		if (addresstmp->personal) {
2738 			add_property_string(&tovals, "personal", addresstmp->personal);
2739 		}
2740 		if (addresstmp->adl) {
2741 			add_property_string(&tovals, "adl", addresstmp->adl);
2742 		}
2743 		add_next_index_object(return_value, &tovals);
2744 	} while ((addresstmp = addresstmp->next));
2745 
2746 	mail_free_envelope(&env);
2747 }
2748 /* }}} */
2749 
2750 /* {{{ proto string imap_utf8(string mime_encoded_text)
2751    Convert a mime-encoded text to UTF-8 */
PHP_FUNCTION(imap_utf8)2752 PHP_FUNCTION(imap_utf8)
2753 {
2754 	zend_string *str;
2755 	SIZEDTEXT src, dest;
2756 
2757 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
2758 		return;
2759 	}
2760 
2761 	src.data  = NULL;
2762 	src.size  = 0;
2763 	dest.data = NULL;
2764 	dest.size = 0;
2765 
2766 	cpytxt(&src, ZSTR_VAL(str), ZSTR_LEN(str));
2767 
2768 #ifndef HAVE_NEW_MIME2TEXT
2769 	utf8_mime2text(&src, &dest);
2770 #else
2771 	utf8_mime2text(&src, &dest, U8T_DECOMPOSE);
2772 #endif
2773 	RETVAL_STRINGL((char*)dest.data, dest.size);
2774 	if (dest.data) {
2775 		free(dest.data);
2776 	}
2777 	if (src.data && src.data != dest.data) {
2778 		free(src.data);
2779 	}
2780 }
2781 /* }}} */
2782 
2783 /* {{{ macros for the modified utf7 conversion functions
2784  *
2785  * author: Andrew Skalski <askalski@chek.com>
2786  */
2787 
2788 /* tests `c' and returns true if it is a special character */
2789 #define SPECIAL(c) ((c) <= 0x1f || (c) >= 0x7f)
2790 
2791 /* validate a modified-base64 character */
2792 #define B64CHAR(c) (isalnum(c) || (c) == '+' || (c) == ',')
2793 
2794 /* map the low 64 bits of `n' to the modified-base64 characters */
2795 #define B64(n)	("ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
2796 				"abcdefghijklmnopqrstuvwxyz0123456789+,"[(n) & 0x3f])
2797 
2798 /* map the modified-base64 character `c' to its 64 bit value */
2799 #define UNB64(c)	((c) == '+' ? 62 : (c) == ',' ? 63 : (c) >= 'a' ? \
2800 					(c) - 71 : (c) >= 'A' ? (c) - 65 : (c) + 4)
2801 /* }}} */
2802 
2803 /* {{{ proto string imap_utf7_decode(string buf)
2804    Decode a modified UTF-7 string */
PHP_FUNCTION(imap_utf7_decode)2805 PHP_FUNCTION(imap_utf7_decode)
2806 {
2807 	/* author: Andrew Skalski <askalski@chek.com> */
2808 	zend_string *arg;
2809 	const unsigned char *in, *inp, *endp;
2810 	unsigned char *out, *outp;
2811 	unsigned char c;
2812 	int inlen, outlen;
2813 	enum {
2814 		ST_NORMAL,	/* printable text */
2815 		ST_DECODE0,	/* encoded text rotation... */
2816 		ST_DECODE1,
2817 		ST_DECODE2,
2818 		ST_DECODE3
2819 	} state;
2820 
2821 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
2822 		return;
2823 	}
2824 
2825 	in = (const unsigned char *) ZSTR_VAL(arg);
2826 	inlen = ZSTR_LEN(arg);
2827 
2828 	/* validate and compute length of output string */
2829 	outlen = 0;
2830 	state = ST_NORMAL;
2831 	for (endp = (inp = in) + inlen; inp < endp; inp++) {
2832 		if (state == ST_NORMAL) {
2833 			/* process printable character */
2834 			if (SPECIAL(*inp)) {
2835 				php_error_docref(NULL, E_WARNING, "Invalid modified UTF-7 character: `%c'", *inp);
2836 				RETURN_FALSE;
2837 			} else if (*inp != '&') {
2838 				outlen++;
2839 			} else if (inp + 1 == endp) {
2840 				php_error_docref(NULL, E_WARNING, "Unexpected end of string");
2841 				RETURN_FALSE;
2842 			} else if (inp[1] != '-') {
2843 				state = ST_DECODE0;
2844 			} else {
2845 				outlen++;
2846 				inp++;
2847 			}
2848 		} else if (*inp == '-') {
2849 			/* return to NORMAL mode */
2850 			if (state == ST_DECODE1) {
2851 				php_error_docref(NULL, E_WARNING, "Stray modified base64 character: `%c'", *--inp);
2852 				RETURN_FALSE;
2853 			}
2854 			state = ST_NORMAL;
2855 		} else if (!B64CHAR(*inp)) {
2856 			php_error_docref(NULL, E_WARNING, "Invalid modified base64 character: `%c'", *inp);
2857 			RETURN_FALSE;
2858 		} else {
2859 			switch (state) {
2860 				case ST_DECODE3:
2861 					outlen++;
2862 					state = ST_DECODE0;
2863 					break;
2864 				case ST_DECODE2:
2865 				case ST_DECODE1:
2866 					outlen++;
2867 				case ST_DECODE0:
2868 					state++;
2869 				case ST_NORMAL:
2870 					break;
2871 			}
2872 		}
2873 	}
2874 
2875 	/* enforce end state */
2876 	if (state != ST_NORMAL) {
2877 		php_error_docref(NULL, E_WARNING, "Unexpected end of string");
2878 		RETURN_FALSE;
2879 	}
2880 
2881 	/* allocate output buffer */
2882 	out = emalloc(outlen + 1);
2883 
2884 	/* decode input string */
2885 	outp = out;
2886 	state = ST_NORMAL;
2887 	for (endp = (inp = in) + inlen; inp < endp; inp++) {
2888 		if (state == ST_NORMAL) {
2889 			if (*inp == '&' && inp[1] != '-') {
2890 				state = ST_DECODE0;
2891 			}
2892 			else if ((*outp++ = *inp) == '&') {
2893 				inp++;
2894 			}
2895 		}
2896 		else if (*inp == '-') {
2897 			state = ST_NORMAL;
2898 		}
2899 		else {
2900 			/* decode input character */
2901 			switch (state) {
2902 			case ST_DECODE0:
2903 				*outp = UNB64(*inp) << 2;
2904 				state = ST_DECODE1;
2905 				break;
2906 			case ST_DECODE1:
2907 				outp[1] = UNB64(*inp);
2908 				c = outp[1] >> 4;
2909 				*outp++ |= c;
2910 				*outp <<= 4;
2911 				state = ST_DECODE2;
2912 				break;
2913 			case ST_DECODE2:
2914 				outp[1] = UNB64(*inp);
2915 				c = outp[1] >> 2;
2916 				*outp++ |= c;
2917 				*outp <<= 6;
2918 				state = ST_DECODE3;
2919 				break;
2920 			case ST_DECODE3:
2921 				*outp++ |= UNB64(*inp);
2922 				state = ST_DECODE0;
2923 			case ST_NORMAL:
2924 				break;
2925 			}
2926 		}
2927 	}
2928 
2929 	*outp = 0;
2930 
2931 #if PHP_DEBUG
2932 	/* warn if we computed outlen incorrectly */
2933 	if (outp - out != outlen) {
2934 		php_error_docref(NULL, E_WARNING, "outp - out [%ld] != outlen [%d]", outp - out, outlen);
2935 	}
2936 #endif
2937 
2938 	RETURN_STRINGL((char*)out, outlen);
2939 }
2940 /* }}} */
2941 
2942 /* {{{ proto string imap_utf7_encode(string buf)
2943    Encode a string in modified UTF-7 */
PHP_FUNCTION(imap_utf7_encode)2944 PHP_FUNCTION(imap_utf7_encode)
2945 {
2946 	/* author: Andrew Skalski <askalski@chek.com> */
2947 	zend_string *arg;
2948 	const unsigned char *in, *inp, *endp;
2949 	zend_string *out;
2950 	unsigned char *outp;
2951 	unsigned char c;
2952 	int inlen, outlen;
2953 	enum {
2954 		ST_NORMAL,	/* printable text */
2955 		ST_ENCODE0,	/* encoded text rotation... */
2956 		ST_ENCODE1,
2957 		ST_ENCODE2
2958 	} state;
2959 
2960 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
2961 		return;
2962 	}
2963 
2964 	in = (const unsigned char *) ZSTR_VAL(arg);
2965 	inlen = ZSTR_LEN(arg);
2966 
2967 	/* compute the length of the result string */
2968 	outlen = 0;
2969 	state = ST_NORMAL;
2970 	endp = (inp = in) + inlen;
2971 	while (inp < endp) {
2972 		if (state == ST_NORMAL) {
2973 			if (SPECIAL(*inp)) {
2974 				state = ST_ENCODE0;
2975 				outlen++;
2976 			} else if (*inp++ == '&') {
2977 				outlen++;
2978 			}
2979 			outlen++;
2980 		} else if (!SPECIAL(*inp)) {
2981 			state = ST_NORMAL;
2982 		} else {
2983 			/* ST_ENCODE0 -> ST_ENCODE1	- two chars
2984 			 * ST_ENCODE1 -> ST_ENCODE2	- one char
2985 			 * ST_ENCODE2 -> ST_ENCODE0	- one char
2986 			 */
2987 			if (state == ST_ENCODE2) {
2988 				state = ST_ENCODE0;
2989 			}
2990 			else if (state++ == ST_ENCODE0) {
2991 				outlen++;
2992 			}
2993 			outlen++;
2994 			inp++;
2995 		}
2996 	}
2997 
2998 	/* allocate output buffer */
2999 	out = zend_string_safe_alloc(1, outlen, 0, 0);
3000 
3001 	/* encode input string */
3002 	outp = (unsigned char*)ZSTR_VAL(out);
3003 	state = ST_NORMAL;
3004 	endp = (inp = in) + inlen;
3005 	while (inp < endp || state != ST_NORMAL) {
3006 		if (state == ST_NORMAL) {
3007 			if (SPECIAL(*inp)) {
3008 				/* begin encoding */
3009 				*outp++ = '&';
3010 				state = ST_ENCODE0;
3011 			} else if ((*outp++ = *inp++) == '&') {
3012 				*outp++ = '-';
3013 			}
3014 		} else if (inp == endp || !SPECIAL(*inp)) {
3015 			/* flush overflow and terminate region */
3016 			if (state != ST_ENCODE0) {
3017 				c = B64(*outp);
3018 				*outp++ = c;
3019 			}
3020 			*outp++ = '-';
3021 			state = ST_NORMAL;
3022 		} else {
3023 			/* encode input character */
3024 			switch (state) {
3025 				case ST_ENCODE0:
3026 					*outp++ = B64(*inp >> 2);
3027 					*outp = *inp++ << 4;
3028 					state = ST_ENCODE1;
3029 					break;
3030 				case ST_ENCODE1:
3031 					c = B64(*outp | *inp >> 4);
3032 					*outp++ = c;
3033 					*outp = *inp++ << 2;
3034 					state = ST_ENCODE2;
3035 					break;
3036 				case ST_ENCODE2:
3037 					c = B64(*outp | *inp >> 6);
3038 					*outp++ = c;
3039 					*outp++ = B64(*inp++);
3040 					state = ST_ENCODE0;
3041 				case ST_NORMAL:
3042 					break;
3043 			}
3044 		}
3045 	}
3046 
3047 	*outp = 0;
3048 
3049 	RETURN_STR(out);
3050 }
3051 /* }}} */
3052 
3053 #undef SPECIAL
3054 #undef B64CHAR
3055 #undef B64
3056 #undef UNB64
3057 
3058 #ifdef HAVE_IMAP_MUTF7
php_imap_mutf7(INTERNAL_FUNCTION_PARAMETERS,int mode)3059 static void php_imap_mutf7(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
3060 {
3061 	zend_string *in;
3062 	unsigned char *out;
3063 
3064 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &in) == FAILURE) {
3065 		return;
3066 	}
3067 
3068 	if (ZSTR_LEN(in) < 1) {
3069 		RETURN_EMPTY_STRING();
3070 	}
3071 
3072 	if (mode == 0) {
3073 		out = utf8_to_mutf7((unsigned char *) ZSTR_VAL(in));
3074 	} else {
3075 		out = utf8_from_mutf7((unsigned char *) ZSTR_VAL(in));
3076 	}
3077 
3078 	if (out == NIL) {
3079 		RETURN_FALSE;
3080 	} else {
3081 		RETURN_STRING((char *)out);
3082 	}
3083 }
3084 /* }}} */
3085 
3086 /* {{{ proto string imap_utf8_to_mutf7(string in)
3087    Encode a UTF-8 string to modified UTF-7 */
PHP_FUNCTION(imap_utf8_to_mutf7)3088 PHP_FUNCTION(imap_utf8_to_mutf7)
3089 {
3090 	php_imap_mutf7(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3091 }
3092 /* }}} */
3093 
3094 /* {{{ proto string imap_mutf7_to_utf8(string in)
3095    Decode a modified UTF-7 string to UTF-8 */
PHP_FUNCTION(imap_mutf7_to_utf8)3096 PHP_FUNCTION(imap_mutf7_to_utf8)
3097 {
3098 	php_imap_mutf7(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3099 }
3100 /* }}} */
3101 #endif
3102 
3103 /* {{{ proto bool imap_setflag_full(resource stream_id, string sequence, string flag [, int options])
3104    Sets flags on messages */
PHP_FUNCTION(imap_setflag_full)3105 PHP_FUNCTION(imap_setflag_full)
3106 {
3107 	zval *streamind;
3108 	zend_string *sequence, *flag;
3109 	zend_long flags = 0;
3110 	pils *imap_le_struct;
3111 
3112 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS|l", &streamind, &sequence, &flag, &flags) == FAILURE) {
3113 		return;
3114 	}
3115 
3116 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3117 		RETURN_FALSE;
3118 	}
3119 
3120 	mail_setflag_full(imap_le_struct->imap_stream, ZSTR_VAL(sequence), ZSTR_VAL(flag), (flags ? flags : NIL));
3121 	RETURN_TRUE;
3122 }
3123 /* }}} */
3124 
3125 /* {{{ proto bool imap_clearflag_full(resource stream_id, string sequence, string flag [, int options])
3126    Clears flags on messages */
PHP_FUNCTION(imap_clearflag_full)3127 PHP_FUNCTION(imap_clearflag_full)
3128 {
3129 	zval *streamind;
3130 	zend_string *sequence, *flag;
3131 	zend_long flags = 0;
3132 	pils *imap_le_struct;
3133 	int argc = ZEND_NUM_ARGS();
3134 
3135 	if (zend_parse_parameters(argc, "rSS|l", &streamind, &sequence, &flag, &flags) ==FAILURE) {
3136 		return;
3137 	}
3138 
3139 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3140 		RETURN_FALSE;
3141 	}
3142 
3143 	mail_clearflag_full(imap_le_struct->imap_stream, ZSTR_VAL(sequence), ZSTR_VAL(flag), (argc == 4 ? flags : NIL));
3144 	RETURN_TRUE;
3145 }
3146 /* }}} */
3147 
3148 /* {{{ proto array imap_sort(resource stream_id, int criteria, int reverse [, int options [, string search_criteria [, string charset]]])
3149    Sort an array of message headers, optionally including only messages that meet specified criteria. */
PHP_FUNCTION(imap_sort)3150 PHP_FUNCTION(imap_sort)
3151 {
3152 	zval *streamind;
3153 	zend_string *criteria = NULL, *charset = NULL;
3154 	zend_long pgm, rev, flags = 0;
3155 	pils *imap_le_struct;
3156 	unsigned long *slst, *sl;
3157 	char *search_criteria;
3158 	SORTPGM *mypgm=NIL;
3159 	SEARCHPGM *spg=NIL;
3160 	int argc = ZEND_NUM_ARGS();
3161 
3162 	if (zend_parse_parameters(argc, "rll|lSS", &streamind, &pgm, &rev, &flags, &criteria, &charset) == FAILURE) {
3163 		return;
3164 	}
3165 
3166 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3167 		RETURN_FALSE;
3168 	}
3169 
3170 	if (pgm > SORTSIZE) {
3171 		php_error_docref(NULL, E_WARNING, "Unrecognized sort criteria");
3172 		RETURN_FALSE;
3173 	}
3174 	if (argc >= 4) {
3175 		if (flags < 0) {
3176 			php_error_docref(NULL, E_WARNING, "Search options parameter has to be greater than or equal to 0");
3177 			RETURN_FALSE;
3178 		}
3179 	}
3180 	if (argc >= 5) {
3181 		search_criteria = estrndup(ZSTR_VAL(criteria), ZSTR_LEN(criteria));
3182 		spg = mail_criteria(search_criteria);
3183 		efree(search_criteria);
3184 	} else {
3185 		spg = mail_newsearchpgm();
3186 	}
3187 
3188 	mypgm = mail_newsortpgm();
3189 	mypgm->reverse = rev;
3190 	mypgm->function = (short) pgm;
3191 	mypgm->next = NIL;
3192 
3193 	slst = mail_sort(imap_le_struct->imap_stream, (argc == 6 ? ZSTR_VAL(charset) : NIL), spg, mypgm, (argc >= 4 ? flags : NIL));
3194 
3195 	if (spg && !(flags & SE_FREE)) {
3196 		mail_free_searchpgm(&spg);
3197 	}
3198 
3199 	array_init(return_value);
3200 	if (slst != NIL && slst != 0) {
3201 		for (sl = slst; *sl; sl++) {
3202 			add_next_index_long(return_value, *sl);
3203 		}
3204 		fs_give ((void **) &slst);
3205 	}
3206 }
3207 /* }}} */
3208 
3209 /* {{{ proto string imap_fetchheader(resource stream_id, int msg_no [, int options])
3210    Get the full unfiltered header for a message */
PHP_FUNCTION(imap_fetchheader)3211 PHP_FUNCTION(imap_fetchheader)
3212 {
3213 	zval *streamind;
3214 	zend_long msgno, flags = 0L;
3215 	pils *imap_le_struct;
3216 	int msgindex, argc = ZEND_NUM_ARGS();
3217 
3218 	if (zend_parse_parameters(argc, "rl|l", &streamind, &msgno, &flags) == FAILURE) {
3219 		return;
3220 	}
3221 
3222 	if (flags && ((flags & ~(FT_UID|FT_INTERNAL|FT_PREFETCHTEXT)) != 0)) {
3223 		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
3224 		RETURN_FALSE;
3225 	}
3226 
3227 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3228 		RETURN_FALSE;
3229 	}
3230 
3231 	if ((argc == 3) && (flags & FT_UID)) {
3232 		/* This should be cached; if it causes an extra RTT to the
3233 		   IMAP server, then that's the price we pay for making sure
3234 		   we don't crash. */
3235 		msgindex = mail_msgno(imap_le_struct->imap_stream, msgno);
3236 	} else {
3237 		msgindex = msgno;
3238 	}
3239 
3240 	PHP_IMAP_CHECK_MSGNO(msgindex);
3241 
3242 	RETVAL_STRING(mail_fetchheader_full(imap_le_struct->imap_stream, msgno, NIL, NIL, (argc == 3 ? flags : NIL)));
3243 }
3244 /* }}} */
3245 
3246 /* {{{ proto int imap_uid(resource stream_id, int msg_no)
3247    Get the unique message id associated with a standard sequential message number */
PHP_FUNCTION(imap_uid)3248 PHP_FUNCTION(imap_uid)
3249 {
3250 	zval *streamind;
3251 	zend_long msgno;
3252 	pils *imap_le_struct;
3253 	int msgindex;
3254 
3255 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &streamind, &msgno) == FAILURE) {
3256 		return;
3257 	}
3258 
3259 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3260 		RETURN_FALSE;
3261 	}
3262 
3263 	msgindex = msgno;
3264 	if ((msgindex < 1) || ((unsigned) msgindex > imap_le_struct->imap_stream->nmsgs)) {
3265 		php_error_docref(NULL, E_WARNING, "Bad message number");
3266 		RETURN_FALSE;
3267 	}
3268 
3269 	RETURN_LONG(mail_uid(imap_le_struct->imap_stream, msgno));
3270 }
3271 /* }}} */
3272 
3273 /* {{{ proto int imap_msgno(resource stream_id, int unique_msg_id)
3274    Get the sequence number associated with a UID */
PHP_FUNCTION(imap_msgno)3275 PHP_FUNCTION(imap_msgno)
3276 {
3277 	zval *streamind;
3278 	zend_long msgno;
3279 	pils *imap_le_struct;
3280 
3281 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &streamind, &msgno) == FAILURE) {
3282 		return;
3283 	}
3284 
3285 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3286 		RETURN_FALSE;
3287 	}
3288 
3289 	RETURN_LONG(mail_msgno(imap_le_struct->imap_stream, msgno));
3290 }
3291 /* }}} */
3292 
3293 /* {{{ proto object imap_status(resource stream_id, string mailbox, int options)
3294    Get status info from a mailbox */
PHP_FUNCTION(imap_status)3295 PHP_FUNCTION(imap_status)
3296 {
3297 	zval *streamind;
3298 	zend_string *mbx;
3299 	zend_long flags;
3300 	pils *imap_le_struct;
3301 
3302 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSl", &streamind, &mbx, &flags) == FAILURE) {
3303 		return;
3304 	}
3305 
3306 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3307 		RETURN_FALSE;
3308 	}
3309 
3310 	object_init(return_value);
3311 
3312 	if (mail_status(imap_le_struct->imap_stream, ZSTR_VAL(mbx), flags)) {
3313 		add_property_long(return_value, "flags", IMAPG(status_flags));
3314 		if (IMAPG(status_flags) & SA_MESSAGES) {
3315 			add_property_long(return_value, "messages", IMAPG(status_messages));
3316 		}
3317 		if (IMAPG(status_flags) & SA_RECENT) {
3318 			add_property_long(return_value, "recent", IMAPG(status_recent));
3319 		}
3320 		if (IMAPG(status_flags) & SA_UNSEEN) {
3321 			add_property_long(return_value, "unseen", IMAPG(status_unseen));
3322 		}
3323 		if (IMAPG(status_flags) & SA_UIDNEXT) {
3324 			add_property_long(return_value, "uidnext", IMAPG(status_uidnext));
3325 		}
3326 		if (IMAPG(status_flags) & SA_UIDVALIDITY) {
3327 			add_property_long(return_value, "uidvalidity", IMAPG(status_uidvalidity));
3328 		}
3329 	} else {
3330 		RETURN_FALSE;
3331 	}
3332 }
3333 /* }}} */
3334 
3335 /* {{{ proto object imap_bodystruct(resource stream_id, int msg_no, string section)
3336    Read the structure of a specified body section of a specific message */
PHP_FUNCTION(imap_bodystruct)3337 PHP_FUNCTION(imap_bodystruct)
3338 {
3339 	zval *streamind;
3340 	zend_long msg;
3341 	zend_string *section;
3342 	pils *imap_le_struct;
3343 	zval parametres, param, dparametres, dparam;
3344 	PARAMETER *par, *dpar;
3345 	BODY *body;
3346 
3347 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlS", &streamind, &msg, &section) == FAILURE) {
3348 		return;
3349 	}
3350 
3351 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3352 		RETURN_FALSE;
3353 	}
3354 
3355 	if (!msg || msg < 1 || (unsigned) msg > imap_le_struct->imap_stream->nmsgs) {
3356 		php_error_docref(NULL, E_WARNING, "Bad message number");
3357 		RETURN_FALSE;
3358 	}
3359 
3360 	object_init(return_value);
3361 
3362 	body=mail_body(imap_le_struct->imap_stream, msg, (unsigned char*)ZSTR_VAL(section));
3363 	if (body == NULL) {
3364 		zval_dtor(return_value);
3365 		RETURN_FALSE;
3366 	}
3367 	if (body->type <= TYPEMAX) {
3368 		add_property_long(return_value, "type", body->type);
3369 	}
3370 	if (body->encoding <= ENCMAX) {
3371 		add_property_long(return_value, "encoding", body->encoding);
3372 	}
3373 
3374 	if (body->subtype) {
3375 		add_property_long(return_value, "ifsubtype", 1);
3376 		add_property_string(return_value, "subtype", body->subtype);
3377 	} else {
3378 		add_property_long(return_value, "ifsubtype", 0);
3379 	}
3380 
3381 	if (body->description) {
3382 		add_property_long(return_value, "ifdescription", 1);
3383 		add_property_string(return_value, "description", body->description);
3384 	} else {
3385 		add_property_long(return_value, "ifdescription", 0);
3386 	}
3387 	if (body->id) {
3388 		add_property_long(return_value, "ifid", 1);
3389 		add_property_string(return_value, "id", body->id);
3390 	} else {
3391 		add_property_long(return_value, "ifid", 0);
3392 	}
3393 
3394 	if (body->size.lines) {
3395 		add_property_long(return_value, "lines", body->size.lines);
3396 	}
3397 	if (body->size.bytes) {
3398 		add_property_long(return_value, "bytes", body->size.bytes);
3399 	}
3400 #ifdef IMAP41
3401 	if (body->disposition.type) {
3402 		add_property_long(return_value, "ifdisposition", 1);
3403 		add_property_string(return_value, "disposition", body->disposition.type);
3404 	} else {
3405 		add_property_long(return_value, "ifdisposition", 0);
3406 	}
3407 
3408 	if (body->disposition.parameter) {
3409 		dpar = body->disposition.parameter;
3410 		add_property_long(return_value, "ifdparameters", 1);
3411 		array_init(&dparametres);
3412 		do {
3413 			object_init(&dparam);
3414 			add_property_string(&dparam, "attribute", dpar->attribute);
3415 			add_property_string(&dparam, "value", dpar->value);
3416 			add_next_index_object(&dparametres, &dparam);
3417 		} while ((dpar = dpar->next));
3418 		add_assoc_object(return_value, "dparameters", &dparametres);
3419 	} else {
3420 		add_property_long(return_value, "ifdparameters", 0);
3421 	}
3422 #endif
3423 
3424 	if ((par = body->parameter)) {
3425 		add_property_long(return_value, "ifparameters", 1);
3426 
3427 		array_init(&parametres);
3428 		do {
3429 			object_init(&param);
3430 			if (par->attribute) {
3431 				add_property_string(&param, "attribute", par->attribute);
3432 			}
3433 			if (par->value) {
3434 				add_property_string(&param, "value", par->value);
3435 			}
3436 
3437 			add_next_index_object(&parametres, &param);
3438 		} while ((par = par->next));
3439 	} else {
3440 		object_init(&parametres);
3441 		add_property_long(return_value, "ifparameters", 0);
3442 	}
3443 	add_assoc_object(return_value, "parameters", &parametres);
3444 }
3445 
3446 /* }}} */
3447 
3448 /* {{{ proto array imap_fetch_overview(resource stream_id, string sequence [, int options])
3449    Read an overview of the information in the headers of the given message sequence */
PHP_FUNCTION(imap_fetch_overview)3450 PHP_FUNCTION(imap_fetch_overview)
3451 {
3452 	zval *streamind;
3453 	zend_string *sequence;
3454 	pils *imap_le_struct;
3455 	zval myoverview;
3456 	zend_string *address;
3457 	zend_long status, flags = 0L;
3458 	int argc = ZEND_NUM_ARGS();
3459 
3460 	if (zend_parse_parameters(argc, "rS|l", &streamind, &sequence, &flags) == FAILURE) {
3461 		return;
3462 	}
3463 
3464 	if (flags && ((flags & ~FT_UID) != 0)) {
3465 		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
3466 		RETURN_FALSE;
3467 	}
3468 
3469 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3470 		RETURN_FALSE;
3471 	}
3472 
3473 	array_init(return_value);
3474 
3475 	status = (flags & FT_UID)
3476 		? mail_uid_sequence(imap_le_struct->imap_stream, (unsigned char*)ZSTR_VAL(sequence))
3477 		: mail_sequence(imap_le_struct->imap_stream, (unsigned char*)ZSTR_VAL(sequence));
3478 
3479 	if (status) {
3480 		MESSAGECACHE *elt;
3481 		ENVELOPE *env;
3482 		unsigned long i;
3483 
3484 		for (i = 1; i <= imap_le_struct->imap_stream->nmsgs; i++) {
3485 			if (((elt = mail_elt (imap_le_struct->imap_stream, i))->sequence) &&
3486 				(env = mail_fetch_structure (imap_le_struct->imap_stream, i, NIL, NIL))) {
3487 				object_init(&myoverview);
3488 				if (env->subject) {
3489 					add_property_string(&myoverview, "subject", env->subject);
3490 				}
3491 				if (env->from) {
3492 					env->from->next=NULL;
3493 					address =_php_rfc822_write_address(env->from);
3494 					if (address) {
3495 						add_property_str(&myoverview, "from", address);
3496 					}
3497 				}
3498 				if (env->to) {
3499 					env->to->next = NULL;
3500 					address = _php_rfc822_write_address(env->to);
3501 					if (address) {
3502 						add_property_str(&myoverview, "to", address);
3503 					}
3504 				}
3505 				if (env->date) {
3506 					add_property_string(&myoverview, "date", (char*)env->date);
3507 				}
3508 				if (env->message_id) {
3509 					add_property_string(&myoverview, "message_id", env->message_id);
3510 				}
3511 				if (env->references) {
3512 					add_property_string(&myoverview, "references", env->references);
3513 				}
3514 				if (env->in_reply_to) {
3515 					add_property_string(&myoverview, "in_reply_to", env->in_reply_to);
3516 				}
3517 				add_property_long(&myoverview, "size", elt->rfc822_size);
3518 				add_property_long(&myoverview, "uid", mail_uid(imap_le_struct->imap_stream, i));
3519 				add_property_long(&myoverview, "msgno", i);
3520 				add_property_long(&myoverview, "recent", elt->recent);
3521 				add_property_long(&myoverview, "flagged", elt->flagged);
3522 				add_property_long(&myoverview, "answered", elt->answered);
3523 				add_property_long(&myoverview, "deleted", elt->deleted);
3524 				add_property_long(&myoverview, "seen", elt->seen);
3525 				add_property_long(&myoverview, "draft", elt->draft);
3526 				add_property_long(&myoverview, "udate", mail_longdate(elt));
3527 				add_next_index_object(return_value, &myoverview);
3528 			}
3529 		}
3530 	}
3531 }
3532 /* }}} */
3533 
3534 /* {{{ proto string imap_mail_compose(array envelope, array body)
3535    Create a MIME message based on given envelope and body sections */
PHP_FUNCTION(imap_mail_compose)3536 PHP_FUNCTION(imap_mail_compose)
3537 {
3538 	zval *envelope, *body;
3539 	zend_string *key;
3540 	zval *data, *pvalue, *disp_data, *env_data;
3541 	char *cookie = NIL;
3542 	ENVELOPE *env;
3543 	BODY *bod=NULL, *topbod=NULL;
3544 	PART *mypart=NULL, *part;
3545 	PARAMETER *param, *disp_param = NULL, *custom_headers_param = NULL, *tmp_param = NULL;
3546 	char *tmp=NULL, *mystring=NULL, *t=NULL, *tempstring=NULL, *str_copy = NULL;
3547 	int toppart = 0;
3548 	int first;
3549 
3550 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &envelope, &body) == FAILURE) {
3551 		return;
3552 	}
3553 
3554 #define PHP_RFC822_PARSE_ADRLIST(target, value) \
3555 	str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \
3556 	rfc822_parse_adrlist(target, str_copy, "NO HOST"); \
3557 	efree(str_copy);
3558 
3559 	env = mail_newenvelope();
3560 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) {
3561 		convert_to_string_ex(pvalue);
3562 		env->remail = cpystr(Z_STRVAL_P(pvalue));
3563 	}
3564 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) {
3565 		convert_to_string_ex(pvalue);
3566 		PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue);
3567 	}
3568 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) {
3569 		convert_to_string_ex(pvalue);
3570 		env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue));
3571 	}
3572 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) {
3573 		convert_to_string_ex(pvalue);
3574 		PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue);
3575 	}
3576 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) {
3577 		convert_to_string_ex(pvalue);
3578 		PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue);
3579 	}
3580 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) {
3581 		convert_to_string_ex(pvalue);
3582 		env->in_reply_to = cpystr(Z_STRVAL_P(pvalue));
3583 	}
3584 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) {
3585 		convert_to_string_ex(pvalue);
3586 		env->subject = cpystr(Z_STRVAL_P(pvalue));
3587 	}
3588 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) {
3589 		convert_to_string_ex(pvalue);
3590 		PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue);
3591 	}
3592 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) {
3593 		convert_to_string_ex(pvalue);
3594 		PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue);
3595 	}
3596 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) {
3597 		convert_to_string_ex(pvalue);
3598 		PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue);
3599 	}
3600 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) {
3601 		convert_to_string_ex(pvalue);
3602 		env->message_id=cpystr(Z_STRVAL_P(pvalue));
3603 	}
3604 
3605 	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "custom_headers", sizeof("custom_headers") - 1)) != NULL) {
3606 		if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3607 			custom_headers_param = tmp_param = NULL;
3608 			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) {
3609 				custom_headers_param = mail_newbody_parameter();
3610 				convert_to_string_ex(env_data);
3611 				custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1);
3612 				custom_headers_param->attribute = NULL;
3613 				memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1);
3614 				custom_headers_param->next = tmp_param;
3615 				tmp_param = custom_headers_param;
3616 			} ZEND_HASH_FOREACH_END();
3617 		}
3618 	}
3619 
3620 	first = 1;
3621 	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(body), data) {
3622 		if (first) {
3623 			first = 0;
3624 
3625 			if (Z_TYPE_P(data) != IS_ARRAY) {
3626 				php_error_docref(NULL, E_WARNING, "body parameter must be a non-empty array");
3627 				RETURN_FALSE;
3628 			}
3629 
3630 			bod = mail_newbody();
3631 			topbod = bod;
3632 
3633 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type", sizeof("type") - 1)) != NULL) {
3634 				convert_to_long_ex(pvalue);
3635 				bod->type = (short) Z_LVAL_P(pvalue);
3636 			}
3637 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "encoding", sizeof("encoding") - 1)) != NULL) {
3638 				convert_to_long_ex(pvalue);
3639 				bod->encoding = (short) Z_LVAL_P(pvalue);
3640 			}
3641 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
3642 				convert_to_string_ex(pvalue);
3643 				tmp_param = mail_newbody_parameter();
3644 				tmp_param->value = cpystr(Z_STRVAL_P(pvalue));
3645 				tmp_param->attribute = cpystr("CHARSET");
3646 				tmp_param->next = bod->parameter;
3647 				bod->parameter = tmp_param;
3648 			}
3649 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type.parameters", sizeof("type.parameters") - 1)) != NULL) {
3650 				if(Z_TYPE_P(pvalue) == IS_ARRAY) {
3651 					disp_param = tmp_param = NULL;
3652 					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3653 						disp_param = mail_newbody_parameter();
3654 						disp_param->attribute = cpystr(ZSTR_VAL(key));
3655 						convert_to_string_ex(disp_data);
3656 						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
3657 						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3658 						disp_param->next = tmp_param;
3659 						tmp_param = disp_param;
3660 					} ZEND_HASH_FOREACH_END();
3661 					bod->parameter = disp_param;
3662 				}
3663 			}
3664 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
3665 				convert_to_string_ex(pvalue);
3666 				bod->subtype = cpystr(Z_STRVAL_P(pvalue));
3667 			}
3668 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
3669 				convert_to_string_ex(pvalue);
3670 				bod->id = cpystr(Z_STRVAL_P(pvalue));
3671 			}
3672 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
3673 				convert_to_string_ex(pvalue);
3674 				bod->description = cpystr(Z_STRVAL_P(pvalue));
3675 			}
3676 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
3677 				convert_to_string_ex(pvalue);
3678 				bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
3679 				memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
3680 			}
3681 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition", sizeof("disposition") - 1)) != NULL) {
3682 				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3683 					disp_param = tmp_param = NULL;
3684 					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3685 						disp_param = mail_newbody_parameter();
3686 						disp_param->attribute = cpystr(ZSTR_VAL(key));
3687 						convert_to_string_ex(disp_data);
3688 						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
3689 						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3690 						disp_param->next = tmp_param;
3691 						tmp_param = disp_param;
3692 					} ZEND_HASH_FOREACH_END();
3693 					bod->disposition.parameter = disp_param;
3694 				}
3695 			}
3696 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "contents.data", sizeof("contents.data") - 1)) != NULL) {
3697 				convert_to_string_ex(pvalue);
3698 				bod->contents.text.data = fs_get(Z_STRLEN_P(pvalue) + 1);
3699 				memcpy(bod->contents.text.data, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
3700 				bod->contents.text.size = Z_STRLEN_P(pvalue);
3701 			} else {
3702 				bod->contents.text.data = fs_get(1);
3703 				memcpy(bod->contents.text.data, "", 1);
3704 				bod->contents.text.size = 0;
3705 			}
3706 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "lines", sizeof("lines") - 1)) != NULL) {
3707 				convert_to_long_ex(pvalue);
3708 				bod->size.lines = Z_LVAL_P(pvalue);
3709 			}
3710 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "bytes", sizeof("bytes") - 1)) != NULL) {
3711 				convert_to_long_ex(pvalue);
3712 				bod->size.bytes = Z_LVAL_P(pvalue);
3713 			}
3714 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
3715 				convert_to_string_ex(pvalue);
3716 				bod->md5 = cpystr(Z_STRVAL_P(pvalue));
3717 			}
3718 		} else if (Z_TYPE_P(data) == IS_ARRAY) {
3719 			short type = -1;
3720 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type", sizeof("type") - 1)) != NULL) {
3721 				convert_to_long_ex(pvalue);
3722 				type = (short) Z_LVAL_P(pvalue);
3723 			}
3724 
3725 			if (!toppart) {
3726 				bod->nested.part = mail_newbody_part();
3727 				mypart = bod->nested.part;
3728 				toppart = 1;
3729 			} else {
3730 				mypart->next = mail_newbody_part();
3731 				mypart = mypart->next;
3732 			}
3733 
3734 			bod = &mypart->body;
3735 
3736 			if (type != TYPEMULTIPART) {
3737 				bod->type = type;
3738 			}
3739 
3740 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "encoding", sizeof("encoding") - 1)) != NULL) {
3741 				convert_to_long_ex(pvalue);
3742 				bod->encoding = (short) Z_LVAL_P(pvalue);
3743 			}
3744 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
3745 				convert_to_string_ex(pvalue);
3746 				tmp_param = mail_newbody_parameter();
3747 				tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
3748 				memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
3749 				tmp_param->attribute = cpystr("CHARSET");
3750 				tmp_param->next = bod->parameter;
3751 				bod->parameter = tmp_param;
3752 			}
3753 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type.parameters", sizeof("type.parameters") - 1)) != NULL) {
3754 				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3755 					disp_param = tmp_param = NULL;
3756 					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3757 						disp_param = mail_newbody_parameter();
3758 						disp_param->attribute = cpystr(ZSTR_VAL(key));
3759 						convert_to_string_ex(disp_data);
3760 						disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1);
3761 						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3762 						disp_param->next = tmp_param;
3763 						tmp_param = disp_param;
3764 					} ZEND_HASH_FOREACH_END();
3765 					bod->parameter = disp_param;
3766 				}
3767 			}
3768 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
3769 				convert_to_string_ex(pvalue);
3770 				bod->subtype = cpystr(Z_STRVAL_P(pvalue));
3771 			}
3772 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
3773 				convert_to_string_ex(pvalue);
3774 				bod->id = cpystr(Z_STRVAL_P(pvalue));
3775 			}
3776 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
3777 				convert_to_string_ex(pvalue);
3778 				bod->description = cpystr(Z_STRVAL_P(pvalue));
3779 			}
3780 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
3781 				convert_to_string_ex(pvalue);
3782 				bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
3783 				memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
3784 			}
3785 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition", sizeof("disposition") - 1)) != NULL) {
3786 				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3787 					disp_param = tmp_param = NULL;
3788 					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3789 						disp_param = mail_newbody_parameter();
3790 						disp_param->attribute = cpystr(ZSTR_VAL(key));
3791 						convert_to_string_ex(disp_data);
3792 						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
3793 						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3794 						disp_param->next = tmp_param;
3795 						tmp_param = disp_param;
3796 					} ZEND_HASH_FOREACH_END();
3797 					bod->disposition.parameter = disp_param;
3798 				}
3799 			}
3800 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "contents.data", sizeof("contents.data") - 1)) != NULL) {
3801 				convert_to_string_ex(pvalue);
3802 				bod->contents.text.data = fs_get(Z_STRLEN_P(pvalue) + 1);
3803 				memcpy(bod->contents.text.data, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
3804 				bod->contents.text.size = Z_STRLEN_P(pvalue);
3805 			} else {
3806 				bod->contents.text.data = fs_get(1);
3807 				memcpy(bod->contents.text.data, "", 1);
3808 				bod->contents.text.size = 0;
3809 			}
3810 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "lines", sizeof("lines") - 1)) != NULL) {
3811 				convert_to_long_ex(pvalue);
3812 				bod->size.lines = Z_LVAL_P(pvalue);
3813 			}
3814 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "bytes", sizeof("bytes") - 1)) != NULL) {
3815 				convert_to_long_ex(pvalue);
3816 				bod->size.bytes = Z_LVAL_P(pvalue);
3817 			}
3818 			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
3819 				convert_to_string_ex(pvalue);
3820 				bod->md5 = cpystr(Z_STRVAL_P(pvalue));
3821 			}
3822 		}
3823 	} ZEND_HASH_FOREACH_END();
3824 
3825 	if (first) {
3826 		php_error_docref(NULL, E_WARNING, "body parameter must be a non-empty array");
3827 		RETURN_FALSE;
3828 	}
3829 
3830 	if (bod && bod->type == TYPEMULTIPART && (!bod->nested.part || !bod->nested.part->next)) {
3831 		php_error_docref(NULL, E_WARNING, "cannot generate multipart e-mail without components.");
3832 		RETVAL_FALSE;
3833 		goto done;
3834 	}
3835 
3836 	rfc822_encode_body_7bit(env, topbod);
3837 
3838 	tmp = emalloc(SENDBUFLEN + 1);
3839 
3840 	rfc822_header(tmp, env, topbod);
3841 
3842 	/* add custom envelope headers */
3843 	if (custom_headers_param) {
3844 		int l = strlen(tmp) - 2, l2;
3845 		PARAMETER *tp = custom_headers_param;
3846 
3847 		/* remove last CRLF from tmp */
3848 		tmp[l] = '\0';
3849 		tempstring = emalloc(l);
3850 		memcpy(tempstring, tmp, l);
3851 
3852 		do {
3853 			l2 = strlen(custom_headers_param->value);
3854 			tempstring = erealloc(tempstring, l + l2 + CRLF_LEN + 1);
3855 			memcpy(tempstring + l, custom_headers_param->value, l2);
3856 			memcpy(tempstring + l + l2, CRLF, CRLF_LEN);
3857 			l += l2 + CRLF_LEN;
3858 		} while ((custom_headers_param = custom_headers_param->next));
3859 
3860 		mail_free_body_parameter(&tp);
3861 
3862 		mystring = emalloc(l + CRLF_LEN + 1);
3863 		memcpy(mystring, tempstring, l);
3864 		memcpy(mystring + l , CRLF, CRLF_LEN);
3865 		mystring[l + CRLF_LEN] = '\0';
3866 
3867 		efree(tempstring);
3868 	} else {
3869 		mystring = estrdup(tmp);
3870 	}
3871 
3872 	bod = topbod;
3873 
3874 	if (bod && bod->type == TYPEMULTIPART) {
3875 
3876 		/* first body part */
3877 			part = bod->nested.part;
3878 
3879 		/* find cookie */
3880 			for (param = bod->parameter; param && !cookie; param = param->next) {
3881 				if (!strcmp (param->attribute, "BOUNDARY")) {
3882 					cookie = param->value;
3883 				}
3884 			}
3885 
3886 		/* yucky default */
3887 			if (!cookie) {
3888 				cookie = "-";
3889 			} else if (strlen(cookie) > (SENDBUFLEN - 2 - 2 - 2)) { /* validate cookie length -- + CRLF * 2 */
3890 				php_error_docref(NULL, E_WARNING, "The boundary should be no longer than 4kb");
3891 				RETVAL_FALSE;
3892 				goto done;
3893 			}
3894 
3895 		/* for each part */
3896 			do {
3897 				t = tmp;
3898 
3899 			/* append mini-header */
3900 				*t = '\0';
3901 				rfc822_write_body_header(&t, &part->body);
3902 
3903 			/* output cookie, mini-header, and contents */
3904 				spprintf(&tempstring, 0, "%s--%s%s%s%s", mystring, cookie, CRLF, tmp, CRLF);
3905 				efree(mystring);
3906 				mystring=tempstring;
3907 
3908 				bod=&part->body;
3909 
3910 				spprintf(&tempstring, 0, "%s%s%s", mystring, bod->contents.text.data, CRLF);
3911 				efree(mystring);
3912 				mystring=tempstring;
3913 			} while ((part = part->next)); /* until done */
3914 
3915 			/* output trailing cookie */
3916 			spprintf(&tempstring, 0, "%s--%s--%s", mystring, cookie, CRLF);
3917 			efree(mystring);
3918 			mystring=tempstring;
3919 	} else if (bod) {
3920 		spprintf(&tempstring, 0, "%s%s%s", mystring, bod->contents.text.data, CRLF);
3921 		efree(mystring);
3922 		mystring=tempstring;
3923 	} else {
3924 		efree(mystring);
3925 		RETVAL_FALSE;
3926 		goto done;
3927 	}
3928 
3929 	RETVAL_STRING(tempstring);
3930 	efree(tempstring);
3931 done:
3932 	if (tmp) {
3933 		efree(tmp);
3934 	}
3935 	mail_free_body(&topbod);
3936 	mail_free_envelope(&env);
3937 }
3938 /* }}} */
3939 
3940 /* {{{ _php_imap_mail
3941  */
_php_imap_mail(char * to,char * subject,char * message,char * headers,char * cc,char * bcc,char * rpath)3942 int _php_imap_mail(char *to, char *subject, char *message, char *headers, char *cc, char *bcc, char* rpath)
3943 {
3944 #ifdef PHP_WIN32
3945 	int tsm_err;
3946 #else
3947 	FILE *sendmail;
3948 	int ret;
3949 #endif
3950 
3951 #ifdef PHP_WIN32
3952 	char *tempMailTo;
3953 	char *tsm_errmsg = NULL;
3954 	ADDRESS *addr;
3955 	char *bufferTo = NULL, *bufferCc = NULL, *bufferBcc = NULL, *bufferHeader = NULL;
3956 	size_t offset, bufferLen = 0;
3957 	size_t bt_len;
3958 
3959 	if (headers) {
3960 		bufferLen += strlen(headers);
3961 	}
3962 	if (to) {
3963 		bufferLen += strlen(to) + 6;
3964 	}
3965 	if (cc) {
3966 		bufferLen += strlen(cc) + 6;
3967 	}
3968 
3969 #define PHP_IMAP_CLEAN	if (bufferTo) efree(bufferTo); if (bufferCc) efree(bufferCc); if (bufferBcc) efree(bufferBcc); if (bufferHeader) efree(bufferHeader);
3970 #define PHP_IMAP_BAD_DEST PHP_IMAP_CLEAN; efree(tempMailTo); return (BAD_MSG_DESTINATION);
3971 
3972 	bufferHeader = (char *)safe_emalloc(bufferLen, 1, 1);
3973 	memset(bufferHeader, 0, bufferLen);
3974 	if (to && *to) {
3975 		strlcat(bufferHeader, "To: ", bufferLen + 1);
3976 		strlcat(bufferHeader, to, bufferLen + 1);
3977 		strlcat(bufferHeader, "\r\n", bufferLen + 1);
3978 		tempMailTo = estrdup(to);
3979 		bt_len = strlen(to);
3980 		bufferTo = (char *)safe_emalloc(bt_len, 1, 1);
3981 		bt_len++;
3982 		offset = 0;
3983 		addr = NULL;
3984 		rfc822_parse_adrlist(&addr, tempMailTo, "NO HOST");
3985 		while (addr) {
3986 			if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) {
3987 				PHP_IMAP_BAD_DEST;
3988 			} else {
3989 				bufferTo = safe_erealloc(bufferTo, bt_len, 1, strlen(addr->mailbox));
3990 				bt_len += strlen(addr->mailbox);
3991 				bufferTo = safe_erealloc(bufferTo, bt_len, 1, strlen(addr->host));
3992 				bt_len += strlen(addr->host);
3993 				offset += slprintf(bufferTo + offset, bt_len - offset, "%s@%s,", addr->mailbox, addr->host);
3994 			}
3995 			addr = addr->next;
3996 		}
3997 		efree(tempMailTo);
3998 		if (offset>0) {
3999 			bufferTo[offset-1] = 0;
4000 		}
4001 	}
4002 
4003 	if (cc && *cc) {
4004 		strlcat(bufferHeader, "Cc: ", bufferLen + 1);
4005 		strlcat(bufferHeader, cc, bufferLen + 1);
4006 		strlcat(bufferHeader, "\r\n", bufferLen + 1);
4007 		tempMailTo = estrdup(cc);
4008 		bt_len = strlen(cc);
4009 		bufferCc = (char *)safe_emalloc(bt_len, 1, 1);
4010 		bt_len++;
4011 		offset = 0;
4012 		addr = NULL;
4013 		rfc822_parse_adrlist(&addr, tempMailTo, "NO HOST");
4014 		while (addr) {
4015 			if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) {
4016 				PHP_IMAP_BAD_DEST;
4017 			} else {
4018 				bufferCc = safe_erealloc(bufferCc, bt_len, 1, strlen(addr->mailbox));
4019 				bt_len += strlen(addr->mailbox);
4020 				bufferCc = safe_erealloc(bufferCc, bt_len, 1, strlen(addr->host));
4021 				bt_len += strlen(addr->host);
4022 				offset += slprintf(bufferCc + offset, bt_len - offset, "%s@%s,", addr->mailbox, addr->host);
4023 			}
4024 			addr = addr->next;
4025 		}
4026 		efree(tempMailTo);
4027 		if (offset>0) {
4028 			bufferCc[offset-1] = 0;
4029 		}
4030 	}
4031 
4032 	if (bcc && *bcc) {
4033 		tempMailTo = estrdup(bcc);
4034 		bt_len = strlen(bcc);
4035 		bufferBcc = (char *)safe_emalloc(bt_len, 1, 1);
4036 		bt_len++;
4037 		offset = 0;
4038 		addr = NULL;
4039 		rfc822_parse_adrlist(&addr, tempMailTo, "NO HOST");
4040 		while (addr) {
4041 			if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) {
4042 				PHP_IMAP_BAD_DEST;
4043 			} else {
4044 				bufferBcc = safe_erealloc(bufferBcc, bt_len, 1, strlen(addr->mailbox));
4045 				bt_len += strlen(addr->mailbox);
4046 				bufferBcc = safe_erealloc(bufferBcc, bt_len, 1, strlen(addr->host));
4047 				bt_len += strlen(addr->host);
4048 				offset += slprintf(bufferBcc + offset, bt_len - offset, "%s@%s,", addr->mailbox, addr->host);
4049 			}
4050 			addr = addr->next;
4051 		}
4052 		efree(tempMailTo);
4053 		if (offset>0) {
4054 			bufferBcc[offset-1] = 0;
4055 		}
4056 	}
4057 
4058 	if (headers && *headers) {
4059 		strlcat(bufferHeader, headers, bufferLen + 1);
4060 	}
4061 
4062 	if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, bufferHeader, subject, bufferTo, message, bufferCc, bufferBcc, rpath) != SUCCESS) {
4063 		if (tsm_errmsg) {
4064 			php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg);
4065 			efree(tsm_errmsg);
4066 		} else {
4067 			php_error_docref(NULL, E_WARNING, "%s", GetSMErrorText(tsm_err));
4068 		}
4069 		PHP_IMAP_CLEAN;
4070 		return 0;
4071 	}
4072 	PHP_IMAP_CLEAN;
4073 #else
4074 	if (!INI_STR("sendmail_path")) {
4075 		return 0;
4076 	}
4077 	sendmail = popen(INI_STR("sendmail_path"), "w");
4078 	if (sendmail) {
4079 		if (rpath && rpath[0]) fprintf(sendmail, "From: %s\n", rpath);
4080 		fprintf(sendmail, "To: %s\n", to);
4081 		if (cc && cc[0]) fprintf(sendmail, "Cc: %s\n", cc);
4082 		if (bcc && bcc[0]) fprintf(sendmail, "Bcc: %s\n", bcc);
4083 		fprintf(sendmail, "Subject: %s\n", subject);
4084 		if (headers != NULL) {
4085 			fprintf(sendmail, "%s\n", headers);
4086 		}
4087 		fprintf(sendmail, "\n%s\n", message);
4088 		ret = pclose(sendmail);
4089 		if (ret == -1) {
4090 			return 0;
4091 		} else {
4092 			return 1;
4093 		}
4094 	} else {
4095 		php_error_docref(NULL, E_WARNING, "Could not execute mail delivery program");
4096 		return 0;
4097 	}
4098 #endif
4099 	return 1;
4100 }
4101 /* }}} */
4102 
4103 /* {{{ proto bool imap_mail(string to, string subject, string message [, string additional_headers [, string cc [, string bcc [, string rpath]]]])
4104    Send an email message */
PHP_FUNCTION(imap_mail)4105 PHP_FUNCTION(imap_mail)
4106 {
4107 	zend_string *to=NULL, *message=NULL, *headers=NULL, *subject=NULL, *cc=NULL, *bcc=NULL, *rpath=NULL;
4108 	int argc = ZEND_NUM_ARGS();
4109 
4110 	if (zend_parse_parameters(argc, "SSS|SSSS", &to, &subject, &message,
4111 		&headers, &cc, &bcc, &rpath) == FAILURE) {
4112 		return;
4113 	}
4114 
4115 	/* To: */
4116 	if (!ZSTR_LEN(to)) {
4117 		php_error_docref(NULL, E_WARNING, "No to field in mail command");
4118 		RETURN_FALSE;
4119 	}
4120 
4121 	/* Subject: */
4122 	if (!ZSTR_LEN(subject)) {
4123 		php_error_docref(NULL, E_WARNING, "No subject field in mail command");
4124 		RETURN_FALSE;
4125 	}
4126 
4127 	/* message body */
4128 	if (!ZSTR_LEN(message)) {
4129 		/* this is not really an error, so it is allowed. */
4130 		php_error_docref(NULL, E_WARNING, "No message string in mail command");
4131 	}
4132 
4133 	if (_php_imap_mail(ZSTR_VAL(to), ZSTR_VAL(subject), ZSTR_VAL(message), headers?ZSTR_VAL(headers):NULL, cc?ZSTR_VAL(cc):NULL,
4134 			bcc?ZSTR_VAL(bcc):NULL, rpath?ZSTR_VAL(rpath):NULL)) {
4135 		RETURN_TRUE;
4136 	} else {
4137 		RETURN_FALSE;
4138 	}
4139 }
4140 /* }}} */
4141 
4142 /* {{{ proto array imap_search(resource stream_id, string criteria [, int options [, string charset]])
4143    Return a list of messages matching the given criteria */
PHP_FUNCTION(imap_search)4144 PHP_FUNCTION(imap_search)
4145 {
4146 	zval *streamind;
4147 	zend_string *criteria, *charset = NULL;
4148 	zend_long flags = SE_FREE;
4149 	pils *imap_le_struct;
4150 	char *search_criteria;
4151 	MESSAGELIST *cur;
4152 	int argc = ZEND_NUM_ARGS();
4153 	SEARCHPGM *pgm = NIL;
4154 
4155 	if (zend_parse_parameters(argc, "rS|lS", &streamind, &criteria, &flags, &charset) == FAILURE) {
4156 		return;
4157 	}
4158 
4159 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
4160 		RETURN_FALSE;
4161 	}
4162 
4163 	search_criteria = estrndup(ZSTR_VAL(criteria), ZSTR_LEN(criteria));
4164 
4165 	IMAPG(imap_messages) = IMAPG(imap_messages_tail) = NIL;
4166 	pgm = mail_criteria(search_criteria);
4167 
4168 	mail_search_full(imap_le_struct->imap_stream, (argc == 4 ? ZSTR_VAL(charset) : NIL), pgm, flags);
4169 
4170 	if (pgm && !(flags & SE_FREE)) {
4171 		mail_free_searchpgm(&pgm);
4172 	}
4173 
4174 	if (IMAPG(imap_messages) == NIL) {
4175 		efree(search_criteria);
4176 		RETURN_FALSE;
4177 	}
4178 
4179 	array_init(return_value);
4180 
4181 	cur = IMAPG(imap_messages);
4182 	while (cur != NIL) {
4183 		add_next_index_long(return_value, cur->msgid);
4184 		cur = cur->next;
4185 	}
4186 	mail_free_messagelist(&IMAPG(imap_messages), &IMAPG(imap_messages_tail));
4187 	efree(search_criteria);
4188 }
4189 /* }}} */
4190 
4191 /* {{{ proto array imap_alerts(void)
4192    Returns an array of all IMAP alerts that have been generated since the last page load or since the last imap_alerts() call, whichever came last. The alert stack is cleared after imap_alerts() is called. */
4193 /* Author: CJH */
PHP_FUNCTION(imap_alerts)4194 PHP_FUNCTION(imap_alerts)
4195 {
4196 	STRINGLIST *cur=NIL;
4197 
4198 	if (zend_parse_parameters_none() == FAILURE) {
4199 		return;
4200 	}
4201 
4202 	if (IMAPG(imap_alertstack) == NIL) {
4203 		RETURN_FALSE;
4204 	}
4205 
4206 	array_init(return_value);
4207 
4208 	cur = IMAPG(imap_alertstack);
4209 	while (cur != NIL) {
4210 		add_next_index_string(return_value, (char*)cur->LTEXT);
4211 		cur = cur->next;
4212 	}
4213 	mail_free_stringlist(&IMAPG(imap_alertstack));
4214 	IMAPG(imap_alertstack) = NIL;
4215 }
4216 /* }}} */
4217 
4218 /* {{{ proto array imap_errors(void)
4219    Returns an array of all IMAP errors generated since the last page load, or since the last imap_errors() call, whichever came last. The error stack is cleared after imap_errors() is called. */
4220 /* Author: CJH */
PHP_FUNCTION(imap_errors)4221 PHP_FUNCTION(imap_errors)
4222 {
4223 	ERRORLIST *cur=NIL;
4224 
4225 	if (zend_parse_parameters_none() == FAILURE) {
4226 		return;
4227 	}
4228 
4229 	if (IMAPG(imap_errorstack) == NIL) {
4230 		RETURN_FALSE;
4231 	}
4232 
4233 	array_init(return_value);
4234 
4235 	cur = IMAPG(imap_errorstack);
4236 	while (cur != NIL) {
4237 		add_next_index_string(return_value, (char*)cur->LTEXT);
4238 		cur = cur->next;
4239 	}
4240 	mail_free_errorlist(&IMAPG(imap_errorstack));
4241 	IMAPG(imap_errorstack) = NIL;
4242 }
4243 /* }}} */
4244 
4245 /* {{{ proto string imap_last_error(void)
4246    Returns the last error that was generated by an IMAP function. The error stack is NOT cleared after this call. */
4247 /* Author: CJH */
PHP_FUNCTION(imap_last_error)4248 PHP_FUNCTION(imap_last_error)
4249 {
4250 	ERRORLIST *cur=NIL;
4251 
4252 	if (zend_parse_parameters_none() == FAILURE) {
4253 		return;
4254 	}
4255 
4256 	if (IMAPG(imap_errorstack) == NIL) {
4257 		RETURN_FALSE;
4258 	}
4259 
4260 	cur = IMAPG(imap_errorstack);
4261 	while (cur != NIL) {
4262 		if (cur->next == NIL) {
4263 			RETURN_STRING((char*)cur->LTEXT);
4264 		}
4265 		cur = cur->next;
4266 	}
4267 }
4268 /* }}} */
4269 
4270 /* {{{ proto array imap_mime_header_decode(string str)
4271    Decode mime header element in accordance with RFC 2047 and return array of objects containing 'charset' encoding and decoded 'text' */
PHP_FUNCTION(imap_mime_header_decode)4272 PHP_FUNCTION(imap_mime_header_decode)
4273 {
4274 	/* Author: Ted Parnefors <ted@mtv.se> */
4275 	zval myobject;
4276 	zend_string *str;
4277 	char *string, *charset, encoding, *text, *decode;
4278 	zend_long charset_token, encoding_token, end_token, end, offset=0, i;
4279 	unsigned long newlength;
4280 
4281 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
4282 		return;
4283 	}
4284 
4285 	array_init(return_value);
4286 
4287 	string = ZSTR_VAL(str);
4288 	end = ZSTR_LEN(str);
4289 
4290 	charset = (char *) safe_emalloc((end + 1), 2, 0);
4291 	text = &charset[end + 1];
4292 	while (offset < end) {	/* Reached end of the string? */
4293 		if ((charset_token = (zend_long)php_memnstr(&string[offset], "=?", 2, string + end))) {	/* Is there anything encoded in the string? */
4294 			charset_token -= (zend_long)string;
4295 			if (offset != charset_token) {	/* Is there anything before the encoded data? */
4296 				/* Retrieve unencoded data that is found before encoded data */
4297 				memcpy(text, &string[offset], charset_token-offset);
4298 				text[charset_token - offset] = 0x00;
4299 				object_init(&myobject);
4300 				add_property_string(&myobject, "charset", "default");
4301 				add_property_string(&myobject, "text", text);
4302 				zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &myobject);
4303 			}
4304 			if ((encoding_token = (zend_long)php_memnstr(&string[charset_token+2], "?", 1, string+end))) {		/* Find token for encoding */
4305 				encoding_token -= (zend_long)string;
4306 				if ((end_token = (zend_long)php_memnstr(&string[encoding_token+3], "?=", 2, string+end))) {	/* Find token for end of encoded data */
4307 					end_token -= (zend_long)string;
4308 					memcpy(charset, &string[charset_token + 2], encoding_token - (charset_token + 2));	/* Extract charset encoding */
4309 					charset[encoding_token-(charset_token + 2)] = 0x00;
4310 					encoding=string[encoding_token + 1];	/* Extract encoding from string */
4311 					memcpy(text, &string[encoding_token + 3], end_token - (encoding_token + 3));	/* Extract text */
4312 					text[end_token - (encoding_token + 3)] = 0x00;
4313 					decode = text;
4314 					if (encoding == 'q' || encoding == 'Q') {	/* Decode 'q' encoded data */
4315 						for(i=0; text[i] != 0x00; i++) if (text[i] == '_') text[i] = ' ';	/* Replace all *_' with space. */
4316 						decode = (char *)rfc822_qprint((unsigned char *) text, strlen(text), &newlength);
4317 					} else if (encoding == 'b' || encoding == 'B') {
4318 						decode = (char *)rfc822_base64((unsigned char *) text, strlen(text), &newlength); /* Decode 'B' encoded data */
4319 					}
4320 					if (decode == NULL) {
4321 						efree(charset);
4322 						zval_dtor(return_value);
4323 						RETURN_FALSE;
4324 					}
4325 					object_init(&myobject);
4326 					add_property_string(&myobject, "charset", charset);
4327 					add_property_string(&myobject, "text", decode);
4328 					zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &myobject);
4329 
4330 					/* only free decode if it was allocated by rfc822_qprint or rfc822_base64 */
4331 					if (decode != text) {
4332 						fs_give((void**)&decode);
4333 					}
4334 
4335 					offset = end_token+2;
4336 					for (i = 0; (string[offset + i] == ' ') || (string[offset + i] == 0x0a) || (string[offset + i] == 0x0d) || (string[offset + i] == '\t'); i++);
4337 					if ((string[offset + i] == '=') && (string[offset + i + 1] == '?') && (offset + i < end)) {
4338 						offset += i;
4339 					}
4340 					continue;	/*/ Iterate the loop again please. */
4341 				}
4342 			}
4343 		} else {
4344 			/* Just some tweaking to optimize the code, and get the end statements work in a general manner.
4345 			 * If we end up here we didn't find a position for "charset_token",
4346 			 * so we need to set it to the start of the yet unextracted data.
4347 			 */
4348 			charset_token = offset;
4349 		}
4350 		/* Return the rest of the data as unencoded, as it was either unencoded or was missing separators
4351 		   which rendered the remainder of the string impossible for us to decode. */
4352 		memcpy(text, &string[charset_token], end - charset_token);	/* Extract unencoded text from string */
4353 		text[end - charset_token] = 0x00;
4354 		object_init(&myobject);
4355 		add_property_string(&myobject, "charset", "default");
4356 		add_property_string(&myobject, "text", text);
4357 		zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &myobject);
4358 
4359 		offset = end;	/* We have reached the end of the string. */
4360 	}
4361 	efree(charset);
4362 }
4363 /* }}} */
4364 
4365 /* Support Functions */
4366 
4367 #ifdef HAVE_RFC822_OUTPUT_ADDRESS_LIST
4368 /* {{{ _php_rfc822_soutr
4369  */
_php_rfc822_soutr(void * stream,char * string)4370 static long _php_rfc822_soutr (void *stream, char *string)
4371 {
4372 	smart_str *ret = (smart_str*)stream;
4373 	int len = strlen(string);
4374 
4375 	smart_str_appendl(ret, string, len);
4376 	return LONGT;
4377 }
4378 /* }}} */
4379 
4380 /* {{{ _php_rfc822_write_address
4381  */
_php_rfc822_write_address(ADDRESS * addresslist)4382 static zend_string* _php_rfc822_write_address(ADDRESS *addresslist)
4383 {
4384 	char address[MAILTMPLEN];
4385 	smart_str ret = {0};
4386 	RFC822BUFFER buf;
4387 
4388 	buf.beg = address;
4389 	buf.cur = buf.beg;
4390 	buf.end = buf.beg + sizeof(address) - 1;
4391 	buf.s = &ret;
4392 	buf.f = _php_rfc822_soutr;
4393 	rfc822_output_address_list(&buf, addresslist, 0, NULL);
4394 	rfc822_output_flush(&buf);
4395 	smart_str_0(&ret);
4396 	return ret.s;
4397 }
4398 /* }}} */
4399 
4400 #else
4401 
4402 /* {{{ _php_rfc822_len
4403  * Calculate string length based on imap's rfc822_cat function.
4404  */
_php_rfc822_len(char * str)4405 static int _php_rfc822_len(char *str)
4406 {
4407 	int len;
4408 	char *p;
4409 
4410 	if (!str || !*str) {
4411 		return 0;
4412 	}
4413 
4414 	/* strings with special characters will need to be quoted, as a safety measure we
4415 	 * add 2 bytes for the quotes just in case.
4416 	 */
4417 	len = strlen(str) + 2;
4418 	p = str;
4419 	/* rfc822_cat() will escape all " and \ characters, therefor we need to increase
4420 	 * our buffer length to account for these characters.
4421 	 */
4422 	while ((p = strpbrk(p, "\\\""))) {
4423 		p++;
4424 		len++;
4425 	}
4426 
4427 	return len;
4428 }
4429 /* }}} */
4430 
4431 /* {{{ _php_imap_get_address_size
4432  */
_php_imap_address_size(ADDRESS * addresslist)4433 static int _php_imap_address_size (ADDRESS *addresslist)
4434 {
4435 	ADDRESS *tmp;
4436 	int ret=0, num_ent=0;
4437 
4438 	tmp = addresslist;
4439 
4440 	if (tmp) do {
4441 		ret += _php_rfc822_len(tmp->personal);
4442 		ret += _php_rfc822_len(tmp->adl);
4443 		ret += _php_rfc822_len(tmp->mailbox);
4444 		ret += _php_rfc822_len(tmp->host);
4445 		num_ent++;
4446 	} while ((tmp = tmp->next));
4447 
4448 	/*
4449 	 * rfc822_write_address_full() needs some extra space for '<>,', etc.
4450 	 * for this perpouse we allocate additional PHP_IMAP_ADDRESS_SIZE_BUF bytes
4451 	 * by default this buffer is 10 bytes long
4452 	*/
4453 	ret += (ret) ? num_ent*PHP_IMAP_ADDRESS_SIZE_BUF : 0;
4454 
4455 	return ret;
4456 }
4457 
4458 /* }}} */
4459 
4460 /* {{{ _php_rfc822_write_address
4461  */
_php_rfc822_write_address(ADDRESS * addresslist)4462 static zend_string* _php_rfc822_write_address(ADDRESS *addresslist)
4463 {
4464 	char address[SENDBUFLEN];
4465 
4466 	if (_php_imap_address_size(addresslist) >= SENDBUFLEN) {
4467 		php_error_docref(NULL, E_ERROR, "Address buffer overflow");
4468 		return NULL;
4469 	}
4470 	address[0] = 0;
4471 	rfc822_write_address(address, addresslist);
4472 	return zend_string_init(address, strlen(address), 0);
4473 }
4474 /* }}} */
4475 #endif
4476 /* {{{ _php_imap_parse_address
4477  */
_php_imap_parse_address(ADDRESS * addresslist,zval * paddress)4478 static zend_string* _php_imap_parse_address (ADDRESS *addresslist, zval *paddress)
4479 {
4480 	zend_string *fulladdress;
4481 	ADDRESS *addresstmp;
4482 	zval tmpvals;
4483 
4484 	addresstmp = addresslist;
4485 
4486 	fulladdress = _php_rfc822_write_address(addresstmp);
4487 
4488 	addresstmp = addresslist;
4489 	do {
4490 		object_init(&tmpvals);
4491 		if (addresstmp->personal) add_property_string(&tmpvals, "personal", addresstmp->personal);
4492 		if (addresstmp->adl) add_property_string(&tmpvals, "adl", addresstmp->adl);
4493 		if (addresstmp->mailbox) add_property_string(&tmpvals, "mailbox", addresstmp->mailbox);
4494 		if (addresstmp->host) add_property_string(&tmpvals, "host", addresstmp->host);
4495 		add_next_index_object(paddress, &tmpvals);
4496 	} while ((addresstmp = addresstmp->next));
4497 	return fulladdress;
4498 }
4499 /* }}} */
4500 
4501 /* {{{ _php_make_header_object
4502  */
_php_make_header_object(zval * myzvalue,ENVELOPE * en)4503 static void _php_make_header_object(zval *myzvalue, ENVELOPE *en)
4504 {
4505 	zval paddress;
4506 	zend_string *fulladdress=NULL;
4507 
4508 	object_init(myzvalue);
4509 
4510 	if (en->remail) add_property_string(myzvalue, "remail", en->remail);
4511 	if (en->date) add_property_string(myzvalue, "date", (char*)en->date);
4512 	if (en->date) add_property_string(myzvalue, "Date", (char*)en->date);
4513 	if (en->subject) add_property_string(myzvalue, "subject", en->subject);
4514 	if (en->subject) add_property_string(myzvalue, "Subject", en->subject);
4515 	if (en->in_reply_to) add_property_string(myzvalue, "in_reply_to", en->in_reply_to);
4516 	if (en->message_id) add_property_string(myzvalue, "message_id", en->message_id);
4517 	if (en->newsgroups) add_property_string(myzvalue, "newsgroups", en->newsgroups);
4518 	if (en->followup_to) add_property_string(myzvalue, "followup_to", en->followup_to);
4519 	if (en->references) add_property_string(myzvalue, "references", en->references);
4520 
4521 	if (en->to) {
4522 		array_init(&paddress);
4523 		fulladdress = _php_imap_parse_address(en->to, &paddress);
4524 		if (fulladdress) {
4525 			add_property_str(myzvalue, "toaddress", fulladdress);
4526 		}
4527 		add_assoc_object(myzvalue, "to", &paddress);
4528 	}
4529 
4530 	if (en->from) {
4531 		array_init(&paddress);
4532 		fulladdress = _php_imap_parse_address(en->from, &paddress);
4533 		if (fulladdress) {
4534 			add_property_str(myzvalue, "fromaddress", fulladdress);
4535 		}
4536 		add_assoc_object(myzvalue, "from", &paddress);
4537 	}
4538 
4539 	if (en->cc) {
4540 		array_init(&paddress);
4541 		fulladdress = _php_imap_parse_address(en->cc, &paddress);
4542 		if (fulladdress) {
4543 			add_property_str(myzvalue, "ccaddress", fulladdress);
4544 		}
4545 		add_assoc_object(myzvalue, "cc", &paddress);
4546 	}
4547 
4548 	if (en->bcc) {
4549 		array_init(&paddress);
4550 		fulladdress = _php_imap_parse_address(en->bcc, &paddress);
4551 		if (fulladdress) {
4552 			add_property_str(myzvalue, "bccaddress", fulladdress);
4553 		}
4554 		add_assoc_object(myzvalue, "bcc", &paddress);
4555 	}
4556 
4557 	if (en->reply_to) {
4558 		array_init(&paddress);
4559 		fulladdress = _php_imap_parse_address(en->reply_to, &paddress);
4560 		if (fulladdress) {
4561 			add_property_str(myzvalue, "reply_toaddress", fulladdress);
4562 		}
4563 		add_assoc_object(myzvalue, "reply_to", &paddress);
4564 	}
4565 
4566 	if (en->sender) {
4567 		array_init(&paddress);
4568 		fulladdress = _php_imap_parse_address(en->sender, &paddress);
4569 		if (fulladdress) {
4570 			add_property_str(myzvalue, "senderaddress", fulladdress);
4571 		}
4572 		add_assoc_object(myzvalue, "sender", &paddress);
4573 	}
4574 
4575 	if (en->return_path) {
4576 		array_init(&paddress);
4577 		fulladdress = _php_imap_parse_address(en->return_path, &paddress);
4578 		if (fulladdress) {
4579 			add_property_str(myzvalue, "return_pathaddress", fulladdress);
4580 		}
4581 		add_assoc_object(myzvalue, "return_path", &paddress);
4582 	}
4583 }
4584 /* }}} */
4585 
4586 /* {{{ _php_imap_add_body
4587  */
_php_imap_add_body(zval * arg,BODY * body)4588 void _php_imap_add_body(zval *arg, BODY *body)
4589 {
4590 	zval parametres, param, dparametres, dparam;
4591 	PARAMETER *par, *dpar;
4592 	PART *part;
4593 
4594 	if (body->type <= TYPEMAX) {
4595 		add_property_long(arg, "type", body->type);
4596 	}
4597 
4598 	if (body->encoding <= ENCMAX) {
4599 		add_property_long(arg, "encoding", body->encoding);
4600 	}
4601 
4602 	if (body->subtype) {
4603 		add_property_long(arg, "ifsubtype", 1);
4604 		add_property_string(arg, "subtype", body->subtype);
4605 	} else {
4606 		add_property_long(arg, "ifsubtype", 0);
4607 	}
4608 
4609 	if (body->description) {
4610 		add_property_long(arg, "ifdescription", 1);
4611 		add_property_string(arg, "description", body->description);
4612 	} else {
4613 		add_property_long(arg, "ifdescription", 0);
4614 	}
4615 
4616 	if (body->id) {
4617 		add_property_long(arg, "ifid", 1);
4618 		add_property_string(arg, "id", body->id);
4619 	} else {
4620 		add_property_long(arg, "ifid", 0);
4621 	}
4622 
4623 	if (body->size.lines) {
4624 		add_property_long(arg, "lines", body->size.lines);
4625 	}
4626 
4627 	if (body->size.bytes) {
4628 		add_property_long(arg, "bytes", body->size.bytes);
4629 	}
4630 
4631 #ifdef IMAP41
4632 	if (body->disposition.type) {
4633 		add_property_long(arg, "ifdisposition", 1);
4634 		add_property_string(arg, "disposition", body->disposition.type);
4635 	} else {
4636 		add_property_long(arg, "ifdisposition", 0);
4637 	}
4638 
4639 	if (body->disposition.parameter) {
4640 		dpar = body->disposition.parameter;
4641 		add_property_long(arg, "ifdparameters", 1);
4642 		array_init(&dparametres);
4643 		do {
4644 			object_init(&dparam);
4645 			add_property_string(&dparam, "attribute", dpar->attribute);
4646 			add_property_string(&dparam, "value", dpar->value);
4647 			add_next_index_object(&dparametres, &dparam);
4648 		} while ((dpar = dpar->next));
4649 		add_assoc_object(arg, "dparameters", &dparametres);
4650 	} else {
4651 		add_property_long(arg, "ifdparameters", 0);
4652 	}
4653 #endif
4654 
4655 	if ((par = body->parameter)) {
4656 		add_property_long(arg, "ifparameters", 1);
4657 
4658 		array_init(&parametres);
4659 		do {
4660 			object_init(&param);
4661 			if (par->attribute) {
4662 				add_property_string(&param, "attribute", par->attribute);
4663 			}
4664 			if (par->value) {
4665 				add_property_string(&param, "value", par->value);
4666 			}
4667 
4668 			add_next_index_object(&parametres, &param);
4669 		} while ((par = par->next));
4670 	} else {
4671 		object_init(&parametres);
4672 		add_property_long(arg, "ifparameters", 0);
4673 	}
4674 	add_assoc_object(arg, "parameters", &parametres);
4675 
4676 	/* multipart message ? */
4677 	if (body->type == TYPEMULTIPART) {
4678 		array_init(&parametres);
4679 		for (part = body->CONTENT_PART; part; part = part->next) {
4680 			object_init(&param);
4681 			_php_imap_add_body(&param, &part->body);
4682 			add_next_index_object(&parametres, &param);
4683 		}
4684 		add_assoc_object(arg, "parts", &parametres);
4685 	}
4686 
4687 	/* encapsulated message ? */
4688 	if ((body->type == TYPEMESSAGE) && (!strcasecmp(body->subtype, "rfc822"))) {
4689 		body = body->CONTENT_MSG_BODY;
4690 		array_init(&parametres);
4691 		object_init(&param);
4692 		_php_imap_add_body(&param, body);
4693 		add_next_index_object(&parametres, &param);
4694 		add_assoc_object(arg, "parts", &parametres);
4695 	}
4696 }
4697 /* }}} */
4698 
4699 /* imap_thread, stealing this from header cclient -rjs3 */
4700 /* {{{ build_thread_tree_helper
4701  */
build_thread_tree_helper(THREADNODE * cur,zval * tree,long * numNodes,char * buf)4702 static void build_thread_tree_helper(THREADNODE *cur, zval *tree, long *numNodes, char *buf)
4703 {
4704 	unsigned long thisNode = *numNodes;
4705 
4706 	/* define "#.num" */
4707 	snprintf(buf, 25, "%ld.num", thisNode);
4708 
4709 	add_assoc_long(tree, buf, cur->num);
4710 
4711 	snprintf(buf, 25, "%ld.next", thisNode);
4712 	if(cur->next) {
4713 		(*numNodes)++;
4714 		add_assoc_long(tree, buf, *numNodes);
4715 		build_thread_tree_helper(cur->next, tree, numNodes, buf);
4716 	} else { /* "null pointer" */
4717 		add_assoc_long(tree, buf, 0);
4718 	}
4719 
4720 	snprintf(buf, 25, "%ld.branch", thisNode);
4721 	if(cur->branch) {
4722 		(*numNodes)++;
4723 		add_assoc_long(tree, buf, *numNodes);
4724 		build_thread_tree_helper(cur->branch, tree, numNodes, buf);
4725 	} else { /* "null pointer" */
4726 		add_assoc_long(tree, buf, 0);
4727 	}
4728 }
4729 /* }}} */
4730 
4731 /* {{{ build_thread_tree
4732  */
build_thread_tree(THREADNODE * top,zval ** tree)4733 static int build_thread_tree(THREADNODE *top, zval **tree)
4734 {
4735 	long numNodes = 0;
4736 	char buf[25];
4737 
4738 	array_init(*tree);
4739 
4740 	build_thread_tree_helper(top, *tree, &numNodes, buf);
4741 
4742 	return SUCCESS;
4743 }
4744 /* }}} */
4745 
4746 /* {{{ proto array imap_thread(resource stream_id [, int options])
4747    Return threaded by REFERENCES tree */
PHP_FUNCTION(imap_thread)4748 PHP_FUNCTION(imap_thread)
4749 {
4750 	zval *streamind;
4751 	pils *imap_le_struct;
4752 	zend_long flags = SE_FREE;
4753 	char criteria[] = "ALL";
4754 	THREADNODE *top;
4755 	int argc = ZEND_NUM_ARGS();
4756 	SEARCHPGM *pgm = NIL;
4757 
4758 	if (zend_parse_parameters(argc, "r|l", &streamind, &flags) == FAILURE) {
4759 		return;
4760 	}
4761 
4762 	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
4763 		RETURN_FALSE;
4764 	}
4765 
4766 	pgm = mail_criteria(criteria);
4767 	top = mail_thread(imap_le_struct->imap_stream, "REFERENCES", NIL, pgm, flags);
4768 	if (pgm && !(flags & SE_FREE)) {
4769 		mail_free_searchpgm(&pgm);
4770 	}
4771 
4772 	if(top == NIL) {
4773 		php_error_docref(NULL, E_WARNING, "Function returned an empty tree");
4774 		RETURN_FALSE;
4775 	}
4776 
4777 	/* Populate our return value data structure here. */
4778 	if(build_thread_tree(top, &return_value) == FAILURE) {
4779 		mail_free_threadnode(&top);
4780 		RETURN_FALSE;
4781 	}
4782 	mail_free_threadnode(&top);
4783 }
4784 /* }}} */
4785 
4786 /* {{{ proto mixed imap_timeout(int timeout_type [, int timeout])
4787    Set or fetch imap timeout */
PHP_FUNCTION(imap_timeout)4788 PHP_FUNCTION(imap_timeout)
4789 {
4790 	zend_long ttype, timeout=-1;
4791 	int timeout_type;
4792 
4793 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &ttype, &timeout) == FAILURE) {
4794 		RETURN_FALSE;
4795 	}
4796 
4797 	if (timeout == -1) {
4798 		switch (ttype) {
4799 			case 1:
4800 				timeout_type = GET_OPENTIMEOUT;
4801 				break;
4802 			case 2:
4803 				timeout_type = GET_READTIMEOUT;
4804 				break;
4805 			case 3:
4806 				timeout_type = GET_WRITETIMEOUT;
4807 				break;
4808 			case 4:
4809 				timeout_type = GET_CLOSETIMEOUT;
4810 				break;
4811 			default:
4812 				RETURN_FALSE;
4813 				break;
4814 		}
4815 
4816 		timeout = (zend_long) mail_parameters(NIL, timeout_type, NIL);
4817 		RETURN_LONG(timeout);
4818 	} else if (timeout >= 0) {
4819 		switch (ttype) {
4820 			case 1:
4821 				timeout_type = SET_OPENTIMEOUT;
4822 				break;
4823 			case 2:
4824 				timeout_type = SET_READTIMEOUT;
4825 				break;
4826 			case 3:
4827 				timeout_type = SET_WRITETIMEOUT;
4828 				break;
4829 			case 4:
4830 				timeout_type = SET_CLOSETIMEOUT;
4831 				break;
4832 			default:
4833 				RETURN_FALSE;
4834 				break;
4835 		}
4836 
4837 		timeout = (zend_long) mail_parameters(NIL, timeout_type, (void *) timeout);
4838 		RETURN_TRUE;
4839 	} else {
4840 		RETURN_FALSE;
4841 	}
4842 }
4843 /* }}} */
4844 
4845 #define GETS_FETCH_SIZE 8196LU
php_mail_gets(readfn_t f,void * stream,unsigned long size,GETS_DATA * md)4846 static char *php_mail_gets(readfn_t f, void *stream, unsigned long size, GETS_DATA *md) /* {{{ */
4847 {
4848 
4849 	/*	write to the gets stream if it is set,
4850 		otherwise forward to c-clients gets */
4851 	if (IMAPG(gets_stream)) {
4852 		char buf[GETS_FETCH_SIZE];
4853 
4854 		while (size) {
4855 			unsigned long read;
4856 
4857 			if (size > GETS_FETCH_SIZE) {
4858 				read = GETS_FETCH_SIZE;
4859 				size -=GETS_FETCH_SIZE;
4860 			} else {
4861 				read = size;
4862 				size = 0;
4863 			}
4864 
4865 			if (!f(stream, read, buf)) {
4866 				php_error_docref(NULL, E_WARNING, "Failed to read from socket");
4867 				break;
4868 			} else if (read != php_stream_write(IMAPG(gets_stream), buf, read)) {
4869 				php_error_docref(NULL, E_WARNING, "Failed to write to stream");
4870 				break;
4871 			}
4872 		}
4873 		return NULL;
4874 	} else {
4875 		char *buf = pemalloc(size + 1, 1);
4876 
4877 		if (f(stream, size, buf)) {
4878 			buf[size] = '\0';
4879 		} else {
4880 			php_error_docref(NULL, E_WARNING, "Failed to read from socket");
4881 			free(buf);
4882 			buf = NULL;
4883 		}
4884 		return buf;
4885 	}
4886 }
4887 /* }}} */
4888 
4889 /* {{{ Interfaces to C-client
4890  */
mm_searched(MAILSTREAM * stream,unsigned long number)4891 PHP_IMAP_EXPORT void mm_searched(MAILSTREAM *stream, unsigned long number)
4892 {
4893 	MESSAGELIST *cur = NIL;
4894 
4895 	if (IMAPG(imap_messages) == NIL) {
4896 		IMAPG(imap_messages) = mail_newmessagelist();
4897 		IMAPG(imap_messages)->msgid = number;
4898 		IMAPG(imap_messages)->next = NIL;
4899 		IMAPG(imap_messages_tail) = IMAPG(imap_messages);
4900 	} else {
4901 		cur = IMAPG(imap_messages_tail);
4902 		cur->next = mail_newmessagelist();
4903 		cur = cur->next;
4904 		cur->msgid = number;
4905 		cur->next = NIL;
4906 		IMAPG(imap_messages_tail) = cur;
4907 	}
4908 }
4909 
mm_exists(MAILSTREAM * stream,unsigned long number)4910 PHP_IMAP_EXPORT void mm_exists(MAILSTREAM *stream, unsigned long number)
4911 {
4912 }
4913 
mm_expunged(MAILSTREAM * stream,unsigned long number)4914 PHP_IMAP_EXPORT void mm_expunged(MAILSTREAM *stream, unsigned long number)
4915 {
4916 }
4917 
mm_flags(MAILSTREAM * stream,unsigned long number)4918 PHP_IMAP_EXPORT void mm_flags(MAILSTREAM *stream, unsigned long number)
4919 {
4920 }
4921 
4922 /* Author: CJH */
mm_notify(MAILSTREAM * stream,char * str,long errflg)4923 PHP_IMAP_EXPORT void mm_notify(MAILSTREAM *stream, char *str, long errflg)
4924 {
4925 	STRINGLIST *cur = NIL;
4926 
4927 	if (strncmp(str, "[ALERT] ", 8) == 0) {
4928 		if (IMAPG(imap_alertstack) == NIL) {
4929 			IMAPG(imap_alertstack) = mail_newstringlist();
4930 			IMAPG(imap_alertstack)->LSIZE = strlen((char*)(IMAPG(imap_alertstack)->LTEXT = (unsigned char*)cpystr(str)));
4931 			IMAPG(imap_alertstack)->next = NIL;
4932 		} else {
4933 			cur = IMAPG(imap_alertstack);
4934 			while (cur->next != NIL) {
4935 				cur = cur->next;
4936 			}
4937 			cur->next = mail_newstringlist ();
4938 			cur = cur->next;
4939 			cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(str)));
4940 			cur->next = NIL;
4941 		}
4942 	}
4943 }
4944 
mm_list(MAILSTREAM * stream,DTYPE delimiter,char * mailbox,long attributes)4945 PHP_IMAP_EXPORT void mm_list(MAILSTREAM *stream, DTYPE delimiter, char *mailbox, long attributes)
4946 {
4947 	STRINGLIST *cur=NIL;
4948 	FOBJECTLIST *ocur=NIL;
4949 
4950 	if (IMAPG(folderlist_style) == FLIST_OBJECT) {
4951 		/* build up a the new array of objects */
4952 		/* Author: CJH */
4953 		if (IMAPG(imap_folder_objects) == NIL) {
4954 			IMAPG(imap_folder_objects) = mail_newfolderobjectlist();
4955 			IMAPG(imap_folder_objects)->LSIZE=strlen((char*)(IMAPG(imap_folder_objects)->LTEXT = (unsigned char*)cpystr(mailbox)));
4956 			IMAPG(imap_folder_objects)->delimiter = delimiter;
4957 			IMAPG(imap_folder_objects)->attributes = attributes;
4958 			IMAPG(imap_folder_objects)->next = NIL;
4959 			IMAPG(imap_folder_objects_tail) = IMAPG(imap_folder_objects);
4960 		} else {
4961 			ocur=IMAPG(imap_folder_objects_tail);
4962 			ocur->next=mail_newfolderobjectlist();
4963 			ocur=ocur->next;
4964 			ocur->LSIZE = strlen((char*)(ocur->LTEXT = (unsigned char*)cpystr(mailbox)));
4965 			ocur->delimiter = delimiter;
4966 			ocur->attributes = attributes;
4967 			ocur->next = NIL;
4968 			IMAPG(imap_folder_objects_tail) = ocur;
4969 		}
4970 
4971 	} else {
4972 		/* build the old IMAPG(imap_folders) variable to allow old imap_listmailbox() to work */
4973 		if (!(attributes & LATT_NOSELECT)) {
4974 			if (IMAPG(imap_folders) == NIL) {
4975 				IMAPG(imap_folders)=mail_newstringlist();
4976 				IMAPG(imap_folders)->LSIZE=strlen((char*)(IMAPG(imap_folders)->LTEXT = (unsigned char*)cpystr(mailbox)));
4977 				IMAPG(imap_folders)->next=NIL;
4978 				IMAPG(imap_folders_tail) = IMAPG(imap_folders);
4979 			} else {
4980 				cur=IMAPG(imap_folders_tail);
4981 				cur->next=mail_newstringlist ();
4982 				cur=cur->next;
4983 				cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(mailbox)));
4984 				cur->next = NIL;
4985 				IMAPG(imap_folders_tail) = cur;
4986 			}
4987 		}
4988 	}
4989 }
4990 
mm_lsub(MAILSTREAM * stream,DTYPE delimiter,char * mailbox,long attributes)4991 PHP_IMAP_EXPORT void mm_lsub(MAILSTREAM *stream, DTYPE delimiter, char *mailbox, long attributes)
4992 {
4993 	STRINGLIST *cur=NIL;
4994 	FOBJECTLIST *ocur=NIL;
4995 
4996 	if (IMAPG(folderlist_style) == FLIST_OBJECT) {
4997 		/* build the array of objects */
4998 		/* Author: CJH */
4999 		if (IMAPG(imap_sfolder_objects) == NIL) {
5000 			IMAPG(imap_sfolder_objects) = mail_newfolderobjectlist();
5001 			IMAPG(imap_sfolder_objects)->LSIZE = strlen((char*)(IMAPG(imap_sfolder_objects)->LTEXT = (unsigned char*)cpystr(mailbox)));
5002 			IMAPG(imap_sfolder_objects)->delimiter = delimiter;
5003 			IMAPG(imap_sfolder_objects)->attributes = attributes;
5004 			IMAPG(imap_sfolder_objects)->next = NIL;
5005 			IMAPG(imap_sfolder_objects_tail) = IMAPG(imap_sfolder_objects);
5006 		} else {
5007 			ocur=IMAPG(imap_sfolder_objects_tail);
5008 			ocur->next=mail_newfolderobjectlist();
5009 			ocur=ocur->next;
5010 			ocur->LSIZE=strlen((char*)(ocur->LTEXT = (unsigned char*)cpystr(mailbox)));
5011 			ocur->delimiter = delimiter;
5012 			ocur->attributes = attributes;
5013 			ocur->next = NIL;
5014 			IMAPG(imap_sfolder_objects_tail) = ocur;
5015 		}
5016 	} else {
5017 		/* build the old simple array for imap_listsubscribed() */
5018 		if (IMAPG(imap_sfolders) == NIL) {
5019 			IMAPG(imap_sfolders)=mail_newstringlist();
5020 			IMAPG(imap_sfolders)->LSIZE=strlen((char*)(IMAPG(imap_sfolders)->LTEXT = (unsigned char*)cpystr(mailbox)));
5021 			IMAPG(imap_sfolders)->next=NIL;
5022 			IMAPG(imap_sfolders_tail) = IMAPG(imap_sfolders);
5023 		} else {
5024 			cur=IMAPG(imap_sfolders_tail);
5025 			cur->next=mail_newstringlist ();
5026 			cur=cur->next;
5027 			cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(mailbox)));
5028 			cur->next = NIL;
5029 			IMAPG(imap_sfolders_tail) = cur;
5030 		}
5031 	}
5032 }
5033 
mm_status(MAILSTREAM * stream,char * mailbox,MAILSTATUS * status)5034 PHP_IMAP_EXPORT void mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
5035 {
5036 
5037 	IMAPG(status_flags)=status->flags;
5038 	if (IMAPG(status_flags) & SA_MESSAGES) {
5039 		IMAPG(status_messages)=status->messages;
5040 	}
5041 	if (IMAPG(status_flags) & SA_RECENT) {
5042 		IMAPG(status_recent)=status->recent;
5043 	}
5044 	if (IMAPG(status_flags) & SA_UNSEEN) {
5045 		IMAPG(status_unseen)=status->unseen;
5046 	}
5047 	if (IMAPG(status_flags) & SA_UIDNEXT) {
5048 		IMAPG(status_uidnext)=status->uidnext;
5049 	}
5050 	if (IMAPG(status_flags) & SA_UIDVALIDITY) {
5051 		IMAPG(status_uidvalidity)=status->uidvalidity;
5052 	}
5053 }
5054 
mm_log(char * str,long errflg)5055 PHP_IMAP_EXPORT void mm_log(char *str, long errflg)
5056 {
5057 	ERRORLIST *cur = NIL;
5058 
5059 	/* Author: CJH */
5060 	if (errflg != NIL) { /* CJH: maybe put these into a more comprehensive log for debugging purposes? */
5061 		if (IMAPG(imap_errorstack) == NIL) {
5062 			IMAPG(imap_errorstack) = mail_newerrorlist();
5063 			IMAPG(imap_errorstack)->LSIZE = strlen((char*)(IMAPG(imap_errorstack)->LTEXT = (unsigned char*)cpystr(str)));
5064 			IMAPG(imap_errorstack)->errflg = errflg;
5065 			IMAPG(imap_errorstack)->next = NIL;
5066 		} else {
5067 			cur = IMAPG(imap_errorstack);
5068 			while (cur->next != NIL) {
5069 				cur = cur->next;
5070 			}
5071 			cur->next = mail_newerrorlist();
5072 			cur = cur->next;
5073 			cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(str)));
5074 			cur->errflg = errflg;
5075 			cur->next = NIL;
5076 		}
5077 	}
5078 }
5079 
mm_dlog(char * str)5080 PHP_IMAP_EXPORT void mm_dlog(char *str)
5081 {
5082 	/* CJH: this is for debugging; it might be useful to allow setting
5083 	   the stream to debug mode and capturing this somewhere - syslog?
5084 	   php debugger? */
5085 }
5086 
mm_login(NETMBX * mb,char * user,char * pwd,long trial)5087 PHP_IMAP_EXPORT void mm_login(NETMBX *mb, char *user, char *pwd, long trial)
5088 {
5089 
5090 	if (*mb->user) {
5091 		strlcpy (user, mb->user, MAILTMPLEN);
5092 	} else {
5093 		strlcpy (user, IMAPG(imap_user), MAILTMPLEN);
5094 	}
5095 	strlcpy (pwd, IMAPG(imap_password), MAILTMPLEN);
5096 }
5097 
mm_critical(MAILSTREAM * stream)5098 PHP_IMAP_EXPORT void mm_critical(MAILSTREAM *stream)
5099 {
5100 }
5101 
mm_nocritical(MAILSTREAM * stream)5102 PHP_IMAP_EXPORT void mm_nocritical(MAILSTREAM *stream)
5103 {
5104 }
5105 
mm_diskerror(MAILSTREAM * stream,long errcode,long serious)5106 PHP_IMAP_EXPORT long mm_diskerror(MAILSTREAM *stream, long errcode, long serious)
5107 {
5108 	return 1;
5109 }
5110 
mm_fatal(char * str)5111 PHP_IMAP_EXPORT void mm_fatal(char *str)
5112 {
5113 }
5114 /* }}} */
5115 
5116 /*
5117  * Local variables:
5118  * tab-width: 4
5119  * c-basic-offset: 4
5120  * End:
5121  * vim600: sw=4 ts=4 fdm=marker
5122  * vim<600: sw=4 ts=4
5123  */
5124