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