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