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