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