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