1703 linhas
49 KiB
C++
1703 linhas
49 KiB
C++
/*
|
|
+----------------------------------------------------------------------+
|
|
| HipHop for PHP |
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
|
|
| Copyright (c) 1997-2010 The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#include <runtime/ext/ext_imap.h>
|
|
#include <runtime/base/zend/zend_string.h>
|
|
#include <util/logger.h>
|
|
|
|
#include <system/lib/systemlib.h>
|
|
|
|
#include <c-client.h> /* includes mail.h and rfc822.h */
|
|
#define namespace namespace_
|
|
#include <imap4r1.h> /* location of c-client quota functions */
|
|
#undef namespace
|
|
|
|
#define PHP_EXPUNGE 32768
|
|
#define PHP_IMAP_ADDRESS_SIZE_BUF 10
|
|
|
|
#ifndef SENDBUFLEN
|
|
#define SENDBUFLEN 16385
|
|
#endif
|
|
|
|
namespace HPHP {
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
class ImapStream : public SweepableResourceData {
|
|
public:
|
|
DECLARE_OBJECT_ALLOCATION(ImapStream);
|
|
|
|
ImapStream(MAILSTREAM *stream, int64_t flag)
|
|
: m_stream(stream), m_flag(flag) {
|
|
}
|
|
~ImapStream() {
|
|
close();
|
|
}
|
|
|
|
// overriding ResourceData
|
|
static StaticString s_class_name;
|
|
virtual CStrRef o_getClassNameHook() const { return s_class_name; }
|
|
|
|
void close();
|
|
|
|
bool checkMsgNumber(int64_t msgindex) {
|
|
if ((msgindex < 1) || ((unsigned) msgindex > m_stream->nmsgs)) {
|
|
Logger::Warning("Bad message number");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
MAILSTREAM *m_stream;
|
|
int64_t m_flag;
|
|
};
|
|
|
|
StaticString ImapStream::s_class_name("imap");
|
|
IMPLEMENT_OBJECT_ALLOCATION(ImapStream);
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
enum FolderListStyle {
|
|
FLIST_ARRAY,
|
|
FLIST_OBJECT
|
|
};
|
|
|
|
struct FOBJECTLIST {
|
|
SIZEDTEXT text;
|
|
int delimiter;
|
|
long attributes;
|
|
struct FOBJECTLIST *next;
|
|
};
|
|
|
|
struct ERRORLIST {
|
|
SIZEDTEXT text;
|
|
long errflg;
|
|
struct ERRORLIST *next;
|
|
};
|
|
static void mail_free_errorlist(ERRORLIST **errlist);
|
|
|
|
struct MESSAGELIST {
|
|
unsigned long msgid;
|
|
struct MESSAGELIST *next;
|
|
};
|
|
|
|
class ImapRequestData : public RequestEventHandler {
|
|
public:
|
|
virtual void requestInit() {
|
|
m_user.clear();
|
|
m_password.clear();
|
|
|
|
m_errorstack = NIL;
|
|
m_alertstack = NIL;
|
|
//m_gets_stream = NIL;
|
|
}
|
|
virtual void requestShutdown() {
|
|
if (m_errorstack != NIL) {
|
|
/* output any remaining errors at their original error level */
|
|
for (ERRORLIST *ecur = m_errorstack; ecur != NIL; ecur = ecur->next) {
|
|
Logger::Warning("%s (errflg=%ld)", ecur->text.data, ecur->errflg);
|
|
}
|
|
mail_free_errorlist(&m_errorstack);
|
|
m_errorstack = NIL;
|
|
}
|
|
|
|
if (m_alertstack != NIL) {
|
|
/* output any remaining alerts at E_NOTICE level */
|
|
for (STRINGLIST *acur = m_alertstack; acur != NIL; acur = acur->next) {
|
|
Logger::Warning("%s", acur->text.data);
|
|
}
|
|
mail_free_stringlist(&m_alertstack);
|
|
m_alertstack = NIL;
|
|
}
|
|
}
|
|
|
|
std::string m_user;
|
|
std::string m_password;
|
|
|
|
STRINGLIST *m_alertstack;
|
|
ERRORLIST *m_errorstack;
|
|
|
|
STRINGLIST *m_folders;
|
|
STRINGLIST *m_folders_tail;
|
|
STRINGLIST *m_sfolders;
|
|
STRINGLIST *m_sfolders_tail;
|
|
MESSAGELIST *m_messages;
|
|
MESSAGELIST *m_messages_tail;
|
|
FOBJECTLIST *m_folder_objects;
|
|
FOBJECTLIST *m_folder_objects_tail;
|
|
FOBJECTLIST *m_sfolder_objects;
|
|
FOBJECTLIST *m_sfolder_objects_tail;
|
|
|
|
FolderListStyle m_folderlist_style;
|
|
long m_status_flags;
|
|
unsigned long m_status_messages;
|
|
unsigned long m_status_recent;
|
|
unsigned long m_status_unseen;
|
|
unsigned long m_status_uidnext;
|
|
unsigned long m_status_uidvalidity;
|
|
};
|
|
IMPLEMENT_STATIC_REQUEST_LOCAL(ImapRequestData, s_imap_data);
|
|
#define IMAPG(name) s_imap_data->m_ ## name
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
static class imapExtension : public Extension {
|
|
public:
|
|
imapExtension() : Extension("imap") {}
|
|
|
|
virtual void moduleInit() {
|
|
mail_link(&unixdriver); /* link in the unix driver */
|
|
mail_link(&mhdriver); /* link in the mh driver */
|
|
/* According to c-client docs (internal.txt) this shouldn't be used. */
|
|
/* mail_link(&mxdriver); */
|
|
mail_link(&mmdfdriver); /* link in the mmdf driver */
|
|
mail_link(&newsdriver); /* link in the news driver */
|
|
mail_link(&philedriver); /* link in the phile driver */
|
|
|
|
mail_link(&imapdriver); /* link in the imap driver */
|
|
mail_link(&nntpdriver); /* link in the nntp driver */
|
|
mail_link(&pop3driver); /* link in the pop3 driver */
|
|
mail_link(&mbxdriver); /* link in the mbx driver */
|
|
mail_link(&tenexdriver); /* link in the tenex driver */
|
|
mail_link(&mtxdriver); /* link in the mtx driver */
|
|
mail_link(&dummydriver); /* link in the dummy driver */
|
|
|
|
auth_link(&auth_log); /* link in the log authenticator */
|
|
auth_link(&auth_md5); /* link in the cram-md5 authenticator */
|
|
|
|
#ifndef SKIP_IMAP_GSS
|
|
auth_link(&auth_gss); /* link in the gss authenticator */
|
|
#endif
|
|
|
|
auth_link(&auth_pla); /* link in the plain authenticator */
|
|
|
|
#ifndef SKIP_IMAP_SSL
|
|
ssl_onceonlyinit();
|
|
#endif
|
|
|
|
/* plug in our gets */
|
|
mail_parameters(NIL, SET_GETS, (void *) NIL);
|
|
|
|
/* set default timeout values */
|
|
void *timeout = reinterpret_cast<void *>
|
|
(RuntimeOption::SocketDefaultTimeout);
|
|
|
|
mail_parameters(NIL, SET_OPENTIMEOUT, timeout);
|
|
mail_parameters(NIL, SET_READTIMEOUT, timeout);
|
|
mail_parameters(NIL, SET_WRITETIMEOUT, timeout);
|
|
mail_parameters(NIL, SET_CLOSETIMEOUT, timeout);
|
|
}
|
|
|
|
} s_imap_extension;
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ImapStream::close() {
|
|
if (m_stream) {
|
|
mail_close_full(m_stream, m_flag);
|
|
IMAPG(user).clear();
|
|
IMAPG(password).clear();
|
|
m_stream = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Calculate string length based on imap's rfc822_cat function.
|
|
*/
|
|
static int _php_rfc822_len(char *str) {
|
|
if (!str || !*str) {
|
|
return 0;
|
|
}
|
|
|
|
/* strings with special characters will need to be quoted, as a safety
|
|
* measure we add 2 bytes for the quotes just in case.
|
|
*/
|
|
int len = strlen(str) + 2;
|
|
char *p = str;
|
|
|
|
/* rfc822_cat() will escape all " and \ characters, therefor we need to
|
|
* increase our buffer length to account for these characters.
|
|
*/
|
|
while ((p = strpbrk(p, "\\\""))) {
|
|
p++;
|
|
len++;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static int _php_imap_address_size (ADDRESS *addresslist) {
|
|
int ret=0, num_ent=0;
|
|
|
|
ADDRESS *tmp = addresslist;
|
|
if (tmp) {
|
|
do {
|
|
ret += _php_rfc822_len(tmp->personal);
|
|
ret += _php_rfc822_len(tmp->adl);
|
|
ret += _php_rfc822_len(tmp->mailbox);
|
|
ret += _php_rfc822_len(tmp->host);
|
|
num_ent++;
|
|
} while ((tmp = tmp->next));
|
|
}
|
|
|
|
/*
|
|
* rfc822_write_address_full() needs some extra space for '<>,', etc.
|
|
* for this perpouse we allocate additional PHP_IMAP_ADDRESS_SIZE_BUF bytes
|
|
* by default this buffer is 10 bytes long
|
|
*/
|
|
ret += (ret) ? num_ent*PHP_IMAP_ADDRESS_SIZE_BUF : 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static char *_php_rfc822_write_address(ADDRESS *addresslist) {
|
|
char address[SENDBUFLEN];
|
|
if (_php_imap_address_size(addresslist) >= SENDBUFLEN) {
|
|
Logger::Error("Address buffer overflow");
|
|
return NULL;
|
|
}
|
|
address[0] = 0;
|
|
rfc822_write_address(address, addresslist);
|
|
return strdup(address);
|
|
}
|
|
|
|
#define OBJ_SET_ENTRY(ret, obj, name, entry) \
|
|
if (obj->entry) ret.o_set(name, String((const char*)obj->entry, CopyString));
|
|
|
|
static char* _php_imap_parse_address(ADDRESS *addresslist, Array &paddress) {
|
|
ADDRESS *addresstmp = addresslist;
|
|
char *fulladdress = _php_rfc822_write_address(addresstmp);
|
|
do {
|
|
Object tmpvals(SystemLib::AllocStdClassObject());
|
|
OBJ_SET_ENTRY(tmpvals, addresstmp, "personal", personal);
|
|
OBJ_SET_ENTRY(tmpvals, addresstmp, "adl", adl);
|
|
OBJ_SET_ENTRY(tmpvals, addresstmp, "mailbox", mailbox);
|
|
OBJ_SET_ENTRY(tmpvals, addresstmp, "host", host);
|
|
paddress.append(tmpvals);
|
|
} while ((addresstmp = addresstmp->next));
|
|
return fulladdress;
|
|
}
|
|
|
|
static void set_address(Object &ret, const char *prop, ADDRESS *addr) {
|
|
if (addr) {
|
|
Array paddress(Array::Create());
|
|
char *fulladdress = _php_imap_parse_address(addr, paddress);
|
|
if (fulladdress) {
|
|
ret.o_set(String(prop) + "address", String(fulladdress, AttachString));
|
|
}
|
|
ret.o_set(prop, paddress);
|
|
}
|
|
}
|
|
|
|
static Object _php_make_header_object(ENVELOPE *en) {
|
|
Object ret(SystemLib::AllocStdClassObject());
|
|
|
|
OBJ_SET_ENTRY(ret, en, "remail", remail);
|
|
OBJ_SET_ENTRY(ret, en, "date", date);
|
|
OBJ_SET_ENTRY(ret, en, "Date", date);
|
|
OBJ_SET_ENTRY(ret, en, "subject", subject);
|
|
OBJ_SET_ENTRY(ret, en, "Subject", subject);
|
|
OBJ_SET_ENTRY(ret, en, "in_reply_to", in_reply_to);
|
|
OBJ_SET_ENTRY(ret, en, "message_id", message_id);
|
|
OBJ_SET_ENTRY(ret, en, "newsgroups", newsgroups);
|
|
OBJ_SET_ENTRY(ret, en, "followup_to", followup_to);
|
|
OBJ_SET_ENTRY(ret, en, "references", references);
|
|
|
|
set_address(ret, "to", en->to);
|
|
set_address(ret, "from", en->from);
|
|
set_address(ret, "cc", en->cc);
|
|
set_address(ret, "bcc", en->bcc);
|
|
set_address(ret, "reply_to", en->reply_to);
|
|
set_address(ret, "sender", en->sender);
|
|
set_address(ret, "return_path", en->return_path);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void _php_imap_add_body(Object &ret, BODY *body, bool do_multipart) {
|
|
|
|
if (body->type <= TYPEMAX) {
|
|
ret.o_set("type", body->type);
|
|
}
|
|
|
|
if (body->encoding <= ENCMAX) {
|
|
ret.o_set("encoding", body->encoding);
|
|
}
|
|
|
|
if (body->subtype) {
|
|
ret.o_set("ifsubtype", 1);
|
|
ret.o_set("subtype", String((const char*)body->subtype, CopyString));
|
|
} else {
|
|
ret.o_set("ifsubtype", 0);
|
|
}
|
|
|
|
if (body->description) {
|
|
ret.o_set("ifdescription", 1);
|
|
ret.o_set("description",
|
|
String((const char*)body->description, CopyString));
|
|
} else {
|
|
ret.o_set("ifdescription", 0);
|
|
}
|
|
|
|
if (body->id) {
|
|
ret.o_set("ifid", 1);
|
|
ret.o_set("id", String((const char*)body->id, CopyString));
|
|
} else {
|
|
ret.o_set("ifid", 0);
|
|
}
|
|
|
|
|
|
if (body->size.lines) {
|
|
ret.o_set("lines", (int64_t)body->size.lines);
|
|
}
|
|
|
|
if (body->size.bytes) {
|
|
ret.o_set("bytes", (int64_t)body->size.bytes);
|
|
}
|
|
|
|
if (body->disposition.type) {
|
|
ret.o_set("ifdisposition", 1);
|
|
ret.o_set("disposition",
|
|
String((const char*)body->disposition.type, CopyString));
|
|
} else {
|
|
ret.o_set("ifdisposition", 0);
|
|
}
|
|
|
|
if (body->disposition.parameter) {
|
|
PARAMETER *dpar;
|
|
dpar = body->disposition.parameter;
|
|
ret.o_set("ifdparameters", 1);
|
|
|
|
Array dparametres(Array::Create());
|
|
do {
|
|
Object dparam(SystemLib::AllocStdClassObject());
|
|
dparam.o_set("attribute",
|
|
String((const char*)dpar->attribute, CopyString));
|
|
dparam.o_set("value", String((const char*)dpar->value, CopyString));
|
|
dparametres.append(dparam);
|
|
} while ((dpar = dpar->next));
|
|
ret.o_set("dparameters", dparametres);
|
|
} else {
|
|
ret.o_set("ifdparameters", 0);
|
|
}
|
|
|
|
PARAMETER *par;
|
|
Array parametres(Array::Create());
|
|
|
|
if ((par = body->parameter)) {
|
|
ret.o_set("ifparameters", 1);
|
|
do {
|
|
Object param(SystemLib::AllocStdClassObject());
|
|
OBJ_SET_ENTRY(param, par, "attribute", attribute);
|
|
OBJ_SET_ENTRY(param, par, "value", value);
|
|
parametres.append(param);
|
|
} while ((par = par->next));
|
|
ret.o_set("parameters", parametres);
|
|
} else {
|
|
ret.o_set("ifparameters", 0);
|
|
}
|
|
|
|
if (do_multipart) {
|
|
/* multipart message ? */
|
|
if (body->type == TYPEMULTIPART) {
|
|
parametres.clear();
|
|
PART *part;
|
|
for (part = body->nested.part; part; part = part->next) {
|
|
Object param(SystemLib::AllocStdClassObject());
|
|
_php_imap_add_body(param, &part->body, do_multipart);
|
|
parametres.append(param);
|
|
}
|
|
ret.o_set("parts", parametres);
|
|
}
|
|
|
|
/* encapsulated message ? */
|
|
if ((body->type == TYPEMESSAGE) && (!strcasecmp(body->subtype, "rfc822"))) {
|
|
body = body->nested.msg->body;
|
|
parametres.clear();
|
|
Object param(SystemLib::AllocStdClassObject());
|
|
_php_imap_add_body(param, body, do_multipart);
|
|
parametres.append(param);
|
|
ret.o_set("parts", parametres);
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// interfaces to C-client
|
|
|
|
/* {{{ mail_newfolderobjectlist
|
|
*
|
|
* Mail instantiate FOBJECTLIST
|
|
* Returns: new FOBJECTLIST list
|
|
* Author: CJH
|
|
*/
|
|
static FOBJECTLIST *mail_newfolderobjectlist(void) {
|
|
return (FOBJECTLIST *)
|
|
memset(fs_get(sizeof(FOBJECTLIST)), 0, sizeof(FOBJECTLIST));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ mail_free_foblist
|
|
*
|
|
* Mail garbage collect FOBJECTLIST
|
|
* Accepts: pointer to FOBJECTLIST pointer
|
|
* Author: CJH
|
|
*/
|
|
void mail_free_foblist(FOBJECTLIST **foblist, FOBJECTLIST **tail) {
|
|
FOBJECTLIST *cur, *next;
|
|
for (cur=*foblist, next=cur->next; cur; cur=next) {
|
|
next = cur->next;
|
|
|
|
if(cur->text.data)
|
|
fs_give((void **)&(cur->text.data));
|
|
|
|
fs_give((void **)&cur);
|
|
}
|
|
|
|
*tail = NIL;
|
|
*foblist = NIL;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ mail_newerrorlist
|
|
*
|
|
* Mail instantiate ERRORLIST
|
|
* Returns: new ERRORLIST list
|
|
* Author: CJH
|
|
*/
|
|
static ERRORLIST *mail_newerrorlist(void) {
|
|
return (ERRORLIST *) memset(fs_get(sizeof(ERRORLIST)), 0, sizeof(ERRORLIST));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ mail_free_errorlist
|
|
*
|
|
* Mail garbage collect FOBJECTLIST
|
|
* Accepts: pointer to FOBJECTLIST pointer
|
|
* Author: CJH
|
|
*/
|
|
static void mail_free_errorlist(ERRORLIST **errlist) {
|
|
if (*errlist) { /* only free if exists */
|
|
if ((*errlist)->text.data) {
|
|
fs_give((void **) &(*errlist)->text.data);
|
|
}
|
|
mail_free_errorlist (&(*errlist)->next);
|
|
fs_give((void **) errlist); /* return string to free storage */
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ mail_newmessagelist
|
|
*
|
|
* Mail instantiate MESSAGELIST
|
|
* Returns: new MESSAGELIST list
|
|
* Author: CJH
|
|
*/
|
|
static MESSAGELIST *mail_newmessagelist(void) {
|
|
return (MESSAGELIST *) memset(fs_get(sizeof(MESSAGELIST)), 0,
|
|
sizeof(MESSAGELIST));
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ mail_free_messagelist
|
|
*
|
|
* Mail garbage collect MESSAGELIST
|
|
* Accepts: pointer to MESSAGELIST pointer
|
|
* Author: CJH
|
|
*/
|
|
void mail_free_messagelist(MESSAGELIST **msglist, MESSAGELIST **tail) {
|
|
MESSAGELIST *cur, *next;
|
|
|
|
for (cur = *msglist, next = cur->next; cur; cur = next) {
|
|
next = cur->next;
|
|
fs_give((void **)&cur);
|
|
}
|
|
|
|
*tail = NIL;
|
|
*msglist = NIL;
|
|
}
|
|
/* }}} */
|
|
|
|
static int mm_strlen(unsigned char *str) {
|
|
return strlen((const char *)str);
|
|
}
|
|
|
|
static unsigned char *mm_cpystr(char *str) {
|
|
return (unsigned char *)cpystr(str);
|
|
}
|
|
|
|
extern "C" {
|
|
|
|
void mm_searched(MAILSTREAM *stream, unsigned long number) {
|
|
MESSAGELIST *cur = NIL;
|
|
if (IMAPG(messages) == NIL) {
|
|
IMAPG(messages) = mail_newmessagelist();
|
|
IMAPG(messages)->msgid = number;
|
|
IMAPG(messages)->next = NIL;
|
|
IMAPG(messages_tail) = IMAPG(messages);
|
|
} else {
|
|
cur = IMAPG(messages_tail);
|
|
cur->next = mail_newmessagelist();
|
|
cur = cur->next;
|
|
cur->msgid = number;
|
|
cur->next = NIL;
|
|
IMAPG(messages_tail) = cur;
|
|
}
|
|
}
|
|
|
|
void mm_exists(MAILSTREAM *stream, unsigned long number) {}
|
|
void mm_expunged(MAILSTREAM *stream, unsigned long number) {}
|
|
void mm_flags(MAILSTREAM *stream, unsigned long number) {}
|
|
|
|
/* Author: CJH */
|
|
void mm_notify(MAILSTREAM *stream, char *str, long errflg) {
|
|
STRINGLIST *cur = NIL;
|
|
if (strncmp(str, "[ALERT] ", 8) == 0) {
|
|
if (IMAPG(alertstack) == NIL) {
|
|
IMAPG(alertstack) = mail_newstringlist();
|
|
IMAPG(alertstack)->text.size =
|
|
mm_strlen((IMAPG(alertstack)->text.data = mm_cpystr(str)));
|
|
IMAPG(alertstack)->next = NIL;
|
|
} else {
|
|
cur = IMAPG(alertstack);
|
|
while (cur->next != NIL) {
|
|
cur = cur->next;
|
|
}
|
|
cur->next = mail_newstringlist ();
|
|
cur = cur->next;
|
|
cur->text.size = mm_strlen(cur->text.data = mm_cpystr(str));
|
|
cur->next = NIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mm_list(MAILSTREAM *stream, int delimiter, char *mailbox,
|
|
long attributes) {
|
|
STRINGLIST *cur=NIL;
|
|
FOBJECTLIST *ocur=NIL;
|
|
|
|
if (IMAPG(folderlist_style) == FLIST_OBJECT) {
|
|
/* build up a the new array of objects */
|
|
/* Author: CJH */
|
|
if (IMAPG(folder_objects) == NIL) {
|
|
IMAPG(folder_objects) = mail_newfolderobjectlist();
|
|
IMAPG(folder_objects)->text.size =
|
|
mm_strlen(IMAPG(folder_objects)->text.data=mm_cpystr(mailbox));
|
|
IMAPG(folder_objects)->delimiter = delimiter;
|
|
IMAPG(folder_objects)->attributes = attributes;
|
|
IMAPG(folder_objects)->next = NIL;
|
|
IMAPG(folder_objects_tail) = IMAPG(folder_objects);
|
|
} else {
|
|
ocur=IMAPG(folder_objects_tail);
|
|
ocur->next=mail_newfolderobjectlist();
|
|
ocur=ocur->next;
|
|
ocur->text.size = mm_strlen(ocur->text.data = mm_cpystr(mailbox));
|
|
ocur->delimiter = delimiter;
|
|
ocur->attributes = attributes;
|
|
ocur->next = NIL;
|
|
IMAPG(folder_objects_tail) = ocur;
|
|
}
|
|
|
|
} else {
|
|
/* build the old IMAPG(folders) variable to allow old
|
|
imap_listmailbox() to work */
|
|
if (!(attributes & LATT_NOSELECT)) {
|
|
if (IMAPG(folders) == NIL) {
|
|
IMAPG(folders)=mail_newstringlist();
|
|
IMAPG(folders)->text.size =
|
|
mm_strlen(IMAPG(folders)->text.data=mm_cpystr(mailbox));
|
|
IMAPG(folders)->next=NIL;
|
|
IMAPG(folders_tail) = IMAPG(folders);
|
|
} else {
|
|
cur=IMAPG(folders_tail);
|
|
cur->next=mail_newstringlist ();
|
|
cur=cur->next;
|
|
cur->text.size = mm_strlen (cur->text.data = mm_cpystr (mailbox));
|
|
cur->next = NIL;
|
|
IMAPG(folders_tail) = cur;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void mm_lsub(MAILSTREAM *stream, int delimiter, char *mailbox,
|
|
long attributes) {
|
|
STRINGLIST *cur=NIL;
|
|
FOBJECTLIST *ocur=NIL;
|
|
|
|
if (IMAPG(folderlist_style) == FLIST_OBJECT) {
|
|
/* build the array of objects */
|
|
/* Author: CJH */
|
|
if (IMAPG(sfolder_objects) == NIL) {
|
|
IMAPG(sfolder_objects) = mail_newfolderobjectlist();
|
|
IMAPG(sfolder_objects)->text.size =
|
|
mm_strlen(IMAPG(sfolder_objects)->text.data=mm_cpystr(mailbox));
|
|
IMAPG(sfolder_objects)->delimiter = delimiter;
|
|
IMAPG(sfolder_objects)->attributes = attributes;
|
|
IMAPG(sfolder_objects)->next = NIL;
|
|
IMAPG(sfolder_objects_tail) = IMAPG(sfolder_objects);
|
|
} else {
|
|
ocur=IMAPG(sfolder_objects_tail);
|
|
ocur->next=mail_newfolderobjectlist();
|
|
ocur=ocur->next;
|
|
ocur->text.size=mm_strlen(ocur->text.data = mm_cpystr(mailbox));
|
|
ocur->delimiter = delimiter;
|
|
ocur->attributes = attributes;
|
|
ocur->next = NIL;
|
|
IMAPG(sfolder_objects_tail) = ocur;
|
|
}
|
|
} else {
|
|
/* build the old simple array for imap_listsubscribed() */
|
|
if (IMAPG(sfolders) == NIL) {
|
|
IMAPG(sfolders)=mail_newstringlist();
|
|
IMAPG(sfolders)->text.size =
|
|
mm_strlen(IMAPG(sfolders)->text.data=mm_cpystr(mailbox));
|
|
IMAPG(sfolders)->next=NIL;
|
|
IMAPG(sfolders_tail) = IMAPG(sfolders);
|
|
} else {
|
|
cur=IMAPG(sfolders_tail);
|
|
cur->next=mail_newstringlist ();
|
|
cur=cur->next;
|
|
cur->text.size = mm_strlen (cur->text.data = mm_cpystr (mailbox));
|
|
cur->next = NIL;
|
|
IMAPG(sfolders_tail) = cur;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mm_status(MAILSTREAM *stream, char *mailbox, MAILSTATUS *status) {
|
|
IMAPG(status_flags)=status->flags;
|
|
if (IMAPG(status_flags) & SA_MESSAGES) {
|
|
IMAPG(status_messages)=status->messages;
|
|
}
|
|
if (IMAPG(status_flags) & SA_RECENT) {
|
|
IMAPG(status_recent)=status->recent;
|
|
}
|
|
if (IMAPG(status_flags) & SA_UNSEEN) {
|
|
IMAPG(status_unseen)=status->unseen;
|
|
}
|
|
if (IMAPG(status_flags) & SA_UIDNEXT) {
|
|
IMAPG(status_uidnext)=status->uidnext;
|
|
}
|
|
if (IMAPG(status_flags) & SA_UIDVALIDITY) {
|
|
IMAPG(status_uidvalidity)=status->uidvalidity;
|
|
}
|
|
}
|
|
|
|
void mm_log(char *str, long errflg) {
|
|
ERRORLIST *cur = NIL;
|
|
|
|
/* Author: CJH */
|
|
if (errflg != NIL) { /* CJH: maybe put these into a more comprehensive
|
|
log for debugging purposes? */
|
|
if (IMAPG(errorstack) == NIL) {
|
|
IMAPG(errorstack) = mail_newerrorlist();
|
|
IMAPG(errorstack)->text.size =
|
|
mm_strlen(IMAPG(errorstack)->text.data = mm_cpystr(str));
|
|
IMAPG(errorstack)->errflg = errflg;
|
|
IMAPG(errorstack)->next = NIL;
|
|
} else {
|
|
cur = IMAPG(errorstack);
|
|
while (cur->next != NIL) {
|
|
cur = cur->next;
|
|
}
|
|
cur->next = mail_newerrorlist();
|
|
cur = cur->next;
|
|
cur->text.size = mm_strlen(cur->text.data = mm_cpystr(str));
|
|
cur->errflg = errflg;
|
|
cur->next = NIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
void mm_login(NETMBX *mb, char *user, char *pwd, long trial) {
|
|
if (*mb->user) {
|
|
string_copy(user, mb->user, MAILTMPLEN);
|
|
} else {
|
|
string_copy(user, IMAPG(user).c_str(), MAILTMPLEN);
|
|
}
|
|
string_copy(pwd, IMAPG(password).c_str(), MAILTMPLEN);
|
|
}
|
|
|
|
void mm_dlog(char *str) {}
|
|
void mm_critical(MAILSTREAM *stream) {}
|
|
void mm_nocritical(MAILSTREAM *stream) {}
|
|
long mm_diskerror(MAILSTREAM *stream, long errcode, long serious) { return 1;}
|
|
void mm_fatal(char *str) {}
|
|
|
|
} // extern "C"
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
Variant f_imap_8bit(CStrRef str) {
|
|
unsigned long newlength;
|
|
|
|
char *decode = (char *)rfc822_8bit((unsigned char *) str.data(),
|
|
str.length(), &newlength);
|
|
if (decode == NULL) {
|
|
return false;
|
|
}
|
|
|
|
String ret = String(decode, newlength, CopyString);
|
|
fs_give((void**) &decode);
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_alerts() {
|
|
if (IMAPG(alertstack) == NIL) {
|
|
return false;
|
|
}
|
|
|
|
Array ret(Array::Create());
|
|
|
|
for (STRINGLIST *cur = IMAPG(alertstack); cur != NIL;
|
|
cur = cur->next) {
|
|
ret.append(String((const char *)cur->text.data, CopyString));
|
|
}
|
|
mail_free_stringlist(&IMAPG(alertstack));
|
|
IMAPG(alertstack) = NIL;
|
|
return ret;
|
|
}
|
|
|
|
bool f_imap_append(CObjRef imap_stream, CStrRef mailbox, CStrRef message,
|
|
CStrRef options /* = "" */) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_base64(CStrRef text) {
|
|
unsigned long newlength;
|
|
|
|
char *decode = (char *)rfc822_base64((unsigned char *) text.data(),
|
|
text.length(), &newlength);
|
|
if (decode == NULL) {
|
|
return false;
|
|
}
|
|
|
|
String ret = String(decode, newlength, CopyString);
|
|
fs_give((void**) &decode);
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_binary(CStrRef str) {
|
|
unsigned long newlength;
|
|
|
|
char *decode = (char *)rfc822_binary((unsigned char *) str.data(),
|
|
str.length(), &newlength);
|
|
if (decode == NULL) {
|
|
return false;
|
|
}
|
|
|
|
String ret = String(decode, newlength, CopyString);
|
|
fs_give((void**) &decode);
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_body(CObjRef imap_stream, int64_t msg_number,
|
|
int64_t options /* = 0 */) {
|
|
if (options && ((options & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
|
|
raise_warning("invalid value for the options parameter");
|
|
return false;
|
|
}
|
|
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
|
|
int msgindex;
|
|
if (options & FT_UID) {
|
|
/* This should be cached; if it causes an extra RTT to the
|
|
IMAP server, then that's the price we pay for making sure
|
|
we don't crash. */
|
|
msgindex = mail_msgno(obj->m_stream, msg_number);
|
|
} else {
|
|
msgindex = msg_number;
|
|
}
|
|
|
|
if (!obj->checkMsgNumber(msgindex)) {
|
|
return false;
|
|
}
|
|
|
|
unsigned long body_len = 0;
|
|
char *body = mail_fetchtext_full(obj->m_stream, msg_number,
|
|
&body_len, (options ? options : NIL));
|
|
if (body_len == 0) {
|
|
return String("");
|
|
} else {
|
|
return String(body, body_len, CopyString);
|
|
}
|
|
}
|
|
|
|
Variant f_imap_bodystruct(CObjRef imap_stream, int64_t msg_number,
|
|
CStrRef section) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (!obj->checkMsgNumber(msg_number)) {
|
|
return false;
|
|
}
|
|
Object ret(SystemLib::AllocStdClassObject());
|
|
|
|
BODY *body;
|
|
body = mail_body(obj->m_stream, msg_number, (unsigned char *)section.data());
|
|
if (body == NULL) {
|
|
return false;
|
|
}
|
|
|
|
_php_imap_add_body(ret, body, false);
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_check(CObjRef imap_stream) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_ping(obj->m_stream) == NIL) {
|
|
return false;
|
|
}
|
|
if (obj->m_stream && obj->m_stream->mailbox) {
|
|
Object ret(SystemLib::AllocStdClassObject());
|
|
char date[100];
|
|
rfc822_date(date);
|
|
ret.o_set("Date", String(date, CopyString));
|
|
ret.o_set("Driver", String(obj->m_stream->dtb->name, CopyString));
|
|
ret.o_set("Mailbox", String(obj->m_stream->mailbox, CopyString));
|
|
ret.o_set("Nmsgs", (int64_t)obj->m_stream->nmsgs);
|
|
ret.o_set("Recent", (int64_t)obj->m_stream->recent);
|
|
return ret;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool f_imap_clearflag_full(CObjRef imap_stream, CStrRef sequence, CStrRef flag,
|
|
int64_t options /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
mail_clearflag_full(obj->m_stream, (char *)sequence.data(),
|
|
(char *)flag.data(), (options ? options : NIL));
|
|
return true;
|
|
}
|
|
|
|
bool f_imap_close(CObjRef imap_stream, int64_t flag /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (flag) {
|
|
if (flag != PHP_EXPUNGE) {
|
|
Logger::Warning("invalid value for the flags parameter");
|
|
return false;
|
|
}
|
|
flag = CL_EXPUNGE;
|
|
}
|
|
obj->m_flag = flag;
|
|
obj->close();
|
|
return true;
|
|
}
|
|
|
|
bool f_imap_createmailbox(CObjRef imap_stream, CStrRef mailbox) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_create(obj->m_stream, (char *)mailbox.data()) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool f_imap_delete(CObjRef imap_stream, CStrRef msg_number,
|
|
int64_t options /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
mail_setflag_full(obj->m_stream, (char *)msg_number.data(),
|
|
"\\DELETED",
|
|
(options ? options : NIL));
|
|
return true;
|
|
}
|
|
|
|
bool f_imap_deletemailbox(CObjRef imap_stream, CStrRef mailbox) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_delete(obj->m_stream, (char *)mailbox.data()) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Variant f_imap_errors() {
|
|
if (IMAPG(errorstack) == NIL) {
|
|
return false;
|
|
}
|
|
|
|
Array ret(Array::Create());
|
|
|
|
for (ERRORLIST *cur = IMAPG(errorstack); cur != NIL;
|
|
cur = cur->next) {
|
|
ret.append(String((const char *)cur->text.data, CopyString));
|
|
}
|
|
IMAPG(errorstack) = NIL;
|
|
return ret;
|
|
}
|
|
|
|
bool f_imap_expunge(CObjRef imap_stream) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
mail_expunge(obj->m_stream);
|
|
return true;
|
|
}
|
|
|
|
Variant f_imap_fetch_overview(CObjRef imap_stream, CStrRef sequence,
|
|
int64_t options /* = 0 */) {
|
|
if (options && options != FT_UID) {
|
|
Logger::Warning("invalid value for the options parameter");
|
|
return false;
|
|
}
|
|
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
|
|
Array ret(Array::Create());
|
|
|
|
long status = (options & FT_UID)
|
|
? mail_uid_sequence(obj->m_stream, (unsigned char *)sequence.data())
|
|
: mail_sequence(obj->m_stream, (unsigned char *)sequence.data());
|
|
|
|
if (status) {
|
|
MESSAGECACHE *elt;
|
|
ENVELOPE *env;
|
|
for (unsigned long i = 1; i <= obj->m_stream->nmsgs; i++) {
|
|
if (((elt = mail_elt(obj->m_stream, i))->sequence) &&
|
|
(env = mail_fetch_structure(obj->m_stream, i, NIL, NIL))) {
|
|
|
|
Object myoverview(SystemLib::AllocStdClassObject());
|
|
OBJ_SET_ENTRY(myoverview, env, "subject", subject);
|
|
|
|
if (env->from) {
|
|
env->from->next = NULL;
|
|
char *address = _php_rfc822_write_address(env->from);
|
|
if (address) {
|
|
myoverview.o_set("from", String(address, AttachString));
|
|
}
|
|
}
|
|
if (env->to) {
|
|
env->to->next = NULL;
|
|
char *address = _php_rfc822_write_address(env->to);
|
|
if (address) {
|
|
myoverview.o_set("to", String(address, AttachString));
|
|
}
|
|
}
|
|
|
|
OBJ_SET_ENTRY(myoverview, env, "date", date);
|
|
OBJ_SET_ENTRY(myoverview, env, "message_id", message_id);
|
|
OBJ_SET_ENTRY(myoverview, env, "references", references);
|
|
OBJ_SET_ENTRY(myoverview, env, "in_reply_to", in_reply_to);
|
|
|
|
myoverview.o_set("size", (int64_t)elt->rfc822_size);
|
|
myoverview.o_set("uid", (int64_t)mail_uid(obj->m_stream, i));
|
|
myoverview.o_set("msgno", (int64_t)i);
|
|
myoverview.o_set("recent", (int64_t)elt->recent);
|
|
myoverview.o_set("flagged", (int64_t)elt->flagged);
|
|
myoverview.o_set("answered", (int64_t)elt->answered);
|
|
myoverview.o_set("deleted", (int64_t)elt->deleted);
|
|
myoverview.o_set("seen", (int64_t)elt->seen);
|
|
myoverview.o_set("draft", (int64_t)elt->draft);
|
|
|
|
ret.append(myoverview);
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_fetchbody(CObjRef imap_stream, int64_t msg_number,
|
|
CStrRef section, int64_t options /* = 0 */) {
|
|
if (options && ((options & ~(FT_UID|FT_PEEK|FT_INTERNAL)) != 0)) {
|
|
raise_warning("invalid value for the options parameter");
|
|
return false;
|
|
}
|
|
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
|
|
if (!options || !(options & FT_UID)) {
|
|
if (!obj->checkMsgNumber(msg_number)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
unsigned long len;
|
|
char *body = mail_fetchbody_full(obj->m_stream, msg_number,
|
|
(char*)section.data(),
|
|
&len, (options ? options : NIL));
|
|
|
|
if (!body) {
|
|
raise_warning("No body information available");
|
|
return false;
|
|
}
|
|
|
|
return String(body, len, CopyString);
|
|
}
|
|
|
|
Variant f_imap_fetchheader(CObjRef imap_stream, int64_t msg_number,
|
|
int64_t options /* = 0 */) {
|
|
if (options && ((options & ~(FT_UID|FT_INTERNAL|FT_PREFETCHTEXT)) != 0)) {
|
|
Logger::Warning("invalid value for the options parameter");
|
|
return false;
|
|
}
|
|
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
int msgindex;
|
|
if (options & FT_UID) {
|
|
/* This should be cached; if it causes an extra RTT to the
|
|
IMAP server, then that's the price we pay for making sure
|
|
we don't crash. */
|
|
msgindex = mail_msgno(obj->m_stream, msg_number);
|
|
} else {
|
|
msgindex = msg_number;
|
|
}
|
|
|
|
if (!obj->checkMsgNumber(msgindex)) {
|
|
return false;
|
|
}
|
|
|
|
return String(mail_fetchheader_full(obj->m_stream, msgindex, NIL, NIL,
|
|
(options ? options : NIL)), CopyString);
|
|
}
|
|
|
|
Variant f_imap_fetchstructure(CObjRef imap_stream, int64_t msg_number,
|
|
int64_t options /* = 0 */) {
|
|
if (options && ((options & ~FT_UID) != 0)) {
|
|
raise_warning("invalid value for the options parameter");
|
|
return false;
|
|
}
|
|
|
|
if (msg_number < 1) {
|
|
return false;
|
|
}
|
|
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
int msgindex;
|
|
if (options & FT_UID) {
|
|
/* This should be cached; if it causes an extra RTT to the
|
|
IMAP server, then that's the price we pay for making sure
|
|
we don't crash. */
|
|
msgindex = mail_msgno(obj->m_stream, msg_number);
|
|
} else {
|
|
msgindex = msg_number;
|
|
}
|
|
|
|
if (!obj->checkMsgNumber(msgindex)) {
|
|
return false;
|
|
}
|
|
|
|
BODY *body;
|
|
|
|
mail_fetchstructure_full(obj->m_stream, msg_number, &body,
|
|
(options ? options : NIL));
|
|
|
|
if (!body) {
|
|
raise_warning("No body information available");
|
|
return false;
|
|
}
|
|
|
|
Object ret(SystemLib::AllocStdClassObject());
|
|
_php_imap_add_body(ret, body, true);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool f_imap_gc(CObjRef imap_stream, int64_t caches) {
|
|
if (caches && ((caches & ~(GC_TEXTS | GC_ELT | GC_ENV)) != 0)) {
|
|
raise_warning("invalid value for the caches parameter");
|
|
return false;
|
|
}
|
|
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
mail_gc(obj->m_stream, caches);
|
|
return true;
|
|
}
|
|
|
|
Variant f_imap_get_quota(CObjRef imap_stream, CStrRef quota_root) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_get_quotaroot(CObjRef imap_stream, CStrRef quota_root) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_getacl(CObjRef imap_stream, CStrRef mailbox) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_getmailboxes(CObjRef imap_stream, CStrRef ref,
|
|
CStrRef pattern) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_getsubscribed(CObjRef imap_stream, CStrRef ref,
|
|
CStrRef pattern) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_header(CObjRef imap_stream, int64_t msg_number,
|
|
int64_t fromlength /* = 0 */,
|
|
int64_t subjectlength /* = 0 */,
|
|
CStrRef defaulthost /* = "" */) {
|
|
return f_imap_headerinfo(imap_stream, msg_number,
|
|
fromlength, subjectlength, defaulthost);
|
|
}
|
|
|
|
Variant f_imap_headerinfo(CObjRef imap_stream, int64_t msg_number,
|
|
int64_t fromlength /* = 0 */,
|
|
int64_t subjectlength /* = 0 */,
|
|
CStrRef defaulthost /* = "" */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (fromlength < 0 || fromlength > MAILTMPLEN) {
|
|
Logger::Warning("From length has to be between 0 and %d", MAILTMPLEN);
|
|
return false;
|
|
}
|
|
if (subjectlength < 0 || subjectlength > MAILTMPLEN) {
|
|
Logger::Warning("Subject length has to be between 0 and %d", MAILTMPLEN);
|
|
return false;
|
|
}
|
|
if (!obj->checkMsgNumber(msg_number)) {
|
|
return false;
|
|
}
|
|
if (!mail_fetchstructure(obj->m_stream, msg_number, NIL)) {
|
|
return false;
|
|
}
|
|
|
|
MESSAGECACHE *cache = mail_elt(obj->m_stream, msg_number);
|
|
ENVELOPE *en = mail_fetchenvelope(obj->m_stream, msg_number);
|
|
|
|
/* call a function to parse all the text, so that we can use the
|
|
same function to parse text from other sources */
|
|
Object ret = _php_make_header_object(en);
|
|
|
|
/* now run through properties that are only going to be returned
|
|
from a server, not text headers */
|
|
ret.o_set("Recent", cache->recent ? (cache->seen ? "R": "N") : " ");
|
|
ret.o_set("Unseen", (cache->recent | cache->seen) ? " " : "U");
|
|
ret.o_set("Flagged", cache->flagged ? "F" : " ");
|
|
ret.o_set("Answered", cache->answered ? "A" : " ");
|
|
ret.o_set("Deleted", cache->deleted ? "D" : " ");
|
|
ret.o_set("Draft", cache->draft ? "X" : " ");
|
|
|
|
char dummy[2000], fulladdress[MAILTMPLEN + 1];
|
|
snprintf(dummy, sizeof(dummy), "%4ld", cache->msgno);
|
|
ret.o_set("Msgno", String(dummy, CopyString));
|
|
|
|
mail_date(dummy, cache);
|
|
ret.o_set("MailDate", String(dummy, CopyString));
|
|
|
|
snprintf(dummy, sizeof(dummy), "%ld", cache->rfc822_size);
|
|
ret.o_set("Size", String(dummy, CopyString));
|
|
|
|
ret.o_set("udate", (int64_t)mail_longdate(cache));
|
|
|
|
if (en->from && fromlength) {
|
|
fulladdress[0] = 0x00;
|
|
mail_fetchfrom(fulladdress, obj->m_stream, msg_number, fromlength);
|
|
ret.o_set("fetchfrom", String(fulladdress, CopyString));
|
|
}
|
|
if (en->subject && subjectlength) {
|
|
fulladdress[0] = 0x00;
|
|
mail_fetchsubject(fulladdress, obj->m_stream, msg_number, subjectlength);
|
|
ret.o_set("fetchsubject", String(fulladdress, CopyString));
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_headers(CObjRef imap_stream) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_last_error() {
|
|
if (IMAPG(errorstack) == NIL) {
|
|
return false;
|
|
}
|
|
for (ERRORLIST *cur = IMAPG(errorstack); cur != NIL;
|
|
cur = cur->next) {
|
|
if (cur->next == NIL) {
|
|
return String((const char *)cur->text.data, CopyString);
|
|
}
|
|
}
|
|
return uninit_null();
|
|
}
|
|
|
|
Variant f_imap_list(CObjRef imap_stream, CStrRef ref, CStrRef pattern) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
|
|
/* set flag for normal, old mailbox list */
|
|
IMAPG(folderlist_style) = FLIST_ARRAY;
|
|
|
|
IMAPG(folders) = IMAPG(folders_tail) = NIL;
|
|
mail_list(obj->m_stream, (char*)ref.data(), (char*)pattern.data());
|
|
if (IMAPG(folders) == NIL) {
|
|
return false;
|
|
}
|
|
|
|
Array ret(Array::Create());
|
|
for (STRINGLIST *cur = IMAPG(folders); cur != NIL; cur = cur->next) {
|
|
ret.append(String((const char *)cur->text.data, CopyString));
|
|
}
|
|
mail_free_stringlist(&IMAPG(folders));
|
|
IMAPG(folders) = IMAPG(folders_tail) = NIL;
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_listmailbox(CObjRef imap_stream, CStrRef ref, CStrRef pattern) {
|
|
return f_imap_list(imap_stream, ref, pattern);
|
|
}
|
|
|
|
Variant f_imap_listscan(CObjRef imap_stream, CStrRef ref, CStrRef pattern,
|
|
CStrRef content) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_listsubscribed(CObjRef imap_stream, CStrRef ref,
|
|
CStrRef pattern) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_lsub(CObjRef imap_stream, CStrRef ref, CStrRef pattern) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_mail_compose(CArrRef envelope, CArrRef body) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
bool f_imap_mail_copy(CObjRef imap_stream, CStrRef msglist, CStrRef mailbox,
|
|
int64_t options /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_copy_full(obj->m_stream, (char *)msglist.data(),
|
|
(char *)mailbox.data(), (options ? options : NIL)) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool f_imap_mail_move(CObjRef imap_stream, CStrRef msglist, CStrRef mailbox,
|
|
int64_t options /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_copy_full(obj->m_stream, (char *)msglist.data(),
|
|
(char *)mailbox.data(),
|
|
(options ? (options | CP_MOVE) : CP_MOVE)) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool f_imap_mail(CStrRef to, CStrRef subject, CStrRef message,
|
|
CStrRef additional_headers /* = "" */,
|
|
CStrRef cc /* = "" */, CStrRef bcc /* = "" */,
|
|
CStrRef rpath /* = "" */) {
|
|
if (to.empty()) {
|
|
raise_warning("No to field in mail command");
|
|
}
|
|
|
|
if (subject.empty()) {
|
|
raise_warning("No subject field in mail command");
|
|
}
|
|
|
|
if (message.empty()) {
|
|
raise_warning("No message string in mail command");
|
|
}
|
|
|
|
if (RuntimeOption::SendmailPath.empty()) {
|
|
return false;
|
|
}
|
|
|
|
FILE *sendmail = popen(RuntimeOption::SendmailPath.c_str(), "w");
|
|
if (sendmail) {
|
|
if (!rpath.empty()) {
|
|
fprintf(sendmail, "From: %s\n", rpath.c_str());
|
|
}
|
|
|
|
fprintf(sendmail, "To: %s\n", to.c_str());
|
|
|
|
if (!cc.empty()) {
|
|
fprintf(sendmail, "Cc: %s\n", cc.c_str());
|
|
}
|
|
if (!bcc.empty()) {
|
|
fprintf(sendmail, "Bcc: %s\n", bcc.c_str());
|
|
}
|
|
|
|
fprintf(sendmail, "Subject: %s\n", subject.c_str());
|
|
|
|
if (!additional_headers.empty()) {
|
|
fprintf(sendmail, "%s\n", additional_headers.c_str());
|
|
}
|
|
|
|
fprintf(sendmail, "\n%s\n", message.c_str());
|
|
int ret = pclose(sendmail);
|
|
return (!ret);
|
|
} else {
|
|
raise_warning("Could not execute mail delivery program");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Variant f_imap_mailboxmsginfo(CObjRef imap_stream) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
Object ret(SystemLib::AllocStdClassObject());
|
|
|
|
int64_t unreadmsg = 0, deletedmsg = 0, msize = 0;
|
|
|
|
for (unsigned long i = 1; i <= obj->m_stream->nmsgs; i++) {
|
|
MESSAGECACHE * cache = mail_elt (obj->m_stream, i);
|
|
mail_fetchstructure (obj->m_stream, i, NIL);
|
|
|
|
if (!cache->seen || cache->recent) {
|
|
unreadmsg++;
|
|
}
|
|
|
|
if (cache->deleted) {
|
|
deletedmsg++;
|
|
}
|
|
msize = msize + cache->rfc822_size;
|
|
}
|
|
|
|
ret.o_set("Unread", (int64_t)unreadmsg);
|
|
ret.o_set("Deleted", (int64_t)deletedmsg);
|
|
ret.o_set("Nmsgs", (int64_t)obj->m_stream->nmsgs);
|
|
ret.o_set("Size", (int64_t)msize);
|
|
|
|
char date[100];
|
|
rfc822_date(date);
|
|
ret.o_set("Date", String(date, CopyString));
|
|
ret.o_set("Driver", String(obj->m_stream->dtb->name, CopyString));
|
|
ret.o_set("Mailbox", String(obj->m_stream->mailbox, CopyString));
|
|
ret.o_set("Recent", (int64_t)msize);
|
|
|
|
return ret;
|
|
}
|
|
|
|
Variant f_imap_mime_header_decode(CStrRef text) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_msgno(CObjRef imap_stream, int64_t uid) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
return (int64_t)mail_msgno(obj->m_stream, uid);
|
|
}
|
|
|
|
Variant f_imap_num_msg(CObjRef imap_stream) {
|
|
return (int64_t)imap_stream.getTyped<ImapStream>()->m_stream->nmsgs;
|
|
}
|
|
|
|
Variant f_imap_num_recent(CObjRef imap_stream) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
return (int64_t)obj->m_stream->recent;
|
|
}
|
|
|
|
Variant f_imap_open(CStrRef mailbox, CStrRef username, CStrRef password,
|
|
int64_t options /* = 0 */, int64_t retries /* = 0 */) {
|
|
String filename = mailbox;
|
|
if (filename[0] != '{') {
|
|
filename = File::TranslatePath(filename);
|
|
if (filename.empty()) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (retries < 0) {
|
|
Logger::Warning("Retries must be greater or equal to 0");
|
|
} else {
|
|
mail_parameters(NIL, SET_MAXLOGINTRIALS, (void *) retries);
|
|
}
|
|
|
|
IMAPG(user) = string(username.data(), username.size());
|
|
IMAPG(password) = string(password.data(), password.size());
|
|
|
|
MAILSTREAM *stream = mail_open(NIL, (char*)filename.data(), options);
|
|
if (stream == NIL) {
|
|
Logger::Warning("Couldn't open stream %s", filename.data());
|
|
IMAPG(user).clear();
|
|
IMAPG(password).clear();
|
|
return false;
|
|
}
|
|
|
|
return NEWOBJ(ImapStream)(stream, (options & PHP_EXPUNGE) ? CL_EXPUNGE : NIL);
|
|
}
|
|
|
|
bool f_imap_ping(CObjRef imap_stream) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
return mail_ping(obj->m_stream);
|
|
}
|
|
|
|
Variant f_imap_qprint(CStrRef str) {
|
|
unsigned long newlength;
|
|
|
|
char *decode = (char *)rfc822_qprint((unsigned char *) str.data(),
|
|
str.length(), &newlength);
|
|
if (decode == NULL) {
|
|
return false;
|
|
}
|
|
|
|
String ret = String(decode, newlength, CopyString);
|
|
fs_give((void**) &decode);
|
|
return ret;
|
|
}
|
|
|
|
bool f_imap_renamemailbox(CObjRef imap_stream, CStrRef old_mbox,
|
|
CStrRef new_mbox) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_rename(obj->m_stream, (char *)old_mbox.data(),
|
|
(char *)new_mbox.data()) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool f_imap_reopen(CObjRef imap_stream, CStrRef mailbox,
|
|
int64_t options /* = 0 */, int64_t retries /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
long flags = NIL;
|
|
long cl_flags = NIL;
|
|
if (options) {
|
|
flags = options;
|
|
if (flags & PHP_EXPUNGE) {
|
|
cl_flags = CL_EXPUNGE;
|
|
flags ^= PHP_EXPUNGE;
|
|
}
|
|
obj->m_flag = cl_flags;
|
|
}
|
|
|
|
if (retries) {
|
|
mail_parameters(NIL, SET_MAXLOGINTRIALS, (void *) retries);
|
|
}
|
|
|
|
MAILSTREAM *stream = mail_open(obj->m_stream, (char*)mailbox.data(), flags);
|
|
if (stream == NIL) {
|
|
raise_warning("Couldn't re-open stream");
|
|
return false;
|
|
}
|
|
obj->m_stream = stream;
|
|
return true;
|
|
}
|
|
|
|
Variant f_imap_rfc822_parse_adrlist(CStrRef address, CStrRef default_host) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_rfc822_parse_headers(CStrRef headers,
|
|
CStrRef defaulthost /* = "" */) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_rfc822_write_address(CStrRef mailbox, CStrRef host,
|
|
CStrRef personal) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
bool f_imap_savebody(CObjRef imap_stream, CVarRef file, int64_t msg_number,
|
|
CStrRef part_number /* = "" */, int64_t options /* = 0 */) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_scanmailbox(CObjRef imap_stream, CStrRef ref, CStrRef pattern,
|
|
CStrRef content) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_search(CObjRef imap_stream, CStrRef criteria,
|
|
int64_t options /* = 0 */, CStrRef charset /* = "" */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
|
|
char *search_criteria = (char*)criteria.data();
|
|
IMAPG(messages) = IMAPG(messages_tail) = NIL;
|
|
|
|
SEARCHPGM *pgm = mail_criteria(search_criteria);
|
|
|
|
mail_search_full(obj->m_stream,
|
|
(charset.empty() ? NIL : (char*)charset.data()),
|
|
pgm,
|
|
options);
|
|
|
|
if (pgm && !(options & SE_FREE)) {
|
|
mail_free_searchpgm(&pgm);
|
|
}
|
|
|
|
if (IMAPG(messages) == NIL) {
|
|
return false;
|
|
}
|
|
|
|
Array ret(Array::Create());
|
|
|
|
MESSAGELIST *cur = IMAPG(messages);
|
|
while (cur != NIL) {
|
|
ret.append((int64_t)cur->msgid);
|
|
cur = cur->next;
|
|
}
|
|
mail_free_messagelist(&IMAPG(messages), &IMAPG(messages_tail));
|
|
return ret;
|
|
}
|
|
|
|
bool f_imap_set_quota(CObjRef imap_stream, CStrRef quota_root,
|
|
int64_t quota_limit) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
bool f_imap_setacl(CObjRef imap_stream, CStrRef mailbox, CStrRef id,
|
|
CStrRef rights) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
bool f_imap_setflag_full(CObjRef imap_stream, CStrRef sequence, CStrRef flag,
|
|
int64_t options /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
mail_setflag_full(obj->m_stream, (char*)sequence.data(), (char*)flag.data(),
|
|
(options ? options : NIL));
|
|
return true;
|
|
}
|
|
|
|
Variant f_imap_sort(CObjRef imap_stream, int64_t criteria, int64_t reverse,
|
|
int64_t options /* = 0 */,
|
|
CStrRef search_criteria /* = "" */,
|
|
CStrRef charset /* = "" */) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_status(CObjRef imap_stream, CStrRef mailbox,
|
|
int64_t options /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
Object ret(SystemLib::AllocStdClassObject());
|
|
|
|
if (mail_status(obj->m_stream, (char *)mailbox.data(), options)) {
|
|
ret.o_set("flags", (int64_t)IMAPG(status_flags));
|
|
|
|
if (IMAPG(status_flags) & SA_MESSAGES) {
|
|
ret.o_set("messages", (int64_t)IMAPG(status_messages));
|
|
}
|
|
if (IMAPG(status_flags) & SA_RECENT) {
|
|
ret.o_set("recent", (int64_t)IMAPG(status_recent));
|
|
}
|
|
if (IMAPG(status_flags) & SA_UNSEEN) {
|
|
ret.o_set("unseen", (int64_t)IMAPG(status_unseen));
|
|
}
|
|
if (IMAPG(status_flags) & SA_UIDNEXT) {
|
|
ret.o_set("uidnext", (int64_t)IMAPG(status_uidnext));
|
|
}
|
|
if (IMAPG(status_flags) & SA_UIDVALIDITY) {
|
|
ret.o_set("uidvalidity", (int64_t)IMAPG(status_uidvalidity));
|
|
}
|
|
} else {
|
|
return false;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
bool f_imap_subscribe(CObjRef imap_stream, CStrRef mailbox) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_subscribe(obj->m_stream, (char *)mailbox.data()) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Variant f_imap_thread(CObjRef imap_stream, int64_t options /* = 0 */) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_timeout(int64_t timeout_type, int64_t timeout /* = -1 */) {
|
|
int actual_type;
|
|
if (timeout == -1) {
|
|
switch (timeout_type) {
|
|
case 1:
|
|
actual_type = GET_OPENTIMEOUT;
|
|
break;
|
|
case 2:
|
|
actual_type = GET_READTIMEOUT;
|
|
break;
|
|
case 3:
|
|
actual_type = GET_WRITETIMEOUT;
|
|
break;
|
|
case 4:
|
|
actual_type = GET_CLOSETIMEOUT;
|
|
break;
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
return (int64_t)mail_parameters(NIL, actual_type, NIL);
|
|
} else if (timeout >= 0) {
|
|
switch (timeout_type) {
|
|
case 1:
|
|
actual_type = SET_OPENTIMEOUT;
|
|
break;
|
|
case 2:
|
|
actual_type = SET_READTIMEOUT;
|
|
break;
|
|
case 3:
|
|
actual_type = SET_WRITETIMEOUT;
|
|
break;
|
|
case 4:
|
|
actual_type = SET_CLOSETIMEOUT;
|
|
break;
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
timeout = (int64_t)mail_parameters(NIL, actual_type, (void *) timeout);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
Variant f_imap_uid(CObjRef imap_stream, int64_t msg_number) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (!obj->checkMsgNumber(msg_number)) {
|
|
return false;
|
|
}
|
|
return (int64_t)mail_uid(obj->m_stream, msg_number);
|
|
}
|
|
|
|
bool f_imap_undelete(CObjRef imap_stream, CStrRef msg_number,
|
|
int64_t flags /* = 0 */) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
mail_clearflag_full(obj->m_stream, (char *)msg_number.data(),
|
|
"\\DELETED", (flags ? flags : NIL));
|
|
return true;
|
|
}
|
|
|
|
bool f_imap_unsubscribe(CObjRef imap_stream, CStrRef mailbox) {
|
|
ImapStream *obj = imap_stream.getTyped<ImapStream>();
|
|
if (mail_unsubscribe(obj->m_stream, (char *)mailbox.data()) == T) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
Variant f_imap_utf7_decode(CStrRef text) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_utf7_encode(CStrRef data) {
|
|
throw NotImplementedException(__func__);
|
|
}
|
|
|
|
Variant f_imap_utf8(CStrRef mime_encoded_text) {
|
|
SIZEDTEXT src, dest;
|
|
src.data = NULL;
|
|
src.size = 0;
|
|
dest.data = NULL;
|
|
dest.size = 0;
|
|
|
|
cpytxt(&src, (char *)mime_encoded_text.data(), mime_encoded_text.length());
|
|
utf8_mime2text(&src, &dest, U8T_DECOMPOSE);
|
|
|
|
if (src.data && src.data != dest.data) {
|
|
free(src.data);
|
|
}
|
|
return String((const char*)dest.data, dest.size, AttachString);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
}
|