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	long regex_flags = 0;				/* Flags (not used) */
1319	long start_offset = 0;				/* Start offset (not used) */
1320	int global = 0;
1321
1322	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS|SS", &streamind, &folder, &message, &flags, &internal_date) == FAILURE) {
1323		return;
1324	}
1325
1326	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);
1327
1328	if (internal_date) {
1329		/* Make sure the given internal_date string matches the RFC specifiedformat */
1330		if ((pce = pcre_get_compiled_regex_cache(regex))== NULL) {
1331			zend_string_free(regex);
1332			RETURN_FALSE;
1333		}
1334
1335		zend_string_free(regex);
1336		php_pcre_match_impl(pce, ZSTR_VAL(internal_date), ZSTR_LEN(internal_date), return_value, subpats, global,
1337			0, regex_flags, start_offset);
1338
1339		if (!Z_LVAL_P(return_value)) {
1340			php_error_docref(NULL, E_WARNING, "internal date not correctly formatted");
1341			internal_date = NULL;
1342		}
1343	}
1344
1345	zend_string_free(regex);
1346	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1347		RETURN_FALSE;
1348	}
1349
1350	INIT (&st, mail_string, (void *) ZSTR_VAL(message), ZSTR_LEN(message));
1351
1352	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)) {
1353		RETURN_TRUE;
1354	} else {
1355		RETURN_FALSE;
1356	}
1357}
1358/* }}} */
1359
1360/* {{{ proto int imap_num_msg(resource stream_id)
1361   Gives the number of messages in the current mailbox */
1362PHP_FUNCTION(imap_num_msg)
1363{
1364	zval *streamind;
1365	pils *imap_le_struct;
1366
1367	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1368		return;
1369	}
1370
1371	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1372		RETURN_FALSE;
1373	}
1374
1375	RETURN_LONG(imap_le_struct->imap_stream->nmsgs);
1376}
1377/* }}} */
1378
1379/* {{{ proto bool imap_ping(resource stream_id)
1380   Check if the IMAP stream is still active */
1381PHP_FUNCTION(imap_ping)
1382{
1383	zval *streamind;
1384	pils *imap_le_struct;
1385
1386	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1387		return;
1388	}
1389
1390	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1391		RETURN_FALSE;
1392	}
1393
1394	RETURN_BOOL(mail_ping(imap_le_struct->imap_stream));
1395}
1396/* }}} */
1397
1398/* {{{ proto int imap_num_recent(resource stream_id)
1399   Gives the number of recent messages in current mailbox */
1400PHP_FUNCTION(imap_num_recent)
1401{
1402	zval *streamind;
1403	pils *imap_le_struct;
1404
1405	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1406		return;
1407	}
1408
1409	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1410		RETURN_FALSE;
1411	}
1412
1413	RETURN_LONG(imap_le_struct->imap_stream->recent);
1414}
1415/* }}} */
1416
1417#if defined(HAVE_IMAP2000) || defined(HAVE_IMAP2001)
1418/* {{{ proto array imap_get_quota(resource stream_id, string qroot)
1419	Returns the quota set to the mailbox account qroot */
1420PHP_FUNCTION(imap_get_quota)
1421{
1422	zval *streamind;
1423	zend_string *qroot;
1424	pils *imap_le_struct;
1425
1426	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &qroot) == FAILURE) {
1427		return;
1428	}
1429
1430	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1431		RETURN_FALSE;
1432	}
1433
1434	array_init(return_value);
1435	IMAPG(quota_return) = &return_value;
1436
1437	/* set the callback for the GET_QUOTA function */
1438	mail_parameters(NIL, SET_QUOTA, (void *) mail_getquota);
1439	if (!imap_getquota(imap_le_struct->imap_stream, ZSTR_VAL(qroot))) {
1440		php_error_docref(NULL, E_WARNING, "c-client imap_getquota failed");
1441		zval_dtor(return_value);
1442		RETURN_FALSE;
1443	}
1444}
1445/* }}} */
1446
1447/* {{{ proto array imap_get_quotaroot(resource stream_id, string mbox)
1448	Returns the quota set to the mailbox account mbox */
1449PHP_FUNCTION(imap_get_quotaroot)
1450{
1451	zval *streamind;
1452	zend_string *mbox;
1453	pils *imap_le_struct;
1454
1455	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &mbox) == FAILURE) {
1456		return;
1457	}
1458
1459	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1460		RETURN_FALSE;
1461	}
1462
1463	array_init(return_value);
1464	IMAPG(quota_return) = &return_value;
1465
1466	/* set the callback for the GET_QUOTAROOT function */
1467	mail_parameters(NIL, SET_QUOTA, (void *) mail_getquota);
1468	if (!imap_getquotaroot(imap_le_struct->imap_stream, ZSTR_VAL(mbox))) {
1469		php_error_docref(NULL, E_WARNING, "c-client imap_getquotaroot failed");
1470		zval_dtor(return_value);
1471		RETURN_FALSE;
1472	}
1473}
1474/* }}} */
1475
1476/* {{{ proto bool imap_set_quota(resource stream_id, string qroot, int mailbox_size)
1477   Will set the quota for qroot mailbox */
1478PHP_FUNCTION(imap_set_quota)
1479{
1480	zval *streamind;
1481	zend_string *qroot;
1482	zend_long mailbox_size;
1483	pils *imap_le_struct;
1484	STRINGLIST	limits;
1485
1486	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSl", &streamind, &qroot, &mailbox_size) == FAILURE) {
1487		return;
1488	}
1489
1490	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1491		RETURN_FALSE;
1492	}
1493
1494	limits.text.data = (unsigned char*)"STORAGE";
1495	limits.text.size = mailbox_size;
1496	limits.next = NIL;
1497
1498	RETURN_BOOL(imap_setquota(imap_le_struct->imap_stream, ZSTR_VAL(qroot), &limits));
1499}
1500/* }}} */
1501
1502/* {{{ proto bool imap_setacl(resource stream_id, string mailbox, string id, string rights)
1503	Sets the ACL for a given mailbox */
1504PHP_FUNCTION(imap_setacl)
1505{
1506	zval *streamind;
1507	zend_string *mailbox, *id, *rights;
1508	pils *imap_le_struct;
1509
1510	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSSS", &streamind, &mailbox, &id, &rights) == FAILURE) {
1511		return;
1512	}
1513
1514	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1515		RETURN_FALSE;
1516	}
1517
1518	RETURN_BOOL(imap_setacl(imap_le_struct->imap_stream, ZSTR_VAL(mailbox), ZSTR_VAL(id), ZSTR_VAL(rights)));
1519}
1520/* }}} */
1521
1522/* {{{ proto array imap_getacl(resource stream_id, string mailbox)
1523	Gets the ACL for a given mailbox */
1524PHP_FUNCTION(imap_getacl)
1525{
1526	zval *streamind;
1527	zend_string *mailbox;
1528	pils *imap_le_struct;
1529
1530	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &mailbox) == FAILURE) {
1531		return;
1532	}
1533
1534	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1535		RETURN_FALSE;
1536	}
1537
1538	/* initializing the special array for the return values */
1539	array_init(return_value);
1540
1541	IMAPG(imap_acl_list) = return_value;
1542
1543	/* set the callback for the GET_ACL function */
1544	mail_parameters(NIL, SET_ACL, (void *) mail_getacl);
1545	if (!imap_getacl(imap_le_struct->imap_stream, ZSTR_VAL(mailbox))) {
1546		php_error(E_WARNING, "c-client imap_getacl failed");
1547		zval_dtor(return_value);
1548		RETURN_FALSE;
1549	}
1550
1551	IMAPG(imap_acl_list) = NIL;
1552}
1553/* }}} */
1554#endif /* HAVE_IMAP2000 || HAVE_IMAP2001 */
1555
1556/* {{{ proto bool imap_expunge(resource stream_id)
1557   Permanently delete all messages marked for deletion */
1558PHP_FUNCTION(imap_expunge)
1559{
1560	zval *streamind;
1561	pils *imap_le_struct;
1562
1563	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1564		return;
1565	}
1566
1567	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1568		RETURN_FALSE;
1569	}
1570
1571	mail_expunge (imap_le_struct->imap_stream);
1572
1573	RETURN_TRUE;
1574}
1575/* }}} */
1576
1577/* {{{ proto bool imap_gc(resource stream_id, int flags)
1578   This function garbage collects (purges) the cache of entries of a specific type. */
1579PHP_FUNCTION(imap_gc)
1580{
1581	zval *streamind;
1582	pils *imap_le_struct;
1583	zend_long flags;
1584
1585	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &streamind, &flags) == FAILURE) {
1586		return;
1587	}
1588
1589	if (flags && ((flags & ~(GC_TEXTS | GC_ELT | GC_ENV)) != 0)) {
1590		php_error_docref(NULL, E_WARNING, "invalid value for the flags parameter");
1591		RETURN_FALSE;
1592	}
1593
1594	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1595		RETURN_FALSE;
1596	}
1597
1598	mail_gc(imap_le_struct->imap_stream, flags);
1599
1600	RETURN_TRUE;
1601}
1602/* }}} */
1603
1604/* {{{ proto bool imap_close(resource stream_id [, int options])
1605   Close an IMAP stream */
1606PHP_FUNCTION(imap_close)
1607{
1608	zval *streamind;
1609	pils *imap_le_struct=NULL;
1610	zend_long options = 0, flags = NIL;
1611	int argc = ZEND_NUM_ARGS();
1612
1613	if (zend_parse_parameters(argc, "r|l", &streamind, &options) == FAILURE) {
1614		return;
1615	}
1616
1617	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1618		RETURN_FALSE;
1619	}
1620
1621	if (argc == 2) {
1622		flags = options;
1623
1624		/* Check that flags is exactly equal to PHP_EXPUNGE or zero */
1625		if (flags && ((flags & ~PHP_EXPUNGE) != 0)) {
1626			php_error_docref(NULL, E_WARNING, "invalid value for the flags parameter");
1627			RETURN_FALSE;
1628		}
1629
1630		/* Do the translation from PHP's internal PHP_EXPUNGE define to c-client's CL_EXPUNGE */
1631		if (flags & PHP_EXPUNGE) {
1632			flags ^= PHP_EXPUNGE;
1633			flags |= CL_EXPUNGE;
1634		}
1635		imap_le_struct->flags = flags;
1636	}
1637
1638	zend_list_close(Z_RES_P(streamind));
1639
1640	RETURN_TRUE;
1641}
1642/* }}} */
1643
1644/* {{{ proto array imap_headers(resource stream_id)
1645   Returns headers for all messages in a mailbox */
1646PHP_FUNCTION(imap_headers)
1647{
1648	zval *streamind;
1649	pils *imap_le_struct;
1650	unsigned long i;
1651	char *t;
1652	unsigned int msgno;
1653	char tmp[MAILTMPLEN];
1654
1655	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1656		return;
1657	}
1658
1659	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1660		RETURN_FALSE;
1661	}
1662
1663	/* Initialize return array */
1664	array_init(return_value);
1665
1666	for (msgno = 1; msgno <= imap_le_struct->imap_stream->nmsgs; msgno++) {
1667		MESSAGECACHE * cache = mail_elt (imap_le_struct->imap_stream, msgno);
1668		mail_fetchstructure(imap_le_struct->imap_stream, msgno, NIL);
1669		tmp[0] = cache->recent ? (cache->seen ? 'R': 'N') : ' ';
1670		tmp[1] = (cache->recent | cache->seen) ? ' ' : 'U';
1671		tmp[2] = cache->flagged ? 'F' : ' ';
1672		tmp[3] = cache->answered ? 'A' : ' ';
1673		tmp[4] = cache->deleted ? 'D' : ' ';
1674		tmp[5] = cache->draft ? 'X' : ' ';
1675		snprintf(tmp + 6, sizeof(tmp) - 6, "%4ld) ", cache->msgno);
1676		mail_date(tmp+11, cache);
1677		tmp[22] = ' ';
1678		tmp[23] = '\0';
1679		mail_fetchfrom(tmp+23, imap_le_struct->imap_stream, msgno, (long)20);
1680		strcat(tmp, " ");
1681		if ((i = cache->user_flags)) {
1682			strcat(tmp, "{");
1683			while (i) {
1684				strlcat(tmp, imap_le_struct->imap_stream->user_flags[find_rightmost_bit (&i)], sizeof(tmp));
1685				if (i) strlcat(tmp, " ", sizeof(tmp));
1686			}
1687			strlcat(tmp, "} ", sizeof(tmp));
1688		}
1689		mail_fetchsubject(t = tmp + strlen(tmp), imap_le_struct->imap_stream, msgno, (long)25);
1690		snprintf(t += strlen(t), sizeof(tmp) - strlen(tmp), " (%ld chars)", cache->rfc822_size);
1691		add_next_index_string(return_value, tmp);
1692	}
1693}
1694/* }}} */
1695
1696/* {{{ proto string imap_body(resource stream_id, int msg_no [, int options])
1697   Read the message body */
1698PHP_FUNCTION(imap_body)
1699{
1700	zval *streamind;
1701	zend_long msgno, flags = 0;
1702	pils *imap_le_struct;
1703	int msgindex, argc = ZEND_NUM_ARGS();
1704	char *body;
1705	unsigned long body_len = 0;
1706
1707	if (zend_parse_parameters(argc, "rl|l", &streamind, &msgno, &flags) == FAILURE) {
1708		return;
1709	}
1710
1711	if (flags && ((flags & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
1712		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
1713		RETURN_FALSE;
1714	}
1715
1716	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1717		RETURN_FALSE;
1718	}
1719
1720	if ((argc == 3) && (flags & FT_UID)) {
1721		/* This should be cached; if it causes an extra RTT to the
1722		   IMAP server, then that's the price we pay for making
1723		   sure we don't crash. */
1724		msgindex = mail_msgno(imap_le_struct->imap_stream, msgno);
1725	} else {
1726		msgindex = msgno;
1727	}
1728	if ((msgindex < 1) || ((unsigned) msgindex > imap_le_struct->imap_stream->nmsgs)) {
1729		php_error_docref(NULL, E_WARNING, "Bad message number");
1730		RETURN_FALSE;
1731	}
1732
1733	body = mail_fetchtext_full (imap_le_struct->imap_stream, msgno, &body_len, (argc == 3 ? flags : NIL));
1734	if (body_len == 0) {
1735		RETVAL_EMPTY_STRING();
1736	} else {
1737		RETVAL_STRINGL(body, body_len);
1738	}
1739}
1740/* }}} */
1741
1742/* {{{ proto bool imap_mail_copy(resource stream_id, string msglist, string mailbox [, int options])
1743   Copy specified message to a mailbox */
1744PHP_FUNCTION(imap_mail_copy)
1745{
1746	zval *streamind;
1747	zend_long options = 0;
1748	zend_string *seq, *folder;
1749	int argc = ZEND_NUM_ARGS();
1750	pils *imap_le_struct;
1751
1752	if (zend_parse_parameters(argc, "rSS|l", &streamind, &seq, &folder, &options) == FAILURE) {
1753		return;
1754	}
1755
1756	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1757		RETURN_FALSE;
1758	}
1759
1760	if (mail_copy_full(imap_le_struct->imap_stream, ZSTR_VAL(seq), ZSTR_VAL(folder), (argc == 4 ? options : NIL)) == T) {
1761		RETURN_TRUE;
1762	} else {
1763		RETURN_FALSE;
1764	}
1765}
1766/* }}} */
1767
1768/* {{{ proto bool imap_mail_move(resource stream_id, string sequence, string mailbox [, int options])
1769   Move specified message to a mailbox */
1770PHP_FUNCTION(imap_mail_move)
1771{
1772	zval *streamind;
1773	zend_string *seq, *folder;
1774	zend_long options = 0;
1775	pils *imap_le_struct;
1776	int argc = ZEND_NUM_ARGS();
1777
1778	if (zend_parse_parameters(argc, "rSS|l", &streamind, &seq, &folder, &options) == FAILURE) {
1779		return;
1780	}
1781
1782	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1783		RETURN_FALSE;
1784	}
1785
1786	if (mail_copy_full(imap_le_struct->imap_stream, ZSTR_VAL(seq), ZSTR_VAL(folder), (argc == 4 ? (options | CP_MOVE) : CP_MOVE)) == T) {
1787		RETURN_TRUE;
1788	} else {
1789		RETURN_FALSE;
1790	}
1791}
1792/* }}} */
1793
1794/* {{{ proto bool imap_createmailbox(resource stream_id, string mailbox)
1795   Create a new mailbox */
1796PHP_FUNCTION(imap_createmailbox)
1797{
1798	zval *streamind;
1799	zend_string *folder;
1800	pils *imap_le_struct;
1801
1802	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
1803		return;
1804	}
1805
1806	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1807		RETURN_FALSE;
1808	}
1809
1810	if (mail_create(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
1811		RETURN_TRUE;
1812	} else {
1813		RETURN_FALSE;
1814	}
1815}
1816/* }}} */
1817
1818/* {{{ proto bool imap_renamemailbox(resource stream_id, string old_name, string new_name)
1819   Rename a mailbox */
1820PHP_FUNCTION(imap_renamemailbox)
1821{
1822	zval *streamind;
1823	zend_string *old_mailbox, *new_mailbox;
1824	pils *imap_le_struct;
1825
1826	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &old_mailbox, &new_mailbox) == FAILURE) {
1827		return;
1828	}
1829
1830	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1831		RETURN_FALSE;
1832	}
1833
1834	if (mail_rename(imap_le_struct->imap_stream, ZSTR_VAL(old_mailbox), ZSTR_VAL(new_mailbox)) == T) {
1835		RETURN_TRUE;
1836	} else {
1837		RETURN_FALSE;
1838	}
1839}
1840/* }}} */
1841
1842/* {{{ proto bool imap_deletemailbox(resource stream_id, string mailbox)
1843   Delete a mailbox */
1844PHP_FUNCTION(imap_deletemailbox)
1845{
1846	zval *streamind;
1847	zend_string *folder;
1848	pils *imap_le_struct;
1849
1850	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
1851		return;
1852	}
1853
1854	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1855		RETURN_FALSE;
1856	}
1857
1858	if (mail_delete(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
1859		RETURN_TRUE;
1860	} else {
1861		RETURN_FALSE;
1862	}
1863}
1864/* }}} */
1865
1866/* {{{ proto array imap_list(resource stream_id, string ref, string pattern)
1867   Read the list of mailboxes */
1868PHP_FUNCTION(imap_list)
1869{
1870	zval *streamind;
1871	zend_string *ref, *pat;
1872	pils *imap_le_struct;
1873	STRINGLIST *cur=NIL;
1874
1875	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
1876		return;
1877	}
1878
1879	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1880		RETURN_FALSE;
1881	}
1882
1883	/* set flag for normal, old mailbox list */
1884	IMAPG(folderlist_style) = FLIST_ARRAY;
1885
1886	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
1887	mail_list(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
1888	if (IMAPG(imap_folders) == NIL) {
1889		RETURN_FALSE;
1890	}
1891
1892	array_init(return_value);
1893	cur=IMAPG(imap_folders);
1894	while (cur != NIL) {
1895		add_next_index_string(return_value, (char*)cur->LTEXT);
1896		cur=cur->next;
1897	}
1898	mail_free_stringlist (&IMAPG(imap_folders));
1899	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
1900}
1901
1902/* }}} */
1903
1904/* {{{ proto array imap_getmailboxes(resource stream_id, string ref, string pattern)
1905   Reads the list of mailboxes and returns a full array of objects containing name, attributes, and delimiter */
1906/* Author: CJH */
1907PHP_FUNCTION(imap_list_full)
1908{
1909	zval *streamind, mboxob;
1910	zend_string *ref, *pat;
1911	pils *imap_le_struct;
1912	FOBJECTLIST *cur=NIL;
1913	char *delim=NIL;
1914
1915	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
1916		return;
1917	}
1918
1919	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1920		RETURN_FALSE;
1921	}
1922
1923	/* set flag for new, improved array of objects mailbox list */
1924	IMAPG(folderlist_style) = FLIST_OBJECT;
1925
1926	IMAPG(imap_folder_objects) = IMAPG(imap_folder_objects_tail) = NIL;
1927	mail_list(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
1928	if (IMAPG(imap_folder_objects) == NIL) {
1929		RETURN_FALSE;
1930	}
1931
1932	array_init(return_value);
1933	delim = safe_emalloc(2, sizeof(char), 0);
1934	cur=IMAPG(imap_folder_objects);
1935	while (cur != NIL) {
1936		object_init(&mboxob);
1937		add_property_string(&mboxob, "name", (char*)cur->LTEXT);
1938		add_property_long(&mboxob, "attributes", cur->attributes);
1939#ifdef IMAP41
1940		delim[0] = (char)cur->delimiter;
1941		delim[1] = 0;
1942		add_property_string(&mboxob, "delimiter", delim);
1943#else
1944		add_property_string(&mboxob, "delimiter", cur->delimiter);
1945#endif
1946		add_next_index_object(return_value, &mboxob);
1947		cur=cur->next;
1948	}
1949	mail_free_foblist(&IMAPG(imap_folder_objects), &IMAPG(imap_folder_objects_tail));
1950	efree(delim);
1951	IMAPG(folderlist_style) = FLIST_ARRAY;		/* reset to default */
1952}
1953/* }}} */
1954
1955/* {{{ proto array imap_listscan(resource stream_id, string ref, string pattern, string content)
1956   Read list of mailboxes containing a certain string */
1957PHP_FUNCTION(imap_listscan)
1958{
1959	zval *streamind;
1960	zend_string *ref, *pat, *content;
1961	pils *imap_le_struct;
1962	STRINGLIST *cur=NIL;
1963
1964	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSSS", &streamind, &ref, &pat, &content) == FAILURE) {
1965		return;
1966	}
1967
1968	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
1969		RETURN_FALSE;
1970	}
1971
1972	IMAPG(imap_folders) = NIL;
1973	mail_scan(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat), ZSTR_VAL(content));
1974	if (IMAPG(imap_folders) == NIL) {
1975		RETURN_FALSE;
1976	}
1977
1978	array_init(return_value);
1979	cur=IMAPG(imap_folders);
1980	while (cur != NIL) {
1981		add_next_index_string(return_value, (char*)cur->LTEXT);
1982		cur=cur->next;
1983	}
1984	mail_free_stringlist (&IMAPG(imap_folders));
1985	IMAPG(imap_folders) = IMAPG(imap_folders_tail) = NIL;
1986}
1987
1988/* }}} */
1989
1990/* {{{ proto object imap_check(resource stream_id)
1991   Get mailbox properties */
1992PHP_FUNCTION(imap_check)
1993{
1994	zval *streamind;
1995	pils *imap_le_struct;
1996	char date[100];
1997
1998	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
1999		return;
2000	}
2001
2002	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2003		RETURN_FALSE;
2004	}
2005
2006	if (mail_ping (imap_le_struct->imap_stream) == NIL) {
2007		RETURN_FALSE;
2008	}
2009
2010	if (imap_le_struct->imap_stream && imap_le_struct->imap_stream->mailbox) {
2011		rfc822_date(date);
2012		object_init(return_value);
2013		add_property_string(return_value, "Date", date);
2014		add_property_string(return_value, "Driver", imap_le_struct->imap_stream->dtb->name);
2015		add_property_string(return_value, "Mailbox", imap_le_struct->imap_stream->mailbox);
2016		add_property_long(return_value, "Nmsgs", imap_le_struct->imap_stream->nmsgs);
2017		add_property_long(return_value, "Recent", imap_le_struct->imap_stream->recent);
2018	} else {
2019		RETURN_FALSE;
2020	}
2021}
2022/* }}} */
2023
2024/* {{{ proto bool imap_delete(resource stream_id, int msg_no [, int options])
2025   Mark a message for deletion */
2026PHP_FUNCTION(imap_delete)
2027{
2028	zval *streamind, *sequence;
2029	pils *imap_le_struct;
2030	zend_long flags = 0;
2031	int argc = ZEND_NUM_ARGS();
2032
2033	if (zend_parse_parameters(argc, "rz|l", &streamind, &sequence, &flags) == FAILURE) {
2034		return;
2035	}
2036
2037	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2038		RETURN_FALSE;
2039	}
2040
2041	convert_to_string_ex(sequence);
2042
2043	mail_setflag_full(imap_le_struct->imap_stream, Z_STRVAL_P(sequence), "\\DELETED", (argc == 3 ? flags : NIL));
2044	RETVAL_TRUE;
2045}
2046/* }}} */
2047
2048/* {{{ proto bool imap_undelete(resource stream_id, int msg_no [, int flags])
2049   Remove the delete flag from a message */
2050PHP_FUNCTION(imap_undelete)
2051{
2052	zval *streamind, *sequence;
2053	zend_long flags = 0;
2054	pils *imap_le_struct;
2055	int argc = ZEND_NUM_ARGS();
2056
2057	if (zend_parse_parameters(argc, "rz|l", &streamind, &sequence, &flags) == FAILURE) {
2058		return;
2059	}
2060
2061	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2062		RETURN_FALSE;
2063	}
2064
2065	convert_to_string_ex(sequence);
2066
2067	mail_clearflag_full(imap_le_struct->imap_stream, Z_STRVAL_P(sequence), "\\DELETED", (argc == 3 ? flags : NIL));
2068	RETVAL_TRUE;
2069}
2070/* }}} */
2071
2072/* {{{ proto object imap_headerinfo(resource stream_id, int msg_no [, int from_length [, int subject_length [, string default_host]]])
2073   Read the headers of the message */
2074PHP_FUNCTION(imap_headerinfo)
2075{
2076	zval *streamind;
2077	zend_string *defaulthost = NULL;
2078	int argc = ZEND_NUM_ARGS();
2079	zend_long msgno, fromlength, subjectlength;
2080	pils *imap_le_struct;
2081	MESSAGECACHE *cache;
2082	ENVELOPE *en;
2083	char dummy[2000], fulladdress[MAILTMPLEN + 1];
2084
2085	if (zend_parse_parameters(argc, "rl|llS", &streamind, &msgno, &fromlength, &subjectlength, &defaulthost) == FAILURE) {
2086		return;
2087	}
2088
2089	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2090		RETURN_FALSE;
2091	}
2092
2093	if (argc >= 3) {
2094		if (fromlength < 0 || fromlength > MAILTMPLEN) {
2095			php_error_docref(NULL, E_WARNING, "From length has to be between 0 and %d", MAILTMPLEN);
2096			RETURN_FALSE;
2097		}
2098	} else {
2099		fromlength = 0x00;
2100	}
2101	if (argc >= 4) {
2102		if (subjectlength < 0 || subjectlength > MAILTMPLEN) {
2103			php_error_docref(NULL, E_WARNING, "Subject length has to be between 0 and %d", MAILTMPLEN);
2104			RETURN_FALSE;
2105		}
2106	} else {
2107		subjectlength = 0x00;
2108	}
2109
2110	PHP_IMAP_CHECK_MSGNO(msgno);
2111
2112	if (mail_fetchstructure(imap_le_struct->imap_stream, msgno, NIL)) {
2113		cache = mail_elt(imap_le_struct->imap_stream, msgno);
2114	} else {
2115		RETURN_FALSE;
2116	}
2117
2118	en = mail_fetchenvelope(imap_le_struct->imap_stream, msgno);
2119
2120	/* call a function to parse all the text, so that we can use the
2121	   same function to parse text from other sources */
2122	_php_make_header_object(return_value, en);
2123
2124	/* now run through properties that are only going to be returned
2125	   from a server, not text headers */
2126	add_property_string(return_value, "Recent", cache->recent ? (cache->seen ? "R": "N") : " ");
2127	add_property_string(return_value, "Unseen", (cache->recent | cache->seen) ? " " : "U");
2128	add_property_string(return_value, "Flagged", cache->flagged ? "F" : " ");
2129	add_property_string(return_value, "Answered", cache->answered ? "A" : " ");
2130	add_property_string(return_value, "Deleted", cache->deleted ? "D" : " ");
2131	add_property_string(return_value, "Draft", cache->draft ? "X" : " ");
2132
2133	snprintf(dummy, sizeof(dummy), "%4ld", cache->msgno);
2134	add_property_string(return_value, "Msgno", dummy);
2135
2136	mail_date(dummy, cache);
2137	add_property_string(return_value, "MailDate", dummy);
2138
2139	snprintf(dummy, sizeof(dummy), "%ld", cache->rfc822_size);
2140	add_property_string(return_value, "Size", dummy);
2141
2142	add_property_long(return_value, "udate", mail_longdate(cache));
2143
2144	if (en->from && fromlength) {
2145		fulladdress[0] = 0x00;
2146		mail_fetchfrom(fulladdress, imap_le_struct->imap_stream, msgno, fromlength);
2147		add_property_string(return_value, "fetchfrom", fulladdress);
2148	}
2149	if (en->subject && subjectlength) {
2150		fulladdress[0] = 0x00;
2151		mail_fetchsubject(fulladdress, imap_le_struct->imap_stream, msgno, subjectlength);
2152		add_property_string(return_value, "fetchsubject", fulladdress);
2153	}
2154}
2155/* }}} */
2156
2157/* {{{ proto object imap_rfc822_parse_headers(string headers [, string default_host])
2158   Parse a set of mail headers contained in a string, and return an object similar to imap_headerinfo() */
2159PHP_FUNCTION(imap_rfc822_parse_headers)
2160{
2161	zend_string *headers, *defaulthost = NULL;
2162	ENVELOPE *en;
2163	int argc = ZEND_NUM_ARGS();
2164
2165	if (zend_parse_parameters(argc, "S|S", &headers, &defaulthost) == FAILURE) {
2166		return;
2167	}
2168
2169	if (argc == 2) {
2170		rfc822_parse_msg(&en, NULL, ZSTR_VAL(headers), ZSTR_LEN(headers), NULL, ZSTR_VAL(defaulthost), NIL);
2171	} else {
2172		rfc822_parse_msg(&en, NULL, ZSTR_VAL(headers), ZSTR_LEN(headers), NULL, "UNKNOWN", NIL);
2173	}
2174
2175	/* call a function to parse all the text, so that we can use the
2176	   same function no matter where the headers are from */
2177	_php_make_header_object(return_value, en);
2178	mail_free_envelope(&en);
2179}
2180/* }}} */
2181
2182/* KMLANG */
2183/* {{{ proto array imap_lsub(resource stream_id, string ref, string pattern)
2184   Return a list of subscribed mailboxes */
2185PHP_FUNCTION(imap_lsub)
2186{
2187	zval *streamind;
2188	zend_string *ref, *pat;
2189	pils *imap_le_struct;
2190	STRINGLIST *cur=NIL;
2191
2192	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
2193		return;
2194	}
2195
2196	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2197		RETURN_FALSE;
2198	}
2199
2200	/* set flag for normal, old mailbox list */
2201	IMAPG(folderlist_style) = FLIST_ARRAY;
2202
2203	IMAPG(imap_sfolders) = NIL;
2204	mail_lsub(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
2205	if (IMAPG(imap_sfolders) == NIL) {
2206		RETURN_FALSE;
2207	}
2208
2209	array_init(return_value);
2210	cur=IMAPG(imap_sfolders);
2211	while (cur != NIL) {
2212		add_next_index_string(return_value, (char*)cur->LTEXT);
2213		cur=cur->next;
2214	}
2215	mail_free_stringlist (&IMAPG(imap_sfolders));
2216	IMAPG(imap_sfolders) = IMAPG(imap_sfolders_tail) = NIL;
2217}
2218/* }}} */
2219
2220/* {{{ proto array imap_getsubscribed(resource stream_id, string ref, string pattern)
2221   Return a list of subscribed mailboxes, in the same format as imap_getmailboxes() */
2222/* Author: CJH */
2223PHP_FUNCTION(imap_lsub_full)
2224{
2225	zval *streamind, mboxob;
2226	zend_string *ref, *pat;
2227	pils *imap_le_struct;
2228	FOBJECTLIST *cur=NIL;
2229	char *delim=NIL;
2230
2231	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS", &streamind, &ref, &pat) == FAILURE) {
2232		return;
2233	}
2234
2235	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2236		RETURN_FALSE;
2237	}
2238
2239	/* set flag for new, improved array of objects list */
2240	IMAPG(folderlist_style) = FLIST_OBJECT;
2241
2242	IMAPG(imap_sfolder_objects) = IMAPG(imap_sfolder_objects_tail) = NIL;
2243	mail_lsub(imap_le_struct->imap_stream, ZSTR_VAL(ref), ZSTR_VAL(pat));
2244	if (IMAPG(imap_sfolder_objects) == NIL) {
2245		RETURN_FALSE;
2246	}
2247
2248	array_init(return_value);
2249	delim = safe_emalloc(2, sizeof(char), 0);
2250	cur=IMAPG(imap_sfolder_objects);
2251	while (cur != NIL) {
2252		object_init(&mboxob);
2253		add_property_string(&mboxob, "name", (char*)cur->LTEXT);
2254		add_property_long(&mboxob, "attributes", cur->attributes);
2255#ifdef IMAP41
2256		delim[0] = (char)cur->delimiter;
2257		delim[1] = 0;
2258		add_property_string(&mboxob, "delimiter", delim);
2259#else
2260		add_property_string(&mboxob, "delimiter", cur->delimiter);
2261#endif
2262		add_next_index_object(return_value, &mboxob);
2263		cur=cur->next;
2264	}
2265	mail_free_foblist (&IMAPG(imap_sfolder_objects), &IMAPG(imap_sfolder_objects_tail));
2266	efree(delim);
2267	IMAPG(folderlist_style) = FLIST_ARRAY; /* reset to default */
2268}
2269/* }}} */
2270
2271/* {{{ proto bool imap_subscribe(resource stream_id, string mailbox)
2272   Subscribe to a mailbox */
2273PHP_FUNCTION(imap_subscribe)
2274{
2275	zval *streamind;
2276	zend_string *folder;
2277	pils *imap_le_struct;
2278
2279	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
2280		return;
2281	}
2282
2283	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2284		RETURN_FALSE;
2285	}
2286
2287	if (mail_subscribe(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
2288		RETURN_TRUE;
2289	} else {
2290		RETURN_FALSE;
2291	}
2292}
2293/* }}} */
2294
2295/* {{{ proto bool imap_unsubscribe(resource stream_id, string mailbox)
2296   Unsubscribe from a mailbox */
2297PHP_FUNCTION(imap_unsubscribe)
2298{
2299	zval *streamind;
2300	zend_string *folder;
2301	pils *imap_le_struct;
2302
2303	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rS", &streamind, &folder) == FAILURE) {
2304		return;
2305	}
2306
2307	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2308		RETURN_FALSE;
2309	}
2310
2311	if (mail_unsubscribe(imap_le_struct->imap_stream, ZSTR_VAL(folder)) == T) {
2312		RETURN_TRUE;
2313	} else {
2314		RETURN_FALSE;
2315	}
2316}
2317/* }}} */
2318
2319/* {{{ proto object imap_fetchstructure(resource stream_id, int msg_no [, int options])
2320   Read the full structure of a message */
2321PHP_FUNCTION(imap_fetchstructure)
2322{
2323	zval *streamind;
2324	zend_long msgno, flags = 0;
2325	pils *imap_le_struct;
2326	BODY *body;
2327	int msgindex, argc = ZEND_NUM_ARGS();
2328
2329	if (zend_parse_parameters(argc, "rl|l", &streamind, &msgno, &flags) == FAILURE) {
2330		return;
2331	}
2332
2333	if (flags && ((flags & ~FT_UID) != 0)) {
2334		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
2335		RETURN_FALSE;
2336	}
2337
2338	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2339		RETURN_FALSE;
2340	}
2341
2342	if (msgno < 1) {
2343		RETURN_FALSE;
2344	}
2345
2346	object_init(return_value);
2347
2348	if ((argc == 3) && (flags & FT_UID)) {
2349		/* This should be cached; if it causes an extra RTT to the
2350		   IMAP server, then that's the price we pay for making
2351		   sure we don't crash. */
2352		msgindex = mail_msgno(imap_le_struct->imap_stream, msgno);
2353	} else {
2354		msgindex = msgno;
2355	}
2356	PHP_IMAP_CHECK_MSGNO(msgindex);
2357
2358	mail_fetchstructure_full(imap_le_struct->imap_stream, msgno, &body , (argc == 3 ? flags : NIL));
2359
2360	if (!body) {
2361		php_error_docref(NULL, E_WARNING, "No body information available");
2362		RETURN_FALSE;
2363	}
2364
2365	_php_imap_add_body(return_value, body);
2366}
2367/* }}} */
2368
2369/* {{{ proto string imap_fetchbody(resource stream_id, int msg_no, string section [, int options])
2370   Get a specific body section */
2371PHP_FUNCTION(imap_fetchbody)
2372{
2373	zval *streamind;
2374	zend_long msgno, flags = 0;
2375	pils *imap_le_struct;
2376	char *body;
2377	zend_string *sec;
2378	unsigned long len;
2379	int argc = ZEND_NUM_ARGS();
2380
2381	if (zend_parse_parameters(argc, "rlS|l", &streamind, &msgno, &sec, &flags) == FAILURE) {
2382		return;
2383	}
2384
2385	if (flags && ((flags & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
2386		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
2387		RETURN_FALSE;
2388	}
2389
2390	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2391		RETURN_FALSE;
2392	}
2393
2394	if (argc < 4 || !(flags & FT_UID)) {
2395		/* only perform the check if the msgno is a message number and not a UID */
2396		PHP_IMAP_CHECK_MSGNO(msgno);
2397	}
2398
2399	body = mail_fetchbody_full(imap_le_struct->imap_stream, msgno, ZSTR_VAL(sec), &len, (argc == 4 ? flags : NIL));
2400
2401	if (!body) {
2402		php_error_docref(NULL, E_WARNING, "No body information available");
2403		RETURN_FALSE;
2404	}
2405	RETVAL_STRINGL(body, len);
2406}
2407
2408/* }}} */
2409
2410
2411/* {{{ proto string imap_fetchmime(resource stream_id, int msg_no, string section [, int options])
2412   Get a specific body section's MIME headers */
2413PHP_FUNCTION(imap_fetchmime)
2414{
2415	zval *streamind;
2416	zend_long msgno, flags = 0;
2417	pils *imap_le_struct;
2418	char *body;
2419	zend_string *sec;
2420	unsigned long len;
2421	int argc = ZEND_NUM_ARGS();
2422
2423	if (zend_parse_parameters(argc, "rlS|l", &streamind, &msgno, &sec, &flags) == FAILURE) {
2424		return;
2425	}
2426
2427	if (flags && ((flags & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
2428		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
2429		RETURN_FALSE;
2430	}
2431
2432	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2433		RETURN_FALSE;
2434	}
2435
2436	if (argc < 4 || !(flags & FT_UID)) {
2437		/* only perform the check if the msgno is a message number and not a UID */
2438		PHP_IMAP_CHECK_MSGNO(msgno);
2439	}
2440
2441	body = mail_fetch_mime(imap_le_struct->imap_stream, msgno, ZSTR_VAL(sec), &len, (argc == 4 ? flags : NIL));
2442
2443	if (!body) {
2444		php_error_docref(NULL, E_WARNING, "No body MIME information available");
2445		RETURN_FALSE;
2446	}
2447	RETVAL_STRINGL(body, len);
2448}
2449
2450/* }}} */
2451
2452/* {{{ proto bool imap_savebody(resource stream_id, string|resource file, int msg_no[, string section = ""[, int options = 0]])
2453	Save a specific body section to a file */
2454PHP_FUNCTION(imap_savebody)
2455{
2456	zval *stream, *out;
2457	pils *imap_ptr = NULL;
2458	php_stream *writer = NULL;
2459	zend_string *section = NULL;
2460	int close_stream = 1;
2461	zend_long msgno, flags = 0;
2462
2463	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rzl|Sl", &stream, &out, &msgno, &section, &flags)) {
2464		RETURN_FALSE;
2465	}
2466
2467	if ((imap_ptr = (pils *)zend_fetch_resource(Z_RES_P(stream), "imap", le_imap)) == NULL) {
2468		RETURN_FALSE;
2469	}
2470
2471	if (!imap_ptr) {
2472		RETURN_FALSE;
2473	}
2474
2475	switch (Z_TYPE_P(out))
2476	{
2477		case IS_LONG:
2478		case IS_RESOURCE:
2479			close_stream = 0;
2480			php_stream_from_zval(writer, out);
2481		break;
2482
2483		default:
2484			convert_to_string_ex(out);
2485			writer = php_stream_open_wrapper(Z_STRVAL_P(out), "wb", REPORT_ERRORS, NULL);
2486		break;
2487	}
2488
2489	if (!writer) {
2490		RETURN_FALSE;
2491	}
2492
2493	IMAPG(gets_stream) = writer;
2494	mail_parameters(NIL, SET_GETS, (void *) php_mail_gets);
2495	mail_fetchbody_full(imap_ptr->imap_stream, msgno, section?ZSTR_VAL(section):"", NULL, flags);
2496	mail_parameters(NIL, SET_GETS, (void *) NULL);
2497	IMAPG(gets_stream) = NULL;
2498
2499	if (close_stream) {
2500		php_stream_close(writer);
2501	}
2502
2503	RETURN_TRUE;
2504}
2505/* }}} */
2506
2507/* {{{ proto string imap_base64(string text)
2508   Decode BASE64 encoded text */
2509PHP_FUNCTION(imap_base64)
2510{
2511	zend_string *text;
2512	char *decode;
2513	unsigned long newlength;
2514
2515	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2516		return;
2517	}
2518
2519	decode = (char *) rfc822_base64((unsigned char *) ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2520
2521	if (decode == NULL) {
2522		RETURN_FALSE;
2523	}
2524
2525	RETVAL_STRINGL(decode, newlength);
2526	fs_give((void**) &decode);
2527}
2528/* }}} */
2529
2530/* {{{ proto string imap_qprint(string text)
2531   Convert a quoted-printable string to an 8-bit string */
2532PHP_FUNCTION(imap_qprint)
2533{
2534	zend_string *text;
2535	char *decode;
2536	unsigned long newlength;
2537
2538	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2539		return;
2540	}
2541
2542	decode = (char *) rfc822_qprint((unsigned char *) ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2543
2544	if (decode == NULL) {
2545		RETURN_FALSE;
2546	}
2547
2548	RETVAL_STRINGL(decode, newlength);
2549	fs_give((void**) &decode);
2550}
2551/* }}} */
2552
2553/* {{{ proto string imap_8bit(string text)
2554   Convert an 8-bit string to a quoted-printable string */
2555PHP_FUNCTION(imap_8bit)
2556{
2557	zend_string *text;
2558	char *decode;
2559	unsigned long newlength;
2560
2561	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2562		return;
2563	}
2564
2565	decode = (char *) rfc822_8bit((unsigned char *) ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2566
2567	if (decode == NULL) {
2568		RETURN_FALSE;
2569	}
2570
2571	RETVAL_STRINGL(decode, newlength);
2572	fs_give((void**) &decode);
2573}
2574/* }}} */
2575
2576/* {{{ proto string imap_binary(string text)
2577   Convert an 8bit string to a base64 string */
2578PHP_FUNCTION(imap_binary)
2579{
2580	zend_string *text;
2581	char *decode;
2582	unsigned long newlength;
2583
2584	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &text) == FAILURE) {
2585		return;
2586	}
2587
2588	decode = (char*)rfc822_binary(ZSTR_VAL(text), ZSTR_LEN(text), &newlength);
2589
2590	if (decode == NULL) {
2591		RETURN_FALSE;
2592	}
2593
2594	RETVAL_STRINGL(decode, newlength);
2595	fs_give((void**) &decode);
2596}
2597/* }}} */
2598
2599/* {{{ proto object imap_mailboxmsginfo(resource stream_id)
2600   Returns info about the current mailbox */
2601PHP_FUNCTION(imap_mailboxmsginfo)
2602{
2603	zval *streamind;
2604	pils *imap_le_struct;
2605	char date[100];
2606	unsigned int msgno, unreadmsg, deletedmsg, msize;
2607
2608	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &streamind) == FAILURE) {
2609		return;
2610	}
2611
2612	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
2613		RETURN_FALSE;
2614	}
2615
2616	/* Initialize return object */
2617	object_init(return_value);
2618
2619	unreadmsg = 0;
2620	deletedmsg = 0;
2621	msize = 0;
2622
2623	for (msgno = 1; msgno <= imap_le_struct->imap_stream->nmsgs; msgno++) {
2624		MESSAGECACHE * cache = mail_elt (imap_le_struct->imap_stream, msgno);
2625		mail_fetchstructure (imap_le_struct->imap_stream, msgno, NIL);
2626
2627		if (!cache->seen || cache->recent) {
2628			unreadmsg++;
2629		}
2630
2631		if (cache->deleted) {
2632			deletedmsg++;
2633		}
2634		msize = msize + cache->rfc822_size;
2635	}
2636	add_property_long(return_value, "Unread", unreadmsg);
2637	add_property_long(return_value, "Deleted", deletedmsg);
2638	add_property_long(return_value, "Nmsgs", imap_le_struct->imap_stream->nmsgs);
2639	add_property_long(return_value, "Size", msize);
2640	rfc822_date(date);
2641	add_property_string(return_value, "Date", date);
2642	add_property_string(return_value, "Driver", imap_le_struct->imap_stream->dtb->name);
2643	add_property_string(return_value, "Mailbox", imap_le_struct->imap_stream->mailbox);
2644	add_property_long(return_value, "Recent", imap_le_struct->imap_stream->recent);
2645}
2646/* }}} */
2647
2648/* {{{ proto string imap_rfc822_write_address(string mailbox, string host, string personal)
2649   Returns a properly formatted email address given the mailbox, host, and personal info */
2650PHP_FUNCTION(imap_rfc822_write_address)
2651{
2652	zend_string *mailbox, *host, *personal;
2653	ADDRESS *addr;
2654	zend_string *string;
2655
2656	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SSS", &mailbox, &host, &personal) == FAILURE) {
2657		return;
2658	}
2659
2660	addr=mail_newaddr();
2661
2662	if (mailbox) {
2663		addr->mailbox = cpystr(ZSTR_VAL(mailbox));
2664	}
2665
2666	if (host) {
2667		addr->host = cpystr(ZSTR_VAL(host));
2668	}
2669
2670	if (personal) {
2671		addr->personal = cpystr(ZSTR_VAL(personal));
2672	}
2673
2674	addr->next=NIL;
2675	addr->error=NIL;
2676	addr->adl=NIL;
2677
2678	string = _php_rfc822_write_address(addr);
2679	if (string) {
2680		RETVAL_STR(string);
2681	} else {
2682		RETURN_FALSE;
2683	}
2684}
2685/* }}} */
2686
2687/* {{{ proto array imap_rfc822_parse_adrlist(string address_string, string default_host)
2688   Parses an address string */
2689PHP_FUNCTION(imap_rfc822_parse_adrlist)
2690{
2691	zval tovals;
2692	zend_string *str, *defaulthost;
2693	char *str_copy;
2694	ADDRESS *addresstmp;
2695	ENVELOPE *env;
2696
2697	if (zend_parse_parameters(ZEND_NUM_ARGS(), "SS", &str, &defaulthost) == FAILURE) {
2698		return;
2699	}
2700
2701	env = mail_newenvelope();
2702
2703	/* rfc822_parse_adrlist() modifies passed string. Copy it. */
2704	str_copy = estrndup(ZSTR_VAL(str), ZSTR_LEN(str));
2705	rfc822_parse_adrlist(&env->to, str_copy, ZSTR_VAL(defaulthost));
2706	efree(str_copy);
2707
2708	array_init(return_value);
2709
2710	addresstmp = env->to;
2711
2712	if (addresstmp) do {
2713		object_init(&tovals);
2714		if (addresstmp->mailbox) {
2715			add_property_string(&tovals, "mailbox", addresstmp->mailbox);
2716		}
2717		if (addresstmp->host) {
2718			add_property_string(&tovals, "host", addresstmp->host);
2719		}
2720		if (addresstmp->personal) {
2721			add_property_string(&tovals, "personal", addresstmp->personal);
2722		}
2723		if (addresstmp->adl) {
2724			add_property_string(&tovals, "adl", addresstmp->adl);
2725		}
2726		add_next_index_object(return_value, &tovals);
2727	} while ((addresstmp = addresstmp->next));
2728
2729	mail_free_envelope(&env);
2730}
2731/* }}} */
2732
2733/* {{{ proto string imap_utf8(string mime_encoded_text)
2734   Convert a mime-encoded text to UTF-8 */
2735PHP_FUNCTION(imap_utf8)
2736{
2737	zend_string *str;
2738	SIZEDTEXT src, dest;
2739
2740	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
2741		return;
2742	}
2743
2744	src.data  = NULL;
2745	src.size  = 0;
2746	dest.data = NULL;
2747	dest.size = 0;
2748
2749	cpytxt(&src, ZSTR_VAL(str), ZSTR_LEN(str));
2750
2751#ifndef HAVE_NEW_MIME2TEXT
2752	utf8_mime2text(&src, &dest);
2753#else
2754	utf8_mime2text(&src, &dest, U8T_DECOMPOSE);
2755#endif
2756	RETVAL_STRINGL((char*)dest.data, dest.size);
2757	if (dest.data) {
2758		free(dest.data);
2759	}
2760	if (src.data && src.data != dest.data) {
2761		free(src.data);
2762	}
2763}
2764/* }}} */
2765
2766/* {{{ macros for the modified utf7 conversion functions
2767 *
2768 * author: Andrew Skalski <askalski@chek.com>
2769 */
2770
2771/* tests `c' and returns true if it is a special character */
2772#define SPECIAL(c) ((c) <= 0x1f || (c) >= 0x7f)
2773
2774/* validate a modified-base64 character */
2775#define B64CHAR(c) (isalnum(c) || (c) == '+' || (c) == ',')
2776
2777/* map the low 64 bits of `n' to the modified-base64 characters */
2778#define B64(n)	("ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
2779				"abcdefghijklmnopqrstuvwxyz0123456789+,"[(n) & 0x3f])
2780
2781/* map the modified-base64 character `c' to its 64 bit value */
2782#define UNB64(c)	((c) == '+' ? 62 : (c) == ',' ? 63 : (c) >= 'a' ? \
2783					(c) - 71 : (c) >= 'A' ? (c) - 65 : (c) + 4)
2784/* }}} */
2785
2786/* {{{ proto string imap_utf7_decode(string buf)
2787   Decode a modified UTF-7 string */
2788PHP_FUNCTION(imap_utf7_decode)
2789{
2790	/* author: Andrew Skalski <askalski@chek.com> */
2791	zend_string *arg;
2792	const unsigned char *in, *inp, *endp;
2793	unsigned char *out, *outp;
2794	unsigned char c;
2795	int inlen, outlen;
2796	enum {
2797		ST_NORMAL,	/* printable text */
2798		ST_DECODE0,	/* encoded text rotation... */
2799		ST_DECODE1,
2800		ST_DECODE2,
2801		ST_DECODE3
2802	} state;
2803
2804	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
2805		return;
2806	}
2807
2808	in = (const unsigned char *) ZSTR_VAL(arg);
2809	inlen = ZSTR_LEN(arg);
2810
2811	/* validate and compute length of output string */
2812	outlen = 0;
2813	state = ST_NORMAL;
2814	for (endp = (inp = in) + inlen; inp < endp; inp++) {
2815		if (state == ST_NORMAL) {
2816			/* process printable character */
2817			if (SPECIAL(*inp)) {
2818				php_error_docref(NULL, E_WARNING, "Invalid modified UTF-7 character: `%c'", *inp);
2819				RETURN_FALSE;
2820			} else if (*inp != '&') {
2821				outlen++;
2822			} else if (inp + 1 == endp) {
2823				php_error_docref(NULL, E_WARNING, "Unexpected end of string");
2824				RETURN_FALSE;
2825			} else if (inp[1] != '-') {
2826				state = ST_DECODE0;
2827			} else {
2828				outlen++;
2829				inp++;
2830			}
2831		} else if (*inp == '-') {
2832			/* return to NORMAL mode */
2833			if (state == ST_DECODE1) {
2834				php_error_docref(NULL, E_WARNING, "Stray modified base64 character: `%c'", *--inp);
2835				RETURN_FALSE;
2836			}
2837			state = ST_NORMAL;
2838		} else if (!B64CHAR(*inp)) {
2839			php_error_docref(NULL, E_WARNING, "Invalid modified base64 character: `%c'", *inp);
2840			RETURN_FALSE;
2841		} else {
2842			switch (state) {
2843				case ST_DECODE3:
2844					outlen++;
2845					state = ST_DECODE0;
2846					break;
2847				case ST_DECODE2:
2848				case ST_DECODE1:
2849					outlen++;
2850				case ST_DECODE0:
2851					state++;
2852				case ST_NORMAL:
2853					break;
2854			}
2855		}
2856	}
2857
2858	/* enforce end state */
2859	if (state != ST_NORMAL) {
2860		php_error_docref(NULL, E_WARNING, "Unexpected end of string");
2861		RETURN_FALSE;
2862	}
2863
2864	/* allocate output buffer */
2865	out = emalloc(outlen + 1);
2866
2867	/* decode input string */
2868	outp = out;
2869	state = ST_NORMAL;
2870	for (endp = (inp = in) + inlen; inp < endp; inp++) {
2871		if (state == ST_NORMAL) {
2872			if (*inp == '&' && inp[1] != '-') {
2873				state = ST_DECODE0;
2874			}
2875			else if ((*outp++ = *inp) == '&') {
2876				inp++;
2877			}
2878		}
2879		else if (*inp == '-') {
2880			state = ST_NORMAL;
2881		}
2882		else {
2883			/* decode input character */
2884			switch (state) {
2885			case ST_DECODE0:
2886				*outp = UNB64(*inp) << 2;
2887				state = ST_DECODE1;
2888				break;
2889			case ST_DECODE1:
2890				outp[1] = UNB64(*inp);
2891				c = outp[1] >> 4;
2892				*outp++ |= c;
2893				*outp <<= 4;
2894				state = ST_DECODE2;
2895				break;
2896			case ST_DECODE2:
2897				outp[1] = UNB64(*inp);
2898				c = outp[1] >> 2;
2899				*outp++ |= c;
2900				*outp <<= 6;
2901				state = ST_DECODE3;
2902				break;
2903			case ST_DECODE3:
2904				*outp++ |= UNB64(*inp);
2905				state = ST_DECODE0;
2906			case ST_NORMAL:
2907				break;
2908			}
2909		}
2910	}
2911
2912	*outp = 0;
2913
2914#if PHP_DEBUG
2915	/* warn if we computed outlen incorrectly */
2916	if (outp - out != outlen) {
2917		php_error_docref(NULL, E_WARNING, "outp - out [%ld] != outlen [%d]", outp - out, outlen);
2918	}
2919#endif
2920
2921	RETURN_STRINGL((char*)out, outlen);
2922}
2923/* }}} */
2924
2925/* {{{ proto string imap_utf7_encode(string buf)
2926   Encode a string in modified UTF-7 */
2927PHP_FUNCTION(imap_utf7_encode)
2928{
2929	/* author: Andrew Skalski <askalski@chek.com> */
2930	zend_string *arg;
2931	const unsigned char *in, *inp, *endp;
2932	zend_string *out;
2933	unsigned char *outp;
2934	unsigned char c;
2935	int inlen, outlen;
2936	enum {
2937		ST_NORMAL,	/* printable text */
2938		ST_ENCODE0,	/* encoded text rotation... */
2939		ST_ENCODE1,
2940		ST_ENCODE2
2941	} state;
2942
2943	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &arg) == FAILURE) {
2944		return;
2945	}
2946
2947	in = (const unsigned char *) ZSTR_VAL(arg);
2948	inlen = ZSTR_LEN(arg);
2949
2950	/* compute the length of the result string */
2951	outlen = 0;
2952	state = ST_NORMAL;
2953	endp = (inp = in) + inlen;
2954	while (inp < endp) {
2955		if (state == ST_NORMAL) {
2956			if (SPECIAL(*inp)) {
2957				state = ST_ENCODE0;
2958				outlen++;
2959			} else if (*inp++ == '&') {
2960				outlen++;
2961			}
2962			outlen++;
2963		} else if (!SPECIAL(*inp)) {
2964			state = ST_NORMAL;
2965		} else {
2966			/* ST_ENCODE0 -> ST_ENCODE1	- two chars
2967			 * ST_ENCODE1 -> ST_ENCODE2	- one char
2968			 * ST_ENCODE2 -> ST_ENCODE0	- one char
2969			 */
2970			if (state == ST_ENCODE2) {
2971				state = ST_ENCODE0;
2972			}
2973			else if (state++ == ST_ENCODE0) {
2974				outlen++;
2975			}
2976			outlen++;
2977			inp++;
2978		}
2979	}
2980
2981	/* allocate output buffer */
2982	out = zend_string_alloc(outlen, 0);
2983
2984	/* encode input string */
2985	outp = (unsigned char*)ZSTR_VAL(out);
2986	state = ST_NORMAL;
2987	endp = (inp = in) + inlen;
2988	while (inp < endp || state != ST_NORMAL) {
2989		if (state == ST_NORMAL) {
2990			if (SPECIAL(*inp)) {
2991				/* begin encoding */
2992				*outp++ = '&';
2993				state = ST_ENCODE0;
2994			} else if ((*outp++ = *inp++) == '&') {
2995				*outp++ = '-';
2996			}
2997		} else if (inp == endp || !SPECIAL(*inp)) {
2998			/* flush overflow and terminate region */
2999			if (state != ST_ENCODE0) {
3000				c = B64(*outp);
3001				*outp++ = c;
3002			}
3003			*outp++ = '-';
3004			state = ST_NORMAL;
3005		} else {
3006			/* encode input character */
3007			switch (state) {
3008				case ST_ENCODE0:
3009					*outp++ = B64(*inp >> 2);
3010					*outp = *inp++ << 4;
3011					state = ST_ENCODE1;
3012					break;
3013				case ST_ENCODE1:
3014					c = B64(*outp | *inp >> 4);
3015					*outp++ = c;
3016					*outp = *inp++ << 2;
3017					state = ST_ENCODE2;
3018					break;
3019				case ST_ENCODE2:
3020					c = B64(*outp | *inp >> 6);
3021					*outp++ = c;
3022					*outp++ = B64(*inp++);
3023					state = ST_ENCODE0;
3024				case ST_NORMAL:
3025					break;
3026			}
3027		}
3028	}
3029
3030	*outp = 0;
3031
3032	RETURN_STR(out);
3033}
3034/* }}} */
3035
3036#undef SPECIAL
3037#undef B64CHAR
3038#undef B64
3039#undef UNB64
3040
3041#ifdef HAVE_IMAP_MUTF7
3042static void php_imap_mutf7(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
3043{
3044	zend_string *in;
3045	unsigned char *out;
3046
3047	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &in) == FAILURE) {
3048		return;
3049	}
3050
3051	if (ZSTR_LEN(in) < 1) {
3052		RETURN_EMPTY_STRING();
3053	}
3054
3055	if (mode == 0) {
3056		out = utf8_to_mutf7((unsigned char *) ZSTR_VAL(in));
3057	} else {
3058		out = utf8_from_mutf7((unsigned char *) ZSTR_VAL(in));
3059	}
3060
3061	if (out == NIL) {
3062		RETURN_FALSE;
3063	} else {
3064		RETURN_STRING((char *)out);
3065	}
3066}
3067/* }}} */
3068
3069/* {{{ proto string imap_utf8_to_mutf7(string in)
3070   Encode a UTF-8 string to modified UTF-7 */
3071PHP_FUNCTION(imap_utf8_to_mutf7)
3072{
3073	php_imap_mutf7(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
3074}
3075/* }}} */
3076
3077/* {{{ proto string imap_mutf7_to_utf8(string in)
3078   Decode a modified UTF-7 string to UTF-8 */
3079PHP_FUNCTION(imap_mutf7_to_utf8)
3080{
3081	php_imap_mutf7(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
3082}
3083/* }}} */
3084#endif
3085
3086/* {{{ proto bool imap_setflag_full(resource stream_id, string sequence, string flag [, int options])
3087   Sets flags on messages */
3088PHP_FUNCTION(imap_setflag_full)
3089{
3090	zval *streamind;
3091	zend_string *sequence, *flag;
3092	zend_long flags = 0;
3093	pils *imap_le_struct;
3094
3095	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSS|l", &streamind, &sequence, &flag, &flags) == FAILURE) {
3096		return;
3097	}
3098
3099	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3100		RETURN_FALSE;
3101	}
3102
3103	mail_setflag_full(imap_le_struct->imap_stream, ZSTR_VAL(sequence), ZSTR_VAL(flag), (flags ? flags : NIL));
3104	RETURN_TRUE;
3105}
3106/* }}} */
3107
3108/* {{{ proto bool imap_clearflag_full(resource stream_id, string sequence, string flag [, int options])
3109   Clears flags on messages */
3110PHP_FUNCTION(imap_clearflag_full)
3111{
3112	zval *streamind;
3113	zend_string *sequence, *flag;
3114	zend_long flags = 0;
3115	pils *imap_le_struct;
3116	int argc = ZEND_NUM_ARGS();
3117
3118	if (zend_parse_parameters(argc, "rSS|l", &streamind, &sequence, &flag, &flags) ==FAILURE) {
3119		return;
3120	}
3121
3122	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3123		RETURN_FALSE;
3124	}
3125
3126	mail_clearflag_full(imap_le_struct->imap_stream, ZSTR_VAL(sequence), ZSTR_VAL(flag), (argc == 4 ? flags : NIL));
3127	RETURN_TRUE;
3128}
3129/* }}} */
3130
3131/* {{{ proto array imap_sort(resource stream_id, int criteria, int reverse [, int options [, string search_criteria [, string charset]]])
3132   Sort an array of message headers, optionally including only messages that meet specified criteria. */
3133PHP_FUNCTION(imap_sort)
3134{
3135	zval *streamind;
3136	zend_string *criteria = NULL, *charset = NULL;
3137	zend_long pgm, rev, flags = 0;
3138	pils *imap_le_struct;
3139	unsigned long *slst, *sl;
3140	char *search_criteria;
3141	SORTPGM *mypgm=NIL;
3142	SEARCHPGM *spg=NIL;
3143	int argc = ZEND_NUM_ARGS();
3144
3145	if (zend_parse_parameters(argc, "rll|lSS", &streamind, &pgm, &rev, &flags, &criteria, &charset) == FAILURE) {
3146		return;
3147	}
3148
3149	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3150		RETURN_FALSE;
3151	}
3152
3153	if (pgm > SORTSIZE) {
3154		php_error_docref(NULL, E_WARNING, "Unrecognized sort criteria");
3155		RETURN_FALSE;
3156	}
3157	if (argc >= 4) {
3158		if (flags < 0) {
3159			php_error_docref(NULL, E_WARNING, "Search options parameter has to be greater than or equal to 0");
3160			RETURN_FALSE;
3161		}
3162	}
3163	if (argc >= 5) {
3164		search_criteria = estrndup(ZSTR_VAL(criteria), ZSTR_LEN(criteria));
3165		spg = mail_criteria(search_criteria);
3166		efree(search_criteria);
3167	} else {
3168		spg = mail_newsearchpgm();
3169	}
3170
3171	mypgm = mail_newsortpgm();
3172	mypgm->reverse = rev;
3173	mypgm->function = (short) pgm;
3174	mypgm->next = NIL;
3175
3176	slst = mail_sort(imap_le_struct->imap_stream, (argc == 6 ? ZSTR_VAL(charset) : NIL), spg, mypgm, (argc >= 4 ? flags : NIL));
3177
3178	if (spg && !(flags & SE_FREE)) {
3179		mail_free_searchpgm(&spg);
3180	}
3181
3182	array_init(return_value);
3183	if (slst != NIL && slst != 0) {
3184		for (sl = slst; *sl; sl++) {
3185			add_next_index_long(return_value, *sl);
3186		}
3187		fs_give ((void **) &slst);
3188	}
3189}
3190/* }}} */
3191
3192/* {{{ proto string imap_fetchheader(resource stream_id, int msg_no [, int options])
3193   Get the full unfiltered header for a message */
3194PHP_FUNCTION(imap_fetchheader)
3195{
3196	zval *streamind;
3197	zend_long msgno, flags = 0L;
3198	pils *imap_le_struct;
3199	int msgindex, argc = ZEND_NUM_ARGS();
3200
3201	if (zend_parse_parameters(argc, "rl|l", &streamind, &msgno, &flags) == FAILURE) {
3202		return;
3203	}
3204
3205	if (flags && ((flags & ~(FT_UID|FT_INTERNAL|FT_PREFETCHTEXT)) != 0)) {
3206		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
3207		RETURN_FALSE;
3208	}
3209
3210	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3211		RETURN_FALSE;
3212	}
3213
3214	if ((argc == 3) && (flags & FT_UID)) {
3215		/* This should be cached; if it causes an extra RTT to the
3216		   IMAP server, then that's the price we pay for making sure
3217		   we don't crash. */
3218		msgindex = mail_msgno(imap_le_struct->imap_stream, msgno);
3219	} else {
3220		msgindex = msgno;
3221	}
3222
3223	PHP_IMAP_CHECK_MSGNO(msgindex);
3224
3225	RETVAL_STRING(mail_fetchheader_full(imap_le_struct->imap_stream, msgno, NIL, NIL, (argc == 3 ? flags : NIL)));
3226}
3227/* }}} */
3228
3229/* {{{ proto int imap_uid(resource stream_id, int msg_no)
3230   Get the unique message id associated with a standard sequential message number */
3231PHP_FUNCTION(imap_uid)
3232{
3233	zval *streamind;
3234	zend_long msgno;
3235	pils *imap_le_struct;
3236	int msgindex;
3237
3238	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &streamind, &msgno) == FAILURE) {
3239		return;
3240	}
3241
3242	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3243		RETURN_FALSE;
3244	}
3245
3246	msgindex = msgno;
3247	if ((msgindex < 1) || ((unsigned) msgindex > imap_le_struct->imap_stream->nmsgs)) {
3248		php_error_docref(NULL, E_WARNING, "Bad message number");
3249		RETURN_FALSE;
3250	}
3251
3252	RETURN_LONG(mail_uid(imap_le_struct->imap_stream, msgno));
3253}
3254/* }}} */
3255
3256/* {{{ proto int imap_msgno(resource stream_id, int unique_msg_id)
3257   Get the sequence number associated with a UID */
3258PHP_FUNCTION(imap_msgno)
3259{
3260	zval *streamind;
3261	zend_long msgno;
3262	pils *imap_le_struct;
3263
3264	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &streamind, &msgno) == FAILURE) {
3265		return;
3266	}
3267
3268	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3269		RETURN_FALSE;
3270	}
3271
3272	RETURN_LONG(mail_msgno(imap_le_struct->imap_stream, msgno));
3273}
3274/* }}} */
3275
3276/* {{{ proto object imap_status(resource stream_id, string mailbox, int options)
3277   Get status info from a mailbox */
3278PHP_FUNCTION(imap_status)
3279{
3280	zval *streamind;
3281	zend_string *mbx;
3282	zend_long flags;
3283	pils *imap_le_struct;
3284
3285	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rSl", &streamind, &mbx, &flags) == FAILURE) {
3286		return;
3287	}
3288
3289	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3290		RETURN_FALSE;
3291	}
3292
3293	object_init(return_value);
3294
3295	if (mail_status(imap_le_struct->imap_stream, ZSTR_VAL(mbx), flags)) {
3296		add_property_long(return_value, "flags", IMAPG(status_flags));
3297		if (IMAPG(status_flags) & SA_MESSAGES) {
3298			add_property_long(return_value, "messages", IMAPG(status_messages));
3299		}
3300		if (IMAPG(status_flags) & SA_RECENT) {
3301			add_property_long(return_value, "recent", IMAPG(status_recent));
3302		}
3303		if (IMAPG(status_flags) & SA_UNSEEN) {
3304			add_property_long(return_value, "unseen", IMAPG(status_unseen));
3305		}
3306		if (IMAPG(status_flags) & SA_UIDNEXT) {
3307			add_property_long(return_value, "uidnext", IMAPG(status_uidnext));
3308		}
3309		if (IMAPG(status_flags) & SA_UIDVALIDITY) {
3310			add_property_long(return_value, "uidvalidity", IMAPG(status_uidvalidity));
3311		}
3312	} else {
3313		RETURN_FALSE;
3314	}
3315}
3316/* }}} */
3317
3318/* {{{ proto object imap_bodystruct(resource stream_id, int msg_no, string section)
3319   Read the structure of a specified body section of a specific message */
3320PHP_FUNCTION(imap_bodystruct)
3321{
3322	zval *streamind;
3323	zend_long msg;
3324	zend_string *section;
3325	pils *imap_le_struct;
3326	zval parametres, param, dparametres, dparam;
3327	PARAMETER *par, *dpar;
3328	BODY *body;
3329
3330	if (zend_parse_parameters(ZEND_NUM_ARGS(), "rlS", &streamind, &msg, &section) == FAILURE) {
3331		return;
3332	}
3333
3334	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3335		RETURN_FALSE;
3336	}
3337
3338	if (!msg || msg < 1 || (unsigned) msg > imap_le_struct->imap_stream->nmsgs) {
3339		php_error_docref(NULL, E_WARNING, "Bad message number");
3340		RETURN_FALSE;
3341	}
3342
3343	object_init(return_value);
3344
3345	body=mail_body(imap_le_struct->imap_stream, msg, (unsigned char*)ZSTR_VAL(section));
3346	if (body == NULL) {
3347		zval_dtor(return_value);
3348		RETURN_FALSE;
3349	}
3350	if (body->type <= TYPEMAX) {
3351		add_property_long(return_value, "type", body->type);
3352	}
3353	if (body->encoding <= ENCMAX) {
3354		add_property_long(return_value, "encoding", body->encoding);
3355	}
3356
3357	if (body->subtype) {
3358		add_property_long(return_value, "ifsubtype", 1);
3359		add_property_string(return_value, "subtype", body->subtype);
3360	} else {
3361		add_property_long(return_value, "ifsubtype", 0);
3362	}
3363
3364	if (body->description) {
3365		add_property_long(return_value, "ifdescription", 1);
3366		add_property_string(return_value, "description", body->description);
3367	} else {
3368		add_property_long(return_value, "ifdescription", 0);
3369	}
3370	if (body->id) {
3371		add_property_long(return_value, "ifid", 1);
3372		add_property_string(return_value, "id", body->id);
3373	} else {
3374		add_property_long(return_value, "ifid", 0);
3375	}
3376
3377	if (body->size.lines) {
3378		add_property_long(return_value, "lines", body->size.lines);
3379	}
3380	if (body->size.bytes) {
3381		add_property_long(return_value, "bytes", body->size.bytes);
3382	}
3383#ifdef IMAP41
3384	if (body->disposition.type) {
3385		add_property_long(return_value, "ifdisposition", 1);
3386		add_property_string(return_value, "disposition", body->disposition.type);
3387	} else {
3388		add_property_long(return_value, "ifdisposition", 0);
3389	}
3390
3391	if (body->disposition.parameter) {
3392		dpar = body->disposition.parameter;
3393		add_property_long(return_value, "ifdparameters", 1);
3394		array_init(&dparametres);
3395		do {
3396			object_init(&dparam);
3397			add_property_string(&dparam, "attribute", dpar->attribute);
3398			add_property_string(&dparam, "value", dpar->value);
3399			add_next_index_object(&dparametres, &dparam);
3400		} while ((dpar = dpar->next));
3401		add_assoc_object(return_value, "dparameters", &dparametres);
3402	} else {
3403		add_property_long(return_value, "ifdparameters", 0);
3404	}
3405#endif
3406
3407	if ((par = body->parameter)) {
3408		add_property_long(return_value, "ifparameters", 1);
3409
3410		array_init(&parametres);
3411		do {
3412			object_init(&param);
3413			if (par->attribute) {
3414				add_property_string(&param, "attribute", par->attribute);
3415			}
3416			if (par->value) {
3417				add_property_string(&param, "value", par->value);
3418			}
3419
3420			add_next_index_object(&parametres, &param);
3421		} while ((par = par->next));
3422	} else {
3423		object_init(&parametres);
3424		add_property_long(return_value, "ifparameters", 0);
3425	}
3426	add_assoc_object(return_value, "parameters", &parametres);
3427}
3428
3429/* }}} */
3430
3431/* {{{ proto array imap_fetch_overview(resource stream_id, string sequence [, int options])
3432   Read an overview of the information in the headers of the given message sequence */
3433PHP_FUNCTION(imap_fetch_overview)
3434{
3435	zval *streamind;
3436	zend_string *sequence;
3437	pils *imap_le_struct;
3438	zval myoverview;
3439	zend_string *address;
3440	zend_long status, flags = 0L;
3441	int argc = ZEND_NUM_ARGS();
3442
3443	if (zend_parse_parameters(argc, "rS|l", &streamind, &sequence, &flags) == FAILURE) {
3444		return;
3445	}
3446
3447	if (flags && ((flags & ~FT_UID) != 0)) {
3448		php_error_docref(NULL, E_WARNING, "invalid value for the options parameter");
3449		RETURN_FALSE;
3450	}
3451
3452	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
3453		RETURN_FALSE;
3454	}
3455
3456	array_init(return_value);
3457
3458	status = (flags & FT_UID)
3459		? mail_uid_sequence(imap_le_struct->imap_stream, (unsigned char*)ZSTR_VAL(sequence))
3460		: mail_sequence(imap_le_struct->imap_stream, (unsigned char*)ZSTR_VAL(sequence));
3461
3462	if (status) {
3463		MESSAGECACHE *elt;
3464		ENVELOPE *env;
3465		unsigned long i;
3466
3467		for (i = 1; i <= imap_le_struct->imap_stream->nmsgs; i++) {
3468			if (((elt = mail_elt (imap_le_struct->imap_stream, i))->sequence) &&
3469				(env = mail_fetch_structure (imap_le_struct->imap_stream, i, NIL, NIL))) {
3470				object_init(&myoverview);
3471				if (env->subject) {
3472					add_property_string(&myoverview, "subject", env->subject);
3473				}
3474				if (env->from) {
3475					env->from->next=NULL;
3476					address =_php_rfc822_write_address(env->from);
3477					if (address) {
3478						add_property_str(&myoverview, "from", address);
3479					}
3480				}
3481				if (env->to) {
3482					env->to->next = NULL;
3483					address = _php_rfc822_write_address(env->to);
3484					if (address) {
3485						add_property_str(&myoverview, "to", address);
3486					}
3487				}
3488				if (env->date) {
3489					add_property_string(&myoverview, "date", (char*)env->date);
3490				}
3491				if (env->message_id) {
3492					add_property_string(&myoverview, "message_id", env->message_id);
3493				}
3494				if (env->references) {
3495					add_property_string(&myoverview, "references", env->references);
3496				}
3497				if (env->in_reply_to) {
3498					add_property_string(&myoverview, "in_reply_to", env->in_reply_to);
3499				}
3500				add_property_long(&myoverview, "size", elt->rfc822_size);
3501				add_property_long(&myoverview, "uid", mail_uid(imap_le_struct->imap_stream, i));
3502				add_property_long(&myoverview, "msgno", i);
3503				add_property_long(&myoverview, "recent", elt->recent);
3504				add_property_long(&myoverview, "flagged", elt->flagged);
3505				add_property_long(&myoverview, "answered", elt->answered);
3506				add_property_long(&myoverview, "deleted", elt->deleted);
3507				add_property_long(&myoverview, "seen", elt->seen);
3508				add_property_long(&myoverview, "draft", elt->draft);
3509				add_property_long(&myoverview, "udate", mail_longdate(elt));
3510				add_next_index_object(return_value, &myoverview);
3511			}
3512		}
3513	}
3514}
3515/* }}} */
3516
3517/* {{{ proto string imap_mail_compose(array envelope, array body)
3518   Create a MIME message based on given envelope and body sections */
3519PHP_FUNCTION(imap_mail_compose)
3520{
3521	zval *envelope, *body;
3522	zend_string *key;
3523	zval *data, *pvalue, *disp_data, *env_data;
3524	char *cookie = NIL;
3525	ENVELOPE *env;
3526	BODY *bod=NULL, *topbod=NULL;
3527	PART *mypart=NULL, *part;
3528	PARAMETER *param, *disp_param = NULL, *custom_headers_param = NULL, *tmp_param = NULL;
3529	char *tmp=NULL, *mystring=NULL, *t=NULL, *tempstring=NULL, *str_copy = NULL;
3530	int toppart = 0;
3531	int first;
3532
3533	if (zend_parse_parameters(ZEND_NUM_ARGS(), "aa", &envelope, &body) == FAILURE) {
3534		return;
3535	}
3536
3537#define PHP_RFC822_PARSE_ADRLIST(target, value) \
3538	str_copy = estrndup(Z_STRVAL_P(value), Z_STRLEN_P(value)); \
3539	rfc822_parse_adrlist(target, str_copy, "NO HOST"); \
3540	efree(str_copy);
3541
3542	env = mail_newenvelope();
3543	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "remail", sizeof("remail") - 1)) != NULL) {
3544		convert_to_string_ex(pvalue);
3545		env->remail = cpystr(Z_STRVAL_P(pvalue));
3546	}
3547	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "return_path", sizeof("return_path") - 1)) != NULL) {
3548		convert_to_string_ex(pvalue);
3549		PHP_RFC822_PARSE_ADRLIST(&env->return_path, pvalue);
3550	}
3551	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "date", sizeof("date") - 1)) != NULL) {
3552		convert_to_string_ex(pvalue);
3553		env->date = (unsigned char*)cpystr(Z_STRVAL_P(pvalue));
3554	}
3555	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "from", sizeof("from") - 1)) != NULL) {
3556		convert_to_string_ex(pvalue);
3557		PHP_RFC822_PARSE_ADRLIST(&env->from, pvalue);
3558	}
3559	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "reply_to", sizeof("reply_to") - 1)) != NULL) {
3560		convert_to_string_ex(pvalue);
3561		PHP_RFC822_PARSE_ADRLIST(&env->reply_to, pvalue);
3562	}
3563	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "in_reply_to", sizeof("in_reply_to") - 1)) != NULL) {
3564		convert_to_string_ex(pvalue);
3565		env->in_reply_to = cpystr(Z_STRVAL_P(pvalue));
3566	}
3567	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "subject", sizeof("subject") - 1)) != NULL) {
3568		convert_to_string_ex(pvalue);
3569		env->subject = cpystr(Z_STRVAL_P(pvalue));
3570	}
3571	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "to", sizeof("to") - 1)) != NULL) {
3572		convert_to_string_ex(pvalue);
3573		PHP_RFC822_PARSE_ADRLIST(&env->to, pvalue);
3574	}
3575	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "cc", sizeof("cc") - 1)) != NULL) {
3576		convert_to_string_ex(pvalue);
3577		PHP_RFC822_PARSE_ADRLIST(&env->cc, pvalue);
3578	}
3579	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "bcc", sizeof("bcc") - 1)) != NULL) {
3580		convert_to_string_ex(pvalue);
3581		PHP_RFC822_PARSE_ADRLIST(&env->bcc, pvalue);
3582	}
3583	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "message_id", sizeof("message_id") - 1)) != NULL) {
3584		convert_to_string_ex(pvalue);
3585		env->message_id=cpystr(Z_STRVAL_P(pvalue));
3586	}
3587
3588	if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(envelope), "custom_headers", sizeof("custom_headers") - 1)) != NULL) {
3589		if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3590			custom_headers_param = tmp_param = NULL;
3591			ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(pvalue), env_data) {
3592				custom_headers_param = mail_newbody_parameter();
3593				convert_to_string_ex(env_data);
3594				custom_headers_param->value = (char *) fs_get(Z_STRLEN_P(env_data) + 1);
3595				custom_headers_param->attribute = NULL;
3596				memcpy(custom_headers_param->value, Z_STRVAL_P(env_data), Z_STRLEN_P(env_data) + 1);
3597				custom_headers_param->next = tmp_param;
3598				tmp_param = custom_headers_param;
3599			} ZEND_HASH_FOREACH_END();
3600		}
3601	}
3602
3603	first = 1;
3604	ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(body), data) {
3605		if (first) {
3606			first = 0;
3607
3608			if (Z_TYPE_P(data) != IS_ARRAY) {
3609				php_error_docref(NULL, E_WARNING, "body parameter must be a non-empty array");
3610				RETURN_FALSE;
3611			}
3612
3613			bod = mail_newbody();
3614			topbod = bod;
3615
3616			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type", sizeof("type") - 1)) != NULL) {
3617				convert_to_long_ex(pvalue);
3618				bod->type = (short) Z_LVAL_P(pvalue);
3619			}
3620			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "encoding", sizeof("encoding") - 1)) != NULL) {
3621				convert_to_long_ex(pvalue);
3622				bod->encoding = (short) Z_LVAL_P(pvalue);
3623			}
3624			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
3625				convert_to_string_ex(pvalue);
3626				tmp_param = mail_newbody_parameter();
3627				tmp_param->value = cpystr(Z_STRVAL_P(pvalue));
3628				tmp_param->attribute = cpystr("CHARSET");
3629				tmp_param->next = bod->parameter;
3630				bod->parameter = tmp_param;
3631			}
3632			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type.parameters", sizeof("type.parameters") - 1)) != NULL) {
3633				if(Z_TYPE_P(pvalue) == IS_ARRAY) {
3634					disp_param = tmp_param = NULL;
3635					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3636						disp_param = mail_newbody_parameter();
3637						disp_param->attribute = cpystr(ZSTR_VAL(key));
3638						convert_to_string_ex(disp_data);
3639						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
3640						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3641						disp_param->next = tmp_param;
3642						tmp_param = disp_param;
3643					} ZEND_HASH_FOREACH_END();
3644					bod->parameter = disp_param;
3645				}
3646			}
3647			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
3648				convert_to_string_ex(pvalue);
3649				bod->subtype = cpystr(Z_STRVAL_P(pvalue));
3650			}
3651			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
3652				convert_to_string_ex(pvalue);
3653				bod->id = cpystr(Z_STRVAL_P(pvalue));
3654			}
3655			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
3656				convert_to_string_ex(pvalue);
3657				bod->description = cpystr(Z_STRVAL_P(pvalue));
3658			}
3659			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
3660				convert_to_string_ex(pvalue);
3661				bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
3662				memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
3663			}
3664			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition", sizeof("disposition") - 1)) != NULL) {
3665				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3666					disp_param = tmp_param = NULL;
3667					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3668						disp_param = mail_newbody_parameter();
3669						disp_param->attribute = cpystr(ZSTR_VAL(key));
3670						convert_to_string_ex(disp_data);
3671						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
3672						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3673						disp_param->next = tmp_param;
3674						tmp_param = disp_param;
3675					} ZEND_HASH_FOREACH_END();
3676					bod->disposition.parameter = disp_param;
3677				}
3678			}
3679			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "contents.data", sizeof("contents.data") - 1)) != NULL) {
3680				convert_to_string_ex(pvalue);
3681				bod->contents.text.data = fs_get(Z_STRLEN_P(pvalue) + 1);
3682				memcpy(bod->contents.text.data, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
3683				bod->contents.text.size = Z_STRLEN_P(pvalue);
3684			} else {
3685				bod->contents.text.data = fs_get(1);
3686				memcpy(bod->contents.text.data, "", 1);
3687				bod->contents.text.size = 0;
3688			}
3689			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "lines", sizeof("lines") - 1)) != NULL) {
3690				convert_to_long_ex(pvalue);
3691				bod->size.lines = Z_LVAL_P(pvalue);
3692			}
3693			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "bytes", sizeof("bytes") - 1)) != NULL) {
3694				convert_to_long_ex(pvalue);
3695				bod->size.bytes = Z_LVAL_P(pvalue);
3696			}
3697			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
3698				convert_to_string_ex(pvalue);
3699				bod->md5 = cpystr(Z_STRVAL_P(pvalue));
3700			}
3701		} else if (Z_TYPE_P(data) == IS_ARRAY) {
3702			short type = -1;
3703			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type", sizeof("type") - 1)) != NULL) {
3704				convert_to_long_ex(pvalue);
3705				type = (short) Z_LVAL_P(pvalue);
3706			}
3707
3708			if (!toppart) {
3709				bod->nested.part = mail_newbody_part();
3710				mypart = bod->nested.part;
3711				toppart = 1;
3712			} else {
3713				mypart->next = mail_newbody_part();
3714				mypart = mypart->next;
3715			}
3716
3717			bod = &mypart->body;
3718
3719			if (type != TYPEMULTIPART) {
3720				bod->type = type;
3721			}
3722
3723			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "encoding", sizeof("encoding") - 1)) != NULL) {
3724				convert_to_long_ex(pvalue);
3725				bod->encoding = (short) Z_LVAL_P(pvalue);
3726			}
3727			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "charset", sizeof("charset") - 1)) != NULL) {
3728				convert_to_string_ex(pvalue);
3729				tmp_param = mail_newbody_parameter();
3730				tmp_param->value = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
3731				memcpy(tmp_param->value, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
3732				tmp_param->attribute = cpystr("CHARSET");
3733				tmp_param->next = bod->parameter;
3734				bod->parameter = tmp_param;
3735			}
3736			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "type.parameters", sizeof("type.parameters") - 1)) != NULL) {
3737				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3738					disp_param = tmp_param = NULL;
3739					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3740						disp_param = mail_newbody_parameter();
3741						disp_param->attribute = cpystr(ZSTR_VAL(key));
3742						convert_to_string_ex(disp_data);
3743						disp_param->value = (char *)fs_get(Z_STRLEN_P(disp_data) + 1);
3744						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3745						disp_param->next = tmp_param;
3746						tmp_param = disp_param;
3747					} ZEND_HASH_FOREACH_END();
3748					bod->parameter = disp_param;
3749				}
3750			}
3751			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "subtype", sizeof("subtype") - 1)) != NULL) {
3752				convert_to_string_ex(pvalue);
3753				bod->subtype = cpystr(Z_STRVAL_P(pvalue));
3754			}
3755			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "id", sizeof("id") - 1)) != NULL) {
3756				convert_to_string_ex(pvalue);
3757				bod->id = cpystr(Z_STRVAL_P(pvalue));
3758			}
3759			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "description", sizeof("description") - 1)) != NULL) {
3760				convert_to_string_ex(pvalue);
3761				bod->description = cpystr(Z_STRVAL_P(pvalue));
3762			}
3763			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition.type", sizeof("disposition.type") - 1)) != NULL) {
3764				convert_to_string_ex(pvalue);
3765				bod->disposition.type = (char *) fs_get(Z_STRLEN_P(pvalue) + 1);
3766				memcpy(bod->disposition.type, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue)+1);
3767			}
3768			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "disposition", sizeof("disposition") - 1)) != NULL) {
3769				if (Z_TYPE_P(pvalue) == IS_ARRAY) {
3770					disp_param = tmp_param = NULL;
3771					ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(pvalue), key, disp_data) {
3772						disp_param = mail_newbody_parameter();
3773						disp_param->attribute = cpystr(ZSTR_VAL(key));
3774						convert_to_string_ex(disp_data);
3775						disp_param->value = (char *) fs_get(Z_STRLEN_P(disp_data) + 1);
3776						memcpy(disp_param->value, Z_STRVAL_P(disp_data), Z_STRLEN_P(disp_data) + 1);
3777						disp_param->next = tmp_param;
3778						tmp_param = disp_param;
3779					} ZEND_HASH_FOREACH_END();
3780					bod->disposition.parameter = disp_param;
3781				}
3782			}
3783			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "contents.data", sizeof("contents.data") - 1)) != NULL) {
3784				convert_to_string_ex(pvalue);
3785				bod->contents.text.data = fs_get(Z_STRLEN_P(pvalue) + 1);
3786				memcpy(bod->contents.text.data, Z_STRVAL_P(pvalue), Z_STRLEN_P(pvalue) + 1);
3787				bod->contents.text.size = Z_STRLEN_P(pvalue);
3788			} else {
3789				bod->contents.text.data = fs_get(1);
3790				memcpy(bod->contents.text.data, "", 1);
3791				bod->contents.text.size = 0;
3792			}
3793			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "lines", sizeof("lines") - 1)) != NULL) {
3794				convert_to_long_ex(pvalue);
3795				bod->size.lines = Z_LVAL_P(pvalue);
3796			}
3797			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "bytes", sizeof("bytes") - 1)) != NULL) {
3798				convert_to_long_ex(pvalue);
3799				bod->size.bytes = Z_LVAL_P(pvalue);
3800			}
3801			if ((pvalue = zend_hash_str_find(Z_ARRVAL_P(data), "md5", sizeof("md5") - 1)) != NULL) {
3802				convert_to_string_ex(pvalue);
3803				bod->md5 = cpystr(Z_STRVAL_P(pvalue));
3804			}
3805		}
3806	} ZEND_HASH_FOREACH_END();
3807
3808	if (first) {
3809		php_error_docref(NULL, E_WARNING, "body parameter must be a non-empty array");
3810		RETURN_FALSE;
3811	}
3812
3813	if (bod && bod->type == TYPEMULTIPART && (!bod->nested.part || !bod->nested.part->next)) {
3814		php_error_docref(NULL, E_WARNING, "cannot generate multipart e-mail without components.");
3815		RETVAL_FALSE;
3816		goto done;
3817	}
3818
3819	rfc822_encode_body_7bit(env, topbod);
3820
3821	tmp = emalloc(SENDBUFLEN + 1);
3822
3823	rfc822_header(tmp, env, topbod);
3824
3825	/* add custom envelope headers */
3826	if (custom_headers_param) {
3827		int l = strlen(tmp) - 2, l2;
3828		PARAMETER *tp = custom_headers_param;
3829
3830		/* remove last CRLF from tmp */
3831		tmp[l] = '\0';
3832		tempstring = emalloc(l);
3833		memcpy(tempstring, tmp, l);
3834
3835		do {
3836			l2 = strlen(custom_headers_param->value);
3837			tempstring = erealloc(tempstring, l + l2 + CRLF_LEN + 1);
3838			memcpy(tempstring + l, custom_headers_param->value, l2);
3839			memcpy(tempstring + l + l2, CRLF, CRLF_LEN);
3840			l += l2 + CRLF_LEN;
3841		} while ((custom_headers_param = custom_headers_param->next));
3842
3843		mail_free_body_parameter(&tp);
3844
3845		mystring = emalloc(l + CRLF_LEN + 1);
3846		memcpy(mystring, tempstring, l);
3847		memcpy(mystring + l , CRLF, CRLF_LEN);
3848		mystring[l + CRLF_LEN] = '\0';
3849
3850		efree(tempstring);
3851	} else {
3852		mystring = estrdup(tmp);
3853	}
3854
3855	bod = topbod;
3856
3857	if (bod && bod->type == TYPEMULTIPART) {
3858
3859		/* first body part */
3860			part = bod->nested.part;
3861
3862		/* find cookie */
3863			for (param = bod->parameter; param && !cookie; param = param->next) {
3864				if (!strcmp (param->attribute, "BOUNDARY")) {
3865					cookie = param->value;
3866				}
3867			}
3868
3869		/* yucky default */
3870			if (!cookie) {
3871				cookie = "-";
3872			} else if (strlen(cookie) > (SENDBUFLEN - 2 - 2 - 2)) { /* validate cookie length -- + CRLF * 2 */
3873				php_error_docref(NULL, E_WARNING, "The boundary should be no longer than 4kb");
3874				RETVAL_FALSE;
3875				goto done;
3876			}
3877
3878		/* for each part */
3879			do {
3880				t = tmp;
3881
3882			/* append mini-header */
3883				*t = '\0';
3884				rfc822_write_body_header(&t, &part->body);
3885
3886			/* output cookie, mini-header, and contents */
3887				spprintf(&tempstring, 0, "%s--%s%s%s%s", mystring, cookie, CRLF, tmp, CRLF);
3888				efree(mystring);
3889				mystring=tempstring;
3890
3891				bod=&part->body;
3892
3893				spprintf(&tempstring, 0, "%s%s%s", mystring, bod->contents.text.data, CRLF);
3894				efree(mystring);
3895				mystring=tempstring;
3896			} while ((part = part->next)); /* until done */
3897
3898			/* output trailing cookie */
3899			spprintf(&tempstring, 0, "%s--%s--%s", mystring, cookie, CRLF);
3900			efree(mystring);
3901			mystring=tempstring;
3902	} else if (bod) {
3903		spprintf(&tempstring, 0, "%s%s%s", mystring, bod->contents.text.data, CRLF);
3904		efree(mystring);
3905		mystring=tempstring;
3906	} else {
3907		efree(mystring);
3908		RETVAL_FALSE;
3909		goto done;
3910	}
3911
3912	RETVAL_STRING(tempstring);
3913	efree(tempstring);
3914done:
3915	if (tmp) {
3916		efree(tmp);
3917	}
3918	mail_free_body(&topbod);
3919	mail_free_envelope(&env);
3920}
3921/* }}} */
3922
3923/* {{{ _php_imap_mail
3924 */
3925int _php_imap_mail(char *to, char *subject, char *message, char *headers, char *cc, char *bcc, char* rpath)
3926{
3927#ifdef PHP_WIN32
3928	int tsm_err;
3929#else
3930	FILE *sendmail;
3931	int ret;
3932#endif
3933
3934#ifdef PHP_WIN32
3935	char *tempMailTo;
3936	char *tsm_errmsg = NULL;
3937	ADDRESS *addr;
3938	char *bufferTo = NULL, *bufferCc = NULL, *bufferBcc = NULL, *bufferHeader = NULL;
3939	int offset, bufferLen = 0;
3940	size_t bt_len;
3941
3942	if (headers) {
3943		bufferLen += strlen(headers);
3944	}
3945	if (to) {
3946		bufferLen += strlen(to) + 6;
3947	}
3948	if (cc) {
3949		bufferLen += strlen(cc) + 6;
3950	}
3951
3952#define PHP_IMAP_CLEAN	if (bufferTo) efree(bufferTo); if (bufferCc) efree(bufferCc); if (bufferBcc) efree(bufferBcc); if (bufferHeader) efree(bufferHeader);
3953#define PHP_IMAP_BAD_DEST PHP_IMAP_CLEAN; efree(tempMailTo); return (BAD_MSG_DESTINATION);
3954
3955	bufferHeader = (char *)emalloc(bufferLen + 1);
3956	memset(bufferHeader, 0, bufferLen);
3957	if (to && *to) {
3958		strlcat(bufferHeader, "To: ", bufferLen + 1);
3959		strlcat(bufferHeader, to, bufferLen + 1);
3960		strlcat(bufferHeader, "\r\n", bufferLen + 1);
3961		tempMailTo = estrdup(to);
3962		bt_len = strlen(to);
3963		bufferTo = (char *)safe_emalloc(bt_len, 1, 1);
3964		bt_len++;
3965		offset = 0;
3966		addr = NULL;
3967		rfc822_parse_adrlist(&addr, tempMailTo, NULL);
3968		while (addr) {
3969			if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) {
3970				PHP_IMAP_BAD_DEST;
3971			} else {
3972				bufferTo = safe_erealloc(bufferTo, bt_len, 1, strlen(addr->mailbox));
3973				bt_len += strlen(addr->mailbox);
3974				bufferTo = safe_erealloc(bufferTo, bt_len, 1, strlen(addr->host));
3975				bt_len += strlen(addr->host);
3976				offset += slprintf(bufferTo + offset, bt_len - offset, "%s@%s,", addr->mailbox, addr->host);
3977			}
3978			addr = addr->next;
3979		}
3980		efree(tempMailTo);
3981		if (offset>0) {
3982			bufferTo[offset-1] = 0;
3983		}
3984	}
3985
3986	if (cc && *cc) {
3987		strlcat(bufferHeader, "Cc: ", bufferLen + 1);
3988		strlcat(bufferHeader, cc, bufferLen + 1);
3989		strlcat(bufferHeader, "\r\n", bufferLen + 1);
3990		tempMailTo = estrdup(cc);
3991		bt_len = strlen(cc);
3992		bufferCc = (char *)safe_emalloc(bt_len, 1, 1);
3993		bt_len++;
3994		offset = 0;
3995		addr = NULL;
3996		rfc822_parse_adrlist(&addr, tempMailTo, NULL);
3997		while (addr) {
3998			if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) {
3999				PHP_IMAP_BAD_DEST;
4000			} else {
4001				bufferCc = safe_erealloc(bufferCc, bt_len, 1, strlen(addr->mailbox));
4002				bt_len += strlen(addr->mailbox);
4003				bufferCc = safe_erealloc(bufferCc, bt_len, 1, strlen(addr->host));
4004				bt_len += strlen(addr->host);
4005				offset += slprintf(bufferCc + offset, bt_len - offset, "%s@%s,", addr->mailbox, addr->host);
4006			}
4007			addr = addr->next;
4008		}
4009		efree(tempMailTo);
4010		if (offset>0) {
4011			bufferCc[offset-1] = 0;
4012		}
4013	}
4014
4015	if (bcc && *bcc) {
4016		tempMailTo = estrdup(bcc);
4017		bt_len = strlen(bcc);
4018		bufferBcc = (char *)safe_emalloc(bt_len, 1, 1);
4019		bt_len++;
4020		offset = 0;
4021		addr = NULL;
4022		rfc822_parse_adrlist(&addr, tempMailTo, NULL);
4023		while (addr) {
4024			if (addr->host == NULL || strcmp(addr->host, ERRHOST) == 0) {
4025				PHP_IMAP_BAD_DEST;
4026			} else {
4027				bufferBcc = safe_erealloc(bufferBcc, bt_len, 1, strlen(addr->mailbox));
4028				bt_len += strlen(addr->mailbox);
4029				bufferBcc = safe_erealloc(bufferBcc, bt_len, 1, strlen(addr->host));
4030				bt_len += strlen(addr->host);
4031				offset += slprintf(bufferBcc + offset, bt_len - offset, "%s@%s,", addr->mailbox, addr->host);
4032			}
4033			addr = addr->next;
4034		}
4035		efree(tempMailTo);
4036		if (offset>0) {
4037			bufferBcc[offset-1] = 0;
4038		}
4039	}
4040
4041	if (headers && *headers) {
4042		strlcat(bufferHeader, headers, bufferLen + 1);
4043	}
4044
4045	if (TSendMail(INI_STR("SMTP"), &tsm_err, &tsm_errmsg, bufferHeader, subject, bufferTo, message, bufferCc, bufferBcc, rpath) != SUCCESS) {
4046		if (tsm_errmsg) {
4047			php_error_docref(NULL, E_WARNING, "%s", tsm_errmsg);
4048			efree(tsm_errmsg);
4049		} else {
4050			php_error_docref(NULL, E_WARNING, "%s", GetSMErrorText(tsm_err));
4051		}
4052		PHP_IMAP_CLEAN;
4053		return 0;
4054	}
4055	PHP_IMAP_CLEAN;
4056#else
4057	if (!INI_STR("sendmail_path")) {
4058		return 0;
4059	}
4060	sendmail = popen(INI_STR("sendmail_path"), "w");
4061	if (sendmail) {
4062		if (rpath && rpath[0]) fprintf(sendmail, "From: %s\n", rpath);
4063		fprintf(sendmail, "To: %s\n", to);
4064		if (cc && cc[0]) fprintf(sendmail, "Cc: %s\n", cc);
4065		if (bcc && bcc[0]) fprintf(sendmail, "Bcc: %s\n", bcc);
4066		fprintf(sendmail, "Subject: %s\n", subject);
4067		if (headers != NULL) {
4068			fprintf(sendmail, "%s\n", headers);
4069		}
4070		fprintf(sendmail, "\n%s\n", message);
4071		ret = pclose(sendmail);
4072		if (ret == -1) {
4073			return 0;
4074		} else {
4075			return 1;
4076		}
4077	} else {
4078		php_error_docref(NULL, E_WARNING, "Could not execute mail delivery program");
4079		return 0;
4080	}
4081#endif
4082	return 1;
4083}
4084/* }}} */
4085
4086/* {{{ proto bool imap_mail(string to, string subject, string message [, string additional_headers [, string cc [, string bcc [, string rpath]]]])
4087   Send an email message */
4088PHP_FUNCTION(imap_mail)
4089{
4090	zend_string *to=NULL, *message=NULL, *headers=NULL, *subject=NULL, *cc=NULL, *bcc=NULL, *rpath=NULL;
4091	int argc = ZEND_NUM_ARGS();
4092
4093	if (zend_parse_parameters(argc, "SSS|SSSS", &to, &subject, &message,
4094		&headers, &cc, &bcc, &rpath) == FAILURE) {
4095		return;
4096	}
4097
4098	/* To: */
4099	if (!ZSTR_LEN(to)) {
4100		php_error_docref(NULL, E_WARNING, "No to field in mail command");
4101		RETURN_FALSE;
4102	}
4103
4104	/* Subject: */
4105	if (!ZSTR_LEN(subject)) {
4106		php_error_docref(NULL, E_WARNING, "No subject field in mail command");
4107		RETURN_FALSE;
4108	}
4109
4110	/* message body */
4111	if (!ZSTR_LEN(message)) {
4112		/* this is not really an error, so it is allowed. */
4113		php_error_docref(NULL, E_WARNING, "No message string in mail command");
4114		message = NULL;
4115	}
4116
4117	if (_php_imap_mail(ZSTR_VAL(to), ZSTR_VAL(subject), ZSTR_VAL(message), headers?ZSTR_VAL(headers):NULL, cc?ZSTR_VAL(cc):NULL,
4118			bcc?ZSTR_VAL(bcc):NULL, rpath?ZSTR_VAL(rpath):NULL)) {
4119		RETURN_TRUE;
4120	} else {
4121		RETURN_FALSE;
4122	}
4123}
4124/* }}} */
4125
4126/* {{{ proto array imap_search(resource stream_id, string criteria [, int options [, string charset]])
4127   Return a list of messages matching the given criteria */
4128PHP_FUNCTION(imap_search)
4129{
4130	zval *streamind;
4131	zend_string *criteria, *charset = NULL;
4132	zend_long flags = SE_FREE;
4133	pils *imap_le_struct;
4134	char *search_criteria;
4135	MESSAGELIST *cur;
4136	int argc = ZEND_NUM_ARGS();
4137	SEARCHPGM *pgm = NIL;
4138
4139	if (zend_parse_parameters(argc, "rS|lS", &streamind, &criteria, &flags, &charset) == FAILURE) {
4140		return;
4141	}
4142
4143	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
4144		RETURN_FALSE;
4145	}
4146
4147	search_criteria = estrndup(ZSTR_VAL(criteria), ZSTR_LEN(criteria));
4148
4149	IMAPG(imap_messages) = IMAPG(imap_messages_tail) = NIL;
4150	pgm = mail_criteria(search_criteria);
4151
4152	mail_search_full(imap_le_struct->imap_stream, (argc == 4 ? ZSTR_VAL(charset) : NIL), pgm, flags);
4153
4154	if (pgm && !(flags & SE_FREE)) {
4155		mail_free_searchpgm(&pgm);
4156	}
4157
4158	if (IMAPG(imap_messages) == NIL) {
4159		efree(search_criteria);
4160		RETURN_FALSE;
4161	}
4162
4163	array_init(return_value);
4164
4165	cur = IMAPG(imap_messages);
4166	while (cur != NIL) {
4167		add_next_index_long(return_value, cur->msgid);
4168		cur = cur->next;
4169	}
4170	mail_free_messagelist(&IMAPG(imap_messages), &IMAPG(imap_messages_tail));
4171	efree(search_criteria);
4172}
4173/* }}} */
4174
4175/* {{{ proto array imap_alerts(void)
4176   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. */
4177/* Author: CJH */
4178PHP_FUNCTION(imap_alerts)
4179{
4180	STRINGLIST *cur=NIL;
4181
4182	if (zend_parse_parameters_none() == FAILURE) {
4183		return;
4184	}
4185
4186	if (IMAPG(imap_alertstack) == NIL) {
4187		RETURN_FALSE;
4188	}
4189
4190	array_init(return_value);
4191
4192	cur = IMAPG(imap_alertstack);
4193	while (cur != NIL) {
4194		add_next_index_string(return_value, (char*)cur->LTEXT);
4195		cur = cur->next;
4196	}
4197	mail_free_stringlist(&IMAPG(imap_alertstack));
4198	IMAPG(imap_alertstack) = NIL;
4199}
4200/* }}} */
4201
4202/* {{{ proto array imap_errors(void)
4203   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. */
4204/* Author: CJH */
4205PHP_FUNCTION(imap_errors)
4206{
4207	ERRORLIST *cur=NIL;
4208
4209	if (zend_parse_parameters_none() == FAILURE) {
4210		return;
4211	}
4212
4213	if (IMAPG(imap_errorstack) == NIL) {
4214		RETURN_FALSE;
4215	}
4216
4217	array_init(return_value);
4218
4219	cur = IMAPG(imap_errorstack);
4220	while (cur != NIL) {
4221		add_next_index_string(return_value, (char*)cur->LTEXT);
4222		cur = cur->next;
4223	}
4224	mail_free_errorlist(&IMAPG(imap_errorstack));
4225	IMAPG(imap_errorstack) = NIL;
4226}
4227/* }}} */
4228
4229/* {{{ proto string imap_last_error(void)
4230   Returns the last error that was generated by an IMAP function. The error stack is NOT cleared after this call. */
4231/* Author: CJH */
4232PHP_FUNCTION(imap_last_error)
4233{
4234	ERRORLIST *cur=NIL;
4235
4236	if (zend_parse_parameters_none() == FAILURE) {
4237		return;
4238	}
4239
4240	if (IMAPG(imap_errorstack) == NIL) {
4241		RETURN_FALSE;
4242	}
4243
4244	cur = IMAPG(imap_errorstack);
4245	while (cur != NIL) {
4246		if (cur->next == NIL) {
4247			RETURN_STRING((char*)cur->LTEXT);
4248		}
4249		cur = cur->next;
4250	}
4251}
4252/* }}} */
4253
4254/* {{{ proto array imap_mime_header_decode(string str)
4255   Decode mime header element in accordance with RFC 2047 and return array of objects containing 'charset' encoding and decoded 'text' */
4256PHP_FUNCTION(imap_mime_header_decode)
4257{
4258	/* Author: Ted Parnefors <ted@mtv.se> */
4259	zval myobject;
4260	zend_string *str;
4261	char *string, *charset, encoding, *text, *decode;
4262	long charset_token, encoding_token, end_token, end, offset=0, i;
4263	unsigned long newlength;
4264
4265	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &str) == FAILURE) {
4266		return;
4267	}
4268
4269	array_init(return_value);
4270
4271	string = ZSTR_VAL(str);
4272	end = ZSTR_LEN(str);
4273
4274	charset = (char *) safe_emalloc((end + 1), 2, 0);
4275	text = &charset[end + 1];
4276	while (offset < end) {	/* Reached end of the string? */
4277		if ((charset_token = (long)php_memnstr(&string[offset], "=?", 2, string + end))) {	/* Is there anything encoded in the string? */
4278			charset_token -= (long)string;
4279			if (offset != charset_token) {	/* Is there anything before the encoded data? */
4280				/* Retrieve unencoded data that is found before encoded data */
4281				memcpy(text, &string[offset], charset_token-offset);
4282				text[charset_token - offset] = 0x00;
4283				object_init(&myobject);
4284				add_property_string(&myobject, "charset", "default");
4285				add_property_string(&myobject, "text", text);
4286				zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &myobject);
4287			}
4288			if ((encoding_token = (long)php_memnstr(&string[charset_token+2], "?", 1, string+end))) {		/* Find token for encoding */
4289				encoding_token -= (long)string;
4290				if ((end_token = (long)php_memnstr(&string[encoding_token+3], "?=", 2, string+end))) {	/* Find token for end of encoded data */
4291					end_token -= (long)string;
4292					memcpy(charset, &string[charset_token + 2], encoding_token - (charset_token + 2));	/* Extract charset encoding */
4293					charset[encoding_token-(charset_token + 2)] = 0x00;
4294					encoding=string[encoding_token + 1];	/* Extract encoding from string */
4295					memcpy(text, &string[encoding_token + 3], end_token - (encoding_token + 3));	/* Extract text */
4296					text[end_token - (encoding_token + 3)] = 0x00;
4297					decode = text;
4298					if (encoding == 'q' || encoding == 'Q') {	/* Decode 'q' encoded data */
4299						for(i=0; text[i] != 0x00; i++) if (text[i] == '_') text[i] = ' ';	/* Replace all *_' with space. */
4300						decode = (char *)rfc822_qprint((unsigned char *) text, strlen(text), &newlength);
4301					} else if (encoding == 'b' || encoding == 'B') {
4302						decode = (char *)rfc822_base64((unsigned char *) text, strlen(text), &newlength); /* Decode 'B' encoded data */
4303					}
4304					if (decode == NULL) {
4305						efree(charset);
4306						zval_dtor(return_value);
4307						RETURN_FALSE;
4308					}
4309					object_init(&myobject);
4310					add_property_string(&myobject, "charset", charset);
4311					add_property_string(&myobject, "text", decode);
4312					zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &myobject);
4313
4314					/* only free decode if it was allocated by rfc822_qprint or rfc822_base64 */
4315					if (decode != text) {
4316						fs_give((void**)&decode);
4317					}
4318
4319					offset = end_token+2;
4320					for (i = 0; (string[offset + i] == ' ') || (string[offset + i] == 0x0a) || (string[offset + i] == 0x0d) || (string[offset + i] == '\t'); i++);
4321					if ((string[offset + i] == '=') && (string[offset + i + 1] == '?') && (offset + i < end)) {
4322						offset += i;
4323					}
4324					continue;	/*/ Iterate the loop again please. */
4325				}
4326			}
4327		} else {
4328			/* Just some tweaking to optimize the code, and get the end statements work in a general manner.
4329			 * If we end up here we didn't find a position for "charset_token",
4330			 * so we need to set it to the start of the yet unextracted data.
4331			 */
4332			charset_token = offset;
4333		}
4334		/* Return the rest of the data as unencoded, as it was either unencoded or was missing separators
4335		   which rendered the remainder of the string impossible for us to decode. */
4336		memcpy(text, &string[charset_token], end - charset_token);	/* Extract unencoded text from string */
4337		text[end - charset_token] = 0x00;
4338		object_init(&myobject);
4339		add_property_string(&myobject, "charset", "default");
4340		add_property_string(&myobject, "text", text);
4341		zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &myobject);
4342
4343		offset = end;	/* We have reached the end of the string. */
4344	}
4345	efree(charset);
4346}
4347/* }}} */
4348
4349/* Support Functions */
4350
4351#ifdef HAVE_RFC822_OUTPUT_ADDRESS_LIST
4352/* {{{ _php_rfc822_soutr
4353 */
4354static long _php_rfc822_soutr (void *stream, char *string)
4355{
4356	smart_str *ret = (smart_str*)stream;
4357	int len = strlen(string);
4358
4359	smart_str_appendl(ret, string, len);
4360	return LONGT;
4361}
4362/* }}} */
4363
4364/* {{{ _php_rfc822_write_address
4365 */
4366static zend_string* _php_rfc822_write_address(ADDRESS *addresslist)
4367{
4368	char address[MAILTMPLEN];
4369	smart_str ret = {0};
4370	RFC822BUFFER buf;
4371
4372	buf.beg = address;
4373	buf.cur = buf.beg;
4374	buf.end = buf.beg + sizeof(address) - 1;
4375	buf.s = &ret;
4376	buf.f = _php_rfc822_soutr;
4377	rfc822_output_address_list(&buf, addresslist, 0, NULL);
4378	rfc822_output_flush(&buf);
4379	smart_str_0(&ret);
4380	return ret.s;
4381}
4382/* }}} */
4383
4384#else
4385
4386/* {{{ _php_rfc822_len
4387 * Calculate string length based on imap's rfc822_cat function.
4388 */
4389static int _php_rfc822_len(char *str)
4390{
4391	int len;
4392	char *p;
4393
4394	if (!str || !*str) {
4395		return 0;
4396	}
4397
4398	/* strings with special characters will need to be quoted, as a safety measure we
4399	 * add 2 bytes for the quotes just in case.
4400	 */
4401	len = strlen(str) + 2;
4402	p = str;
4403	/* rfc822_cat() will escape all " and \ characters, therefor we need to increase
4404	 * our buffer length to account for these characters.
4405	 */
4406	while ((p = strpbrk(p, "\\\""))) {
4407		p++;
4408		len++;
4409	}
4410
4411	return len;
4412}
4413/* }}} */
4414
4415/* {{{ _php_imap_get_address_size
4416 */
4417static int _php_imap_address_size (ADDRESS *addresslist)
4418{
4419	ADDRESS *tmp;
4420	int ret=0, num_ent=0;
4421
4422	tmp = addresslist;
4423
4424	if (tmp) do {
4425		ret += _php_rfc822_len(tmp->personal);
4426		ret += _php_rfc822_len(tmp->adl);
4427		ret += _php_rfc822_len(tmp->mailbox);
4428		ret += _php_rfc822_len(tmp->host);
4429		num_ent++;
4430	} while ((tmp = tmp->next));
4431
4432	/*
4433	 * rfc822_write_address_full() needs some extra space for '<>,', etc.
4434	 * for this perpouse we allocate additional PHP_IMAP_ADDRESS_SIZE_BUF bytes
4435	 * by default this buffer is 10 bytes long
4436	*/
4437	ret += (ret) ? num_ent*PHP_IMAP_ADDRESS_SIZE_BUF : 0;
4438
4439	return ret;
4440}
4441
4442/* }}} */
4443
4444/* {{{ _php_rfc822_write_address
4445 */
4446static zend_string* _php_rfc822_write_address(ADDRESS *addresslist)
4447{
4448	char address[SENDBUFLEN];
4449
4450	if (_php_imap_address_size(addresslist) >= SENDBUFLEN) {
4451		php_error_docref(NULL, E_ERROR, "Address buffer overflow");
4452		return NULL;
4453	}
4454	address[0] = 0;
4455	rfc822_write_address(address, addresslist);
4456	return zend_string_init(address, strlen(address), 0);
4457}
4458/* }}} */
4459#endif
4460/* {{{ _php_imap_parse_address
4461 */
4462static zend_string* _php_imap_parse_address (ADDRESS *addresslist, zval *paddress)
4463{
4464	zend_string *fulladdress;
4465	ADDRESS *addresstmp;
4466	zval tmpvals;
4467
4468	addresstmp = addresslist;
4469
4470	fulladdress = _php_rfc822_write_address(addresstmp);
4471
4472	addresstmp = addresslist;
4473	do {
4474		object_init(&tmpvals);
4475		if (addresstmp->personal) add_property_string(&tmpvals, "personal", addresstmp->personal);
4476		if (addresstmp->adl) add_property_string(&tmpvals, "adl", addresstmp->adl);
4477		if (addresstmp->mailbox) add_property_string(&tmpvals, "mailbox", addresstmp->mailbox);
4478		if (addresstmp->host) add_property_string(&tmpvals, "host", addresstmp->host);
4479		add_next_index_object(paddress, &tmpvals);
4480	} while ((addresstmp = addresstmp->next));
4481	return fulladdress;
4482}
4483/* }}} */
4484
4485/* {{{ _php_make_header_object
4486 */
4487static void _php_make_header_object(zval *myzvalue, ENVELOPE *en)
4488{
4489	zval paddress;
4490	zend_string *fulladdress=NULL;
4491
4492	object_init(myzvalue);
4493
4494	if (en->remail) add_property_string(myzvalue, "remail", en->remail);
4495	if (en->date) add_property_string(myzvalue, "date", (char*)en->date);
4496	if (en->date) add_property_string(myzvalue, "Date", (char*)en->date);
4497	if (en->subject) add_property_string(myzvalue, "subject", en->subject);
4498	if (en->subject) add_property_string(myzvalue, "Subject", en->subject);
4499	if (en->in_reply_to) add_property_string(myzvalue, "in_reply_to", en->in_reply_to);
4500	if (en->message_id) add_property_string(myzvalue, "message_id", en->message_id);
4501	if (en->newsgroups) add_property_string(myzvalue, "newsgroups", en->newsgroups);
4502	if (en->followup_to) add_property_string(myzvalue, "followup_to", en->followup_to);
4503	if (en->references) add_property_string(myzvalue, "references", en->references);
4504
4505	if (en->to) {
4506		array_init(&paddress);
4507		fulladdress = _php_imap_parse_address(en->to, &paddress);
4508		if (fulladdress) {
4509			add_property_str(myzvalue, "toaddress", fulladdress);
4510		}
4511		add_assoc_object(myzvalue, "to", &paddress);
4512	}
4513
4514	if (en->from) {
4515		array_init(&paddress);
4516		fulladdress = _php_imap_parse_address(en->from, &paddress);
4517		if (fulladdress) {
4518			add_property_str(myzvalue, "fromaddress", fulladdress);
4519		}
4520		add_assoc_object(myzvalue, "from", &paddress);
4521	}
4522
4523	if (en->cc) {
4524		array_init(&paddress);
4525		fulladdress = _php_imap_parse_address(en->cc, &paddress);
4526		if (fulladdress) {
4527			add_property_str(myzvalue, "ccaddress", fulladdress);
4528		}
4529		add_assoc_object(myzvalue, "cc", &paddress);
4530	}
4531
4532	if (en->bcc) {
4533		array_init(&paddress);
4534		fulladdress = _php_imap_parse_address(en->bcc, &paddress);
4535		if (fulladdress) {
4536			add_property_str(myzvalue, "bccaddress", fulladdress);
4537		}
4538		add_assoc_object(myzvalue, "bcc", &paddress);
4539	}
4540
4541	if (en->reply_to) {
4542		array_init(&paddress);
4543		fulladdress = _php_imap_parse_address(en->reply_to, &paddress);
4544		if (fulladdress) {
4545			add_property_str(myzvalue, "reply_toaddress", fulladdress);
4546		}
4547		add_assoc_object(myzvalue, "reply_to", &paddress);
4548	}
4549
4550	if (en->sender) {
4551		array_init(&paddress);
4552		fulladdress = _php_imap_parse_address(en->sender, &paddress);
4553		if (fulladdress) {
4554			add_property_str(myzvalue, "senderaddress", fulladdress);
4555		}
4556		add_assoc_object(myzvalue, "sender", &paddress);
4557	}
4558
4559	if (en->return_path) {
4560		array_init(&paddress);
4561		fulladdress = _php_imap_parse_address(en->return_path, &paddress);
4562		if (fulladdress) {
4563			add_property_str(myzvalue, "return_pathaddress", fulladdress);
4564		}
4565		add_assoc_object(myzvalue, "return_path", &paddress);
4566	}
4567}
4568/* }}} */
4569
4570/* {{{ _php_imap_add_body
4571 */
4572void _php_imap_add_body(zval *arg, BODY *body)
4573{
4574	zval parametres, param, dparametres, dparam;
4575	PARAMETER *par, *dpar;
4576	PART *part;
4577
4578	if (body->type <= TYPEMAX) {
4579		add_property_long(arg, "type", body->type);
4580	}
4581
4582	if (body->encoding <= ENCMAX) {
4583		add_property_long(arg, "encoding", body->encoding);
4584	}
4585
4586	if (body->subtype) {
4587		add_property_long(arg, "ifsubtype", 1);
4588		add_property_string(arg, "subtype", body->subtype);
4589	} else {
4590		add_property_long(arg, "ifsubtype", 0);
4591	}
4592
4593	if (body->description) {
4594		add_property_long(arg, "ifdescription", 1);
4595		add_property_string(arg, "description", body->description);
4596	} else {
4597		add_property_long(arg, "ifdescription", 0);
4598	}
4599
4600	if (body->id) {
4601		add_property_long(arg, "ifid", 1);
4602		add_property_string(arg, "id", body->id);
4603	} else {
4604		add_property_long(arg, "ifid", 0);
4605	}
4606
4607	if (body->size.lines) {
4608		add_property_long(arg, "lines", body->size.lines);
4609	}
4610
4611	if (body->size.bytes) {
4612		add_property_long(arg, "bytes", body->size.bytes);
4613	}
4614
4615#ifdef IMAP41
4616	if (body->disposition.type) {
4617		add_property_long(arg, "ifdisposition", 1);
4618		add_property_string(arg, "disposition", body->disposition.type);
4619	} else {
4620		add_property_long(arg, "ifdisposition", 0);
4621	}
4622
4623	if (body->disposition.parameter) {
4624		dpar = body->disposition.parameter;
4625		add_property_long(arg, "ifdparameters", 1);
4626		array_init(&dparametres);
4627		do {
4628			object_init(&dparam);
4629			add_property_string(&dparam, "attribute", dpar->attribute);
4630			add_property_string(&dparam, "value", dpar->value);
4631			add_next_index_object(&dparametres, &dparam);
4632		} while ((dpar = dpar->next));
4633		add_assoc_object(arg, "dparameters", &dparametres);
4634	} else {
4635		add_property_long(arg, "ifdparameters", 0);
4636	}
4637#endif
4638
4639	if ((par = body->parameter)) {
4640		add_property_long(arg, "ifparameters", 1);
4641
4642		array_init(&parametres);
4643		do {
4644			object_init(&param);
4645			if (par->attribute) {
4646				add_property_string(&param, "attribute", par->attribute);
4647			}
4648			if (par->value) {
4649				add_property_string(&param, "value", par->value);
4650			}
4651
4652			add_next_index_object(&parametres, &param);
4653		} while ((par = par->next));
4654	} else {
4655		object_init(&parametres);
4656		add_property_long(arg, "ifparameters", 0);
4657	}
4658	add_assoc_object(arg, "parameters", &parametres);
4659
4660	/* multipart message ? */
4661	if (body->type == TYPEMULTIPART) {
4662		array_init(&parametres);
4663		for (part = body->CONTENT_PART; part; part = part->next) {
4664			object_init(&param);
4665			_php_imap_add_body(&param, &part->body);
4666			add_next_index_object(&parametres, &param);
4667		}
4668		add_assoc_object(arg, "parts", &parametres);
4669	}
4670
4671	/* encapsulated message ? */
4672	if ((body->type == TYPEMESSAGE) && (!strcasecmp(body->subtype, "rfc822"))) {
4673		body = body->CONTENT_MSG_BODY;
4674		array_init(&parametres);
4675		object_init(&param);
4676		_php_imap_add_body(&param, body);
4677		add_next_index_object(&parametres, &param);
4678		add_assoc_object(arg, "parts", &parametres);
4679	}
4680}
4681/* }}} */
4682
4683/* imap_thread, stealing this from header cclient -rjs3 */
4684/* {{{ build_thread_tree_helper
4685 */
4686static void build_thread_tree_helper(THREADNODE *cur, zval *tree, long *numNodes, char *buf)
4687{
4688	unsigned long thisNode = *numNodes;
4689
4690	/* define "#.num" */
4691	snprintf(buf, 25, "%ld.num", thisNode);
4692
4693	add_assoc_long(tree, buf, cur->num);
4694
4695	snprintf(buf, 25, "%ld.next", thisNode);
4696	if(cur->next) {
4697		(*numNodes)++;
4698		add_assoc_long(tree, buf, *numNodes);
4699		build_thread_tree_helper(cur->next, tree, numNodes, buf);
4700	} else { /* "null pointer" */
4701		add_assoc_long(tree, buf, 0);
4702	}
4703
4704	snprintf(buf, 25, "%ld.branch", thisNode);
4705	if(cur->branch) {
4706		(*numNodes)++;
4707		add_assoc_long(tree, buf, *numNodes);
4708		build_thread_tree_helper(cur->branch, tree, numNodes, buf);
4709	} else { /* "null pointer" */
4710		add_assoc_long(tree, buf, 0);
4711	}
4712}
4713/* }}} */
4714
4715/* {{{ build_thread_tree
4716 */
4717static int build_thread_tree(THREADNODE *top, zval **tree)
4718{
4719	long numNodes = 0;
4720	char buf[25];
4721
4722	array_init(*tree);
4723
4724	build_thread_tree_helper(top, *tree, &numNodes, buf);
4725
4726	return SUCCESS;
4727}
4728/* }}} */
4729
4730/* {{{ proto array imap_thread(resource stream_id [, int options])
4731   Return threaded by REFERENCES tree */
4732PHP_FUNCTION(imap_thread)
4733{
4734	zval *streamind;
4735	pils *imap_le_struct;
4736	zend_long flags = SE_FREE;
4737	char criteria[] = "ALL";
4738	THREADNODE *top;
4739	int argc = ZEND_NUM_ARGS();
4740	SEARCHPGM *pgm = NIL;
4741
4742	if (zend_parse_parameters(argc, "r|l", &streamind, &flags) == FAILURE) {
4743		return;
4744	}
4745
4746	if ((imap_le_struct = (pils *)zend_fetch_resource(Z_RES_P(streamind), "imap", le_imap)) == NULL) {
4747		RETURN_FALSE;
4748	}
4749
4750	pgm = mail_criteria(criteria);
4751	top = mail_thread(imap_le_struct->imap_stream, "REFERENCES", NIL, pgm, flags);
4752	if (pgm && !(flags & SE_FREE)) {
4753		mail_free_searchpgm(&pgm);
4754	}
4755
4756	if(top == NIL) {
4757		php_error_docref(NULL, E_WARNING, "Function returned an empty tree");
4758		RETURN_FALSE;
4759	}
4760
4761	/* Populate our return value data structure here. */
4762	if(build_thread_tree(top, &return_value) == FAILURE) {
4763		mail_free_threadnode(&top);
4764		RETURN_FALSE;
4765	}
4766	mail_free_threadnode(&top);
4767}
4768/* }}} */
4769
4770/* {{{ proto mixed imap_timeout(int timeout_type [, int timeout])
4771   Set or fetch imap timeout */
4772PHP_FUNCTION(imap_timeout)
4773{
4774	zend_long ttype, timeout=-1;
4775	int timeout_type;
4776
4777	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &ttype, &timeout) == FAILURE) {
4778		RETURN_FALSE;
4779	}
4780
4781	if (timeout == -1) {
4782		switch (ttype) {
4783			case 1:
4784				timeout_type = GET_OPENTIMEOUT;
4785				break;
4786			case 2:
4787				timeout_type = GET_READTIMEOUT;
4788				break;
4789			case 3:
4790				timeout_type = GET_WRITETIMEOUT;
4791				break;
4792			case 4:
4793				timeout_type = GET_CLOSETIMEOUT;
4794				break;
4795			default:
4796				RETURN_FALSE;
4797				break;
4798		}
4799
4800		timeout = (long) mail_parameters(NIL, timeout_type, NIL);
4801		RETURN_LONG(timeout);
4802	} else if (timeout >= 0) {
4803		switch (ttype) {
4804			case 1:
4805				timeout_type = SET_OPENTIMEOUT;
4806				break;
4807			case 2:
4808				timeout_type = SET_READTIMEOUT;
4809				break;
4810			case 3:
4811				timeout_type = SET_WRITETIMEOUT;
4812				break;
4813			case 4:
4814				timeout_type = SET_CLOSETIMEOUT;
4815				break;
4816			default:
4817				RETURN_FALSE;
4818				break;
4819		}
4820
4821		timeout = (long) mail_parameters(NIL, timeout_type, (void *) timeout);
4822		RETURN_TRUE;
4823	} else {
4824		RETURN_FALSE;
4825	}
4826}
4827/* }}} */
4828
4829#define GETS_FETCH_SIZE 8196LU
4830static char *php_mail_gets(readfn_t f, void *stream, unsigned long size, GETS_DATA *md) /* {{{ */
4831{
4832
4833	/*	write to the gets stream if it is set,
4834		otherwise forward to c-clients gets */
4835	if (IMAPG(gets_stream)) {
4836		char buf[GETS_FETCH_SIZE];
4837
4838		while (size) {
4839			unsigned long read;
4840
4841			if (size > GETS_FETCH_SIZE) {
4842				read = GETS_FETCH_SIZE;
4843				size -=GETS_FETCH_SIZE;
4844			} else {
4845				read = size;
4846				size = 0;
4847			}
4848
4849			if (!f(stream, read, buf)) {
4850				php_error_docref(NULL, E_WARNING, "Failed to read from socket");
4851				break;
4852			} else if (read != php_stream_write(IMAPG(gets_stream), buf, read)) {
4853				php_error_docref(NULL, E_WARNING, "Failed to write to stream");
4854				break;
4855			}
4856		}
4857		return NULL;
4858	} else {
4859		char *buf = pemalloc(size + 1, 1);
4860
4861		if (f(stream, size, buf)) {
4862			buf[size] = '\0';
4863		} else {
4864			php_error_docref(NULL, E_WARNING, "Failed to read from socket");
4865			free(buf);
4866			buf = NULL;
4867		}
4868		return buf;
4869	}
4870}
4871/* }}} */
4872
4873/* {{{ Interfaces to C-client
4874 */
4875PHP_IMAP_EXPORT void mm_searched(MAILSTREAM *stream, unsigned long number)
4876{
4877	MESSAGELIST *cur = NIL;
4878
4879	if (IMAPG(imap_messages) == NIL) {
4880		IMAPG(imap_messages) = mail_newmessagelist();
4881		IMAPG(imap_messages)->msgid = number;
4882		IMAPG(imap_messages)->next = NIL;
4883		IMAPG(imap_messages_tail) = IMAPG(imap_messages);
4884	} else {
4885		cur = IMAPG(imap_messages_tail);
4886		cur->next = mail_newmessagelist();
4887		cur = cur->next;
4888		cur->msgid = number;
4889		cur->next = NIL;
4890		IMAPG(imap_messages_tail) = cur;
4891	}
4892}
4893
4894PHP_IMAP_EXPORT void mm_exists(MAILSTREAM *stream, unsigned long number)
4895{
4896}
4897
4898PHP_IMAP_EXPORT void mm_expunged(MAILSTREAM *stream, unsigned long number)
4899{
4900}
4901
4902PHP_IMAP_EXPORT void mm_flags(MAILSTREAM *stream, unsigned long number)
4903{
4904}
4905
4906/* Author: CJH */
4907PHP_IMAP_EXPORT void mm_notify(MAILSTREAM *stream, char *str, long errflg)
4908{
4909	STRINGLIST *cur = NIL;
4910
4911	if (strncmp(str, "[ALERT] ", 8) == 0) {
4912		if (IMAPG(imap_alertstack) == NIL) {
4913			IMAPG(imap_alertstack) = mail_newstringlist();
4914			IMAPG(imap_alertstack)->LSIZE = strlen((char*)(IMAPG(imap_alertstack)->LTEXT = (unsigned char*)cpystr(str)));
4915			IMAPG(imap_alertstack)->next = NIL;
4916		} else {
4917			cur = IMAPG(imap_alertstack);
4918			while (cur->next != NIL) {
4919				cur = cur->next;
4920			}
4921			cur->next = mail_newstringlist ();
4922			cur = cur->next;
4923			cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(str)));
4924			cur->next = NIL;
4925		}
4926	}
4927}
4928
4929PHP_IMAP_EXPORT void mm_list(MAILSTREAM *stream, DTYPE delimiter, char *mailbox, long attributes)
4930{
4931	STRINGLIST *cur=NIL;
4932	FOBJECTLIST *ocur=NIL;
4933
4934	if (IMAPG(folderlist_style) == FLIST_OBJECT) {
4935		/* build up a the new array of objects */
4936		/* Author: CJH */
4937		if (IMAPG(imap_folder_objects) == NIL) {
4938			IMAPG(imap_folder_objects) = mail_newfolderobjectlist();
4939			IMAPG(imap_folder_objects)->LSIZE=strlen((char*)(IMAPG(imap_folder_objects)->LTEXT = (unsigned char*)cpystr(mailbox)));
4940			IMAPG(imap_folder_objects)->delimiter = delimiter;
4941			IMAPG(imap_folder_objects)->attributes = attributes;
4942			IMAPG(imap_folder_objects)->next = NIL;
4943			IMAPG(imap_folder_objects_tail) = IMAPG(imap_folder_objects);
4944		} else {
4945			ocur=IMAPG(imap_folder_objects_tail);
4946			ocur->next=mail_newfolderobjectlist();
4947			ocur=ocur->next;
4948			ocur->LSIZE = strlen((char*)(ocur->LTEXT = (unsigned char*)cpystr(mailbox)));
4949			ocur->delimiter = delimiter;
4950			ocur->attributes = attributes;
4951			ocur->next = NIL;
4952			IMAPG(imap_folder_objects_tail) = ocur;
4953		}
4954
4955	} else {
4956		/* build the old IMAPG(imap_folders) variable to allow old imap_listmailbox() to work */
4957		if (!(attributes & LATT_NOSELECT)) {
4958			if (IMAPG(imap_folders) == NIL) {
4959				IMAPG(imap_folders)=mail_newstringlist();
4960				IMAPG(imap_folders)->LSIZE=strlen((char*)(IMAPG(imap_folders)->LTEXT = (unsigned char*)cpystr(mailbox)));
4961				IMAPG(imap_folders)->next=NIL;
4962				IMAPG(imap_folders_tail) = IMAPG(imap_folders);
4963			} else {
4964				cur=IMAPG(imap_folders_tail);
4965				cur->next=mail_newstringlist ();
4966				cur=cur->next;
4967				cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(mailbox)));
4968				cur->next = NIL;
4969				IMAPG(imap_folders_tail) = cur;
4970			}
4971		}
4972	}
4973}
4974
4975PHP_IMAP_EXPORT void mm_lsub(MAILSTREAM *stream, DTYPE delimiter, char *mailbox, long attributes)
4976{
4977	STRINGLIST *cur=NIL;
4978	FOBJECTLIST *ocur=NIL;
4979
4980	if (IMAPG(folderlist_style) == FLIST_OBJECT) {
4981		/* build the array of objects */
4982		/* Author: CJH */
4983		if (IMAPG(imap_sfolder_objects) == NIL) {
4984			IMAPG(imap_sfolder_objects) = mail_newfolderobjectlist();
4985			IMAPG(imap_sfolder_objects)->LSIZE = strlen((char*)(IMAPG(imap_sfolder_objects)->LTEXT = (unsigned char*)cpystr(mailbox)));
4986			IMAPG(imap_sfolder_objects)->delimiter = delimiter;
4987			IMAPG(imap_sfolder_objects)->attributes = attributes;
4988			IMAPG(imap_sfolder_objects)->next = NIL;
4989			IMAPG(imap_sfolder_objects_tail) = IMAPG(imap_sfolder_objects);
4990		} else {
4991			ocur=IMAPG(imap_sfolder_objects_tail);
4992			ocur->next=mail_newfolderobjectlist();
4993			ocur=ocur->next;
4994			ocur->LSIZE=strlen((char*)(ocur->LTEXT = (unsigned char*)cpystr(mailbox)));
4995			ocur->delimiter = delimiter;
4996			ocur->attributes = attributes;
4997			ocur->next = NIL;
4998			IMAPG(imap_sfolder_objects_tail) = ocur;
4999		}
5000	} else {
5001		/* build the old simple array for imap_listsubscribed() */
5002		if (IMAPG(imap_sfolders) == NIL) {
5003			IMAPG(imap_sfolders)=mail_newstringlist();
5004			IMAPG(imap_sfolders)->LSIZE=strlen((char*)(IMAPG(imap_sfolders)->LTEXT = (unsigned char*)cpystr(mailbox)));
5005			IMAPG(imap_sfolders)->next=NIL;
5006			IMAPG(imap_sfolders_tail) = IMAPG(imap_sfolders);
5007		} else {
5008			cur=IMAPG(imap_sfolders_tail);
5009			cur->next=mail_newstringlist ();
5010			cur=cur->next;
5011			cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(mailbox)));
5012			cur->next = NIL;
5013			IMAPG(imap_sfolders_tail) = cur;
5014		}
5015	}
5016}
5017
5018PHP_IMAP_EXPORT void mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status)
5019{
5020
5021	IMAPG(status_flags)=status->flags;
5022	if (IMAPG(status_flags) & SA_MESSAGES) {
5023		IMAPG(status_messages)=status->messages;
5024	}
5025	if (IMAPG(status_flags) & SA_RECENT) {
5026		IMAPG(status_recent)=status->recent;
5027	}
5028	if (IMAPG(status_flags) & SA_UNSEEN) {
5029		IMAPG(status_unseen)=status->unseen;
5030	}
5031	if (IMAPG(status_flags) & SA_UIDNEXT) {
5032		IMAPG(status_uidnext)=status->uidnext;
5033	}
5034	if (IMAPG(status_flags) & SA_UIDVALIDITY) {
5035		IMAPG(status_uidvalidity)=status->uidvalidity;
5036	}
5037}
5038
5039PHP_IMAP_EXPORT void mm_log(char *str, long errflg)
5040{
5041	ERRORLIST *cur = NIL;
5042
5043	/* Author: CJH */
5044	if (errflg != NIL) { /* CJH: maybe put these into a more comprehensive log for debugging purposes? */
5045		if (IMAPG(imap_errorstack) == NIL) {
5046			IMAPG(imap_errorstack) = mail_newerrorlist();
5047			IMAPG(imap_errorstack)->LSIZE = strlen((char*)(IMAPG(imap_errorstack)->LTEXT = (unsigned char*)cpystr(str)));
5048			IMAPG(imap_errorstack)->errflg = errflg;
5049			IMAPG(imap_errorstack)->next = NIL;
5050		} else {
5051			cur = IMAPG(imap_errorstack);
5052			while (cur->next != NIL) {
5053				cur = cur->next;
5054			}
5055			cur->next = mail_newerrorlist();
5056			cur = cur->next;
5057			cur->LSIZE = strlen((char*)(cur->LTEXT = (unsigned char*)cpystr(str)));
5058			cur->errflg = errflg;
5059			cur->next = NIL;
5060		}
5061	}
5062}
5063
5064PHP_IMAP_EXPORT void mm_dlog(char *str)
5065{
5066	/* CJH: this is for debugging; it might be useful to allow setting
5067	   the stream to debug mode and capturing this somewhere - syslog?
5068	   php debugger? */
5069}
5070
5071PHP_IMAP_EXPORT void mm_login(NETMBX *mb, char *user, char *pwd, long trial)
5072{
5073
5074	if (*mb->user) {
5075		strlcpy (user, mb->user, MAILTMPLEN);
5076	} else {
5077		strlcpy (user, IMAPG(imap_user), MAILTMPLEN);
5078	}
5079	strlcpy (pwd, IMAPG(imap_password), MAILTMPLEN);
5080}
5081
5082PHP_IMAP_EXPORT void mm_critical(MAILSTREAM *stream)
5083{
5084}
5085
5086PHP_IMAP_EXPORT void mm_nocritical(MAILSTREAM *stream)
5087{
5088}
5089
5090PHP_IMAP_EXPORT long mm_diskerror(MAILSTREAM *stream, long errcode, long serious)
5091{
5092	return 1;
5093}
5094
5095PHP_IMAP_EXPORT void mm_fatal(char *str)
5096{
5097}
5098/* }}} */
5099
5100/*
5101 * Local variables:
5102 * tab-width: 4
5103 * c-basic-offset: 4
5104 * End:
5105 * vim600: sw=4 ts=4 fdm=marker
5106 * vim<600: sw=4 ts=4
5107 */
5108