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