Commit bb5056ea authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

inetcomm: Moved sub_stream_t implementation before MimeBody implementation.

parent a8ab3107
......@@ -166,1550 +166,1547 @@ typedef struct MimeBody
BODYOFFSETS body_offsets;
} MimeBody;
static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
{
return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
}
typedef struct propschema
typedef struct
{
IMimePropertySchema IMimePropertySchema_iface;
IStream IStream_iface;
LONG ref;
} propschema;
IStream *base;
ULARGE_INTEGER pos, start, length;
} sub_stream_t;
static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
static inline sub_stream_t *impl_from_IStream(IStream *iface)
{
return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
}
static LPSTR strdupA(LPCSTR str)
static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
{
char *ret;
int len = strlen(str);
ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
memcpy(ret, str, len + 1);
return ret;
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;
}
#define PARSER_BUF_SIZE 1024
static ULONG WINAPI sub_stream_AddRef(IStream *iface)
{
sub_stream_t *This = impl_from_IStream(iface);
LONG ref = InterlockedIncrement(&This->ref);
/*****************************************************
* 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)
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static ULONG WINAPI sub_stream_Release(IStream *iface)
{
char *buf = NULL;
DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
HRESULT hr;
BOOL done = FALSE;
sub_stream_t *This = impl_from_IStream(iface);
LONG ref = InterlockedDecrement(&This->ref);
*ptr = NULL;
TRACE("(%p) ref=%d\n", This, ref);
do
if(!ref)
{
char *end;
DWORD read;
IStream_Release(This->base);
HeapFree(GetProcessHeap(), 0, This);
}
return ref;
}
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;
}
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;
hr = IStream_Read(stm, buf + offset, size - offset, &read);
if(FAILED(hr)) goto fail;
TRACE("(%p, %d, %p)\n", pv, cb, pcbRead);
offset += read;
buf[offset] = '\0';
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(read == 0) done = TRUE;
if(This->pos.QuadPart + cb > This->length.QuadPart)
cb = This->length.QuadPart - This->pos.QuadPart;
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);
hr = IStream_Read(This->base, pv, cb, pcbRead);
*ptr = buf;
return S_OK;
This->pos.QuadPart += *pcbRead;
tmp_pos.QuadPart = base_pos.QuadPart;
IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL);
fail:
HeapFree(GetProcessHeap(), 0, buf);
return hr;
}
static header_t *read_prop(MimeBody *body, char **ptr)
static HRESULT WINAPI sub_stream_Write(
IStream* iface,
const void *pv,
ULONG cb,
ULONG *pcbWritten)
{
char *colon = strchr(*ptr, ':');
const property_t *prop;
header_t *ret;
FIXME("stub\n");
return E_NOTIMPL;
}
if(!colon) return NULL;
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;
*colon = '\0';
TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
for(prop = default_props; prop->name; prop++)
switch(dwOrigin)
{
if(!lstrcmpiA(*ptr, prop->name))
{
TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
break;
}
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(!prop->name)
{
property_list_entry_t *prop_entry;
LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
{
if(!lstrcmpiA(*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);
}
}
if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
ret->prop = prop;
PropVariantInit(&ret->value);
list_init(&ret->params);
*ptr = colon + 1;
This->pos.QuadPart = new_pos.QuadPart;
return ret;
if(plibNewPosition) *plibNewPosition = This->pos;
return S_OK;
}
static void unfold_header(char *header, int len)
static HRESULT WINAPI sub_stream_SetSize(
IStream* iface,
ULARGE_INTEGER libNewSize)
{
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';
FIXME("stub\n");
return E_NOTIMPL;
}
static char *unquote_string(const char *str)
static HRESULT WINAPI sub_stream_CopyTo(
IStream* iface,
IStream *pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten)
{
BOOL quoted = FALSE;
char *ret, *cp;
HRESULT hr = S_OK;
BYTE tmpBuffer[128];
ULONG bytesRead, bytesWritten, copySize;
ULARGE_INTEGER totalBytesRead;
ULARGE_INTEGER totalBytesWritten;
while(*str == ' ' || *str == '\t') str++;
TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
if(*str == '"')
totalBytesRead.QuadPart = 0;
totalBytesWritten.QuadPart = 0;
while ( cb.QuadPart > 0 )
{
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;
}
if ( cb.QuadPart >= sizeof(tmpBuffer) )
copySize = sizeof(tmpBuffer);
else
copySize = cb.u.LowPart;
static void add_param(header_t *header, const char *p)
{
const char *key = p, *value, *cp = p;
param_t *param;
char *name;
hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
if (FAILED(hr)) break;
TRACE("got param %s\n", p);
totalBytesRead.QuadPart += bytesRead;
while (*key == ' ' || *key == '\t' ) key++;
if (bytesRead)
{
hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
if (FAILED(hr)) break;
totalBytesWritten.QuadPart += bytesWritten;
}
cp = strchr(key, '=');
if(!cp)
{
WARN("malformed parameter - skipping\n");
return;
if (bytesRead != copySize)
cb.QuadPart = 0;
else
cb.QuadPart -= bytesRead;
}
name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
memcpy(name, key, cp - key);
name[cp - key] = '\0';
value = cp + 1;
if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
param->name = name;
param->value = unquote_string(value);
list_add_tail(&header->params, &param->entry);
return hr;
}
static void split_params(header_t *header, char *value)
static HRESULT WINAPI sub_stream_Commit(
IStream* iface,
DWORD grfCommitFlags)
{
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);
FIXME("stub\n");
return E_NOTIMPL;
}
static void read_value(header_t *header, char **cur)
static HRESULT WINAPI sub_stream_Revert(
IStream* iface)
{
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;
FIXME("stub\n");
return E_NOTIMPL;
}
*cur = end;
static HRESULT WINAPI sub_stream_LockRegion(
IStream* iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
FIXME("stub\n");
return E_NOTIMPL;
}
static void init_content_type(MimeBody *body, header_t *header)
static HRESULT WINAPI sub_stream_UnlockRegion(
IStream* iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
{
char *slash;
DWORD len;
FIXME("stub\n");
return E_NOTIMPL;
}
if(header->prop->id != PID_HDR_CNTTYPE)
{
ERR("called with header %s\n", header->prop->name);
return;
}
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;
}
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 WINAPI sub_stream_Clone(
IStream* iface,
IStream **ppstm)
{
FIXME("stub\n");
return E_NOTIMPL;
}
static HRESULT parse_headers(MimeBody *body, IStream *stm)
static struct IStreamVtbl sub_stream_vtbl =
{
char *header_buf, *cur_header_ptr;
HRESULT hr;
header_t *header;
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
};
hr = copy_headers_to_buf(stm, &header_buf);
if(FAILED(hr)) return hr;
static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
{
sub_stream_t *This;
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);
*out = NULL;
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
if(!This) return E_OUTOFMEMORY;
if(header->prop->id == PID_HDR_CNTTYPE)
init_content_type(body, header);
}
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;
HeapFree(GetProcessHeap(), 0, header_buf);
return hr;
*out = &This->IStream_iface;
return S_OK;
}
static void empty_param_list(struct list *list)
static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface)
{
param_t *param, *cursor2;
LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
{
list_remove(&param->entry);
HeapFree(GetProcessHeap(), 0, param->name);
HeapFree(GetProcessHeap(), 0, param->value);
HeapFree(GetProcessHeap(), 0, param);
}
return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface);
}
static void empty_header_list(struct list *list)
typedef struct propschema
{
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);
}
}
IMimePropertySchema IMimePropertySchema_iface;
LONG ref;
} propschema;
static void empty_new_prop_list(struct list *list)
static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface)
{
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);
}
return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface);
}
static void release_data(REFIID riid, void *data)
static LPSTR strdupA(LPCSTR str)
{
if(!data) return;
if(IsEqualIID(riid, &IID_IStream))
IStream_Release((IStream *)data);
else
FIXME("Unhandled data format %s\n", debugstr_guid(riid));
char *ret;
int len = strlen(str);
ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
memcpy(ret, str, len + 1);
return ret;
}
static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
#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)
{
header_t *header;
char *buf = NULL;
DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
HRESULT hr;
BOOL done = FALSE;
*prop = NULL;
*ptr = NULL;
LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
do
{
if(ISPIDSTR(name))
char *end;
DWORD read;
if(!buf)
buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
else
{
if(STRTOPID(name) == header->prop->id)
{
*prop = header;
return S_OK;
}
size *= 2;
buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
}
else if(!lstrcmpiA(name, header->prop->name))
if(!buf)
{
*prop = header;
return S_OK;
hr = E_OUTOFMEMORY;
goto fail;
}
}
return MIME_E_NOT_FOUND;
}
hr = IStream_Read(stm, buf + offset, size - offset, &read);
if(FAILED(hr)) goto fail;
static const property_t *find_default_prop(const char *name)
{
const property_t *prop_def = NULL;
offset += read;
buf[offset] = '\0';
for(prop_def = default_props; prop_def->name; prop_def++)
{
if(ISPIDSTR(name))
if(read == 0) done = TRUE;
while(!done && (end = strstr(buf + last_end, "\r\n")))
{
if(STRTOPID(name) == prop_def->id)
DWORD new_end = end - buf + 2;
if(new_end - last_end == 2)
{
break;
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;
}
else if(!lstrcmpiA(name, prop_def->name))
{
break;
}
}
} while(!done);
if(prop_def->id)
TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
else
prop_def = NULL;
*ptr = buf;
return S_OK;
return prop_def;
fail:
HeapFree(GetProcessHeap(), 0, buf);
return hr;
}
static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
REFIID riid,
void** ppvObject)
static header_t *read_prop(MimeBody *body, char **ptr)
{
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
char *colon = strchr(*ptr, ':');
const property_t *prop;
header_t *ret;
*ppvObject = NULL;
if(!colon) return NULL;
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IPersist) ||
IsEqualIID(riid, &IID_IPersistStreamInit) ||
IsEqualIID(riid, &IID_IMimePropertySet) ||
IsEqualIID(riid, &IID_IMimeBody))
*colon = '\0';
for(prop = default_props; prop->name; prop++)
{
*ppvObject = iface;
if(!lstrcmpiA(*ptr, prop->name))
{
TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
break;
}
}
if(*ppvObject)
if(!prop->name)
{
IUnknown_AddRef((IUnknown*)*ppvObject);
return S_OK;
property_list_entry_t *prop_entry;
LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
{
if(!lstrcmpiA(*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);
}
}
FIXME("no interface for %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
ret->prop = prop;
PropVariantInit(&ret->value);
list_init(&ret->params);
*ptr = colon + 1;
return ret;
}
static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
static void unfold_header(char *header, int len)
{
MimeBody *This = impl_from_IMimeBody(iface);
LONG ref = InterlockedIncrement(&This->ref);
char *start = header, *cp = header;
TRACE("(%p) ref=%d\n", This, ref);
do {
while(*cp == ' ' || *cp == '\t')
{
cp++;
len--;
}
if(cp != start)
memmove(start, cp, len + 1);
return ref;
cp = strstr(start, "\r\n");
len -= (cp - start);
start = cp;
*start = ' ';
start++;
len--;
cp += 2;
} while(*cp == ' ' || *cp == '\t');
*(start - 1) = '\0';
}
static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
static char *unquote_string(const char *str)
{
MimeBody *This = impl_from_IMimeBody(iface);
LONG ref = InterlockedDecrement(&This->ref);
BOOL quoted = FALSE;
char *ret, *cp;
TRACE("(%p) ref=%d\n", This, ref);
while(*str == ' ' || *str == '\t') str++;
if (!ref)
if(*str == '"')
{
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);
quoted = TRUE;
str++;
}
return ref;
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 HRESULT WINAPI MimeBody_GetClassID(
IMimeBody* iface,
CLSID* pClassID)
static void add_param(header_t *header, const char *p)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, pClassID);
return E_NOTIMPL;
}
const char *key = p, *value, *cp = p;
param_t *param;
char *name;
TRACE("got param %s\n", p);
static HRESULT WINAPI MimeBody_IsDirty(
IMimeBody* iface)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->() stub\n", This);
return E_NOTIMPL;
}
while (*key == ' ' || *key == '\t' ) key++;
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);
}
cp = strchr(key, '=');
if(!cp)
{
WARN("malformed parameter - skipping\n");
return;
}
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;
}
name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
memcpy(name, key, cp - key);
name[cp - key] = '\0';
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;
}
value = cp + 1;
static HRESULT WINAPI MimeBody_InitNew(
IMimeBody* iface)
{
MimeBody *This = impl_from_IMimeBody(iface);
TRACE("(%p)->()\n", This);
return S_OK;
param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
param->name = name;
param->value = unquote_string(value);
list_add_tail(&header->params, &param->entry);
}
static HRESULT WINAPI MimeBody_GetPropInfo(
IMimeBody* iface,
LPCSTR pszName,
LPMIMEPROPINFO pInfo)
static void split_params(header_t *header, char *value)
{
MimeBody *This = impl_from_IMimeBody(iface);
header_t *header;
HRESULT hr;
DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
if(!pszName || !pInfo)
return E_INVALIDARG;
TRACE("mask 0x%04x\n", pInfo->dwMask);
if(pInfo->dwMask & ~supported)
FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
char *cp = value, *start = value;
BOOL in_quotes = FALSE, done_value = FALSE;
hr = find_prop(This, pszName, &header);
if(hr == S_OK)
while(*cp)
{
if(pInfo->dwMask & PIM_CHARSET)
pInfo->hCharset = 0;
if(pInfo->dwMask & PIM_FLAGS)
pInfo->dwFlags = 0x00000000;
if(pInfo->dwMask & PIM_ROWNUMBER)
pInfo->dwRowNumber = 0;
if(pInfo->dwMask & PIM_ENCODINGTYPE)
pInfo->ietEncoding = 0;
if(pInfo->dwMask & PIM_VALUES)
pInfo->cValues = 0;
if(pInfo->dwMask & PIM_PROPID)
pInfo->dwPropId = header->prop->id;
if(pInfo->dwMask & PIM_VTDEFAULT)
pInfo->vtDefault = header->prop->default_vt;
if(pInfo->dwMask & PIM_VTCURRENT)
pInfo->vtCurrent = 0;
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++;
}
return hr;
if(done_value) add_param(header, start);
}
static HRESULT WINAPI MimeBody_SetPropInfo(
IMimeBody* iface,
LPCSTR pszName,
LPCMIMEPROPINFO pInfo)
static void read_value(header_t *header, char **cur)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
return E_NOTIMPL;
}
char *end = *cur, *value;
DWORD len;
static HRESULT WINAPI MimeBody_GetProp(
IMimeBody* iface,
LPCSTR pszName,
DWORD dwFlags,
LPPROPVARIANT pValue)
{
MimeBody *This = impl_from_IMimeBody(iface);
header_t *header;
HRESULT hr;
do {
end = strstr(end, "\r\n");
end += 2;
} while(*end == ' ' || *end == '\t');
TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
len = end - *cur;
value = HeapAlloc(GetProcessHeap(), 0, len + 1);
memcpy(value, *cur, len);
value[len] = '\0';
if(!pszName || !pValue)
return E_INVALIDARG;
unfold_header(value, len);
TRACE("value %s\n", debugstr_a(value));
if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
if(header->prop->flags & MPF_HASPARAMS)
{
PropVariantClear(pValue);
pValue->vt = VT_LPSTR;
pValue->u.pszVal = strdupA(This->content_pri_type);
return S_OK;
split_params(header, value);
TRACE("value w/o params %s\n", debugstr_a(value));
}
hr = find_prop(This, pszName, &header);
if(hr == S_OK)
{
TRACE("type %d->%d\n", header->value.vt, pValue->vt);
hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
if(FAILED(hr))
FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
}
header->value.vt = VT_LPSTR;
header->value.u.pszVal = value;
return hr;
*cur = end;
}
static HRESULT WINAPI MimeBody_SetProp(
IMimeBody* iface,
LPCSTR pszName,
DWORD dwFlags,
LPCPROPVARIANT pValue)
static void init_content_type(MimeBody *body, header_t *header)
{
MimeBody *This = impl_from_IMimeBody(iface);
header_t *header;
HRESULT hr;
TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
if(!pszName || !pValue)
return E_INVALIDARG;
char *slash;
DWORD len;
hr = find_prop(This, pszName, &header);
if(hr != S_OK)
if(header->prop->id != PID_HDR_CNTTYPE)
{
property_list_entry_t *prop_entry;
const property_t *prop = NULL;
LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
{
if(ISPIDSTR(pszName))
{
if(STRTOPID(pszName) == prop_entry->prop.id)
{
TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
prop = &prop_entry->prop;
break;
}
}
else if(!lstrcmpiA(pszName, prop_entry->prop.name))
{
TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
prop = &prop_entry->prop;
break;
}
}
header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
if(!header)
return E_OUTOFMEMORY;
if(!prop)
{
const property_t *prop_def = NULL;
prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
if(!prop_entry)
{
HeapFree(GetProcessHeap(), 0, header);
return E_OUTOFMEMORY;
}
prop_def = find_default_prop(pszName);
if(prop_def)
{
prop_entry->prop.name = strdupA(prop_def->name);
prop_entry->prop.id = prop_def->id;
}
else
{
if(ISPIDSTR(pszName))
{
HeapFree(GetProcessHeap(), 0, prop_entry);
HeapFree(GetProcessHeap(), 0, header);
return MIME_E_NOT_FOUND;
}
prop_entry->prop.name = strdupA(pszName);
prop_entry->prop.id = This->next_prop_id++;
}
prop_entry->prop.flags = 0;
prop_entry->prop.default_vt = pValue->vt;
list_add_tail(&This->new_props, &prop_entry->entry);
prop = &prop_entry->prop;
TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
}
header->prop = prop;
PropVariantInit(&header->value);
list_init(&header->params);
list_add_tail(&This->headers, &header->entry);
ERR("called with header %s\n", header->prop->name);
return;
}
PropVariantCopy(&header->value, pValue);
return S_OK;
}
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;
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 WINAPI MimeBody_DeleteProp(
IMimeBody* iface,
LPCSTR pszName)
static HRESULT parse_headers(MimeBody *body, IStream *stm)
{
MimeBody *This = impl_from_IMimeBody(iface);
header_t *cursor;
BOOL found;
char *header_buf, *cur_header_ptr;
HRESULT hr;
header_t *header;
TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
hr = copy_headers_to_buf(stm, &header_buf);
if(FAILED(hr)) return hr;
LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
cur_header_ptr = header_buf;
while((header = read_prop(body, &cur_header_ptr)))
{
if(ISPIDSTR(pszName))
found = STRTOPID(pszName) == cursor->prop->id;
else
found = !lstrcmpiA(pszName, cursor->prop->name);
read_value(header, &cur_header_ptr);
list_add_tail(&body->headers, &header->entry);
if(found)
{
list_remove(&cursor->entry);
HeapFree(GetProcessHeap(), 0, cursor);
return S_OK;
}
if(header->prop->id == PID_HDR_CNTTYPE)
init_content_type(body, header);
}
return MIME_E_NOT_FOUND;
HeapFree(GetProcessHeap(), 0, header_buf);
return hr;
}
static HRESULT WINAPI MimeBody_CopyProps(
IMimeBody* iface,
ULONG cNames,
LPCSTR* prgszName,
IMimePropertySet* pPropertySet)
static void empty_param_list(struct list *list)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
return E_NOTIMPL;
param_t *param, *cursor2;
LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
{
list_remove(&param->entry);
HeapFree(GetProcessHeap(), 0, param->name);
HeapFree(GetProcessHeap(), 0, param->value);
HeapFree(GetProcessHeap(), 0, param);
}
}
static HRESULT WINAPI MimeBody_MoveProps(
IMimeBody* iface,
ULONG cNames,
LPCSTR* prgszName,
IMimePropertySet* pPropertySet)
static void empty_header_list(struct list *list)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
return E_NOTIMPL;
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 HRESULT WINAPI MimeBody_DeleteExcept(
IMimeBody* iface,
ULONG cNames,
LPCSTR* prgszName)
static void empty_new_prop_list(struct list *list)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
return E_NOTIMPL;
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 HRESULT WINAPI MimeBody_QueryProp(
IMimeBody* iface,
LPCSTR pszName,
LPCSTR pszCriteria,
boolean fSubString,
boolean fCaseSensitive)
static void release_data(REFIID riid, void *data)
{
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;
if(!data) return;
if(IsEqualIID(riid, &IID_IStream))
IStream_Release((IStream *)data);
else
FIXME("Unhandled data format %s\n", debugstr_guid(riid));
}
static HRESULT WINAPI MimeBody_GetCharset(
IMimeBody* iface,
LPHCHARSET phCharset)
static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, phCharset);
*phCharset = NULL;
return S_OK;
header_t *header;
*prop = NULL;
LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
{
if(ISPIDSTR(name))
{
if(STRTOPID(name) == header->prop->id)
{
*prop = header;
return S_OK;
}
}
else if(!lstrcmpiA(name, header->prop->name))
{
*prop = header;
return S_OK;
}
}
return MIME_E_NOT_FOUND;
}
static HRESULT WINAPI MimeBody_SetCharset(
IMimeBody* iface,
HCHARSET hCharset,
CSETAPPLYTYPE applytype)
static const property_t *find_default_prop(const char *name)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
return E_NOTIMPL;
const property_t *prop_def = NULL;
for(prop_def = default_props; prop_def->name; prop_def++)
{
if(ISPIDSTR(name))
{
if(STRTOPID(name) == prop_def->id)
{
break;
}
}
else if(!lstrcmpiA(name, prop_def->name))
{
break;
}
}
if(prop_def->id)
TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id);
else
prop_def = NULL;
return prop_def;
}
static HRESULT WINAPI MimeBody_GetParameters(
IMimeBody* iface,
LPCSTR pszName,
ULONG* pcParams,
LPMIMEPARAMINFO* pprgParam)
static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
REFIID riid,
void** ppvObject)
{
MimeBody *This = impl_from_IMimeBody(iface);
HRESULT hr;
header_t *header;
TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
*pprgParam = NULL;
*pcParams = 0;
*ppvObject = NULL;
hr = find_prop(This, pszName, &header);
if(hr != S_OK) return hr;
if (IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_IPersist) ||
IsEqualIID(riid, &IID_IPersistStreamInit) ||
IsEqualIID(riid, &IID_IMimePropertySet) ||
IsEqualIID(riid, &IID_IMimeBody))
{
*ppvObject = iface;
}
*pcParams = list_count(&header->params);
if(*pcParams)
if(*ppvObject)
{
IMimeAllocator *alloc;
param_t *param;
MIMEPARAMINFO *info;
IUnknown_AddRef((IUnknown*)*ppvObject);
return S_OK;
}
MimeOleGetAllocator(&alloc);
FIXME("no interface for %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
*pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
{
int len;
static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface)
{
MimeBody *This = impl_from_IMimeBody(iface);
LONG ref = InterlockedIncrement(&This->ref);
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;
TRACE("(%p) ref=%d\n", This, ref);
return ref;
}
static HRESULT WINAPI MimeBody_IsContentType(
IMimeBody* iface,
LPCSTR pszPriType,
LPCSTR pszSubType)
static ULONG WINAPI MimeBody_Release(IMimeBody *iface)
{
MimeBody *This = impl_from_IMimeBody(iface);
LONG ref = InterlockedDecrement(&This->ref);
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(lstrcmpiA(pri, pszPriType)) return S_FALSE;
}
TRACE("(%p) ref=%d\n", This, ref);
if(pszSubType)
if (!ref)
{
const char *sub = This->content_sub_type;
if(!sub) sub = "plain";
if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
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 S_OK;
return ref;
}
static HRESULT WINAPI MimeBody_BindToObject(
IMimeBody* iface,
REFIID riid,
void** ppvObject)
static HRESULT WINAPI MimeBody_GetClassID(
IMimeBody* iface,
CLSID* pClassID)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
FIXME("(%p)->(%p) stub\n", This, pClassID);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_Clone(
IMimeBody* iface,
IMimePropertySet** ppPropertySet)
static HRESULT WINAPI MimeBody_IsDirty(
IMimeBody* iface)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
FIXME("(%p)->() stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_SetOption(
IMimeBody* iface,
const TYPEDID oid,
LPCPROPVARIANT pValue)
static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm)
{
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;
case OID_TRANSMIT_BODY_ENCODING:
FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
hr = S_OK;
break;
default:
FIXME("Unhandled oid %08x\n", oid);
}
return hr;
TRACE("(%p)->(%p)\n", This, pStm);
return parse_headers(This, pStm);
}
static HRESULT WINAPI MimeBody_GetOption(
IMimeBody* iface,
const TYPEDID oid,
LPPROPVARIANT pValue)
static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_EnumProps(
IMimeBody* iface,
DWORD dwFlags,
IMimeEnumProperties** ppEnum)
static HRESULT WINAPI MimeBody_GetSizeMax(
IMimeBody* iface,
ULARGE_INTEGER* pcbSize)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
FIXME("(%p)->(%p) stub\n", This, pcbSize);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_IsType(
IMimeBody* iface,
IMSGBODYTYPE bodytype)
static HRESULT WINAPI MimeBody_InitNew(
IMimeBody* iface)
{
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);
}
TRACE("(%p)->()\n", This);
return S_OK;
}
static HRESULT WINAPI MimeBody_SetDisplayName(
IMimeBody* iface,
LPCSTR pszDisplay)
static HRESULT WINAPI MimeBody_GetPropInfo(
IMimeBody* iface,
LPCSTR pszName,
LPMIMEPROPINFO pInfo)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
return E_NOTIMPL;
header_t *header;
HRESULT hr;
DWORD supported = PIM_PROPID | PIM_VTDEFAULT;
TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo);
if(!pszName || !pInfo)
return E_INVALIDARG;
TRACE("mask 0x%04x\n", pInfo->dwMask);
if(pInfo->dwMask & ~supported)
FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported);
hr = find_prop(This, pszName, &header);
if(hr == S_OK)
{
if(pInfo->dwMask & PIM_CHARSET)
pInfo->hCharset = 0;
if(pInfo->dwMask & PIM_FLAGS)
pInfo->dwFlags = 0x00000000;
if(pInfo->dwMask & PIM_ROWNUMBER)
pInfo->dwRowNumber = 0;
if(pInfo->dwMask & PIM_ENCODINGTYPE)
pInfo->ietEncoding = 0;
if(pInfo->dwMask & PIM_VALUES)
pInfo->cValues = 0;
if(pInfo->dwMask & PIM_PROPID)
pInfo->dwPropId = header->prop->id;
if(pInfo->dwMask & PIM_VTDEFAULT)
pInfo->vtDefault = header->prop->default_vt;
if(pInfo->dwMask & PIM_VTCURRENT)
pInfo->vtCurrent = 0;
}
return hr;
}
static HRESULT WINAPI MimeBody_GetDisplayName(
IMimeBody* iface,
LPSTR* ppszDisplay)
static HRESULT WINAPI MimeBody_SetPropInfo(
IMimeBody* iface,
LPCSTR pszName,
LPCMIMEPROPINFO pInfo)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_GetOffsets(
IMimeBody* iface,
LPBODYOFFSETS pOffsets)
static HRESULT WINAPI MimeBody_GetProp(
IMimeBody* iface,
LPCSTR pszName,
DWORD dwFlags,
LPPROPVARIANT pValue)
{
MimeBody *This = impl_from_IMimeBody(iface);
TRACE("(%p)->(%p)\n", This, pOffsets);
header_t *header;
HRESULT hr;
*pOffsets = This->body_offsets;
TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
return S_OK;
}
if(!pszName || !pValue)
return E_INVALIDARG;
static HRESULT WINAPI MimeBody_GetCurrentEncoding(
IMimeBody* iface,
ENCODINGTYPE* pietEncoding)
{
MimeBody *This = impl_from_IMimeBody(iface);
if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type"))
{
PropVariantClear(pValue);
pValue->vt = VT_LPSTR;
pValue->u.pszVal = strdupA(This->content_pri_type);
return S_OK;
}
TRACE("(%p)->(%p)\n", This, pietEncoding);
hr = find_prop(This, pszName, &header);
if(hr == S_OK)
{
TRACE("type %d->%d\n", header->value.vt, pValue->vt);
*pietEncoding = This->encoding;
return S_OK;
hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt);
if(FAILED(hr))
FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt);
}
return hr;
}
static HRESULT WINAPI MimeBody_SetCurrentEncoding(
IMimeBody* iface,
ENCODINGTYPE ietEncoding)
static HRESULT WINAPI MimeBody_SetProp(
IMimeBody* iface,
LPCSTR pszName,
DWORD dwFlags,
LPCPROPVARIANT pValue)
{
MimeBody *This = impl_from_IMimeBody(iface);
header_t *header;
HRESULT hr;
TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue);
if(!pszName || !pValue)
return E_INVALIDARG;
hr = find_prop(This, pszName, &header);
if(hr != S_OK)
{
property_list_entry_t *prop_entry;
const property_t *prop = NULL;
LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry)
{
if(ISPIDSTR(pszName))
{
if(STRTOPID(pszName) == prop_entry->prop.id)
{
TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
prop = &prop_entry->prop;
break;
}
}
else if(!lstrcmpiA(pszName, prop_entry->prop.name))
{
TRACE("Found match with already added new property id %d\n", prop_entry->prop.id);
prop = &prop_entry->prop;
break;
}
}
header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header));
if(!header)
return E_OUTOFMEMORY;
if(!prop)
{
const property_t *prop_def = NULL;
prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
if(!prop_entry)
{
HeapFree(GetProcessHeap(), 0, header);
return E_OUTOFMEMORY;
}
prop_def = find_default_prop(pszName);
if(prop_def)
{
prop_entry->prop.name = strdupA(prop_def->name);
prop_entry->prop.id = prop_def->id;
}
else
{
if(ISPIDSTR(pszName))
{
HeapFree(GetProcessHeap(), 0, prop_entry);
HeapFree(GetProcessHeap(), 0, header);
return MIME_E_NOT_FOUND;
}
prop_entry->prop.name = strdupA(pszName);
prop_entry->prop.id = This->next_prop_id++;
}
prop_entry->prop.flags = 0;
prop_entry->prop.default_vt = pValue->vt;
list_add_tail(&This->new_props, &prop_entry->entry);
prop = &prop_entry->prop;
TRACE("Allocating new prop id %d\n", prop_entry->prop.id);
}
TRACE("(%p)->(%d)\n", This, ietEncoding);
header->prop = prop;
PropVariantInit(&header->value);
list_init(&header->params);
list_add_tail(&This->headers, &header->entry);
}
This->encoding = ietEncoding;
return S_OK;
}
PropVariantCopy(&header->value, pValue);
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;
return S_OK;
}
static HRESULT WINAPI MimeBody_GetDataHere(
IMimeBody* iface,
ENCODINGTYPE ietEncoding,
IStream* pStream)
static HRESULT WINAPI MimeBody_AppendProp(
IMimeBody* iface,
LPCSTR pszName,
DWORD dwFlags,
LPPROPVARIANT pValue)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream);
FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_GetData(
IMimeBody* iface,
ENCODINGTYPE ietEncoding,
IStream** ppStream)
static HRESULT WINAPI MimeBody_DeleteProp(
IMimeBody* iface,
LPCSTR pszName)
{
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;
}
header_t *cursor;
BOOL found;
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);
TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName));
if(IsEqualIID(riid, &IID_IStream))
IStream_AddRef((IStream *)pvObject);
else
LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry)
{
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);
if(ISPIDSTR(pszName))
found = STRTOPID(pszName) == cursor->prop->id;
else
found = !lstrcmpiA(pszName, cursor->prop->name);
/* FIXME: Update the content type.
If pszPriType == NULL use 'application'
If pszSubType == NULL use 'octet-stream' */
if(found)
{
list_remove(&cursor->entry);
HeapFree(GetProcessHeap(), 0, cursor);
return S_OK;
}
}
return S_OK;
return MIME_E_NOT_FOUND;
}
static HRESULT WINAPI MimeBody_EmptyData(
IMimeBody* iface)
static HRESULT WINAPI MimeBody_CopyProps(
IMimeBody* iface,
ULONG cNames,
LPCSTR* prgszName,
IMimePropertySet* pPropertySet)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->() stub\n", This);
FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_CopyTo(
IMimeBody* iface,
IMimeBody* pBody)
static HRESULT WINAPI MimeBody_MoveProps(
IMimeBody* iface,
ULONG cNames,
LPCSTR* prgszName,
IMimePropertySet* pPropertySet)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, pBody);
FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_GetTransmitInfo(
IMimeBody* iface,
LPTRANSMITINFO pTransmitInfo)
static HRESULT WINAPI MimeBody_DeleteExcept(
IMimeBody* iface,
ULONG cNames,
LPCSTR* prgszName)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_SaveToFile(
IMimeBody* iface,
ENCODINGTYPE ietEncoding,
LPCSTR pszFilePath)
static HRESULT WINAPI MimeBody_QueryProp(
IMimeBody* iface,
LPCSTR pszName,
LPCSTR pszCriteria,
boolean fSubString,
boolean fCaseSensitive)
{
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive);
return E_NOTIMPL;
}
static HRESULT WINAPI MimeBody_GetHandle(
IMimeBody* iface,
LPHBODY phBody)
static HRESULT WINAPI MimeBody_GetCharset(
IMimeBody* iface,
LPHCHARSET phCharset)
{
MimeBody *This = impl_from_IMimeBody(iface);
TRACE("(%p)->(%p)\n", iface, phBody);
if(!phBody)
return E_INVALIDARG;
*phBody = This->handle;
return This->handle ? S_OK : MIME_E_NO_DATA;
FIXME("(%p)->(%p) stub\n", This, phCharset);
*phCharset = NULL;
return S_OK;
}
static IMimeBodyVtbl body_vtbl =
static HRESULT WINAPI MimeBody_SetCharset(
IMimeBody* iface,
HCHARSET hCharset,
CSETAPPLYTYPE applytype)
{
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
};
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype);
return E_NOTIMPL;
}
static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
static HRESULT WINAPI MimeBody_GetParameters(
IMimeBody* iface,
LPCSTR pszName,
ULONG* pcParams,
LPMIMEPARAMINFO* pprgParam)
{
TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart,
offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd);
MimeBody *This = impl_from_IMimeBody(iface);
HRESULT hr;
header_t *header;
body->body_offsets = *offsets;
return S_OK;
}
TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
#define FIRST_CUSTOM_PROP_ID 0x100
*pprgParam = NULL;
*pcParams = 0;
static MimeBody *mimebody_create(void)
{
MimeBody *This;
BODYOFFSETS body_offsets;
hr = find_prop(This, pszName, &header);
if(hr != S_OK) return hr;
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
if (!This)
return NULL;
*pcParams = list_count(&header->params);
if(*pcParams)
{
IMimeAllocator *alloc;
param_t *param;
MIMEPARAMINFO *info;
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;
MimeOleGetAllocator(&alloc);
body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0;
body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0;
MimeBody_set_offsets(This, &body_offsets);
*pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
{
int len;
return This;
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;
}
HRESULT MimeBody_create(IUnknown *outer, void **ppv)
static HRESULT WINAPI MimeBody_IsContentType(
IMimeBody* iface,
LPCSTR pszPriType,
LPCSTR pszSubType)
{
MimeBody *mb;
if(outer)
return CLASS_E_NOAGGREGATION;
MimeBody *This = impl_from_IMimeBody(iface);
if ((mb = mimebody_create()))
TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
if(pszPriType)
{
*ppv = &mb->IMimeBody_iface;
return S_OK;
const char *pri = This->content_pri_type;
if(!pri) pri = "text";
if(lstrcmpiA(pri, pszPriType)) return S_FALSE;
}
else
if(pszSubType)
{
*ppv = NULL;
return E_OUTOFMEMORY;
const char *sub = This->content_sub_type;
if(!sub) sub = "plain";
if(lstrcmpiA(sub, pszSubType)) return S_FALSE;
}
}
return S_OK;
}
typedef struct
static HRESULT WINAPI MimeBody_BindToObject(
IMimeBody* iface,
REFIID riid,
void** ppvObject)
{
IStream IStream_iface;
LONG ref;
IStream *base;
ULARGE_INTEGER pos, start, length;
} sub_stream_t;
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject);
return E_NOTIMPL;
}
static inline sub_stream_t *impl_from_IStream(IStream *iface)
static HRESULT WINAPI MimeBody_Clone(
IMimeBody* iface,
IMimePropertySet** ppPropertySet)
{
return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface);
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, ppPropertySet);
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv)
static HRESULT WINAPI MimeBody_SetOption(
IMimeBody* iface,
const TYPEDID oid,
LPCPROPVARIANT pValue)
{
sub_stream_t *This = impl_from_IStream(iface);
MimeBody *This = impl_from_IMimeBody(iface);
HRESULT hr = E_NOTIMPL;
TRACE("(%p)->(%08x, %p)\n", This, oid, pValue);
TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv);
*ppv = NULL;
if(pValue->vt != TYPEDID_TYPE(oid))
{
WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid);
return E_INVALIDARG;
}
if(IsEqualIID(riid, &IID_IUnknown) ||
IsEqualIID(riid, &IID_ISequentialStream) ||
IsEqualIID(riid, &IID_IStream))
switch(oid)
{
IStream_AddRef(iface);
*ppv = iface;
return S_OK;
case OID_SECURITY_HWND_OWNER:
FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal);
hr = S_OK;
break;
case OID_TRANSMIT_BODY_ENCODING:
FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal);
hr = S_OK;
break;
default:
FIXME("Unhandled oid %08x\n", oid);
}
return E_NOINTERFACE;
return hr;
}
static ULONG WINAPI sub_stream_AddRef(IStream *iface)
static HRESULT WINAPI MimeBody_GetOption(
IMimeBody* iface,
const TYPEDID oid,
LPPROPVARIANT pValue)
{
sub_stream_t *This = impl_from_IStream(iface);
LONG ref = InterlockedIncrement(&This->ref);
TRACE("(%p) ref=%d\n", This, ref);
return ref;
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue);
return E_NOTIMPL;
}
static ULONG WINAPI sub_stream_Release(IStream *iface)
static HRESULT WINAPI MimeBody_EnumProps(
IMimeBody* iface,
DWORD dwFlags,
IMimeEnumProperties** ppEnum)
{
sub_stream_t *This = impl_from_IStream(iface);
LONG ref = InterlockedDecrement(&This->ref);
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum);
return E_NOTIMPL;
}
TRACE("(%p) ref=%d\n", This, ref);
static HRESULT WINAPI MimeBody_IsType(
IMimeBody* iface,
IMSGBODYTYPE bodytype)
{
MimeBody *This = impl_from_IMimeBody(iface);
if(!ref)
TRACE("(%p)->(%d)\n", This, bodytype);
switch(bodytype)
{
IStream_Release(This->base);
HeapFree(GetProcessHeap(), 0, This);
case IBT_EMPTY:
return This->data ? S_FALSE : S_OK;
default:
FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype);
}
return ref;
return S_OK;
}
static HRESULT WINAPI sub_stream_Read(
IStream* iface,
void *pv,
ULONG cb,
ULONG *pcbRead)
static HRESULT WINAPI MimeBody_SetDisplayName(
IMimeBody* iface,
LPCSTR pszDisplay)
{
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;
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay));
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_Write(
IStream* iface,
const void *pv,
ULONG cb,
ULONG *pcbWritten)
static HRESULT WINAPI MimeBody_GetDisplayName(
IMimeBody* iface,
LPSTR* ppszDisplay)
{
FIXME("stub\n");
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, ppszDisplay);
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_Seek(
IStream* iface,
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
static HRESULT WINAPI MimeBody_GetOffsets(
IMimeBody* iface,
LPBODYOFFSETS pOffsets)
{
sub_stream_t *This = impl_from_IStream(iface);
LARGE_INTEGER new_pos;
MimeBody *This = impl_from_IMimeBody(iface);
TRACE("(%p)->(%p)\n", This, pOffsets);
TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition);
*pOffsets = This->body_offsets;
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(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
return S_OK;
}
if(new_pos.QuadPart < 0) new_pos.QuadPart = 0;
else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart;
static HRESULT WINAPI MimeBody_GetCurrentEncoding(
IMimeBody* iface,
ENCODINGTYPE* pietEncoding)
{
MimeBody *This = impl_from_IMimeBody(iface);
This->pos.QuadPart = new_pos.QuadPart;
TRACE("(%p)->(%p)\n", This, pietEncoding);
if(plibNewPosition) *plibNewPosition = This->pos;
*pietEncoding = This->encoding;
return S_OK;
}
static HRESULT WINAPI sub_stream_SetSize(
IStream* iface,
ULARGE_INTEGER libNewSize)
static HRESULT WINAPI MimeBody_SetCurrentEncoding(
IMimeBody* iface,
ENCODINGTYPE ietEncoding)
{
FIXME("stub\n");
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 sub_stream_CopyTo(
IStream* iface,
IStream *pstm,
ULARGE_INTEGER cb,
ULARGE_INTEGER *pcbRead,
ULARGE_INTEGER *pcbWritten)
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)
{
HRESULT hr = S_OK;
BYTE tmpBuffer[128];
ULONG bytesRead, bytesWritten, copySize;
ULARGE_INTEGER totalBytesRead;
ULARGE_INTEGER totalBytesWritten;
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten);
*ppStream = This->data;
IStream_AddRef(*ppStream);
return S_OK;
}
totalBytesRead.QuadPart = 0;
totalBytesWritten.QuadPart = 0;
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);
while ( cb.QuadPart > 0 )
if(IsEqualIID(riid, &IID_IStream))
IStream_AddRef((IStream *)pvObject);
else
{
if ( cb.QuadPart >= sizeof(tmpBuffer) )
copySize = sizeof(tmpBuffer);
else
copySize = cb.u.LowPart;
hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
if (FAILED(hr)) break;
FIXME("Unhandled object type %s\n", debugstr_guid(riid));
return E_INVALIDARG;
}
totalBytesRead.QuadPart += bytesRead;
if(This->data)
FIXME("release old data\n");
if (bytesRead)
{
hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
if (FAILED(hr)) break;
totalBytesWritten.QuadPart += bytesWritten;
}
This->data_iid = *riid;
This->data = pvObject;
if (bytesRead != copySize)
cb.QuadPart = 0;
else
cb.QuadPart -= bytesRead;
}
IMimeBody_SetCurrentEncoding(iface, ietEncoding);
if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart;
if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart;
/* FIXME: Update the content type.
If pszPriType == NULL use 'application'
If pszSubType == NULL use 'octet-stream' */
return hr;
return S_OK;
}
static HRESULT WINAPI sub_stream_Commit(
IStream* iface,
DWORD grfCommitFlags)
static HRESULT WINAPI MimeBody_EmptyData(
IMimeBody* iface)
{
FIXME("stub\n");
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->() stub\n", This);
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_Revert(
IStream* iface)
static HRESULT WINAPI MimeBody_CopyTo(
IMimeBody* iface,
IMimeBody* pBody)
{
FIXME("stub\n");
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, pBody);
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_LockRegion(
IStream* iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
static HRESULT WINAPI MimeBody_GetTransmitInfo(
IMimeBody* iface,
LPTRANSMITINFO pTransmitInfo)
{
FIXME("stub\n");
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%p) stub\n", This, pTransmitInfo);
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_UnlockRegion(
IStream* iface,
ULARGE_INTEGER libOffset,
ULARGE_INTEGER cb,
DWORD dwLockType)
static HRESULT WINAPI MimeBody_SaveToFile(
IMimeBody* iface,
ENCODINGTYPE ietEncoding,
LPCSTR pszFilePath)
{
FIXME("stub\n");
MimeBody *This = impl_from_IMimeBody(iface);
FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath));
return E_NOTIMPL;
}
static HRESULT WINAPI sub_stream_Stat(
IStream* iface,
STATSTG *pstatstg,
DWORD grfStatFlag)
static HRESULT WINAPI MimeBody_GetHandle(
IMimeBody* iface,
LPHBODY phBody)
{
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;
}
MimeBody *This = impl_from_IMimeBody(iface);
TRACE("(%p)->(%p)\n", iface, phBody);
static HRESULT WINAPI sub_stream_Clone(
IStream* iface,
IStream **ppstm)
{
FIXME("stub\n");
return E_NOTIMPL;
if(!phBody)
return E_INVALIDARG;
*phBody = This->handle;
return This->handle ? S_OK : MIME_E_NO_DATA;
}
static struct IStreamVtbl sub_stream_vtbl =
static IMimeBodyVtbl body_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
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 create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out)
static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets)
{
sub_stream_t *This;
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;
*out = NULL;
This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
if(!This) return E_OUTOFMEMORY;
if (!This)
return NULL;
This->IStream_iface.lpVtbl = &sub_stream_vtbl;
This->IMimeBody_iface.lpVtbl = &body_vtbl;
This->ref = 1;
This->start = start;
This->length = length;
This->pos.QuadPart = 0;
IStream_AddRef(stream);
This->base = stream;
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;
*out = &This->IStream_iface;
return S_OK;
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 body_t
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment