3040 lines
78 KiB
C
3040 lines
78 KiB
C
/*
|
|
* MIME OLE Interfaces
|
|
*
|
|
* Copyright 2006 Robert Shearman for CodeWeavers
|
|
* Copyright 2007 Huw Davies for CodeWeavers
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#define COBJMACROS
|
|
#define NONAMELESSUNION
|
|
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winuser.h"
|
|
#include "objbase.h"
|
|
#include "ole2.h"
|
|
#include "mimeole.h"
|
|
|
|
#include "wine/list.h"
|
|
#include "wine/debug.h"
|
|
|
|
#include "inetcomm_private.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
|
|
|
|
typedef struct
|
|
{
|
|
LPCSTR name;
|
|
DWORD id;
|
|
DWORD flags; /* MIMEPROPFLAGS */
|
|
VARTYPE default_vt;
|
|
} property_t;
|
|
|
|
typedef struct
|
|
{
|
|
struct list entry;
|
|
property_t prop;
|
|
} property_list_entry_t;
|
|
|
|
static const property_t default_props[] =
|
|
{
|
|
{"References", PID_HDR_REFS, 0, VT_LPSTR},
|
|
{"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR},
|
|
{"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR},
|
|
{"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR},
|
|
{"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR},
|
|
{"Date", PID_HDR_DATE, 0, VT_LPSTR},
|
|
{"Received", PID_HDR_RECEIVED, 0, VT_LPSTR},
|
|
{"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR},
|
|
{"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR},
|
|
{"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR},
|
|
{"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR},
|
|
{"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
|
|
{"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR},
|
|
{"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR},
|
|
{"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR},
|
|
{"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR},
|
|
{"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR},
|
|
{"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR},
|
|
{"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR},
|
|
{NULL, 0, 0, 0}
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
struct list entry;
|
|
char *name;
|
|
char *value;
|
|
} param_t;
|
|
|
|
typedef struct
|
|
{
|
|
struct list entry;
|
|
const property_t *prop;
|
|
PROPVARIANT value;
|
|
struct list params;
|
|
} header_t;
|
|
|
|
typedef struct MimeBody
|
|
{
|
|
IMimeBody IMimeBody_iface;
|
|
LONG ref;
|
|
|
|
HBODY handle;
|
|
|
|
struct list headers;
|
|
struct list new_props; /* FIXME: This should be in a PropertySchema */
|
|
DWORD next_prop_id;
|
|
char *content_pri_type;
|
|
char *content_sub_type;
|
|
ENCODINGTYPE encoding;
|
|
void *data;
|
|
IID data_iid;
|
|
BODYOFFSETS body_offsets;
|
|
} MimeBody;
|
|
|
|
static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
|
|
}
|
|
|
|
static LPSTR strdupA(LPCSTR str)
|
|
{
|
|
char *ret;
|
|
int len = strlen(str);
|
|
ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
|
|
memcpy(ret, str, len + 1);
|
|
return ret;
|
|
}
|
|
|
|
#define PARSER_BUF_SIZE 1024
|
|
|
|
/*****************************************************
|
|
* copy_headers_to_buf [internal]
|
|
*
|
|
* Copies the headers into a '\0' terminated memory block and leave
|
|
* the stream's current position set to after the blank line.
|
|
*/
|
|
static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
|
|
{
|
|
char *buf = NULL;
|
|
DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
|
|
HRESULT hr;
|
|
BOOL done = FALSE;
|
|
|
|
*ptr = NULL;
|
|
|
|
do
|
|
{
|
|
char *end;
|
|
DWORD read;
|
|
|
|
if(!buf)
|
|
buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
|
|
else
|
|
{
|
|
size *= 2;
|
|
buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
|
|
}
|
|
if(!buf)
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto fail;
|
|
}
|
|
|
|
hr = IStream_Read(stm, buf + offset, size - offset, &read);
|
|
if(FAILED(hr)) goto fail;
|
|
|
|
offset += read;
|
|
buf[offset] = '\0';
|
|
|
|
if(read == 0) done = TRUE;
|
|
|
|
while(!done && (end = strstr(buf + last_end, "\r\n")))
|
|
{
|
|
DWORD new_end = end - buf + 2;
|
|
if(new_end - last_end == 2)
|
|
{
|
|
LARGE_INTEGER off;
|
|
off.QuadPart = new_end;
|
|
IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
|
|
buf[new_end] = '\0';
|
|
done = TRUE;
|
|
}
|
|
else
|
|
last_end = new_end;
|
|
}
|
|
} while(!done);
|
|
|
|
*ptr = buf;
|
|
return S_OK;
|
|
|
|
fail:
|
|
HeapFree(GetProcessHeap(), 0, buf);
|
|
return hr;
|
|
}
|
|
|
|
static header_t *read_prop(MimeBody *body, char **ptr)
|
|
{
|
|
char *colon = strchr(*ptr, ':');
|
|
const property_t *prop;
|
|
header_t *ret;
|
|
|
|
if(!colon) return NULL;
|
|
|
|
*colon = '\0';
|
|
|
|
for(prop = default_props; prop->name; prop++)
|
|
{
|
|
if(!strcasecmp(*ptr, prop->name))
|
|
{
|
|
TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!prop->name)
|
|
{
|
|
property_list_entry_t *prop_entry;
|
|
LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
|
|
{
|
|
if(!strcasecmp(*ptr, prop_entry->prop.name))
|
|
{
|
|
TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
|
|
prop = &prop_entry->prop;
|
|
break;
|
|
}
|
|
}
|
|
if(!prop->name)
|
|
{
|
|
prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
|
|
prop_entry->prop.name = strdupA(*ptr);
|
|
prop_entry->prop.id = body->next_prop_id++;
|
|
prop_entry->prop.flags = 0;
|
|
prop_entry->prop.default_vt = VT_LPSTR;
|
|
list_add_tail(&body->new_props, &prop_entry->entry);
|
|
prop = &prop_entry->prop;
|
|
TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
|
|
}
|
|
}
|
|
|
|
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
|
|
ret->prop = prop;
|
|
PropVariantInit(&ret->value);
|
|
list_init(&ret->params);
|
|
*ptr = colon + 1;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void unfold_header(char *header, int len)
|
|
{
|
|
char *start = header, *cp = header;
|
|
|
|
do {
|
|
while(*cp == ' ' || *cp == '\t')
|
|
{
|
|
cp++;
|
|
len--;
|
|
}
|
|
if(cp != start)
|
|
memmove(start, cp, len + 1);
|
|
|
|
cp = strstr(start, "\r\n");
|
|
len -= (cp - start);
|
|
start = cp;
|
|
*start = ' ';
|
|
start++;
|
|
len--;
|
|
cp += 2;
|
|
} while(*cp == ' ' || *cp == '\t');
|
|
|
|
*(start - 1) = '\0';
|
|
}
|
|
|
|
static char *unquote_string(const char *str)
|
|
{
|
|
BOOL quoted = FALSE;
|
|
char *ret, *cp;
|
|
|
|
while(*str == ' ' || *str == '\t') str++;
|
|
|
|
if(*str == '"')
|
|
{
|
|
quoted = TRUE;
|
|
str++;
|
|
}
|
|
ret = strdupA(str);
|
|
for(cp = ret; *cp; cp++)
|
|
{
|
|
if(*cp == '\\')
|
|
memmove(cp, cp + 1, strlen(cp + 1) + 1);
|
|
else if(*cp == '"')
|
|
{
|
|
if(!quoted)
|
|
{
|
|
WARN("quote in unquoted string\n");
|
|
}
|
|
else
|
|
{
|
|
*cp = '\0';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void add_param(header_t *header, const char *p)
|
|
{
|
|
const char *key = p, *value, *cp = p;
|
|
param_t *param;
|
|
char *name;
|
|
|
|
TRACE("got param %s\n", p);
|
|
|
|
while (*key == ' ' || *key == '\t' ) key++;
|
|
|
|
cp = strchr(key, '=');
|
|
if(!cp)
|
|
{
|
|
WARN("malformed parameter - skipping\n");
|
|
return;
|
|
}
|
|
|
|
name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
|
|
memcpy(name, key, cp - key);
|
|
name[cp - key] = '\0';
|
|
|
|
value = cp + 1;
|
|
|
|
param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
|
|
param->name = name;
|
|
param->value = unquote_string(value);
|
|
list_add_tail(&header->params, ¶m->entry);
|
|
}
|
|
|
|
static void split_params(header_t *header, char *value)
|
|
{
|
|
char *cp = value, *start = value;
|
|
BOOL in_quotes = FALSE, done_value = FALSE;
|
|
|
|
while(*cp)
|
|
{
|
|
if(!in_quotes && *cp == ';')
|
|
{
|
|
*cp = '\0';
|
|
if(done_value) add_param(header, start);
|
|
done_value = TRUE;
|
|
start = cp + 1;
|
|
}
|
|
else if(*cp == '"')
|
|
in_quotes = !in_quotes;
|
|
cp++;
|
|
}
|
|
if(done_value) add_param(header, start);
|
|
}
|
|
|
|
static void read_value(header_t *header, char **cur)
|
|
{
|
|
char *end = *cur, *value;
|
|
DWORD len;
|
|
|
|
do {
|
|
end = strstr(end, "\r\n");
|
|
end += 2;
|
|
} while(*end == ' ' || *end == '\t');
|
|
|
|
len = end - *cur;
|
|
value = HeapAlloc(GetProcessHeap(), 0, len + 1);
|
|
memcpy(value, *cur, len);
|
|
value[len] = '\0';
|
|
|
|
unfold_header(value, len);
|
|
TRACE("value %s\n", debugstr_a(value));
|
|
|
|
if(header->prop->flags & MPF_HASPARAMS)
|
|
{
|
|
split_params(header, value);
|
|
TRACE("value w/o params %s\n", debugstr_a(value));
|
|
}
|
|
|
|
header->value.vt = VT_LPSTR;
|
|
header->value.u.pszVal = value;
|
|
|
|
*cur = end;
|
|
}
|
|
|
|
static void init_content_type(MimeBody *body, header_t *header)
|
|
{
|
|
char *slash;
|
|
DWORD len;
|
|
|
|
if(header->prop->id != PID_HDR_CNTTYPE)
|
|
{
|
|
ERR("called with header %s\n", header->prop->name);
|
|
return;
|
|
}
|
|
|
|
slash = strchr(header->value.u.pszVal, '/');
|
|
if(!slash)
|
|
{
|
|
WARN("malformed context type value\n");
|
|
return;
|
|
}
|
|
len = slash - header->value.u.pszVal;
|
|
body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
|
|
memcpy(body->content_pri_type, header->value.u.pszVal, len);
|
|
body->content_pri_type[len] = '\0';
|
|
body->content_sub_type = strdupA(slash + 1);
|
|
}
|
|
|
|
static HRESULT parse_headers(MimeBody *body, IStream *stm)
|
|
{
|
|
char *header_buf, *cur_header_ptr;
|
|
HRESULT hr;
|
|
header_t *header;
|
|
|
|
hr = copy_headers_to_buf(stm, &header_buf);
|
|
if(FAILED(hr)) return hr;
|
|
|
|
cur_header_ptr = header_buf;
|
|
while((header = read_prop(body, &cur_header_ptr)))
|
|
{
|
|
read_value(header, &cur_header_ptr);
|
|
list_add_tail(&body->headers, &header->entry);
|
|
|
|
if(header->prop->id == PID_HDR_CNTTYPE)
|
|
init_content_type(body, header);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, header_buf);
|
|
return hr;
|
|
}
|
|
|
|
static void empty_param_list(struct list *list)
|
|
{
|
|
param_t *param, *cursor2;
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
|
|
{
|
|
list_remove(¶m->entry);
|
|
HeapFree(GetProcessHeap(), 0, param->name);
|
|
HeapFree(GetProcessHeap(), 0, param->value);
|
|
HeapFree(GetProcessHeap(), 0, param);
|
|
}
|
|
}
|
|
|
|
static void empty_header_list(struct list *list)
|
|
{
|
|
header_t *header, *cursor2;
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
|
|
{
|
|
list_remove(&header->entry);
|
|
PropVariantClear(&header->value);
|
|
empty_param_list(&header->params);
|
|
HeapFree(GetProcessHeap(), 0, header);
|
|
}
|
|
}
|
|
|
|
static void empty_new_prop_list(struct list *list)
|
|
{
|
|
property_list_entry_t *prop, *cursor2;
|
|
|
|
LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
|
|
{
|
|
list_remove(&prop->entry);
|
|
HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
|
|
HeapFree(GetProcessHeap(), 0, prop);
|
|
}
|
|
}
|
|
|
|
static void release_data(REFIID riid, void *data)
|
|
{
|
|
if(!data) return;
|
|
|
|
if(IsEqualIID(riid, &IID_IStream))
|
|
IStream_Release((IStream *)data);
|
|
else
|
|
FIXME("Unhandled data format %s\n", debugstr_guid(riid));
|
|
}
|
|
|
|
static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
|
|
{
|
|
header_t *header;
|
|
|
|
*prop = NULL;
|
|
|
|
LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
|
|
{
|
|
if(!strcasecmp(name, header->prop->name))
|
|
{
|
|
*prop = header;
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
return MIME_E_NOT_FOUND;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
|
|
REFIID riid,
|
|
void** ppvObject)
|
|
{
|
|
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
|
|
|
|
*ppvObject = NULL;
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IPersist) ||
|
|
IsEqualIID(riid, &IID_IPersistStreamInit) ||
|
|
IsEqualIID(riid, &IID_IMimePropertySet) ||
|
|
IsEqualIID(riid, &IID_IMimeBody))
|
|
{
|
|
*ppvObject = iface;
|
|
}
|
|
|
|
if(*ppvObject)
|
|
{
|
|
IUnknown_AddRef((IUnknown*)*ppvObject);
|
|
return S_OK;
|
|
}
|
|
|
|
FIXME("no interface for %s\n", debugstr_guid(riid));
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
LONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
LONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
if (!ref)
|
|
{
|
|
empty_header_list(&This->headers);
|
|
empty_new_prop_list(&This->new_props);
|
|
|
|
HeapFree(GetProcessHeap(), 0, This->content_pri_type);
|
|
HeapFree(GetProcessHeap(), 0, This->content_sub_type);
|
|
|
|
release_data(&This->data_iid, This->data);
|
|
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetClassID(
|
|
IMimeBody* iface,
|
|
CLSID* pClassID)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, pClassID);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI MimeBody_IsDirty(
|
|
IMimeBody* iface)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->() stub\n", This);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
TRACE("(%p)->(%p)\n", This, pStm);
|
|
return parse_headers(This, pStm);
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetSizeMax(
|
|
IMimeBody* iface,
|
|
ULARGE_INTEGER* pcbSize)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, pcbSize);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_InitNew(
|
|
IMimeBody* iface)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
TRACE("(%p)->()\n", This);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetPropInfo(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
LPMIMEPROPINFO pInfo)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetPropInfo(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
LPCMIMEPROPINFO pInfo)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetProp(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
TRACE("(%p)->(%s, 0x%x, %p)\n", This, pszName, dwFlags, pValue);
|
|
|
|
if(!strcasecmp(pszName, "att:pri-content-type"))
|
|
{
|
|
PropVariantClear(pValue);
|
|
pValue->vt = VT_LPSTR;
|
|
pValue->u.pszVal = strdupA(This->content_pri_type);
|
|
return S_OK;
|
|
}
|
|
|
|
FIXME("stub!\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetProp(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPCPROPVARIANT pValue)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_AppendProp(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_DeleteProp(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszName));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_CopyProps(
|
|
IMimeBody* iface,
|
|
ULONG cNames,
|
|
LPCSTR* prgszName,
|
|
IMimePropertySet* pPropertySet)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_MoveProps(
|
|
IMimeBody* iface,
|
|
ULONG cNames,
|
|
LPCSTR* prgszName,
|
|
IMimePropertySet* pPropertySet)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_DeleteExcept(
|
|
IMimeBody* iface,
|
|
ULONG cNames,
|
|
LPCSTR* prgszName)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_QueryProp(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
LPCSTR pszCriteria,
|
|
boolean fSubString,
|
|
boolean fCaseSensitive)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetCharset(
|
|
IMimeBody* iface,
|
|
LPHCHARSET phCharset)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, phCharset);
|
|
*phCharset = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetCharset(
|
|
IMimeBody* iface,
|
|
HCHARSET hCharset,
|
|
CSETAPPLYTYPE applytype)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetParameters(
|
|
IMimeBody* iface,
|
|
LPCSTR pszName,
|
|
ULONG* pcParams,
|
|
LPMIMEPARAMINFO* pprgParam)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
HRESULT hr;
|
|
header_t *header;
|
|
|
|
TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
|
|
|
|
*pprgParam = NULL;
|
|
*pcParams = 0;
|
|
|
|
hr = find_prop(This, pszName, &header);
|
|
if(hr != S_OK) return hr;
|
|
|
|
*pcParams = list_count(&header->params);
|
|
if(*pcParams)
|
|
{
|
|
IMimeAllocator *alloc;
|
|
param_t *param;
|
|
MIMEPARAMINFO *info;
|
|
|
|
MimeOleGetAllocator(&alloc);
|
|
|
|
*pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
|
|
LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
|
|
{
|
|
int len;
|
|
|
|
len = strlen(param->name) + 1;
|
|
info->pszName = IMimeAllocator_Alloc(alloc, len);
|
|
memcpy(info->pszName, param->name, len);
|
|
len = strlen(param->value) + 1;
|
|
info->pszData = IMimeAllocator_Alloc(alloc, len);
|
|
memcpy(info->pszData, param->value, len);
|
|
info++;
|
|
}
|
|
IMimeAllocator_Release(alloc);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_IsContentType(
|
|
IMimeBody* iface,
|
|
LPCSTR pszPriType,
|
|
LPCSTR pszSubType)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
|
|
TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
|
|
if(pszPriType)
|
|
{
|
|
const char *pri = This->content_pri_type;
|
|
if(!pri) pri = "text";
|
|
if(strcasecmp(pri, pszPriType)) return S_FALSE;
|
|
}
|
|
|
|
if(pszSubType)
|
|
{
|
|
const char *sub = This->content_sub_type;
|
|
if(!sub) sub = "plain";
|
|
if(strcasecmp(sub, pszSubType)) return S_FALSE;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_BindToObject(
|
|
IMimeBody* iface,
|
|
REFIID riid,
|
|
void** ppvObject)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_Clone(
|
|
IMimeBody* iface,
|
|
IMimePropertySet** ppPropertySet)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetOption(
|
|
IMimeBody* iface,
|
|
const TYPEDID oid,
|
|
LPCPROPVARIANT pValue)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
HRESULT hr = E_NOTIMPL;
|
|
TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
|
|
|
|
if(pValue->vt != TYPEDID_TYPE(oid))
|
|
{
|
|
WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
switch(oid)
|
|
{
|
|
case OID_SECURITY_HWND_OWNER:
|
|
FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
|
|
hr = S_OK;
|
|
break;
|
|
default:
|
|
FIXME("Unhandled oid %08x\n", oid);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetOption(
|
|
IMimeBody* iface,
|
|
const TYPEDID oid,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_EnumProps(
|
|
IMimeBody* iface,
|
|
DWORD dwFlags,
|
|
IMimeEnumProperties** ppEnum)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_IsType(
|
|
IMimeBody* iface,
|
|
IMSGBODYTYPE bodytype)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
|
|
TRACE("(%p)->(%d)\n", This, bodytype);
|
|
switch(bodytype)
|
|
{
|
|
case IBT_EMPTY:
|
|
return This->data ? S_FALSE : S_OK;
|
|
default:
|
|
FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetDisplayName(
|
|
IMimeBody* iface,
|
|
LPCSTR pszDisplay)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetDisplayName(
|
|
IMimeBody* iface,
|
|
LPSTR* ppszDisplay)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetOffsets(
|
|
IMimeBody* iface,
|
|
LPBODYOFFSETS pOffsets)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
TRACE("(%p)->(%p)\n", This, pOffsets);
|
|
|
|
*pOffsets = This->body_offsets;
|
|
|
|
if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetCurrentEncoding(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE* pietEncoding)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
|
|
TRACE("(%p)->(%p)\n", This, pietEncoding);
|
|
|
|
*pietEncoding = This->encoding;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetCurrentEncoding(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE ietEncoding)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
|
|
TRACE("(%p)->(%d)\n", This, ietEncoding);
|
|
|
|
This->encoding = ietEncoding;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetEstimatedSize(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE ietEncoding,
|
|
ULONG* pcbSize)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetDataHere(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE ietEncoding,
|
|
IStream* pStream)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetData(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE ietEncoding,
|
|
IStream** ppStream)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
|
|
|
|
*ppStream = This->data;
|
|
IStream_AddRef(*ppStream);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SetData(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE ietEncoding,
|
|
LPCSTR pszPriType,
|
|
LPCSTR pszSubType,
|
|
REFIID riid,
|
|
LPVOID pvObject)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
|
|
debugstr_guid(riid), pvObject);
|
|
|
|
if(IsEqualIID(riid, &IID_IStream))
|
|
IStream_AddRef((IStream *)pvObject);
|
|
else
|
|
{
|
|
FIXME("Unhandled object type %s\n", debugstr_guid(riid));
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if(This->data)
|
|
FIXME("release old data\n");
|
|
|
|
This->data_iid = *riid;
|
|
This->data = pvObject;
|
|
|
|
IMimeBody_SetCurrentEncoding(iface, ietEncoding);
|
|
|
|
/* FIXME: Update the content type.
|
|
If pszPriType == NULL use 'application'
|
|
If pszSubType == NULL use 'octet-stream' */
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_EmptyData(
|
|
IMimeBody* iface)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->() stub\n", This);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_CopyTo(
|
|
IMimeBody* iface,
|
|
IMimeBody* pBody)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, pBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetTransmitInfo(
|
|
IMimeBody* iface,
|
|
LPTRANSMITINFO pTransmitInfo)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_SaveToFile(
|
|
IMimeBody* iface,
|
|
ENCODINGTYPE ietEncoding,
|
|
LPCSTR pszFilePath)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeBody_GetHandle(
|
|
IMimeBody* iface,
|
|
LPHBODY phBody)
|
|
{
|
|
MimeBody *This = impl_from_IMimeBody(iface);
|
|
TRACE("(%p)->(%p)\n", iface, phBody);
|
|
|
|
*phBody = This->handle;
|
|
return This->handle ? S_OK : MIME_E_NO_DATA;
|
|
}
|
|
|
|
static IMimeBodyVtbl body_vtbl =
|
|
{
|
|
MimeBody_QueryInterface,
|
|
MimeBody_AddRef,
|
|
MimeBody_Release,
|
|
MimeBody_GetClassID,
|
|
MimeBody_IsDirty,
|
|
MimeBody_Load,
|
|
MimeBody_Save,
|
|
MimeBody_GetSizeMax,
|
|
MimeBody_InitNew,
|
|
MimeBody_GetPropInfo,
|
|
MimeBody_SetPropInfo,
|
|
MimeBody_GetProp,
|
|
MimeBody_SetProp,
|
|
MimeBody_AppendProp,
|
|
MimeBody_DeleteProp,
|
|
MimeBody_CopyProps,
|
|
MimeBody_MoveProps,
|
|
MimeBody_DeleteExcept,
|
|
MimeBody_QueryProp,
|
|
MimeBody_GetCharset,
|
|
MimeBody_SetCharset,
|
|
MimeBody_GetParameters,
|
|
MimeBody_IsContentType,
|
|
MimeBody_BindToObject,
|
|
MimeBody_Clone,
|
|
MimeBody_SetOption,
|
|
MimeBody_GetOption,
|
|
MimeBody_EnumProps,
|
|
MimeBody_IsType,
|
|
MimeBody_SetDisplayName,
|
|
MimeBody_GetDisplayName,
|
|
MimeBody_GetOffsets,
|
|
MimeBody_GetCurrentEncoding,
|
|
MimeBody_SetCurrentEncoding,
|
|
MimeBody_GetEstimatedSize,
|
|
MimeBody_GetDataHere,
|
|
MimeBody_GetData,
|
|
MimeBody_SetData,
|
|
MimeBody_EmptyData,
|
|
MimeBody_CopyTo,
|
|
MimeBody_GetTransmitInfo,
|
|
MimeBody_SaveToFile,
|
|
MimeBody_GetHandle
|
|
};
|
|
|
|
static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
|
|
{
|
|
TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
|
|
offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
|
|
|
|
body->body_offsets = *offsets;
|
|
return S_OK;
|
|
}
|
|
|
|
#define FIRST_CUSTOM_PROP_ID 0x100
|
|
|
|
static MimeBody *mimebody_create(void)
|
|
{
|
|
MimeBody *This;
|
|
BODYOFFSETS body_offsets;
|
|
|
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
if (!This)
|
|
return NULL;
|
|
|
|
This->IMimeBody_iface.lpVtbl = &body_vtbl;
|
|
This->ref = 1;
|
|
This->handle = NULL;
|
|
list_init(&This->headers);
|
|
list_init(&This->new_props);
|
|
This->next_prop_id = FIRST_CUSTOM_PROP_ID;
|
|
This->content_pri_type = NULL;
|
|
This->content_sub_type = NULL;
|
|
This->encoding = IET_7BIT;
|
|
This->data = NULL;
|
|
This->data_iid = IID_NULL;
|
|
|
|
body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
|
|
body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
|
|
MimeBody_set_offsets(This, &body_offsets);
|
|
|
|
return This;
|
|
}
|
|
|
|
HRESULT MimeBody_create(IUnknown *outer, void **ppv)
|
|
{
|
|
MimeBody *mb;
|
|
|
|
if(outer)
|
|
return CLASS_E_NOAGGREGATION;
|
|
|
|
if ((mb = mimebody_create()))
|
|
{
|
|
*ppv = &mb->IMimeBody_iface;
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
{
|
|
IStream IStream_iface;
|
|
LONG ref;
|
|
IStream *base;
|
|
ULARGE_INTEGER pos, start, length;
|
|
} sub_stream_t;
|
|
|
|
static inline sub_stream_t *impl_from_IStream(IStream *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
|
|
{
|
|
sub_stream_t *This = impl_from_IStream(iface);
|
|
|
|
TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
|
|
*ppv = NULL;
|
|
|
|
if(IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_ISequentialStream) ||
|
|
IsEqualIID(riid, &IID_IStream))
|
|
{
|
|
IStream_AddRef(iface);
|
|
*ppv = iface;
|
|
return S_OK;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI sub_stream_AddRef(IStream *iface)
|
|
{
|
|
sub_stream_t *This = impl_from_IStream(iface);
|
|
LONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI sub_stream_Release(IStream *iface)
|
|
{
|
|
sub_stream_t *This = impl_from_IStream(iface);
|
|
LONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
if(!ref)
|
|
{
|
|
IStream_Release(This->base);
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Read(
|
|
IStream* iface,
|
|
void *pv,
|
|
ULONG cb,
|
|
ULONG *pcbRead)
|
|
{
|
|
sub_stream_t *This = impl_from_IStream(iface);
|
|
HRESULT hr;
|
|
ULARGE_INTEGER base_pos;
|
|
LARGE_INTEGER tmp_pos;
|
|
|
|
TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
|
|
|
|
tmp_pos.QuadPart = 0;
|
|
IStream_Seek(This->base, tmp_pos, STREAM_SEEK_CUR, &base_pos);
|
|
tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart;
|
|
IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
|
|
|
|
if(This->pos.QuadPart + cb > This->length.QuadPart)
|
|
cb = This->length.QuadPart - This->pos.QuadPart;
|
|
|
|
hr = IStream_Read(This->base, pv, cb, pcbRead);
|
|
|
|
This->pos.QuadPart += *pcbRead;
|
|
|
|
tmp_pos.QuadPart = base_pos.QuadPart;
|
|
IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Write(
|
|
IStream* iface,
|
|
const void *pv,
|
|
ULONG cb,
|
|
ULONG *pcbWritten)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Seek(
|
|
IStream* iface,
|
|
LARGE_INTEGER dlibMove,
|
|
DWORD dwOrigin,
|
|
ULARGE_INTEGER *plibNewPosition)
|
|
{
|
|
sub_stream_t *This = impl_from_IStream(iface);
|
|
LARGE_INTEGER new_pos;
|
|
|
|
TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
|
|
|
|
switch(dwOrigin)
|
|
{
|
|
case STREAM_SEEK_SET:
|
|
new_pos = dlibMove;
|
|
break;
|
|
case STREAM_SEEK_CUR:
|
|
new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart;
|
|
break;
|
|
case STREAM_SEEK_END:
|
|
new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart;
|
|
break;
|
|
default:
|
|
return STG_E_INVALIDFUNCTION;
|
|
}
|
|
|
|
if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
|
|
else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
|
|
|
|
This->pos.QuadPart = new_pos.QuadPart;
|
|
|
|
if(plibNewPosition) *plibNewPosition = This->pos;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_SetSize(
|
|
IStream* iface,
|
|
ULARGE_INTEGER libNewSize)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_CopyTo(
|
|
IStream* iface,
|
|
IStream *pstm,
|
|
ULARGE_INTEGER cb,
|
|
ULARGE_INTEGER *pcbRead,
|
|
ULARGE_INTEGER *pcbWritten)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
BYTE tmpBuffer[128];
|
|
ULONG bytesRead, bytesWritten, copySize;
|
|
ULARGE_INTEGER totalBytesRead;
|
|
ULARGE_INTEGER totalBytesWritten;
|
|
|
|
TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
|
|
|
|
totalBytesRead.QuadPart = 0;
|
|
totalBytesWritten.QuadPart = 0;
|
|
|
|
while ( cb.QuadPart > 0 )
|
|
{
|
|
if ( cb.QuadPart >= sizeof(tmpBuffer) )
|
|
copySize = sizeof(tmpBuffer);
|
|
else
|
|
copySize = cb.u.LowPart;
|
|
|
|
hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
|
|
if (FAILED(hr)) break;
|
|
|
|
totalBytesRead.QuadPart += bytesRead;
|
|
|
|
if (bytesRead)
|
|
{
|
|
hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
|
|
if (FAILED(hr)) break;
|
|
totalBytesWritten.QuadPart += bytesWritten;
|
|
}
|
|
|
|
if (bytesRead != copySize)
|
|
cb.QuadPart = 0;
|
|
else
|
|
cb.QuadPart -= bytesRead;
|
|
}
|
|
|
|
if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
|
|
if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Commit(
|
|
IStream* iface,
|
|
DWORD grfCommitFlags)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Revert(
|
|
IStream* iface)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_LockRegion(
|
|
IStream* iface,
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_UnlockRegion(
|
|
IStream* iface,
|
|
ULARGE_INTEGER libOffset,
|
|
ULARGE_INTEGER cb,
|
|
DWORD dwLockType)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Stat(
|
|
IStream* iface,
|
|
STATSTG *pstatstg,
|
|
DWORD grfStatFlag)
|
|
{
|
|
sub_stream_t *This = impl_from_IStream(iface);
|
|
FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag);
|
|
memset(pstatstg, 0, sizeof(*pstatstg));
|
|
pstatstg->cbSize = This->length;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI sub_stream_Clone(
|
|
IStream* iface,
|
|
IStream **ppstm)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static struct IStreamVtbl sub_stream_vtbl =
|
|
{
|
|
sub_stream_QueryInterface,
|
|
sub_stream_AddRef,
|
|
sub_stream_Release,
|
|
sub_stream_Read,
|
|
sub_stream_Write,
|
|
sub_stream_Seek,
|
|
sub_stream_SetSize,
|
|
sub_stream_CopyTo,
|
|
sub_stream_Commit,
|
|
sub_stream_Revert,
|
|
sub_stream_LockRegion,
|
|
sub_stream_UnlockRegion,
|
|
sub_stream_Stat,
|
|
sub_stream_Clone
|
|
};
|
|
|
|
static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
|
|
{
|
|
sub_stream_t *This;
|
|
|
|
*out = NULL;
|
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
if(!This) return E_OUTOFMEMORY;
|
|
|
|
This->IStream_iface.lpVtbl = &sub_stream_vtbl;
|
|
This->ref = 1;
|
|
This->start = start;
|
|
This->length = length;
|
|
This->pos.QuadPart = 0;
|
|
IStream_AddRef(stream);
|
|
This->base = stream;
|
|
|
|
*out = &This->IStream_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
typedef struct body_t
|
|
{
|
|
struct list entry;
|
|
DWORD index;
|
|
MimeBody *mime_body;
|
|
|
|
struct body_t *parent;
|
|
struct list children;
|
|
} body_t;
|
|
|
|
typedef struct MimeMessage
|
|
{
|
|
IMimeMessage IMimeMessage_iface;
|
|
LONG ref;
|
|
IStream *stream;
|
|
|
|
struct list body_tree;
|
|
DWORD next_index;
|
|
} MimeMessage;
|
|
|
|
static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv)
|
|
{
|
|
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IPersist) ||
|
|
IsEqualIID(riid, &IID_IPersistStreamInit) ||
|
|
IsEqualIID(riid, &IID_IMimeMessageTree) ||
|
|
IsEqualIID(riid, &IID_IMimeMessage))
|
|
{
|
|
*ppv = iface;
|
|
IMimeMessage_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
FIXME("no interface for %s\n", debugstr_guid(riid));
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
ULONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static void empty_body_list(struct list *list)
|
|
{
|
|
body_t *body, *cursor2;
|
|
LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry)
|
|
{
|
|
empty_body_list(&body->children);
|
|
list_remove(&body->entry);
|
|
IMimeBody_Release(&body->mime_body->IMimeBody_iface);
|
|
HeapFree(GetProcessHeap(), 0, body);
|
|
}
|
|
}
|
|
|
|
static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
ULONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
if (!ref)
|
|
{
|
|
empty_body_list(&This->body_tree);
|
|
|
|
if(This->stream) IStream_Release(This->stream);
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
}
|
|
|
|
return ref;
|
|
}
|
|
|
|
/*** IPersist methods ***/
|
|
static HRESULT WINAPI MimeMessage_GetClassID(
|
|
IMimeMessage *iface,
|
|
CLSID *pClassID)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, pClassID);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
/*** IPersistStreamInit methods ***/
|
|
static HRESULT WINAPI MimeMessage_IsDirty(
|
|
IMimeMessage *iface)
|
|
{
|
|
FIXME("(%p)->()\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent)
|
|
{
|
|
body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body));
|
|
if(body)
|
|
{
|
|
body->mime_body = mime_body;
|
|
body->index = index;
|
|
list_init(&body->children);
|
|
body->parent = parent;
|
|
}
|
|
return body;
|
|
}
|
|
|
|
typedef struct
|
|
{
|
|
struct list entry;
|
|
BODYOFFSETS offsets;
|
|
} offset_entry_t;
|
|
|
|
static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets)
|
|
{
|
|
HRESULT hr;
|
|
DWORD read;
|
|
int boundary_len = strlen(boundary);
|
|
char *buf, *nl_boundary, *ptr, *overlap;
|
|
DWORD start = 0, overlap_no;
|
|
offset_entry_t *cur_body = NULL;
|
|
ULARGE_INTEGER cur;
|
|
LARGE_INTEGER zero;
|
|
|
|
list_init(body_offsets);
|
|
nl_boundary = HeapAlloc(GetProcessHeap(), 0, 4 + boundary_len + 1);
|
|
memcpy(nl_boundary, "\r\n--", 4);
|
|
memcpy(nl_boundary + 4, boundary, boundary_len + 1);
|
|
|
|
overlap_no = boundary_len + 5;
|
|
|
|
overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1);
|
|
|
|
zero.QuadPart = 0;
|
|
hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur);
|
|
start = cur.u.LowPart;
|
|
|
|
do {
|
|
hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read);
|
|
if(FAILED(hr)) goto end;
|
|
if(read == 0) break;
|
|
overlap[read] = '\0';
|
|
|
|
ptr = buf;
|
|
do {
|
|
ptr = strstr(ptr, nl_boundary);
|
|
if(ptr)
|
|
{
|
|
DWORD boundary_start = start + ptr - buf;
|
|
char *end = ptr + boundary_len + 4;
|
|
|
|
if(*end == '\0' || *(end + 1) == '\0')
|
|
break;
|
|
|
|
if(*end == '\r' && *(end + 1) == '\n')
|
|
{
|
|
if(cur_body)
|
|
{
|
|
cur_body->offsets.cbBodyEnd = boundary_start;
|
|
list_add_tail(body_offsets, &cur_body->entry);
|
|
}
|
|
cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body));
|
|
cur_body->offsets.cbBoundaryStart = boundary_start + 2; /* doesn't including the leading \r\n */
|
|
cur_body->offsets.cbHeaderStart = boundary_start + boundary_len + 6;
|
|
}
|
|
else if(*end == '-' && *(end + 1) == '-')
|
|
{
|
|
if(cur_body)
|
|
{
|
|
cur_body->offsets.cbBodyEnd = boundary_start;
|
|
list_add_tail(body_offsets, &cur_body->entry);
|
|
goto end;
|
|
}
|
|
}
|
|
ptr = end + 2;
|
|
}
|
|
} while(ptr);
|
|
|
|
if(overlap == buf) /* 1st iteration */
|
|
{
|
|
memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no);
|
|
overlap = buf + overlap_no;
|
|
start += read - overlap_no;
|
|
}
|
|
else
|
|
{
|
|
memmove(buf, buf + PARSER_BUF_SIZE, overlap_no);
|
|
start += read;
|
|
}
|
|
} while(1);
|
|
|
|
end:
|
|
HeapFree(GetProcessHeap(), 0, nl_boundary);
|
|
HeapFree(GetProcessHeap(), 0, buf);
|
|
return hr;
|
|
}
|
|
|
|
static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent)
|
|
{
|
|
MimeBody *mime_body;
|
|
HRESULT hr;
|
|
body_t *body;
|
|
ULARGE_INTEGER cur;
|
|
LARGE_INTEGER zero;
|
|
|
|
mime_body = mimebody_create();
|
|
IMimeBody_Load(&mime_body->IMimeBody_iface, pStm);
|
|
zero.QuadPart = 0;
|
|
hr = IStream_Seek(pStm, zero, STREAM_SEEK_CUR, &cur);
|
|
offset->cbBodyStart = cur.u.LowPart + offset->cbHeaderStart;
|
|
if (parent) MimeBody_set_offsets(mime_body, offset);
|
|
IMimeBody_SetData(&mime_body->IMimeBody_iface, IET_BINARY, NULL, NULL, &IID_IStream, pStm);
|
|
body = new_body_entry(mime_body, msg->next_index++, parent);
|
|
|
|
if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK)
|
|
{
|
|
MIMEPARAMINFO *param_info;
|
|
ULONG count, i;
|
|
IMimeAllocator *alloc;
|
|
|
|
hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count,
|
|
¶m_info);
|
|
if(hr != S_OK || count == 0) return body;
|
|
|
|
MimeOleGetAllocator(&alloc);
|
|
|
|
for(i = 0; i < count; i++)
|
|
{
|
|
if(!strcasecmp(param_info[i].pszName, "boundary"))
|
|
{
|
|
struct list offset_list;
|
|
offset_entry_t *cur, *cursor2;
|
|
hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list);
|
|
LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry)
|
|
{
|
|
body_t *sub_body;
|
|
IStream *sub_stream;
|
|
ULARGE_INTEGER start, length;
|
|
|
|
start.QuadPart = cur->offsets.cbHeaderStart;
|
|
length.QuadPart = cur->offsets.cbBodyEnd - cur->offsets.cbHeaderStart;
|
|
create_sub_stream(pStm, start, length, &sub_stream);
|
|
sub_body = create_sub_body(msg, sub_stream, &cur->offsets, body);
|
|
IStream_Release(sub_stream);
|
|
list_add_tail(&body->children, &sub_body->entry);
|
|
list_remove(&cur->entry);
|
|
HeapFree(GetProcessHeap(), 0, cur);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE);
|
|
IMimeAllocator_Release(alloc);
|
|
}
|
|
return body;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
body_t *root_body;
|
|
BODYOFFSETS offsets;
|
|
ULARGE_INTEGER cur;
|
|
LARGE_INTEGER zero;
|
|
|
|
TRACE("(%p)->(%p)\n", iface, pStm);
|
|
|
|
if(This->stream)
|
|
{
|
|
FIXME("already loaded a message\n");
|
|
return E_FAIL;
|
|
}
|
|
|
|
empty_body_list(&This->body_tree);
|
|
|
|
IStream_AddRef(pStm);
|
|
This->stream = pStm;
|
|
offsets.cbBoundaryStart = offsets.cbHeaderStart = 0;
|
|
offsets.cbBodyStart = offsets.cbBodyEnd = 0;
|
|
|
|
root_body = create_sub_body(This, pStm, &offsets, NULL);
|
|
|
|
zero.QuadPart = 0;
|
|
IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur);
|
|
offsets.cbBodyEnd = cur.u.LowPart;
|
|
MimeBody_set_offsets(root_body->mime_body, &offsets);
|
|
|
|
list_add_head(&This->body_tree, &root_body->entry);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty)
|
|
{
|
|
FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetSizeMax(
|
|
IMimeMessage *iface,
|
|
ULARGE_INTEGER *pcbSize)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, pcbSize);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_InitNew(
|
|
IMimeMessage *iface)
|
|
{
|
|
FIXME("(%p)->()\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
/*** IMimeMessageTree methods ***/
|
|
static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream,
|
|
DWORD dwFlags)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
|
|
FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags);
|
|
|
|
IStream_AddRef(This->stream);
|
|
*ppStream = This->stream;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetMessageSize(
|
|
IMimeMessage *iface,
|
|
ULONG *pcbSize,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_LoadOffsetTable(
|
|
IMimeMessage *iface,
|
|
IStream *pStream)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, pStream);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SaveOffsetTable(
|
|
IMimeMessage *iface,
|
|
IStream *pStream,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI MimeMessage_GetFlags(
|
|
IMimeMessage *iface,
|
|
DWORD *pdwFlags)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, pdwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_Commit(
|
|
IMimeMessage *iface,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(0x%x)\n", iface, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI MimeMessage_HandsOffStorage(
|
|
IMimeMessage *iface)
|
|
{
|
|
FIXME("(%p)->()\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT find_body(struct list *list, HBODY hbody, body_t **body)
|
|
{
|
|
body_t *cur;
|
|
HRESULT hr;
|
|
|
|
if(hbody == HBODY_ROOT)
|
|
{
|
|
*body = LIST_ENTRY(list_head(list), body_t, entry);
|
|
return S_OK;
|
|
}
|
|
|
|
LIST_FOR_EACH_ENTRY(cur, list, body_t, entry)
|
|
{
|
|
if(cur->index == HandleToUlong(hbody))
|
|
{
|
|
*body = cur;
|
|
return S_OK;
|
|
}
|
|
hr = find_body(&cur->children, hbody, body);
|
|
if(hr == S_OK) return S_OK;
|
|
}
|
|
return S_FALSE;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
HRESULT hr;
|
|
body_t *body;
|
|
|
|
TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject);
|
|
|
|
hr = find_body(&This->body_tree, hBody, &body);
|
|
|
|
if(hr != S_OK) return hr;
|
|
|
|
if(IsEqualIID(riid, &IID_IMimeBody))
|
|
{
|
|
IMimeBody_AddRef(&body->mime_body->IMimeBody_iface);
|
|
*ppvObject = &body->mime_body->IMimeBody_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SaveBody(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
DWORD dwFlags,
|
|
IStream *pStream)
|
|
{
|
|
FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out)
|
|
{
|
|
body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry);
|
|
body_t *body;
|
|
HRESULT hr;
|
|
struct list *list;
|
|
|
|
if(location == IBL_ROOT)
|
|
{
|
|
*out = root;
|
|
return S_OK;
|
|
}
|
|
|
|
hr = find_body(&msg->body_tree, pivot, &body);
|
|
|
|
if(hr == S_OK)
|
|
{
|
|
switch(location)
|
|
{
|
|
case IBL_PARENT:
|
|
*out = body->parent;
|
|
break;
|
|
|
|
case IBL_FIRST:
|
|
list = list_head(&body->children);
|
|
if(list)
|
|
*out = LIST_ENTRY(list, body_t, entry);
|
|
else
|
|
hr = MIME_E_NOT_FOUND;
|
|
break;
|
|
|
|
case IBL_LAST:
|
|
list = list_tail(&body->children);
|
|
if(list)
|
|
*out = LIST_ENTRY(list, body_t, entry);
|
|
else
|
|
hr = MIME_E_NOT_FOUND;
|
|
break;
|
|
|
|
case IBL_NEXT:
|
|
list = list_next(&body->parent->children, &body->entry);
|
|
if(list)
|
|
*out = LIST_ENTRY(list, body_t, entry);
|
|
else
|
|
hr = MIME_E_NOT_FOUND;
|
|
break;
|
|
|
|
case IBL_PREVIOUS:
|
|
list = list_prev(&body->parent->children, &body->entry);
|
|
if(list)
|
|
*out = LIST_ENTRY(list, body_t, entry);
|
|
else
|
|
hr = MIME_E_NOT_FOUND;
|
|
break;
|
|
|
|
default:
|
|
hr = E_FAIL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI MimeMessage_InsertBody(
|
|
IMimeMessage *iface,
|
|
BODYLOCATION location,
|
|
HBODY hPivot,
|
|
LPHBODY phBody)
|
|
{
|
|
FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot,
|
|
HBODY *phBody)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
body_t *body;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody);
|
|
|
|
hr = get_body(This, location, hPivot, &body);
|
|
|
|
if(hr == S_OK) *phBody = UlongToHandle(body->index);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_DeleteBody(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_MoveBody(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
BODYLOCATION location)
|
|
{
|
|
FIXME("(%p)->(%d)\n", iface, location);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static void count_children(body_t *body, boolean recurse, ULONG *count)
|
|
{
|
|
body_t *child;
|
|
|
|
LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry)
|
|
{
|
|
(*count)++;
|
|
if(recurse) count_children(child, recurse, count);
|
|
}
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse,
|
|
ULONG *pcBodies)
|
|
{
|
|
HRESULT hr;
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
body_t *body;
|
|
|
|
TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies);
|
|
|
|
hr = find_body(&This->body_tree, hParent, &body);
|
|
if(hr != S_OK) return hr;
|
|
|
|
*pcBodies = 1;
|
|
count_children(body, fRecurse, pcBodies);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out)
|
|
{
|
|
struct list *ptr;
|
|
HBODY next;
|
|
|
|
for (;;)
|
|
{
|
|
if (!body) ptr = list_head( &This->body_tree );
|
|
else
|
|
{
|
|
ptr = list_head( &body->children );
|
|
while (!ptr)
|
|
{
|
|
if (!body->parent) return MIME_E_NOT_FOUND;
|
|
if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent;
|
|
}
|
|
}
|
|
|
|
body = LIST_ENTRY( ptr, body_t, entry );
|
|
next = UlongToHandle( body->index );
|
|
find->dwReserved = body->index;
|
|
if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType,
|
|
find->pszSubType) == S_OK)
|
|
{
|
|
*out = next;
|
|
return S_OK;
|
|
}
|
|
}
|
|
return MIME_E_NOT_FOUND;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
|
|
TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
|
|
|
|
pFindBody->dwReserved = 0;
|
|
return find_next(This, NULL, pFindBody, phBody);
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody)
|
|
{
|
|
MimeMessage *This = impl_from_IMimeMessage(iface);
|
|
body_t *body;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody);
|
|
|
|
hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body );
|
|
if (hr != S_OK) return MIME_E_NOT_FOUND;
|
|
return find_next(This, body, pFindBody, phBody);
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_ResolveURL(
|
|
IMimeMessage *iface,
|
|
HBODY hRelated,
|
|
LPCSTR pszBase,
|
|
LPCSTR pszURL,
|
|
DWORD dwFlags,
|
|
LPHBODY phBody)
|
|
{
|
|
FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_ToMultipart(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPCSTR pszSubType,
|
|
LPHBODY phMultipart)
|
|
{
|
|
FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetBodyOffsets(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPBODYOFFSETS pOffsets)
|
|
{
|
|
FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetCharset(
|
|
IMimeMessage *iface,
|
|
LPHCHARSET phCharset)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, phCharset);
|
|
*phCharset = NULL;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SetCharset(
|
|
IMimeMessage *iface,
|
|
HCHARSET hCharset,
|
|
CSETAPPLYTYPE applytype)
|
|
{
|
|
FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_IsBodyType(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
IMSGBODYTYPE bodytype)
|
|
{
|
|
HRESULT hr;
|
|
IMimeBody *mime_body;
|
|
TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype);
|
|
|
|
hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
|
|
if(hr != S_OK) return hr;
|
|
|
|
hr = IMimeBody_IsType(mime_body, bodytype);
|
|
MimeBody_Release(mime_body);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_IsContentType(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPCSTR pszPriType,
|
|
LPCSTR pszSubType)
|
|
{
|
|
HRESULT hr;
|
|
IMimeBody *mime_body;
|
|
TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType),
|
|
debugstr_a(pszSubType));
|
|
|
|
hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
|
|
if(FAILED(hr)) return hr;
|
|
|
|
hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType);
|
|
IMimeBody_Release(mime_body);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_QueryBodyProp(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPCSTR pszName,
|
|
LPCSTR pszCriteria,
|
|
boolean fSubString,
|
|
boolean fCaseSensitive)
|
|
{
|
|
FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetBodyProp(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
HRESULT hr;
|
|
IMimeBody *mime_body;
|
|
|
|
TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
|
|
|
|
hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body);
|
|
if(hr != S_OK) return hr;
|
|
|
|
hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue);
|
|
IMimeBody_Release(mime_body);
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SetBodyProp(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPCPROPVARIANT pValue)
|
|
{
|
|
FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_DeleteBodyProp(
|
|
IMimeMessage *iface,
|
|
HBODY hBody,
|
|
LPCSTR pszName)
|
|
{
|
|
FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SetOption(
|
|
IMimeMessage *iface,
|
|
const TYPEDID oid,
|
|
LPCPROPVARIANT pValue)
|
|
{
|
|
HRESULT hr = E_NOTIMPL;
|
|
TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue);
|
|
|
|
if(pValue->vt != TYPEDID_TYPE(oid))
|
|
{
|
|
WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
switch(oid)
|
|
{
|
|
case OID_HIDE_TNEF_ATTACHMENTS:
|
|
FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal);
|
|
hr = S_OK;
|
|
break;
|
|
case OID_SHOW_MACBINARY:
|
|
FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal);
|
|
hr = S_OK;
|
|
break;
|
|
default:
|
|
FIXME("Unhandled oid %08x\n", oid);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetOption(
|
|
IMimeMessage *iface,
|
|
const TYPEDID oid,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
/*** IMimeMessage methods ***/
|
|
static HRESULT WINAPI MimeMessage_CreateWebPage(
|
|
IMimeMessage *iface,
|
|
IStream *pRootStm,
|
|
LPWEBPAGEOPTIONS pOptions,
|
|
IMimeMessageCallback *pCallback,
|
|
IMoniker **ppMoniker)
|
|
{
|
|
FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker);
|
|
*ppMoniker = NULL;
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetProp(
|
|
IMimeMessage *iface,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SetProp(
|
|
IMimeMessage *iface,
|
|
LPCSTR pszName,
|
|
DWORD dwFlags,
|
|
LPCPROPVARIANT pValue)
|
|
{
|
|
FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_DeleteProp(
|
|
IMimeMessage *iface,
|
|
LPCSTR pszName)
|
|
{
|
|
FIXME("(%p)->(%s)\n", iface, pszName);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_QueryProp(
|
|
IMimeMessage *iface,
|
|
LPCSTR pszName,
|
|
LPCSTR pszCriteria,
|
|
boolean fSubString,
|
|
boolean fCaseSensitive)
|
|
{
|
|
FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetTextBody(
|
|
IMimeMessage *iface,
|
|
DWORD dwTxtType,
|
|
ENCODINGTYPE ietEncoding,
|
|
IStream **pStream,
|
|
LPHBODY phBody)
|
|
{
|
|
HRESULT hr;
|
|
HBODY hbody;
|
|
FINDBODY find_struct;
|
|
IMimeBody *mime_body;
|
|
static char text[] = "text";
|
|
static char plain[] = "plain";
|
|
static char html[] = "html";
|
|
|
|
TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody);
|
|
|
|
find_struct.pszPriType = text;
|
|
|
|
switch(dwTxtType)
|
|
{
|
|
case TXT_PLAIN:
|
|
find_struct.pszSubType = plain;
|
|
break;
|
|
case TXT_HTML:
|
|
find_struct.pszSubType = html;
|
|
break;
|
|
default:
|
|
return MIME_E_INVALID_TEXT_TYPE;
|
|
}
|
|
|
|
hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
|
|
if(hr != S_OK)
|
|
{
|
|
TRACE("not found hr %08x\n", hr);
|
|
*phBody = NULL;
|
|
return hr;
|
|
}
|
|
|
|
IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body);
|
|
|
|
IMimeBody_GetData(mime_body, ietEncoding, pStream);
|
|
*phBody = hbody;
|
|
IMimeBody_Release(mime_body);
|
|
return hr;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SetTextBody(
|
|
IMimeMessage *iface,
|
|
DWORD dwTxtType,
|
|
ENCODINGTYPE ietEncoding,
|
|
HBODY hAlternative,
|
|
IStream *pStream,
|
|
LPHBODY phBody)
|
|
{
|
|
FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_AttachObject(
|
|
IMimeMessage *iface,
|
|
REFIID riid,
|
|
void *pvObject,
|
|
LPHBODY phBody)
|
|
{
|
|
FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_AttachFile(
|
|
IMimeMessage *iface,
|
|
LPCSTR pszFilePath,
|
|
IStream *pstmFile,
|
|
LPHBODY phBody)
|
|
{
|
|
FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_AttachURL(
|
|
IMimeMessage *iface,
|
|
LPCSTR pszBase,
|
|
LPCSTR pszURL,
|
|
DWORD dwFlags,
|
|
IStream *pstmURL,
|
|
LPSTR *ppszCIDURL,
|
|
LPHBODY phBody)
|
|
{
|
|
FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetAttachments(
|
|
IMimeMessage *iface,
|
|
ULONG *pcAttach,
|
|
LPHBODY *pprghAttach)
|
|
{
|
|
HRESULT hr;
|
|
FINDBODY find_struct;
|
|
HBODY hbody;
|
|
LPHBODY array;
|
|
ULONG size = 10;
|
|
|
|
TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach);
|
|
|
|
*pcAttach = 0;
|
|
array = CoTaskMemAlloc(size * sizeof(HBODY));
|
|
|
|
find_struct.pszPriType = find_struct.pszSubType = NULL;
|
|
hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody);
|
|
while(hr == S_OK)
|
|
{
|
|
hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL);
|
|
TRACE("IsCT rets %08x %d\n", hr, *pcAttach);
|
|
if(hr != S_OK)
|
|
{
|
|
if(*pcAttach + 1 > size)
|
|
{
|
|
size *= 2;
|
|
array = CoTaskMemRealloc(array, size * sizeof(HBODY));
|
|
}
|
|
array[*pcAttach] = hbody;
|
|
(*pcAttach)++;
|
|
}
|
|
hr = IMimeMessage_FindNext(iface, &find_struct, &hbody);
|
|
}
|
|
|
|
*pprghAttach = array;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetAddressTable(
|
|
IMimeMessage *iface,
|
|
IMimeAddressTable **ppTable)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, ppTable);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetSender(
|
|
IMimeMessage *iface,
|
|
LPADDRESSPROPS pAddress)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, pAddress);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetAddressTypes(
|
|
IMimeMessage *iface,
|
|
DWORD dwAdrTypes,
|
|
DWORD dwProps,
|
|
LPADDRESSLIST pList)
|
|
{
|
|
FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetAddressFormat(
|
|
IMimeMessage *iface,
|
|
DWORD dwAdrTypes,
|
|
ADDRESSFORMAT format,
|
|
LPSTR *ppszFormat)
|
|
{
|
|
FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_EnumAddressTypes(
|
|
IMimeMessage *iface,
|
|
DWORD dwAdrTypes,
|
|
DWORD dwProps,
|
|
IMimeEnumAddressTypes **ppEnum)
|
|
{
|
|
FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_SplitMessage(
|
|
IMimeMessage *iface,
|
|
ULONG cbMaxPart,
|
|
IMimeMessageParts **ppParts)
|
|
{
|
|
FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeMessage_GetRootMoniker(
|
|
IMimeMessage *iface,
|
|
IMoniker **ppMoniker)
|
|
{
|
|
FIXME("(%p)->(%p)\n", iface, ppMoniker);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static const IMimeMessageVtbl MimeMessageVtbl =
|
|
{
|
|
MimeMessage_QueryInterface,
|
|
MimeMessage_AddRef,
|
|
MimeMessage_Release,
|
|
MimeMessage_GetClassID,
|
|
MimeMessage_IsDirty,
|
|
MimeMessage_Load,
|
|
MimeMessage_Save,
|
|
MimeMessage_GetSizeMax,
|
|
MimeMessage_InitNew,
|
|
MimeMessage_GetMessageSource,
|
|
MimeMessage_GetMessageSize,
|
|
MimeMessage_LoadOffsetTable,
|
|
MimeMessage_SaveOffsetTable,
|
|
MimeMessage_GetFlags,
|
|
MimeMessage_Commit,
|
|
MimeMessage_HandsOffStorage,
|
|
MimeMessage_BindToObject,
|
|
MimeMessage_SaveBody,
|
|
MimeMessage_InsertBody,
|
|
MimeMessage_GetBody,
|
|
MimeMessage_DeleteBody,
|
|
MimeMessage_MoveBody,
|
|
MimeMessage_CountBodies,
|
|
MimeMessage_FindFirst,
|
|
MimeMessage_FindNext,
|
|
MimeMessage_ResolveURL,
|
|
MimeMessage_ToMultipart,
|
|
MimeMessage_GetBodyOffsets,
|
|
MimeMessage_GetCharset,
|
|
MimeMessage_SetCharset,
|
|
MimeMessage_IsBodyType,
|
|
MimeMessage_IsContentType,
|
|
MimeMessage_QueryBodyProp,
|
|
MimeMessage_GetBodyProp,
|
|
MimeMessage_SetBodyProp,
|
|
MimeMessage_DeleteBodyProp,
|
|
MimeMessage_SetOption,
|
|
MimeMessage_GetOption,
|
|
MimeMessage_CreateWebPage,
|
|
MimeMessage_GetProp,
|
|
MimeMessage_SetProp,
|
|
MimeMessage_DeleteProp,
|
|
MimeMessage_QueryProp,
|
|
MimeMessage_GetTextBody,
|
|
MimeMessage_SetTextBody,
|
|
MimeMessage_AttachObject,
|
|
MimeMessage_AttachFile,
|
|
MimeMessage_AttachURL,
|
|
MimeMessage_GetAttachments,
|
|
MimeMessage_GetAddressTable,
|
|
MimeMessage_GetSender,
|
|
MimeMessage_GetAddressTypes,
|
|
MimeMessage_GetAddressFormat,
|
|
MimeMessage_EnumAddressTypes,
|
|
MimeMessage_SplitMessage,
|
|
MimeMessage_GetRootMoniker,
|
|
};
|
|
|
|
HRESULT MimeMessage_create(IUnknown *outer, void **obj)
|
|
{
|
|
MimeMessage *This;
|
|
MimeBody *mime_body;
|
|
body_t *root_body;
|
|
|
|
TRACE("(%p, %p)\n", outer, obj);
|
|
|
|
if (outer)
|
|
{
|
|
FIXME("outer unknown not supported yet\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
*obj = NULL;
|
|
|
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl;
|
|
This->ref = 1;
|
|
This->stream = NULL;
|
|
list_init(&This->body_tree);
|
|
This->next_index = 1;
|
|
|
|
mime_body = mimebody_create();
|
|
root_body = new_body_entry(mime_body, This->next_index++, NULL);
|
|
list_add_head(&This->body_tree, &root_body->entry);
|
|
|
|
*obj = &This->IMimeMessage_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MimeOleCreateMessage (INETCOMM.@)
|
|
*/
|
|
HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage)
|
|
{
|
|
TRACE("(%p, %p)\n", pUnkOuter, ppMessage);
|
|
return MimeMessage_create(NULL, (void **)ppMessage);
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MimeOleSetCompatMode (INETCOMM.@)
|
|
*/
|
|
HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode)
|
|
{
|
|
FIXME("(0x%x)\n", dwMode);
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MimeOleCreateVirtualStream (INETCOMM.@)
|
|
*/
|
|
HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream)
|
|
{
|
|
HRESULT hr;
|
|
FIXME("(%p)\n", ppStream);
|
|
|
|
hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream);
|
|
return hr;
|
|
}
|
|
|
|
typedef struct MimeSecurity
|
|
{
|
|
IMimeSecurity IMimeSecurity_iface;
|
|
LONG ref;
|
|
} MimeSecurity;
|
|
|
|
static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface)
|
|
{
|
|
return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface);
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv)
|
|
{
|
|
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IMimeSecurity))
|
|
{
|
|
*ppv = iface;
|
|
IMimeSecurity_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
FIXME("no interface for %s\n", debugstr_guid(riid));
|
|
*ppv = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface)
|
|
{
|
|
MimeSecurity *This = impl_from_IMimeSecurity(iface);
|
|
LONG ref = InterlockedIncrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface)
|
|
{
|
|
MimeSecurity *This = impl_from_IMimeSecurity(iface);
|
|
LONG ref = InterlockedDecrement(&This->ref);
|
|
|
|
TRACE("(%p) ref=%d\n", This, ref);
|
|
|
|
if (!ref)
|
|
HeapFree(GetProcessHeap(), 0, This);
|
|
|
|
return ref;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_InitNew(
|
|
IMimeSecurity* iface)
|
|
{
|
|
FIXME("(%p)->(): stub\n", iface);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_CheckInit(
|
|
IMimeSecurity* iface)
|
|
{
|
|
FIXME("(%p)->(): stub\n", iface);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_EncodeMessage(
|
|
IMimeSecurity* iface,
|
|
IMimeMessageTree* pTree,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_EncodeBody(
|
|
IMimeSecurity* iface,
|
|
IMimeMessageTree* pTree,
|
|
HBODY hEncodeRoot,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_DecodeMessage(
|
|
IMimeSecurity* iface,
|
|
IMimeMessageTree* pTree,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_DecodeBody(
|
|
IMimeSecurity* iface,
|
|
IMimeMessageTree* pTree,
|
|
HBODY hDecodeRoot,
|
|
DWORD dwFlags)
|
|
{
|
|
FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_EnumCertificates(
|
|
IMimeSecurity* iface,
|
|
HCAPICERTSTORE hc,
|
|
DWORD dwUsage,
|
|
PCX509CERT pPrev,
|
|
PCX509CERT* ppCert)
|
|
{
|
|
FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_GetCertificateName(
|
|
IMimeSecurity* iface,
|
|
const PCX509CERT pX509Cert,
|
|
const CERTNAMETYPE cn,
|
|
LPSTR* ppszName)
|
|
{
|
|
FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_GetMessageType(
|
|
IMimeSecurity* iface,
|
|
const HWND hwndParent,
|
|
IMimeBody* pBody,
|
|
DWORD* pdwSecType)
|
|
{
|
|
FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeSecurity_GetCertData(
|
|
IMimeSecurity* iface,
|
|
const PCX509CERT pX509Cert,
|
|
const CERTDATAID dataid,
|
|
LPPROPVARIANT pValue)
|
|
{
|
|
FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue);
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static const IMimeSecurityVtbl MimeSecurityVtbl =
|
|
{
|
|
MimeSecurity_QueryInterface,
|
|
MimeSecurity_AddRef,
|
|
MimeSecurity_Release,
|
|
MimeSecurity_InitNew,
|
|
MimeSecurity_CheckInit,
|
|
MimeSecurity_EncodeMessage,
|
|
MimeSecurity_EncodeBody,
|
|
MimeSecurity_DecodeMessage,
|
|
MimeSecurity_DecodeBody,
|
|
MimeSecurity_EnumCertificates,
|
|
MimeSecurity_GetCertificateName,
|
|
MimeSecurity_GetMessageType,
|
|
MimeSecurity_GetCertData
|
|
};
|
|
|
|
HRESULT MimeSecurity_create(IUnknown *outer, void **obj)
|
|
{
|
|
MimeSecurity *This;
|
|
|
|
*obj = NULL;
|
|
|
|
if (outer) return CLASS_E_NOAGGREGATION;
|
|
|
|
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
|
|
if (!This) return E_OUTOFMEMORY;
|
|
|
|
This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl;
|
|
This->ref = 1;
|
|
|
|
*obj = &This->IMimeSecurity_iface;
|
|
return S_OK;
|
|
}
|
|
|
|
/***********************************************************************
|
|
* MimeOleCreateSecurity (INETCOMM.@)
|
|
*/
|
|
HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity)
|
|
{
|
|
return MimeSecurity_create(NULL, (void **)ppSecurity);
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_QueryInterface(
|
|
IMimeAllocator* iface,
|
|
REFIID riid,
|
|
void **obj)
|
|
{
|
|
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj);
|
|
|
|
if (IsEqualIID(riid, &IID_IUnknown) ||
|
|
IsEqualIID(riid, &IID_IMalloc) ||
|
|
IsEqualIID(riid, &IID_IMimeAllocator))
|
|
{
|
|
*obj = iface;
|
|
IMimeAllocator_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
|
|
FIXME("no interface for %s\n", debugstr_guid(riid));
|
|
*obj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
static ULONG WINAPI MimeAlloc_AddRef(
|
|
IMimeAllocator* iface)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
static ULONG WINAPI MimeAlloc_Release(
|
|
IMimeAllocator* iface)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
static LPVOID WINAPI MimeAlloc_Alloc(
|
|
IMimeAllocator* iface,
|
|
SIZE_T cb)
|
|
{
|
|
return CoTaskMemAlloc(cb);
|
|
}
|
|
|
|
static LPVOID WINAPI MimeAlloc_Realloc(
|
|
IMimeAllocator* iface,
|
|
LPVOID pv,
|
|
SIZE_T cb)
|
|
{
|
|
return CoTaskMemRealloc(pv, cb);
|
|
}
|
|
|
|
static void WINAPI MimeAlloc_Free(
|
|
IMimeAllocator* iface,
|
|
LPVOID pv)
|
|
{
|
|
CoTaskMemFree(pv);
|
|
}
|
|
|
|
static SIZE_T WINAPI MimeAlloc_GetSize(
|
|
IMimeAllocator* iface,
|
|
LPVOID pv)
|
|
{
|
|
FIXME("stub\n");
|
|
return 0;
|
|
}
|
|
|
|
static int WINAPI MimeAlloc_DidAlloc(
|
|
IMimeAllocator* iface,
|
|
LPVOID pv)
|
|
{
|
|
FIXME("stub\n");
|
|
return 0;
|
|
}
|
|
|
|
static void WINAPI MimeAlloc_HeapMinimize(
|
|
IMimeAllocator* iface)
|
|
{
|
|
FIXME("stub\n");
|
|
return;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_FreeParamInfoArray(
|
|
IMimeAllocator* iface,
|
|
ULONG cParams,
|
|
LPMIMEPARAMINFO prgParam,
|
|
boolean fFreeArray)
|
|
{
|
|
ULONG i;
|
|
TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray);
|
|
|
|
for(i = 0; i < cParams; i++)
|
|
{
|
|
IMimeAllocator_Free(iface, prgParam[i].pszName);
|
|
IMimeAllocator_Free(iface, prgParam[i].pszData);
|
|
}
|
|
if(fFreeArray) IMimeAllocator_Free(iface, prgParam);
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_FreeAddressList(
|
|
IMimeAllocator* iface,
|
|
LPADDRESSLIST pList)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_FreeAddressProps(
|
|
IMimeAllocator* iface,
|
|
LPADDRESSPROPS pAddress)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_ReleaseObjects(
|
|
IMimeAllocator* iface,
|
|
ULONG cObjects,
|
|
IUnknown **prgpUnknown,
|
|
boolean fFreeArray)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray(
|
|
IMimeAllocator* iface,
|
|
ULONG cRows,
|
|
LPENUMHEADERROW prgRow,
|
|
boolean fFreeArray)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray(
|
|
IMimeAllocator* iface,
|
|
ULONG cProps,
|
|
LPENUMPROPERTY prgProp,
|
|
boolean fFreeArray)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static HRESULT WINAPI MimeAlloc_FreeThumbprint(
|
|
IMimeAllocator* iface,
|
|
THUMBBLOB *pthumbprint)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
static HRESULT WINAPI MimeAlloc_PropVariantClear(
|
|
IMimeAllocator* iface,
|
|
LPPROPVARIANT pProp)
|
|
{
|
|
FIXME("stub\n");
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
static IMimeAllocatorVtbl mime_alloc_vtbl =
|
|
{
|
|
MimeAlloc_QueryInterface,
|
|
MimeAlloc_AddRef,
|
|
MimeAlloc_Release,
|
|
MimeAlloc_Alloc,
|
|
MimeAlloc_Realloc,
|
|
MimeAlloc_Free,
|
|
MimeAlloc_GetSize,
|
|
MimeAlloc_DidAlloc,
|
|
MimeAlloc_HeapMinimize,
|
|
MimeAlloc_FreeParamInfoArray,
|
|
MimeAlloc_FreeAddressList,
|
|
MimeAlloc_FreeAddressProps,
|
|
MimeAlloc_ReleaseObjects,
|
|
MimeAlloc_FreeEnumHeaderRowArray,
|
|
MimeAlloc_FreeEnumPropertyArray,
|
|
MimeAlloc_FreeThumbprint,
|
|
MimeAlloc_PropVariantClear
|
|
};
|
|
|
|
static IMimeAllocator mime_allocator =
|
|
{
|
|
&mime_alloc_vtbl
|
|
};
|
|
|
|
HRESULT MimeAllocator_create(IUnknown *outer, void **obj)
|
|
{
|
|
if(outer) return CLASS_E_NOAGGREGATION;
|
|
|
|
*obj = &mime_allocator;
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc)
|
|
{
|
|
return MimeAllocator_create(NULL, (void**)alloc);
|
|
}
|
|
|
|
HRESULT VirtualStream_create(IUnknown *outer, void **obj)
|
|
{
|
|
FIXME("(%p, %p)\n", outer, obj);
|
|
|
|
*obj = NULL;
|
|
if (outer) return CLASS_E_NOAGGREGATION;
|
|
|
|
return MimeOleCreateVirtualStream((IStream **)obj);
|
|
}
|
|
|
|
HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema)
|
|
{
|
|
FIXME("(%p) stub\n", schema);
|
|
return E_NOTIMPL;
|
|
}
|