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