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