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