~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/inetcomm/mimeole.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * MIME OLE Interfaces
  3  *
  4  * Copyright 2006 Robert Shearman for CodeWeavers
  5  * Copyright 2007 Huw Davies for CodeWeavers
  6  *
  7  * This library is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU Lesser General Public
  9  * License as published by the Free Software Foundation; either
 10  * version 2.1 of the License, or (at your option) any later version.
 11  *
 12  * This library is distributed in the hope that it will be useful,
 13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 15  * Lesser General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Lesser General Public
 18  * License along with this library; if not, write to the Free Software
 19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 20  */
 21 
 22 #define COBJMACROS
 23 #define NONAMELESSUNION
 24 
 25 #include <stdarg.h>
 26 #include <stdio.h>
 27 
 28 #include "windef.h"
 29 #include "winbase.h"
 30 #include "winuser.h"
 31 #include "objbase.h"
 32 #include "ole2.h"
 33 #include "mimeole.h"
 34 
 35 #include "wine/list.h"
 36 #include "wine/debug.h"
 37 
 38 #include "inetcomm_private.h"
 39 
 40 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
 41 
 42 typedef struct
 43 {
 44     LPCSTR     name;
 45     DWORD      id;
 46     DWORD      flags; /* MIMEPROPFLAGS */
 47     VARTYPE    default_vt;
 48 } property_t;
 49 
 50 typedef struct
 51 {
 52     struct list entry;
 53     property_t prop;
 54 } property_list_entry_t;
 55 
 56 static const property_t default_props[] =
 57 {
 58     {"References",                   PID_HDR_REFS,       0,                               VT_LPSTR},
 59     {"Subject",                      PID_HDR_SUBJECT,    0,                               VT_LPSTR},
 60     {"From",                         PID_HDR_FROM,       MPF_ADDRESS,                     VT_LPSTR},
 61     {"Message-ID",                   PID_HDR_MESSAGEID,  0,                               VT_LPSTR},
 62     {"Return-Path",                  PID_HDR_RETURNPATH, MPF_ADDRESS,                     VT_LPSTR},
 63     {"Date",                         PID_HDR_DATE,       0,                               VT_LPSTR},
 64     {"Received",                     PID_HDR_RECEIVED,   0,                               VT_LPSTR},
 65     {"Reply-To",                     PID_HDR_REPLYTO,    MPF_ADDRESS,                     VT_LPSTR},
 66     {"X-Mailer",                     PID_HDR_XMAILER,    0,                               VT_LPSTR},
 67     {"Bcc",                          PID_HDR_BCC,        MPF_ADDRESS,                     VT_LPSTR},
 68     {"MIME-Version",                 PID_HDR_MIMEVER,    MPF_MIME,                        VT_LPSTR},
 69     {"Content-Type",                 PID_HDR_CNTTYPE,    MPF_MIME | MPF_HASPARAMS,        VT_LPSTR},
 70     {"Content-Transfer-Encoding",    PID_HDR_CNTXFER,    MPF_MIME,                        VT_LPSTR},
 71     {"Content-ID",                   PID_HDR_CNTID,      MPF_MIME,                        VT_LPSTR},
 72     {"Content-Disposition",          PID_HDR_CNTDISP,    MPF_MIME,                        VT_LPSTR},
 73     {"To",                           PID_HDR_TO,         MPF_ADDRESS,                     VT_LPSTR},
 74     {"Cc",                           PID_HDR_CC,         MPF_ADDRESS,                     VT_LPSTR},
 75     {"Sender",                       PID_HDR_SENDER,     MPF_ADDRESS,                     VT_LPSTR},
 76     {"In-Reply-To",                  PID_HDR_INREPLYTO,  0,                               VT_LPSTR},
 77     {NULL,                           0,                  0,                               0}
 78 };
 79 
 80 typedef struct
 81 {
 82     struct list entry;
 83     char *name;
 84     char *value;
 85 } param_t;
 86 
 87 typedef struct
 88 {
 89     struct list entry;
 90     const property_t *prop;
 91     PROPVARIANT value;
 92     struct list params;
 93 } header_t;
 94 
 95 typedef struct MimeBody
 96 {
 97     const IMimeBodyVtbl *lpVtbl;
 98     LONG refs;
 99 
100     HBODY handle;
101 
102     struct list headers;
103     struct list new_props; /* FIXME: This should be in a PropertySchema */
104     DWORD next_prop_id;
105     char *content_pri_type;
106     char *content_sub_type;
107     ENCODINGTYPE encoding;
108     void *data;
109     IID data_iid;
110     BODYOFFSETS body_offsets;
111 } MimeBody;
112 
113 static inline MimeBody *impl_from_IMimeBody( IMimeBody *iface )
114 {
115     return (MimeBody *)((char*)iface - FIELD_OFFSET(MimeBody, lpVtbl));
116 }
117 
118 static LPSTR strdupA(LPCSTR str)
119 {
120     char *ret;
121     int len = strlen(str);
122     ret = HeapAlloc(GetProcessHeap(), 0, len + 1);
123     memcpy(ret, str, len + 1);
124     return ret;
125 }
126 
127 #define PARSER_BUF_SIZE 1024
128 
129 /*****************************************************
130  *        copy_headers_to_buf [internal]
131  *
132  * Copies the headers into a '\0' terminated memory block and leave
133  * the stream's current position set to after the blank line.
134  */
135 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr)
136 {
137     char *buf = NULL;
138     DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0;
139     HRESULT hr;
140     int done = 0;
141 
142     *ptr = NULL;
143 
144     do
145     {
146         char *end;
147         DWORD read;
148 
149         if(!buf)
150             buf = HeapAlloc(GetProcessHeap(), 0, size + 1);
151         else
152         {
153             size *= 2;
154             buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1);
155         }
156         if(!buf)
157         {
158             hr = E_OUTOFMEMORY;
159             goto fail;
160         }
161 
162         hr = IStream_Read(stm, buf + offset, size - offset, &read);
163         if(FAILED(hr)) goto fail;
164 
165         offset += read;
166         buf[offset] = '\0';
167 
168         if(read == 0) done = 1;
169 
170         while(!done && (end = strstr(buf + last_end, "\r\n")))
171         {
172             DWORD new_end = end - buf + 2;
173             if(new_end - last_end == 2)
174             {
175                 LARGE_INTEGER off;
176                 off.QuadPart = new_end;
177                 IStream_Seek(stm, off, STREAM_SEEK_SET, NULL);
178                 buf[new_end] = '\0';
179                 done = 1;
180             }
181             else
182                 last_end = new_end;
183         }
184     } while(!done);
185 
186     *ptr = buf;
187     return S_OK;
188 
189 fail:
190     HeapFree(GetProcessHeap(), 0, buf);
191     return hr;
192 }
193 
194 static header_t *read_prop(MimeBody *body, char **ptr)
195 {
196     char *colon = strchr(*ptr, ':');
197     const property_t *prop;
198     header_t *ret;
199 
200     if(!colon) return NULL;
201 
202     *colon = '\0';
203 
204     for(prop = default_props; prop->name; prop++)
205     {
206         if(!strcasecmp(*ptr, prop->name))
207         {
208             TRACE("%s: found match with default property id %d\n", *ptr, prop->id);
209             break;
210         }
211     }
212 
213     if(!prop->name)
214     {
215         property_list_entry_t *prop_entry;
216         LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry)
217         {
218             if(!strcasecmp(*ptr, prop_entry->prop.name))
219             {
220                 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id);
221                 prop = &prop_entry->prop;
222                 break;
223             }
224         }
225         if(!prop->name)
226         {
227             prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry));
228             prop_entry->prop.name = strdupA(*ptr);
229             prop_entry->prop.id = body->next_prop_id++;
230             prop_entry->prop.flags = 0;
231             prop_entry->prop.default_vt = VT_LPSTR;
232             list_add_tail(&body->new_props, &prop_entry->entry);
233             prop = &prop_entry->prop;
234             TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id);
235         }
236     }
237 
238     ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
239     ret->prop = prop;
240     PropVariantInit(&ret->value);
241     list_init(&ret->params);
242     *ptr = colon + 1;
243 
244     return ret;
245 }
246 
247 static void unfold_header(char *header, int len)
248 {
249     char *start = header, *cp = header;
250 
251     do {
252         while(*cp == ' ' || *cp == '\t')
253         {
254             cp++;
255             len--;
256         }
257         if(cp != start)
258             memmove(start, cp, len + 1);
259 
260         cp = strstr(start, "\r\n");
261         len -= (cp - start);
262         start = cp;
263         *start = ' ';
264         start++;
265         len--;
266         cp += 2;
267     } while(*cp == ' ' || *cp == '\t');
268 
269     *(start - 1) = '\0';
270 }
271 
272 static char *unquote_string(const char *str)
273 {
274     int quoted = 0;
275     char *ret, *cp;
276 
277     while(*str == ' ' || *str == '\t') str++;
278 
279     if(*str == '"')
280     {
281         quoted = 1;
282         str++;
283     }
284     ret = strdupA(str);
285     for(cp = ret; *cp; cp++)
286     {
287         if(*cp == '\\')
288             memmove(cp, cp + 1, strlen(cp + 1) + 1);
289         else if(*cp == '"')
290         {
291             if(!quoted)
292             {
293                 WARN("quote in unquoted string\n");
294             }
295             else
296             {
297                 *cp = '\0';
298                 break;
299             }
300         }
301     }
302     return ret;
303 }
304 
305 static void add_param(header_t *header, const char *p)
306 {
307     const char *key = p, *value, *cp = p;
308     param_t *param;
309     char *name;
310 
311     TRACE("got param %s\n", p);
312 
313     while (*key == ' ' || *key == '\t' ) key++;
314 
315     cp = strchr(key, '=');
316     if(!cp)
317     {
318         WARN("malformed parameter - skipping\n");
319         return;
320     }
321 
322     name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1);
323     memcpy(name, key, cp - key);
324     name[cp - key] = '\0';
325 
326     value = cp + 1;
327 
328     param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param));
329     param->name = name;
330     param->value = unquote_string(value);
331     list_add_tail(&header->params, &param->entry);
332 }
333 
334 static void split_params(header_t *header, char *value)
335 {
336     char *cp = value, *start = value;
337     int in_quote = 0;
338     int done_value = 0;
339 
340     while(*cp)
341     {
342         if(!in_quote && *cp == ';')
343         {
344             *cp = '\0';
345             if(done_value) add_param(header, start);
346             done_value = 1;
347             start = cp + 1;
348         }
349         else if(*cp == '"')
350             in_quote = !in_quote;
351         cp++;
352     }
353     if(done_value) add_param(header, start);
354 }
355 
356 static void read_value(header_t *header, char **cur)
357 {
358     char *end = *cur, *value;
359     DWORD len;
360 
361     do {
362         end = strstr(end, "\r\n");
363         end += 2;
364     } while(*end == ' ' || *end == '\t');
365 
366     len = end - *cur;
367     value = HeapAlloc(GetProcessHeap(), 0, len + 1);
368     memcpy(value, *cur, len);
369     value[len] = '\0';
370 
371     unfold_header(value, len);
372     TRACE("value %s\n", debugstr_a(value));
373 
374     if(header->prop->flags & MPF_HASPARAMS)
375     {
376         split_params(header, value);
377         TRACE("value w/o params %s\n", debugstr_a(value));
378     }
379 
380     header->value.vt = VT_LPSTR;
381     header->value.u.pszVal = value;
382 
383     *cur = end;
384 }
385 
386 static void init_content_type(MimeBody *body, header_t *header)
387 {
388     char *slash;
389     DWORD len;
390 
391     if(header->prop->id != PID_HDR_CNTTYPE)
392     {
393         ERR("called with header %s\n", header->prop->name);
394         return;
395     }
396 
397     slash = strchr(header->value.u.pszVal, '/');
398     if(!slash)
399     {
400         WARN("malformed context type value\n");
401         return;
402     }
403     len = slash - header->value.u.pszVal;
404     body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1);
405     memcpy(body->content_pri_type, header->value.u.pszVal, len);
406     body->content_pri_type[len] = '\0';
407     body->content_sub_type = strdupA(slash + 1);
408 }
409 
410 static HRESULT parse_headers(MimeBody *body, IStream *stm)
411 {
412     char *header_buf, *cur_header_ptr;
413     HRESULT hr;
414     header_t *header;
415 
416     hr = copy_headers_to_buf(stm, &header_buf);
417     if(FAILED(hr)) return hr;
418 
419     cur_header_ptr = header_buf;
420     while((header = read_prop(body, &cur_header_ptr)))
421     {
422         read_value(header, &cur_header_ptr);
423         list_add_tail(&body->headers, &header->entry);
424 
425         if(header->prop->id == PID_HDR_CNTTYPE)
426             init_content_type(body, header);
427     }
428 
429     HeapFree(GetProcessHeap(), 0, header_buf);
430     return hr;
431 }
432 
433 static void empty_param_list(struct list *list)
434 {
435     param_t *param, *cursor2;
436 
437     LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry)
438     {
439         list_remove(&param->entry);
440         HeapFree(GetProcessHeap(), 0, param->name);
441         HeapFree(GetProcessHeap(), 0, param->value);
442         HeapFree(GetProcessHeap(), 0, param);
443     }
444 }
445 
446 static void empty_header_list(struct list *list)
447 {
448     header_t *header, *cursor2;
449 
450     LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry)
451     {
452         list_remove(&header->entry);
453         PropVariantClear(&header->value);
454         empty_param_list(&header->params);
455         HeapFree(GetProcessHeap(), 0, header);
456     }
457 }
458 
459 static void empty_new_prop_list(struct list *list)
460 {
461     property_list_entry_t *prop, *cursor2;
462 
463     LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry)
464     {
465         list_remove(&prop->entry);
466         HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name);
467         HeapFree(GetProcessHeap(), 0, prop);
468     }
469 }
470 
471 static void release_data(REFIID riid, void *data)
472 {
473     if(!data) return;
474 
475     if(IsEqualIID(riid, &IID_IStream))
476         IStream_Release((IStream *)data);
477     else
478         FIXME("Unhandled data format %s\n", debugstr_guid(riid));
479 }
480 
481 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop)
482 {
483     header_t *header;
484 
485     *prop = NULL;
486 
487     LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry)
488     {
489         if(!strcasecmp(name, header->prop->name))
490         {
491             *prop = header;
492             return S_OK;
493         }
494     }
495 
496     return MIME_E_NOT_FOUND;
497 }
498 
499 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface,
500                                      REFIID riid,
501                                      void** ppvObject)
502 {
503     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject);
504 
505     *ppvObject = NULL;
506 
507     if (IsEqualIID(riid, &IID_IUnknown) ||
508         IsEqualIID(riid, &IID_IPersist) ||
509         IsEqualIID(riid, &IID_IPersistStreamInit) ||
510         IsEqualIID(riid, &IID_IMimePropertySet) ||
511         IsEqualIID(riid, &IID_IMimeBody))
512     {
513         *ppvObject = iface;
514     }
515 
516     if(*ppvObject)
517     {
518         IUnknown_AddRef((IUnknown*)*ppvObject);
519         return S_OK;
520     }
521 
522     FIXME("no interface for %s\n", debugstr_guid(riid));
523     return E_NOINTERFACE;
524 }
525 
526 static ULONG WINAPI MimeBody_AddRef(IMimeBody* iface)
527 {
528     MimeBody *This = impl_from_IMimeBody(iface);
529     TRACE("(%p)->()\n", iface);
530     return InterlockedIncrement(&This->refs);
531 }
532 
533 static ULONG WINAPI MimeBody_Release(IMimeBody* iface)
534 {
535     MimeBody *This = impl_from_IMimeBody(iface);
536     ULONG refs;
537 
538     TRACE("(%p)->()\n", iface);
539 
540     refs = InterlockedDecrement(&This->refs);
541     if (!refs)
542     {
543         empty_header_list(&This->headers);
544         empty_new_prop_list(&This->new_props);
545 
546         HeapFree(GetProcessHeap(), 0, This->content_pri_type);
547         HeapFree(GetProcessHeap(), 0, This->content_sub_type);
548 
549         release_data(&This->data_iid, This->data);
550 
551         HeapFree(GetProcessHeap(), 0, This);
552     }
553 
554     return refs;
555 }
556 
557 static HRESULT WINAPI MimeBody_GetClassID(
558                                  IMimeBody* iface,
559                                  CLSID* pClassID)
560 {
561     FIXME("stub\n");
562     return E_NOTIMPL;
563 }
564 
565 
566 static HRESULT WINAPI MimeBody_IsDirty(
567                               IMimeBody* iface)
568 {
569     FIXME("stub\n");
570     return E_NOTIMPL;
571 }
572 
573 static HRESULT WINAPI MimeBody_Load(
574                            IMimeBody* iface,
575                            LPSTREAM pStm)
576 {
577     MimeBody *This = impl_from_IMimeBody(iface);
578     TRACE("(%p)->(%p)\n", iface, pStm);
579     return parse_headers(This, pStm);
580 }
581 
582 static HRESULT WINAPI MimeBody_Save(
583                            IMimeBody* iface,
584                            LPSTREAM pStm,
585                            BOOL fClearDirty)
586 {
587     FIXME("stub\n");
588     return E_NOTIMPL;
589 }
590 
591 static HRESULT WINAPI MimeBody_GetSizeMax(
592                                  IMimeBody* iface,
593                                  ULARGE_INTEGER* pcbSize)
594 {
595     FIXME("stub\n");
596     return E_NOTIMPL;
597 }
598 
599 static HRESULT WINAPI MimeBody_InitNew(
600                               IMimeBody* iface)
601 {
602     TRACE("%p->()\n", iface);
603     return S_OK;
604 }
605 
606 static HRESULT WINAPI MimeBody_GetPropInfo(
607                                   IMimeBody* iface,
608                                   LPCSTR pszName,
609                                   LPMIMEPROPINFO pInfo)
610 {
611     FIXME("stub\n");
612     return E_NOTIMPL;
613 }
614 
615 static HRESULT WINAPI MimeBody_SetPropInfo(
616                                   IMimeBody* iface,
617                                   LPCSTR pszName,
618                                   LPCMIMEPROPINFO pInfo)
619 {
620     FIXME("stub\n");
621     return E_NOTIMPL;
622 }
623 
624 static HRESULT WINAPI MimeBody_GetProp(
625                               IMimeBody* iface,
626                               LPCSTR pszName,
627                               DWORD dwFlags,
628                               LPPROPVARIANT pValue)
629 {
630     MimeBody *This = impl_from_IMimeBody(iface);
631     TRACE("(%p)->(%s, %d, %p)\n", This, pszName, dwFlags, pValue);
632 
633     if(!strcasecmp(pszName, "att:pri-content-type"))
634     {
635         PropVariantClear(pValue);
636         pValue->vt = VT_LPSTR;
637         pValue->u.pszVal = strdupA(This->content_pri_type);
638         return S_OK;
639     }
640 
641     FIXME("stub!\n");
642     return E_FAIL;
643 }
644 
645 static HRESULT WINAPI MimeBody_SetProp(
646                               IMimeBody* iface,
647                               LPCSTR pszName,
648                               DWORD dwFlags,
649                               LPCPROPVARIANT pValue)
650 {
651     FIXME("stub\n");
652     return E_NOTIMPL;
653 }
654 
655 static HRESULT WINAPI MimeBody_AppendProp(
656                                  IMimeBody* iface,
657                                  LPCSTR pszName,
658                                  DWORD dwFlags,
659                                  LPPROPVARIANT pValue)
660 {
661     FIXME("stub\n");
662     return E_NOTIMPL;
663 }
664 
665 static HRESULT WINAPI MimeBody_DeleteProp(
666                                  IMimeBody* iface,
667                                  LPCSTR pszName)
668 {
669     FIXME("stub\n");
670     return E_NOTIMPL;
671 }
672 
673 static HRESULT WINAPI MimeBody_CopyProps(
674                                 IMimeBody* iface,
675                                 ULONG cNames,
676                                 LPCSTR* prgszName,
677                                 IMimePropertySet* pPropertySet)
678 {
679     FIXME("stub\n");
680     return E_NOTIMPL;
681 }
682 
683 static HRESULT WINAPI MimeBody_MoveProps(
684                                 IMimeBody* iface,
685                                 ULONG cNames,
686                                 LPCSTR* prgszName,
687                                 IMimePropertySet* pPropertySet)
688 {
689     FIXME("stub\n");
690     return E_NOTIMPL;
691 }
692 
693 static HRESULT WINAPI MimeBody_DeleteExcept(
694                                    IMimeBody* iface,
695                                    ULONG cNames,
696                                    LPCSTR* prgszName)
697 {
698     FIXME("stub\n");
699     return E_NOTIMPL;
700 }
701 
702 static HRESULT WINAPI MimeBody_QueryProp(
703                                 IMimeBody* iface,
704                                 LPCSTR pszName,
705                                 LPCSTR pszCriteria,
706                                 boolean fSubString,
707                                 boolean fCaseSensitive)
708 {
709     FIXME("stub\n");
710     return E_NOTIMPL;
711 }
712 
713 static HRESULT WINAPI MimeBody_GetCharset(
714                                  IMimeBody* iface,
715                                  LPHCHARSET phCharset)
716 {
717     FIXME("stub\n");
718     *phCharset = NULL;
719     return S_OK;
720 }
721 
722 static HRESULT WINAPI MimeBody_SetCharset(
723                                  IMimeBody* iface,
724                                  HCHARSET hCharset,
725                                  CSETAPPLYTYPE applytype)
726 {
727     FIXME("stub\n");
728     return E_NOTIMPL;
729 }
730 
731 static HRESULT WINAPI MimeBody_GetParameters(
732                                     IMimeBody* iface,
733                                     LPCSTR pszName,
734                                     ULONG* pcParams,
735                                     LPMIMEPARAMINFO* pprgParam)
736 {
737     MimeBody *This = impl_from_IMimeBody(iface);
738     HRESULT hr;
739     header_t *header;
740 
741     TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam);
742 
743     *pprgParam = NULL;
744     *pcParams = 0;
745 
746     hr = find_prop(This, pszName, &header);
747     if(hr != S_OK) return hr;
748 
749     *pcParams = list_count(&header->params);
750     if(*pcParams)
751     {
752         IMimeAllocator *alloc;
753         param_t *param;
754         MIMEPARAMINFO *info;
755 
756         MimeOleGetAllocator(&alloc);
757 
758         *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam));
759         LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry)
760         {
761             int len;
762 
763             len = strlen(param->name) + 1;
764             info->pszName = IMimeAllocator_Alloc(alloc, len);
765             memcpy(info->pszName, param->name, len);
766             len = strlen(param->value) + 1;
767             info->pszData = IMimeAllocator_Alloc(alloc, len);
768             memcpy(info->pszData, param->value, len);
769             info++;
770         }
771         IMimeAllocator_Release(alloc);
772     }
773     return S_OK;
774 }
775 
776 static HRESULT WINAPI MimeBody_IsContentType(
777                                     IMimeBody* iface,
778                                     LPCSTR pszPriType,
779                                     LPCSTR pszSubType)
780 {
781     MimeBody *This = impl_from_IMimeBody(iface);
782 
783     TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType));
784     if(pszPriType)
785     {
786         const char *pri = This->content_pri_type;
787         if(!pri) pri = "text";
788         if(strcasecmp(pri, pszPriType)) return S_FALSE;
789     }
790 
791     if(pszSubType)
792     {
793         const char *sub = This->content_sub_type;
794         if(!sub) sub = "plain";
795         if(strcasecmp(sub, pszSubType)) return S_FALSE;
796     }
797 
798     return S_OK;
799 }
800 
801 static HRESULT WINAPI MimeBody_BindToObject(
802                                    IMimeBody* iface,
803                                    REFIID riid,
804                                    void** ppvObject)
805 {
806     FIXME("stub\n");
807     return E_NOTIMPL;
808 }
809 
810 static HRESULT WINAPI MimeBody_Clone(
811                             IMimeBody* iface,
812                             IMimePropertySet** ppPropertySet)
813 {
814     FIXME("stub\n");
815     return E_NOTIMPL;
816 }
817 
818 static HRESULT WINAPI MimeBody_SetOption(
819                                 IMimeBody* iface,
820                                 const TYPEDID oid,
821                                 LPCPROPVARIANT pValue)
822 {
823     FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
824     return E_NOTIMPL;
825 }
826 
827 static HRESULT WINAPI MimeBody_GetOption(
828                                 IMimeBody* iface,
829                                 const TYPEDID oid,
830                                 LPPROPVARIANT pValue)
831 {
832     FIXME("(%p)->(%08x, %p): stub\n", iface, oid, pValue);
833     return E_NOTIMPL;
834 }
835 
836 static HRESULT WINAPI MimeBody_EnumProps(
837                                 IMimeBody* iface,
838                                 DWORD dwFlags,
839                                 IMimeEnumProperties** ppEnum)
840 {
841     FIXME("stub\n");
842     return E_NOTIMPL;
843 }
844 
845 static HRESULT WINAPI MimeBody_IsType(
846                              IMimeBody* iface,
847                              IMSGBODYTYPE bodytype)
848 {
849     FIXME("(%p)->(%d): stub\n", iface, bodytype);
850     return E_NOTIMPL;
851 }
852 
853 static HRESULT WINAPI MimeBody_SetDisplayName(
854                                      IMimeBody* iface,
855                                      LPCSTR pszDisplay)
856 {
857     FIXME("stub\n");
858     return E_NOTIMPL;
859 }
860 
861 static HRESULT WINAPI MimeBody_GetDisplayName(
862                                      IMimeBody* iface,
863                                      LPSTR* ppszDisplay)
864 {
865     FIXME("stub\n");
866     return E_NOTIMPL;
867 }
868 
869 static HRESULT WINAPI MimeBody_GetOffsets(
870                                  IMimeBody* iface,
871                                  LPBODYOFFSETS pOffsets)
872 {
873     MimeBody *This = impl_from_IMimeBody(iface);
874     TRACE("(%p)->(%p)\n", This, pOffsets);
875 
876     *pOffsets = This->body_offsets;
877 
878     if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA;
879     return S_OK;
880 }
881 
882 static HRESULT WINAPI MimeBody_GetCurrentEncoding(
883                                          IMimeBody* iface,
884                                          ENCODINGTYPE* pietEncoding)
885 {
886     MimeBody *This = impl_from_IMimeBody(iface);
887 
888     TRACE("(%p)->(%p)\n", This, pietEncoding);
889 
890     *pietEncoding = This->encoding;
891     return S_OK;
892 }
893 
894 static HRESULT WINAPI MimeBody_SetCurrentEncoding(
895                                          IMimeBody* iface,
896                                          ENCODINGTYPE ietEncoding)
897 {
898     MimeBody *This = impl_from_IMimeBody(iface);
899 
900     TRACE("(%p)->(%d)\n", This, ietEncoding);
901 
902     This->encoding = ietEncoding;
903     return S_OK;
904 }
905 
906 static HRESULT WINAPI MimeBody_GetEstimatedSize(
907                                        IMimeBody* iface,
908                                        ENCODINGTYPE ietEncoding,
909                                        ULONG* pcbSize)
910 {
911     FIXME("stub\n");
912     return E_NOTIMPL;
913 }
914 
915 static HRESULT WINAPI MimeBody_GetDataHere(
916                                   IMimeBody* iface,
917                                   ENCODINGTYPE ietEncoding,
918                                   IStream* pStream)
919 {
920     FIXME("stub\n");
921     return E_NOTIMPL;
922 }
923 
924 static HRESULT WINAPI MimeBody_GetData(
925                               IMimeBody* iface,
926                               ENCODINGTYPE ietEncoding,
927                               IStream** ppStream)
928 {
929     MimeBody *This = impl_from_IMimeBody(iface);
930     FIXME("(%p)->(%d, %p). Ignoring encoding type.\n", This, ietEncoding, ppStream);
931 
932     *ppStream = This->data;
933     IStream_AddRef(*ppStream);
934     return S_OK;
935 }
936 
937 static HRESULT WINAPI MimeBody_SetData(
938                               IMimeBody* iface,
939                               ENCODINGTYPE ietEncoding,
940                               LPCSTR pszPriType,
941                               LPCSTR pszSubType,
942                               REFIID riid,
943                               LPVOID pvObject)
944 {
945     MimeBody *This = impl_from_IMimeBody(iface);
946     TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType),
947           debugstr_guid(riid), pvObject);
948 
949     if(IsEqualIID(riid, &IID_IStream))
950         IStream_AddRef((IStream *)pvObject);
951     else
952     {
953         FIXME("Unhandled object type %s\n", debugstr_guid(riid));
954         return E_INVALIDARG;
955     }
956 
957     if(This->data)
958         FIXME("release old data\n");
959 
960     This->data_iid = *riid;
961     This->data = pvObject;
962 
963     IMimeBody_SetCurrentEncoding(iface, ietEncoding);
964 
965     /* FIXME: Update the content type.
966        If pszPriType == NULL use 'application'
967        If pszSubType == NULL use 'octet-stream' */
968 
969     return S_OK;
970 }
971 
972 static HRESULT WINAPI MimeBody_EmptyData(
973                                 IMimeBody* iface)
974 {
975     FIXME("stub\n");
976     return E_NOTIMPL;
977 }
978