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