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