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