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