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