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 #ifdef __REACTOS__ 35 #include <winreg.h> 36 #endif 37 #include "propvarutil.h" 38 39 #include "wine/heap.h" 40 #include "wine/list.h" 41 #include "wine/debug.h" 42 #include "wine/unicode.h" 43 44 #include "inetcomm_private.h" 45 46 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm); 47 48 typedef struct 49 { 50 LPCSTR name; 51 DWORD id; 52 DWORD flags; /* MIMEPROPFLAGS */ 53 VARTYPE default_vt; 54 } property_t; 55 56 typedef struct 57 { 58 struct list entry; 59 property_t prop; 60 } property_list_entry_t; 61 62 static const property_t default_props[] = 63 { 64 {"X-Newsgroup", PID_HDR_NEWSGROUP, 0, VT_LPSTR}, 65 {"Newsgroups", PID_HDR_NEWSGROUPS, 0, VT_LPSTR}, 66 {"References", PID_HDR_REFS, 0, VT_LPSTR}, 67 {"Subject", PID_HDR_SUBJECT, 0, VT_LPSTR}, 68 {"From", PID_HDR_FROM, MPF_ADDRESS, VT_LPSTR}, 69 {"Message-ID", PID_HDR_MESSAGEID, 0, VT_LPSTR}, 70 {"Return-Path", PID_HDR_RETURNPATH, MPF_ADDRESS, VT_LPSTR}, 71 {"Rr", PID_HDR_RR, 0, VT_LPSTR}, 72 {"Return-Receipt-To", PID_HDR_RETRCPTO, MPF_ADDRESS, VT_LPSTR}, 73 {"Apparently-To", PID_HDR_APPARTO, MPF_ADDRESS, VT_LPSTR}, 74 {"Date", PID_HDR_DATE, 0, VT_LPSTR}, 75 {"Received", PID_HDR_RECEIVED, 0, VT_LPSTR}, 76 {"Reply-To", PID_HDR_REPLYTO, MPF_ADDRESS, VT_LPSTR}, 77 {"X-Mailer", PID_HDR_XMAILER, 0, VT_LPSTR}, 78 {"Bcc", PID_HDR_BCC, MPF_ADDRESS, VT_LPSTR}, 79 {"MIME-Version", PID_HDR_MIMEVER, MPF_MIME, VT_LPSTR}, 80 {"Content-Type", PID_HDR_CNTTYPE, MPF_MIME | MPF_HASPARAMS, VT_LPSTR}, 81 {"Content-Transfer-Encoding", PID_HDR_CNTXFER, MPF_MIME, VT_LPSTR}, 82 {"Content-ID", PID_HDR_CNTID, MPF_MIME, VT_LPSTR}, 83 {"Content-Description", PID_HDR_CNTDESC, MPF_MIME, VT_LPSTR}, 84 {"Content-Disposition", PID_HDR_CNTDISP, MPF_MIME | MPF_HASPARAMS, VT_LPSTR}, 85 {"Content-Base", PID_HDR_CNTBASE, MPF_MIME, VT_LPSTR}, 86 {"Content-Location", PID_HDR_CNTLOC, MPF_MIME, VT_LPSTR}, 87 {"To", PID_HDR_TO, MPF_ADDRESS, VT_LPSTR}, 88 {"Path", PID_HDR_PATH, 0, VT_LPSTR}, 89 {"Followup-To", PID_HDR_FOLLOWUPTO, 0, VT_LPSTR}, 90 {"Expires", PID_HDR_EXPIRES, 0, VT_LPSTR}, 91 {"Cc", PID_HDR_CC, MPF_ADDRESS, VT_LPSTR}, 92 {"Control", PID_HDR_CONTROL, 0, VT_LPSTR}, 93 {"Distribution", PID_HDR_DISTRIB, 0, VT_LPSTR}, 94 {"Keywords", PID_HDR_KEYWORDS, 0, VT_LPSTR}, 95 {"Summary", PID_HDR_SUMMARY, 0, VT_LPSTR}, 96 {"Approved", PID_HDR_APPROVED, 0, VT_LPSTR}, 97 {"Lines", PID_HDR_LINES, 0, VT_LPSTR}, 98 {"Xref", PID_HDR_XREF, 0, VT_LPSTR}, 99 {"Organization", PID_HDR_ORG, 0, VT_LPSTR}, 100 {"X-Newsreader", PID_HDR_XNEWSRDR, 0, VT_LPSTR}, 101 {"X-Priority", PID_HDR_XPRI, 0, VT_LPSTR}, 102 {"X-MSMail-Priority", PID_HDR_XMSPRI, 0, VT_LPSTR}, 103 {"par:content-disposition:filename", PID_PAR_FILENAME, 0, VT_LPSTR}, 104 {"par:content-type:boundary", PID_PAR_BOUNDARY, 0, VT_LPSTR}, 105 {"par:content-type:charset", PID_PAR_CHARSET, 0, VT_LPSTR}, 106 {"par:content-type:name", PID_PAR_NAME, 0, VT_LPSTR}, 107 {"att:filename", PID_ATT_FILENAME, 0, VT_LPSTR}, 108 {"att:pri-content-type", PID_ATT_PRITYPE, 0, VT_LPSTR}, 109 {"att:sub-content-type", PID_ATT_SUBTYPE, 0, VT_LPSTR}, 110 {"att:illegal-lines", PID_ATT_ILLEGAL, 0, VT_LPSTR}, 111 {"att:rendered", PID_ATT_RENDERED, 0, VT_LPSTR}, 112 {"att:sent-time", PID_ATT_SENTTIME, 0, VT_LPSTR}, 113 {"att:priority", PID_ATT_PRIORITY, 0, VT_LPSTR}, 114 {"Comment", PID_HDR_COMMENT, 0, VT_LPSTR}, 115 {"Encoding", PID_HDR_ENCODING, 0, VT_LPSTR}, 116 {"Encrypted", PID_HDR_ENCRYPTED, 0, VT_LPSTR}, 117 {"X-Offsets", PID_HDR_OFFSETS, 0, VT_LPSTR}, 118 {"X-Unsent", PID_HDR_XUNSENT, 0, VT_LPSTR}, 119 {"X-ArticleId", PID_HDR_ARTICLEID, 0, VT_LPSTR}, 120 {"Sender", PID_HDR_SENDER, MPF_ADDRESS, VT_LPSTR}, 121 {"att:athena-server", PID_ATT_SERVER, 0, VT_LPSTR}, 122 {"att:athena-account-id", PID_ATT_ACCOUNT, 0, VT_LPSTR}, 123 {"att:athena-pop3-uidl", PID_ATT_UIDL, 0, VT_LPSTR}, 124 {"att:athena-store-msgid", PID_ATT_STOREMSGID, 0, VT_LPSTR}, 125 {"att:athena-user-name", PID_ATT_USERNAME, 0, VT_LPSTR}, 126 {"att:athena-forward-to", PID_ATT_FORWARDTO, 0, VT_LPSTR}, 127 {"att:athena-store-fdrid", PID_ATT_STOREFOLDERID,0, VT_LPSTR}, 128 {"att:athena-ghosted", PID_ATT_GHOSTED, 0, VT_LPSTR}, 129 {"att:athena-uncachedsize", PID_ATT_UNCACHEDSIZE, 0, VT_LPSTR}, 130 {"att:athena-combined", PID_ATT_COMBINED, 0, VT_LPSTR}, 131 {"att:auto-inlined", PID_ATT_AUTOINLINED, 0, VT_LPSTR}, 132 {"Disposition-Notification-To", PID_HDR_DISP_NOTIFICATION_TO, 0, VT_LPSTR}, 133 {"par:Content-Type:reply-type", PID_PAR_REPLYTYPE, 0, VT_LPSTR}, 134 {"par:Content-Type:format", PID_PAR_FORMAT , 0, VT_LPSTR}, 135 {"att:format", PID_ATT_FORMAT , 0, VT_LPSTR}, 136 {"In-Reply-To", PID_HDR_INREPLYTO, 0, VT_LPSTR}, 137 {"att:athena-account-name", PID_ATT_ACCOUNTNAME, 0, VT_LPSTR}, 138 {NULL, 0, 0, 0} 139 }; 140 141 typedef struct 142 { 143 struct list entry; 144 char *name; 145 char *value; 146 } param_t; 147 148 typedef struct 149 { 150 struct list entry; 151 const property_t *prop; 152 PROPVARIANT value; 153 struct list params; 154 } header_t; 155 156 typedef struct MimeBody 157 { 158 IMimeBody IMimeBody_iface; 159 LONG ref; 160 161 HBODY handle; 162 163 struct list headers; 164 struct list new_props; /* FIXME: This should be in a PropertySchema */ 165 DWORD next_prop_id; 166 char *content_pri_type; 167 char *content_sub_type; 168 ENCODINGTYPE encoding; 169 void *data; 170 IID data_iid; 171 BODYOFFSETS body_offsets; 172 } MimeBody; 173 174 typedef struct 175 { 176 IStream IStream_iface; 177 LONG ref; 178 IStream *base; 179 ULARGE_INTEGER pos, start, length; 180 } sub_stream_t; 181 182 static inline sub_stream_t *impl_from_IStream(IStream *iface) 183 { 184 return CONTAINING_RECORD(iface, sub_stream_t, IStream_iface); 185 } 186 187 static HRESULT WINAPI sub_stream_QueryInterface(IStream *iface, REFIID riid, void **ppv) 188 { 189 sub_stream_t *This = impl_from_IStream(iface); 190 191 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), ppv); 192 *ppv = NULL; 193 194 if(IsEqualIID(riid, &IID_IUnknown) || 195 IsEqualIID(riid, &IID_ISequentialStream) || 196 IsEqualIID(riid, &IID_IStream)) 197 { 198 IStream_AddRef(iface); 199 *ppv = iface; 200 return S_OK; 201 } 202 return E_NOINTERFACE; 203 } 204 205 static ULONG WINAPI sub_stream_AddRef(IStream *iface) 206 { 207 sub_stream_t *This = impl_from_IStream(iface); 208 LONG ref = InterlockedIncrement(&This->ref); 209 210 TRACE("(%p) ref=%d\n", This, ref); 211 212 return ref; 213 } 214 215 static ULONG WINAPI sub_stream_Release(IStream *iface) 216 { 217 sub_stream_t *This = impl_from_IStream(iface); 218 LONG ref = InterlockedDecrement(&This->ref); 219 220 TRACE("(%p) ref=%d\n", This, ref); 221 222 if(!ref) 223 { 224 IStream_Release(This->base); 225 HeapFree(GetProcessHeap(), 0, This); 226 } 227 return ref; 228 } 229 230 static HRESULT WINAPI sub_stream_Read( 231 IStream* iface, 232 void *pv, 233 ULONG cb, 234 ULONG *pcbRead) 235 { 236 sub_stream_t *This = impl_from_IStream(iface); 237 HRESULT hr; 238 LARGE_INTEGER tmp_pos; 239 240 TRACE("(%p, %d, %p)\n", pv, cb, pcbRead); 241 242 tmp_pos.QuadPart = This->pos.QuadPart + This->start.QuadPart; 243 IStream_Seek(This->base, tmp_pos, STREAM_SEEK_SET, NULL); 244 245 if(This->pos.QuadPart + cb > This->length.QuadPart) 246 cb = This->length.QuadPart - This->pos.QuadPart; 247 248 hr = IStream_Read(This->base, pv, cb, pcbRead); 249 250 This->pos.QuadPart += *pcbRead; 251 252 return hr; 253 } 254 255 static HRESULT WINAPI sub_stream_Write( 256 IStream* iface, 257 const void *pv, 258 ULONG cb, 259 ULONG *pcbWritten) 260 { 261 FIXME("stub\n"); 262 return E_NOTIMPL; 263 } 264 265 static HRESULT WINAPI sub_stream_Seek( 266 IStream* iface, 267 LARGE_INTEGER dlibMove, 268 DWORD dwOrigin, 269 ULARGE_INTEGER *plibNewPosition) 270 { 271 sub_stream_t *This = impl_from_IStream(iface); 272 LARGE_INTEGER new_pos; 273 274 TRACE("(%08x.%08x, %x, %p)\n", dlibMove.u.HighPart, dlibMove.u.LowPart, dwOrigin, plibNewPosition); 275 276 switch(dwOrigin) 277 { 278 case STREAM_SEEK_SET: 279 new_pos = dlibMove; 280 break; 281 case STREAM_SEEK_CUR: 282 new_pos.QuadPart = This->pos.QuadPart + dlibMove.QuadPart; 283 break; 284 case STREAM_SEEK_END: 285 new_pos.QuadPart = This->length.QuadPart + dlibMove.QuadPart; 286 break; 287 default: 288 return STG_E_INVALIDFUNCTION; 289 } 290 291 if(new_pos.QuadPart < 0) new_pos.QuadPart = 0; 292 else if(new_pos.QuadPart > This->length.QuadPart) new_pos.QuadPart = This->length.QuadPart; 293 294 This->pos.QuadPart = new_pos.QuadPart; 295 296 if(plibNewPosition) *plibNewPosition = This->pos; 297 return S_OK; 298 } 299 300 static HRESULT WINAPI sub_stream_SetSize( 301 IStream* iface, 302 ULARGE_INTEGER libNewSize) 303 { 304 FIXME("stub\n"); 305 return E_NOTIMPL; 306 } 307 308 static HRESULT WINAPI sub_stream_CopyTo( 309 IStream* iface, 310 IStream *pstm, 311 ULARGE_INTEGER cb, 312 ULARGE_INTEGER *pcbRead, 313 ULARGE_INTEGER *pcbWritten) 314 { 315 HRESULT hr = S_OK; 316 BYTE tmpBuffer[128]; 317 ULONG bytesRead, bytesWritten, copySize; 318 ULARGE_INTEGER totalBytesRead; 319 ULARGE_INTEGER totalBytesWritten; 320 321 TRACE("(%p)->(%p, %d, %p, %p)\n", iface, pstm, cb.u.LowPart, pcbRead, pcbWritten); 322 323 totalBytesRead.QuadPart = 0; 324 totalBytesWritten.QuadPart = 0; 325 326 while ( cb.QuadPart > 0 ) 327 { 328 if ( cb.QuadPart >= sizeof(tmpBuffer) ) 329 copySize = sizeof(tmpBuffer); 330 else 331 copySize = cb.u.LowPart; 332 333 hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead); 334 if (FAILED(hr)) break; 335 336 totalBytesRead.QuadPart += bytesRead; 337 338 if (bytesRead) 339 { 340 hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); 341 if (FAILED(hr)) break; 342 totalBytesWritten.QuadPart += bytesWritten; 343 } 344 345 if (bytesRead != copySize) 346 cb.QuadPart = 0; 347 else 348 cb.QuadPart -= bytesRead; 349 } 350 351 if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart; 352 if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart; 353 354 return hr; 355 } 356 357 static HRESULT WINAPI sub_stream_Commit( 358 IStream* iface, 359 DWORD grfCommitFlags) 360 { 361 FIXME("stub\n"); 362 return E_NOTIMPL; 363 } 364 365 static HRESULT WINAPI sub_stream_Revert( 366 IStream* iface) 367 { 368 FIXME("stub\n"); 369 return E_NOTIMPL; 370 } 371 372 static HRESULT WINAPI sub_stream_LockRegion( 373 IStream* iface, 374 ULARGE_INTEGER libOffset, 375 ULARGE_INTEGER cb, 376 DWORD dwLockType) 377 { 378 FIXME("stub\n"); 379 return E_NOTIMPL; 380 } 381 382 static HRESULT WINAPI sub_stream_UnlockRegion( 383 IStream* iface, 384 ULARGE_INTEGER libOffset, 385 ULARGE_INTEGER cb, 386 DWORD dwLockType) 387 { 388 FIXME("stub\n"); 389 return E_NOTIMPL; 390 } 391 392 static HRESULT WINAPI sub_stream_Stat( 393 IStream* iface, 394 STATSTG *pstatstg, 395 DWORD grfStatFlag) 396 { 397 sub_stream_t *This = impl_from_IStream(iface); 398 FIXME("(%p)->(%p, %08x)\n", This, pstatstg, grfStatFlag); 399 memset(pstatstg, 0, sizeof(*pstatstg)); 400 pstatstg->cbSize = This->length; 401 return S_OK; 402 } 403 404 static HRESULT WINAPI sub_stream_Clone( 405 IStream* iface, 406 IStream **ppstm) 407 { 408 FIXME("stub\n"); 409 return E_NOTIMPL; 410 } 411 412 static struct IStreamVtbl sub_stream_vtbl = 413 { 414 sub_stream_QueryInterface, 415 sub_stream_AddRef, 416 sub_stream_Release, 417 sub_stream_Read, 418 sub_stream_Write, 419 sub_stream_Seek, 420 sub_stream_SetSize, 421 sub_stream_CopyTo, 422 sub_stream_Commit, 423 sub_stream_Revert, 424 sub_stream_LockRegion, 425 sub_stream_UnlockRegion, 426 sub_stream_Stat, 427 sub_stream_Clone 428 }; 429 430 static HRESULT create_sub_stream(IStream *stream, ULARGE_INTEGER start, ULARGE_INTEGER length, IStream **out) 431 { 432 sub_stream_t *This; 433 434 *out = NULL; 435 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 436 if(!This) return E_OUTOFMEMORY; 437 438 This->IStream_iface.lpVtbl = &sub_stream_vtbl; 439 This->ref = 1; 440 This->start = start; 441 This->length = length; 442 This->pos.QuadPart = 0; 443 IStream_AddRef(stream); 444 This->base = stream; 445 446 *out = &This->IStream_iface; 447 return S_OK; 448 } 449 450 static HRESULT get_stream_size(IStream *stream, ULARGE_INTEGER *size) 451 { 452 STATSTG statstg = {NULL}; 453 LARGE_INTEGER zero; 454 HRESULT hres; 455 456 hres = IStream_Stat(stream, &statstg, STATFLAG_NONAME); 457 if(SUCCEEDED(hres)) { 458 *size = statstg.cbSize; 459 return S_OK; 460 } 461 462 zero.QuadPart = 0; 463 return IStream_Seek(stream, zero, STREAM_SEEK_END, size); 464 } 465 466 static inline MimeBody *impl_from_IMimeBody(IMimeBody *iface) 467 { 468 return CONTAINING_RECORD(iface, MimeBody, IMimeBody_iface); 469 } 470 471 typedef struct propschema 472 { 473 IMimePropertySchema IMimePropertySchema_iface; 474 LONG ref; 475 } propschema; 476 477 static inline propschema *impl_from_IMimePropertySchema(IMimePropertySchema *iface) 478 { 479 return CONTAINING_RECORD(iface, propschema, IMimePropertySchema_iface); 480 } 481 482 static LPSTR strdupA(LPCSTR str) 483 { 484 char *ret; 485 int len = strlen(str); 486 ret = HeapAlloc(GetProcessHeap(), 0, len + 1); 487 memcpy(ret, str, len + 1); 488 return ret; 489 } 490 491 #define PARSER_BUF_SIZE 1024 492 493 /***************************************************** 494 * copy_headers_to_buf [internal] 495 * 496 * Copies the headers into a '\0' terminated memory block and leave 497 * the stream's current position set to after the blank line. 498 */ 499 static HRESULT copy_headers_to_buf(IStream *stm, char **ptr) 500 { 501 char *buf = NULL; 502 DWORD size = PARSER_BUF_SIZE, offset = 0, last_end = 0; 503 HRESULT hr; 504 BOOL done = FALSE; 505 506 *ptr = NULL; 507 508 do 509 { 510 char *end; 511 DWORD read; 512 513 if(!buf) 514 buf = HeapAlloc(GetProcessHeap(), 0, size + 1); 515 else 516 { 517 size *= 2; 518 buf = HeapReAlloc(GetProcessHeap(), 0, buf, size + 1); 519 } 520 if(!buf) 521 { 522 hr = E_OUTOFMEMORY; 523 goto fail; 524 } 525 526 hr = IStream_Read(stm, buf + offset, size - offset, &read); 527 if(FAILED(hr)) goto fail; 528 529 offset += read; 530 buf[offset] = '\0'; 531 532 if(read == 0) done = TRUE; 533 534 while(!done && (end = strstr(buf + last_end, "\r\n"))) 535 { 536 DWORD new_end = end - buf + 2; 537 if(new_end - last_end == 2) 538 { 539 LARGE_INTEGER off; 540 off.QuadPart = (LONGLONG)new_end - offset; 541 IStream_Seek(stm, off, STREAM_SEEK_CUR, NULL); 542 buf[new_end] = '\0'; 543 done = TRUE; 544 } 545 else 546 last_end = new_end; 547 } 548 } while(!done); 549 550 *ptr = buf; 551 return S_OK; 552 553 fail: 554 HeapFree(GetProcessHeap(), 0, buf); 555 return hr; 556 } 557 558 static header_t *read_prop(MimeBody *body, char **ptr) 559 { 560 char *colon = strchr(*ptr, ':'); 561 const property_t *prop; 562 header_t *ret; 563 564 if(!colon) return NULL; 565 566 *colon = '\0'; 567 568 for(prop = default_props; prop->name; prop++) 569 { 570 if(!lstrcmpiA(*ptr, prop->name)) 571 { 572 TRACE("%s: found match with default property id %d\n", *ptr, prop->id); 573 break; 574 } 575 } 576 577 if(!prop->name) 578 { 579 property_list_entry_t *prop_entry; 580 LIST_FOR_EACH_ENTRY(prop_entry, &body->new_props, property_list_entry_t, entry) 581 { 582 if(!lstrcmpiA(*ptr, prop_entry->prop.name)) 583 { 584 TRACE("%s: found match with already added new property id %d\n", *ptr, prop_entry->prop.id); 585 prop = &prop_entry->prop; 586 break; 587 } 588 } 589 if(!prop->name) 590 { 591 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry)); 592 prop_entry->prop.name = strdupA(*ptr); 593 prop_entry->prop.id = body->next_prop_id++; 594 prop_entry->prop.flags = 0; 595 prop_entry->prop.default_vt = VT_LPSTR; 596 list_add_tail(&body->new_props, &prop_entry->entry); 597 prop = &prop_entry->prop; 598 TRACE("%s: allocating new prop id %d\n", *ptr, prop_entry->prop.id); 599 } 600 } 601 602 ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); 603 ret->prop = prop; 604 PropVariantInit(&ret->value); 605 list_init(&ret->params); 606 *ptr = colon + 1; 607 608 return ret; 609 } 610 611 static void unfold_header(char *header, int len) 612 { 613 char *start = header, *cp = header; 614 615 do { 616 while(*cp == ' ' || *cp == '\t') 617 { 618 cp++; 619 len--; 620 } 621 if(cp != start) 622 memmove(start, cp, len + 1); 623 624 cp = strstr(start, "\r\n"); 625 len -= (cp - start); 626 start = cp; 627 *start = ' '; 628 start++; 629 len--; 630 cp += 2; 631 } while(*cp == ' ' || *cp == '\t'); 632 633 *(start - 1) = '\0'; 634 } 635 636 static char *unquote_string(const char *str) 637 { 638 BOOL quoted = FALSE; 639 char *ret, *cp; 640 641 while(*str == ' ' || *str == '\t') str++; 642 643 if(*str == '"') 644 { 645 quoted = TRUE; 646 str++; 647 } 648 ret = strdupA(str); 649 for(cp = ret; *cp; cp++) 650 { 651 if(*cp == '\\') 652 memmove(cp, cp + 1, strlen(cp + 1) + 1); 653 else if(*cp == '"') 654 { 655 if(!quoted) 656 { 657 WARN("quote in unquoted string\n"); 658 } 659 else 660 { 661 *cp = '\0'; 662 break; 663 } 664 } 665 } 666 return ret; 667 } 668 669 static void add_param(header_t *header, const char *p) 670 { 671 const char *key = p, *value, *cp = p; 672 param_t *param; 673 char *name; 674 675 TRACE("got param %s\n", p); 676 677 while (*key == ' ' || *key == '\t' ) key++; 678 679 cp = strchr(key, '='); 680 if(!cp) 681 { 682 WARN("malformed parameter - skipping\n"); 683 return; 684 } 685 686 name = HeapAlloc(GetProcessHeap(), 0, cp - key + 1); 687 memcpy(name, key, cp - key); 688 name[cp - key] = '\0'; 689 690 value = cp + 1; 691 692 param = HeapAlloc(GetProcessHeap(), 0, sizeof(*param)); 693 param->name = name; 694 param->value = unquote_string(value); 695 list_add_tail(&header->params, ¶m->entry); 696 } 697 698 static void split_params(header_t *header, char *value) 699 { 700 char *cp = value, *start = value; 701 BOOL in_quotes = FALSE, done_value = FALSE; 702 703 while(*cp) 704 { 705 if(!in_quotes && *cp == ';') 706 { 707 *cp = '\0'; 708 if(done_value) add_param(header, start); 709 done_value = TRUE; 710 start = cp + 1; 711 } 712 else if(*cp == '"') 713 in_quotes = !in_quotes; 714 cp++; 715 } 716 if(done_value) add_param(header, start); 717 } 718 719 static void read_value(header_t *header, char **cur) 720 { 721 char *end = *cur, *value; 722 DWORD len; 723 724 do { 725 end = strstr(end, "\r\n"); 726 end += 2; 727 } while(*end == ' ' || *end == '\t'); 728 729 len = end - *cur; 730 value = HeapAlloc(GetProcessHeap(), 0, len + 1); 731 memcpy(value, *cur, len); 732 value[len] = '\0'; 733 734 unfold_header(value, len); 735 TRACE("value %s\n", debugstr_a(value)); 736 737 if(header->prop->flags & MPF_HASPARAMS) 738 { 739 split_params(header, value); 740 TRACE("value w/o params %s\n", debugstr_a(value)); 741 } 742 743 header->value.vt = VT_LPSTR; 744 header->value.u.pszVal = value; 745 746 *cur = end; 747 } 748 749 static void init_content_type(MimeBody *body, header_t *header) 750 { 751 char *slash; 752 DWORD len; 753 754 slash = strchr(header->value.u.pszVal, '/'); 755 if(!slash) 756 { 757 WARN("malformed context type value\n"); 758 return; 759 } 760 len = slash - header->value.u.pszVal; 761 body->content_pri_type = HeapAlloc(GetProcessHeap(), 0, len + 1); 762 memcpy(body->content_pri_type, header->value.u.pszVal, len); 763 body->content_pri_type[len] = '\0'; 764 body->content_sub_type = strdupA(slash + 1); 765 } 766 767 static void init_content_encoding(MimeBody *body, header_t *header) 768 { 769 const char *encoding = header->value.u.pszVal; 770 771 if(!strcasecmp(encoding, "base64")) 772 body->encoding = IET_BASE64; 773 else if(!strcasecmp(encoding, "quoted-printable")) 774 body->encoding = IET_QP; 775 else if(!strcasecmp(encoding, "7bit")) 776 body->encoding = IET_7BIT; 777 else if(!strcasecmp(encoding, "8bit")) 778 body->encoding = IET_8BIT; 779 else 780 FIXME("unknown encoding %s\n", debugstr_a(encoding)); 781 } 782 783 static HRESULT parse_headers(MimeBody *body, IStream *stm) 784 { 785 char *header_buf, *cur_header_ptr; 786 HRESULT hr; 787 header_t *header; 788 789 hr = copy_headers_to_buf(stm, &header_buf); 790 if(FAILED(hr)) return hr; 791 792 cur_header_ptr = header_buf; 793 while((header = read_prop(body, &cur_header_ptr))) 794 { 795 read_value(header, &cur_header_ptr); 796 list_add_tail(&body->headers, &header->entry); 797 798 switch(header->prop->id) { 799 case PID_HDR_CNTTYPE: 800 init_content_type(body, header); 801 break; 802 case PID_HDR_CNTXFER: 803 init_content_encoding(body, header); 804 break; 805 } 806 } 807 808 HeapFree(GetProcessHeap(), 0, header_buf); 809 return hr; 810 } 811 812 static void empty_param_list(struct list *list) 813 { 814 param_t *param, *cursor2; 815 816 LIST_FOR_EACH_ENTRY_SAFE(param, cursor2, list, param_t, entry) 817 { 818 list_remove(¶m->entry); 819 HeapFree(GetProcessHeap(), 0, param->name); 820 HeapFree(GetProcessHeap(), 0, param->value); 821 HeapFree(GetProcessHeap(), 0, param); 822 } 823 } 824 825 static void empty_header_list(struct list *list) 826 { 827 header_t *header, *cursor2; 828 829 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry) 830 { 831 list_remove(&header->entry); 832 PropVariantClear(&header->value); 833 empty_param_list(&header->params); 834 HeapFree(GetProcessHeap(), 0, header); 835 } 836 } 837 838 static void empty_new_prop_list(struct list *list) 839 { 840 property_list_entry_t *prop, *cursor2; 841 842 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry) 843 { 844 list_remove(&prop->entry); 845 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name); 846 HeapFree(GetProcessHeap(), 0, prop); 847 } 848 } 849 850 static void release_data(REFIID riid, void *data) 851 { 852 if(!data) return; 853 854 if(IsEqualIID(riid, &IID_IStream)) 855 IStream_Release((IStream *)data); 856 else 857 FIXME("Unhandled data format %s\n", debugstr_guid(riid)); 858 } 859 860 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop) 861 { 862 header_t *header; 863 864 *prop = NULL; 865 866 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry) 867 { 868 if(ISPIDSTR(name)) 869 { 870 if(STRTOPID(name) == header->prop->id) 871 { 872 *prop = header; 873 return S_OK; 874 } 875 } 876 else if(!lstrcmpiA(name, header->prop->name)) 877 { 878 *prop = header; 879 return S_OK; 880 } 881 } 882 883 return MIME_E_NOT_FOUND; 884 } 885 886 static const property_t *find_default_prop(const char *name) 887 { 888 const property_t *prop_def = NULL; 889 890 for(prop_def = default_props; prop_def->name; prop_def++) 891 { 892 if(ISPIDSTR(name)) 893 { 894 if(STRTOPID(name) == prop_def->id) 895 { 896 break; 897 } 898 } 899 else if(!lstrcmpiA(name, prop_def->name)) 900 { 901 break; 902 } 903 } 904 905 if(prop_def->id) 906 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id); 907 else 908 prop_def = NULL; 909 910 return prop_def; 911 } 912 913 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface, 914 REFIID riid, 915 void** ppvObject) 916 { 917 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject); 918 919 *ppvObject = NULL; 920 921 if (IsEqualIID(riid, &IID_IUnknown) || 922 IsEqualIID(riid, &IID_IPersist) || 923 IsEqualIID(riid, &IID_IPersistStreamInit) || 924 IsEqualIID(riid, &IID_IMimePropertySet) || 925 IsEqualIID(riid, &IID_IMimeBody)) 926 { 927 *ppvObject = iface; 928 } 929 930 if(*ppvObject) 931 { 932 IUnknown_AddRef((IUnknown*)*ppvObject); 933 return S_OK; 934 } 935 936 FIXME("no interface for %s\n", debugstr_guid(riid)); 937 return E_NOINTERFACE; 938 } 939 940 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface) 941 { 942 MimeBody *This = impl_from_IMimeBody(iface); 943 LONG ref = InterlockedIncrement(&This->ref); 944 945 TRACE("(%p) ref=%d\n", This, ref); 946 947 return ref; 948 } 949 950 static ULONG WINAPI MimeBody_Release(IMimeBody *iface) 951 { 952 MimeBody *This = impl_from_IMimeBody(iface); 953 LONG ref = InterlockedDecrement(&This->ref); 954 955 TRACE("(%p) ref=%d\n", This, ref); 956 957 if (!ref) 958 { 959 empty_header_list(&This->headers); 960 empty_new_prop_list(&This->new_props); 961 962 HeapFree(GetProcessHeap(), 0, This->content_pri_type); 963 HeapFree(GetProcessHeap(), 0, This->content_sub_type); 964 965 release_data(&This->data_iid, This->data); 966 967 HeapFree(GetProcessHeap(), 0, This); 968 } 969 970 return ref; 971 } 972 973 static HRESULT WINAPI MimeBody_GetClassID( 974 IMimeBody* iface, 975 CLSID* pClassID) 976 { 977 MimeBody *This = impl_from_IMimeBody(iface); 978 979 TRACE("(%p)->(%p)\n", This, pClassID); 980 981 if(!pClassID) 982 return E_INVALIDARG; 983 984 *pClassID = IID_IMimeBody; 985 return S_OK; 986 } 987 988 static HRESULT WINAPI MimeBody_IsDirty( 989 IMimeBody* iface) 990 { 991 MimeBody *This = impl_from_IMimeBody(iface); 992 FIXME("(%p)->() stub\n", This); 993 return E_NOTIMPL; 994 } 995 996 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm) 997 { 998 MimeBody *This = impl_from_IMimeBody(iface); 999 TRACE("(%p)->(%p)\n", This, pStm); 1000 return parse_headers(This, pStm); 1001 } 1002 1003 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty) 1004 { 1005 MimeBody *This = impl_from_IMimeBody(iface); 1006 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty); 1007 return E_NOTIMPL; 1008 } 1009 1010 static HRESULT WINAPI MimeBody_GetSizeMax( 1011 IMimeBody* iface, 1012 ULARGE_INTEGER* pcbSize) 1013 { 1014 MimeBody *This = impl_from_IMimeBody(iface); 1015 FIXME("(%p)->(%p) stub\n", This, pcbSize); 1016 return E_NOTIMPL; 1017 } 1018 1019 static HRESULT WINAPI MimeBody_InitNew( 1020 IMimeBody* iface) 1021 { 1022 MimeBody *This = impl_from_IMimeBody(iface); 1023 TRACE("(%p)->()\n", This); 1024 return S_OK; 1025 } 1026 1027 static HRESULT WINAPI MimeBody_GetPropInfo( 1028 IMimeBody* iface, 1029 LPCSTR pszName, 1030 LPMIMEPROPINFO pInfo) 1031 { 1032 MimeBody *This = impl_from_IMimeBody(iface); 1033 header_t *header; 1034 HRESULT hr; 1035 DWORD supported = PIM_PROPID | PIM_VTDEFAULT; 1036 1037 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo); 1038 1039 if(!pszName || !pInfo) 1040 return E_INVALIDARG; 1041 1042 TRACE("mask 0x%04x\n", pInfo->dwMask); 1043 1044 if(pInfo->dwMask & ~supported) 1045 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported); 1046 1047 hr = find_prop(This, pszName, &header); 1048 if(hr == S_OK) 1049 { 1050 if(pInfo->dwMask & PIM_CHARSET) 1051 pInfo->hCharset = 0; 1052 if(pInfo->dwMask & PIM_FLAGS) 1053 pInfo->dwFlags = 0x00000000; 1054 if(pInfo->dwMask & PIM_ROWNUMBER) 1055 pInfo->dwRowNumber = 0; 1056 if(pInfo->dwMask & PIM_ENCODINGTYPE) 1057 pInfo->ietEncoding = 0; 1058 if(pInfo->dwMask & PIM_VALUES) 1059 pInfo->cValues = 0; 1060 if(pInfo->dwMask & PIM_PROPID) 1061 pInfo->dwPropId = header->prop->id; 1062 if(pInfo->dwMask & PIM_VTDEFAULT) 1063 pInfo->vtDefault = header->prop->default_vt; 1064 if(pInfo->dwMask & PIM_VTCURRENT) 1065 pInfo->vtCurrent = 0; 1066 } 1067 1068 return hr; 1069 } 1070 1071 static HRESULT WINAPI MimeBody_SetPropInfo( 1072 IMimeBody* iface, 1073 LPCSTR pszName, 1074 LPCMIMEPROPINFO pInfo) 1075 { 1076 MimeBody *This = impl_from_IMimeBody(iface); 1077 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo); 1078 return E_NOTIMPL; 1079 } 1080 1081 static HRESULT WINAPI MimeBody_GetProp( 1082 IMimeBody* iface, 1083 LPCSTR pszName, 1084 DWORD dwFlags, 1085 LPPROPVARIANT pValue) 1086 { 1087 MimeBody *This = impl_from_IMimeBody(iface); 1088 header_t *header; 1089 HRESULT hr; 1090 1091 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue); 1092 1093 if(!pszName || !pValue) 1094 return E_INVALIDARG; 1095 1096 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type")) 1097 { 1098 PropVariantClear(pValue); 1099 pValue->vt = VT_LPSTR; 1100 pValue->u.pszVal = strdupA(This->content_pri_type); 1101 return S_OK; 1102 } 1103 1104 hr = find_prop(This, pszName, &header); 1105 if(hr == S_OK) 1106 { 1107 TRACE("type %d->%d\n", header->value.vt, pValue->vt); 1108 1109 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt); 1110 if(FAILED(hr)) 1111 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt); 1112 } 1113 1114 return hr; 1115 } 1116 1117 static HRESULT WINAPI MimeBody_SetProp( 1118 IMimeBody* iface, 1119 LPCSTR pszName, 1120 DWORD dwFlags, 1121 LPCPROPVARIANT pValue) 1122 { 1123 MimeBody *This = impl_from_IMimeBody(iface); 1124 header_t *header; 1125 HRESULT hr; 1126 1127 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue); 1128 1129 if(!pszName || !pValue) 1130 return E_INVALIDARG; 1131 1132 hr = find_prop(This, pszName, &header); 1133 if(hr != S_OK) 1134 { 1135 property_list_entry_t *prop_entry; 1136 const property_t *prop = NULL; 1137 1138 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry) 1139 { 1140 if(ISPIDSTR(pszName)) 1141 { 1142 if(STRTOPID(pszName) == prop_entry->prop.id) 1143 { 1144 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id); 1145 prop = &prop_entry->prop; 1146 break; 1147 } 1148 } 1149 else if(!lstrcmpiA(pszName, prop_entry->prop.name)) 1150 { 1151 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id); 1152 prop = &prop_entry->prop; 1153 break; 1154 } 1155 } 1156 1157 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header)); 1158 if(!header) 1159 return E_OUTOFMEMORY; 1160 1161 if(!prop) 1162 { 1163 const property_t *prop_def = NULL; 1164 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry)); 1165 if(!prop_entry) 1166 { 1167 HeapFree(GetProcessHeap(), 0, header); 1168 return E_OUTOFMEMORY; 1169 } 1170 1171 prop_def = find_default_prop(pszName); 1172 if(prop_def) 1173 { 1174 prop_entry->prop.name = strdupA(prop_def->name); 1175 prop_entry->prop.id = prop_def->id; 1176 } 1177 else 1178 { 1179 if(ISPIDSTR(pszName)) 1180 { 1181 HeapFree(GetProcessHeap(), 0, prop_entry); 1182 HeapFree(GetProcessHeap(), 0, header); 1183 return MIME_E_NOT_FOUND; 1184 } 1185 1186 prop_entry->prop.name = strdupA(pszName); 1187 prop_entry->prop.id = This->next_prop_id++; 1188 } 1189 1190 prop_entry->prop.flags = 0; 1191 prop_entry->prop.default_vt = pValue->vt; 1192 list_add_tail(&This->new_props, &prop_entry->entry); 1193 prop = &prop_entry->prop; 1194 TRACE("Allocating new prop id %d\n", prop_entry->prop.id); 1195 } 1196 1197 header->prop = prop; 1198 PropVariantInit(&header->value); 1199 list_init(&header->params); 1200 list_add_tail(&This->headers, &header->entry); 1201 } 1202 1203 PropVariantCopy(&header->value, pValue); 1204 1205 return S_OK; 1206 } 1207 1208 static HRESULT WINAPI MimeBody_AppendProp( 1209 IMimeBody* iface, 1210 LPCSTR pszName, 1211 DWORD dwFlags, 1212 LPPROPVARIANT pValue) 1213 { 1214 MimeBody *This = impl_from_IMimeBody(iface); 1215 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue); 1216 return E_NOTIMPL; 1217 } 1218 1219 static HRESULT WINAPI MimeBody_DeleteProp( 1220 IMimeBody* iface, 1221 LPCSTR pszName) 1222 { 1223 MimeBody *This = impl_from_IMimeBody(iface); 1224 header_t *cursor; 1225 BOOL found; 1226 1227 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName)); 1228 1229 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry) 1230 { 1231 if(ISPIDSTR(pszName)) 1232 found = STRTOPID(pszName) == cursor->prop->id; 1233 else 1234 found = !lstrcmpiA(pszName, cursor->prop->name); 1235 1236 if(found) 1237 { 1238 list_remove(&cursor->entry); 1239 HeapFree(GetProcessHeap(), 0, cursor); 1240 return S_OK; 1241 } 1242 } 1243 1244 return MIME_E_NOT_FOUND; 1245 } 1246 1247 static HRESULT WINAPI MimeBody_CopyProps( 1248 IMimeBody* iface, 1249 ULONG cNames, 1250 LPCSTR* prgszName, 1251 IMimePropertySet* pPropertySet) 1252 { 1253 MimeBody *This = impl_from_IMimeBody(iface); 1254 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet); 1255 return E_NOTIMPL; 1256 } 1257 1258 static HRESULT WINAPI MimeBody_MoveProps( 1259 IMimeBody* iface, 1260 ULONG cNames, 1261 LPCSTR* prgszName, 1262 IMimePropertySet* pPropertySet) 1263 { 1264 MimeBody *This = impl_from_IMimeBody(iface); 1265 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet); 1266 return E_NOTIMPL; 1267 } 1268 1269 static HRESULT WINAPI MimeBody_DeleteExcept( 1270 IMimeBody* iface, 1271 ULONG cNames, 1272 LPCSTR* prgszName) 1273 { 1274 MimeBody *This = impl_from_IMimeBody(iface); 1275 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName); 1276 return E_NOTIMPL; 1277 } 1278 1279 static HRESULT WINAPI MimeBody_QueryProp( 1280 IMimeBody* iface, 1281 LPCSTR pszName, 1282 LPCSTR pszCriteria, 1283 boolean fSubString, 1284 boolean fCaseSensitive) 1285 { 1286 MimeBody *This = impl_from_IMimeBody(iface); 1287 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive); 1288 return E_NOTIMPL; 1289 } 1290 1291 static HRESULT WINAPI MimeBody_GetCharset( 1292 IMimeBody* iface, 1293 LPHCHARSET phCharset) 1294 { 1295 MimeBody *This = impl_from_IMimeBody(iface); 1296 FIXME("(%p)->(%p) stub\n", This, phCharset); 1297 *phCharset = NULL; 1298 return S_OK; 1299 } 1300 1301 static HRESULT WINAPI MimeBody_SetCharset( 1302 IMimeBody* iface, 1303 HCHARSET hCharset, 1304 CSETAPPLYTYPE applytype) 1305 { 1306 MimeBody *This = impl_from_IMimeBody(iface); 1307 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype); 1308 return E_NOTIMPL; 1309 } 1310 1311 static HRESULT WINAPI MimeBody_GetParameters( 1312 IMimeBody* iface, 1313 LPCSTR pszName, 1314 ULONG* pcParams, 1315 LPMIMEPARAMINFO* pprgParam) 1316 { 1317 MimeBody *This = impl_from_IMimeBody(iface); 1318 HRESULT hr; 1319 header_t *header; 1320 1321 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam); 1322 1323 *pprgParam = NULL; 1324 *pcParams = 0; 1325 1326 hr = find_prop(This, pszName, &header); 1327 if(hr != S_OK) return hr; 1328 1329 *pcParams = list_count(&header->params); 1330 if(*pcParams) 1331 { 1332 IMimeAllocator *alloc; 1333 param_t *param; 1334 MIMEPARAMINFO *info; 1335 1336 MimeOleGetAllocator(&alloc); 1337 1338 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam)); 1339 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry) 1340 { 1341 int len; 1342 1343 len = strlen(param->name) + 1; 1344 info->pszName = IMimeAllocator_Alloc(alloc, len); 1345 memcpy(info->pszName, param->name, len); 1346 len = strlen(param->value) + 1; 1347 info->pszData = IMimeAllocator_Alloc(alloc, len); 1348 memcpy(info->pszData, param->value, len); 1349 info++; 1350 } 1351 IMimeAllocator_Release(alloc); 1352 } 1353 return S_OK; 1354 } 1355 1356 static HRESULT WINAPI MimeBody_IsContentType( 1357 IMimeBody* iface, 1358 LPCSTR pszPriType, 1359 LPCSTR pszSubType) 1360 { 1361 MimeBody *This = impl_from_IMimeBody(iface); 1362 1363 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType)); 1364 if(pszPriType) 1365 { 1366 const char *pri = This->content_pri_type; 1367 if(!pri) pri = "text"; 1368 if(lstrcmpiA(pri, pszPriType)) return S_FALSE; 1369 } 1370 1371 if(pszSubType) 1372 { 1373 const char *sub = This->content_sub_type; 1374 if(!sub) sub = "plain"; 1375 if(lstrcmpiA(sub, pszSubType)) return S_FALSE; 1376 } 1377 1378 return S_OK; 1379 } 1380 1381 static HRESULT WINAPI MimeBody_BindToObject( 1382 IMimeBody* iface, 1383 REFIID riid, 1384 void** ppvObject) 1385 { 1386 MimeBody *This = impl_from_IMimeBody(iface); 1387 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject); 1388 return E_NOTIMPL; 1389 } 1390 1391 static HRESULT WINAPI MimeBody_Clone( 1392 IMimeBody* iface, 1393 IMimePropertySet** ppPropertySet) 1394 { 1395 MimeBody *This = impl_from_IMimeBody(iface); 1396 FIXME("(%p)->(%p) stub\n", This, ppPropertySet); 1397 return E_NOTIMPL; 1398 } 1399 1400 static HRESULT WINAPI MimeBody_SetOption( 1401 IMimeBody* iface, 1402 const TYPEDID oid, 1403 LPCPROPVARIANT pValue) 1404 { 1405 MimeBody *This = impl_from_IMimeBody(iface); 1406 HRESULT hr = E_NOTIMPL; 1407 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue); 1408 1409 if(pValue->vt != TYPEDID_TYPE(oid)) 1410 { 1411 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid); 1412 return E_INVALIDARG; 1413 } 1414 1415 switch(oid) 1416 { 1417 case OID_SECURITY_HWND_OWNER: 1418 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal); 1419 hr = S_OK; 1420 break; 1421 case OID_TRANSMIT_BODY_ENCODING: 1422 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal); 1423 hr = S_OK; 1424 break; 1425 default: 1426 FIXME("Unhandled oid %08x\n", oid); 1427 } 1428 1429 return hr; 1430 } 1431 1432 static HRESULT WINAPI MimeBody_GetOption( 1433 IMimeBody* iface, 1434 const TYPEDID oid, 1435 LPPROPVARIANT pValue) 1436 { 1437 MimeBody *This = impl_from_IMimeBody(iface); 1438 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue); 1439 return E_NOTIMPL; 1440 } 1441 1442 static HRESULT WINAPI MimeBody_EnumProps( 1443 IMimeBody* iface, 1444 DWORD dwFlags, 1445 IMimeEnumProperties** ppEnum) 1446 { 1447 MimeBody *This = impl_from_IMimeBody(iface); 1448 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum); 1449 return E_NOTIMPL; 1450 } 1451 1452 static HRESULT WINAPI MimeBody_IsType( 1453 IMimeBody* iface, 1454 IMSGBODYTYPE bodytype) 1455 { 1456 MimeBody *This = impl_from_IMimeBody(iface); 1457 1458 TRACE("(%p)->(%d)\n", This, bodytype); 1459 switch(bodytype) 1460 { 1461 case IBT_EMPTY: 1462 return This->data ? S_FALSE : S_OK; 1463 default: 1464 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype); 1465 } 1466 return S_OK; 1467 } 1468 1469 static HRESULT WINAPI MimeBody_SetDisplayName( 1470 IMimeBody* iface, 1471 LPCSTR pszDisplay) 1472 { 1473 MimeBody *This = impl_from_IMimeBody(iface); 1474 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay)); 1475 return E_NOTIMPL; 1476 } 1477 1478 static HRESULT WINAPI MimeBody_GetDisplayName( 1479 IMimeBody* iface, 1480 LPSTR* ppszDisplay) 1481 { 1482 MimeBody *This = impl_from_IMimeBody(iface); 1483 FIXME("(%p)->(%p) stub\n", This, ppszDisplay); 1484 return E_NOTIMPL; 1485 } 1486 1487 static HRESULT WINAPI MimeBody_GetOffsets( 1488 IMimeBody* iface, 1489 LPBODYOFFSETS pOffsets) 1490 { 1491 MimeBody *This = impl_from_IMimeBody(iface); 1492 TRACE("(%p)->(%p)\n", This, pOffsets); 1493 1494 *pOffsets = This->body_offsets; 1495 1496 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA; 1497 return S_OK; 1498 } 1499 1500 static HRESULT WINAPI MimeBody_GetCurrentEncoding( 1501 IMimeBody* iface, 1502 ENCODINGTYPE* pietEncoding) 1503 { 1504 MimeBody *This = impl_from_IMimeBody(iface); 1505 1506 TRACE("(%p)->(%p)\n", This, pietEncoding); 1507 1508 *pietEncoding = This->encoding; 1509 return S_OK; 1510 } 1511 1512 static HRESULT WINAPI MimeBody_SetCurrentEncoding( 1513 IMimeBody* iface, 1514 ENCODINGTYPE ietEncoding) 1515 { 1516 MimeBody *This = impl_from_IMimeBody(iface); 1517 1518 TRACE("(%p)->(%d)\n", This, ietEncoding); 1519 1520 This->encoding = ietEncoding; 1521 return S_OK; 1522 } 1523 1524 static HRESULT WINAPI MimeBody_GetEstimatedSize( 1525 IMimeBody* iface, 1526 ENCODINGTYPE ietEncoding, 1527 ULONG* pcbSize) 1528 { 1529 MimeBody *This = impl_from_IMimeBody(iface); 1530 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize); 1531 return E_NOTIMPL; 1532 } 1533 1534 static HRESULT WINAPI MimeBody_GetDataHere( 1535 IMimeBody* iface, 1536 ENCODINGTYPE ietEncoding, 1537 IStream* pStream) 1538 { 1539 MimeBody *This = impl_from_IMimeBody(iface); 1540 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream); 1541 return E_NOTIMPL; 1542 } 1543 1544 static const signed char base64_decode_table[] = 1545 { 1546 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */ 1547 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */ 1548 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */ 1549 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */ 1550 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */ 1551 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */ 1552 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */ 1553 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */ 1554 }; 1555 1556 static HRESULT decode_base64(IStream *input, IStream **ret_stream) 1557 { 1558 const unsigned char *ptr, *end; 1559 unsigned char buf[1024]; 1560 LARGE_INTEGER pos; 1561 unsigned char *ret; 1562 unsigned char in[4]; 1563 IStream *output; 1564 DWORD size; 1565 int n = 0; 1566 HRESULT hres; 1567 1568 pos.QuadPart = 0; 1569 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL); 1570 if(FAILED(hres)) 1571 return hres; 1572 1573 hres = CreateStreamOnHGlobal(NULL, TRUE, &output); 1574 if(FAILED(hres)) 1575 return hres; 1576 1577 while(1) { 1578 hres = IStream_Read(input, buf, sizeof(buf), &size); 1579 if(FAILED(hres) || !size) 1580 break; 1581 1582 ptr = ret = buf; 1583 end = buf + size; 1584 1585 while(1) { 1586 /* skip invalid chars */ 1587 while(ptr < end && 1588 (*ptr >= sizeof(base64_decode_table)/sizeof(*base64_decode_table) 1589 || base64_decode_table[*ptr] == -1)) 1590 ptr++; 1591 if(ptr == end) 1592 break; 1593 1594 in[n++] = base64_decode_table[*ptr++]; 1595 switch(n) { 1596 case 2: 1597 *ret++ = in[0] << 2 | in[1] >> 4; 1598 continue; 1599 case 3: 1600 *ret++ = in[1] << 4 | in[2] >> 2; 1601 continue; 1602 case 4: 1603 *ret++ = ((in[2] << 6) & 0xc0) | in[3]; 1604 n = 0; 1605 } 1606 } 1607 1608 if(ret > buf) { 1609 hres = IStream_Write(output, buf, ret - buf, NULL); 1610 if(FAILED(hres)) 1611 break; 1612 } 1613 } 1614 1615 if(SUCCEEDED(hres)) 1616 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL); 1617 if(FAILED(hres)) { 1618 IStream_Release(output); 1619 return hres; 1620 } 1621 1622 *ret_stream = output; 1623 return S_OK; 1624 } 1625 1626 static int hex_digit(char c) 1627 { 1628 if('0' <= c && c <= '9') 1629 return c - '0'; 1630 if('A' <= c && c <= 'F') 1631 return c - 'A' + 10; 1632 if('a' <= c && c <= 'f') 1633 return c - 'a' + 10; 1634 return -1; 1635 } 1636 1637 static HRESULT decode_qp(IStream *input, IStream **ret_stream) 1638 { 1639 const unsigned char *ptr, *end; 1640 unsigned char *ret, prev = 0; 1641 unsigned char buf[1024]; 1642 LARGE_INTEGER pos; 1643 IStream *output; 1644 DWORD size; 1645 int n = -1; 1646 HRESULT hres; 1647 1648 pos.QuadPart = 0; 1649 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL); 1650 if(FAILED(hres)) 1651 return hres; 1652 1653 hres = CreateStreamOnHGlobal(NULL, TRUE, &output); 1654 if(FAILED(hres)) 1655 return hres; 1656 1657 while(1) { 1658 hres = IStream_Read(input, buf, sizeof(buf), &size); 1659 if(FAILED(hres) || !size) 1660 break; 1661 1662 ptr = ret = buf; 1663 end = buf + size; 1664 1665 while(ptr < end) { 1666 unsigned char byte = *ptr++; 1667 1668 switch(n) { 1669 case -1: 1670 if(byte == '=') 1671 n = 0; 1672 else 1673 *ret++ = byte; 1674 continue; 1675 case 0: 1676 prev = byte; 1677 n = 1; 1678 continue; 1679 case 1: 1680 if(prev != '\r' || byte != '\n') { 1681 int h1 = hex_digit(prev), h2 = hex_digit(byte); 1682 if(h1 != -1 && h2 != -1) 1683 *ret++ = (h1 << 4) | h2; 1684 else 1685 *ret++ = '='; 1686 } 1687 n = -1; 1688 continue; 1689 } 1690 } 1691 1692 if(ret > buf) { 1693 hres = IStream_Write(output, buf, ret - buf, NULL); 1694 if(FAILED(hres)) 1695 break; 1696 } 1697 } 1698 1699 if(SUCCEEDED(hres)) 1700 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL); 1701 if(FAILED(hres)) { 1702 IStream_Release(output); 1703 return hres; 1704 } 1705 1706 *ret_stream = output; 1707 return S_OK; 1708 } 1709 1710 static HRESULT WINAPI MimeBody_GetData( 1711 IMimeBody* iface, 1712 ENCODINGTYPE ietEncoding, 1713 IStream** ppStream) 1714 { 1715 MimeBody *This = impl_from_IMimeBody(iface); 1716 ULARGE_INTEGER start, size; 1717 HRESULT hres; 1718 1719 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream); 1720 1721 if(This->encoding != ietEncoding) { 1722 switch(This->encoding) { 1723 case IET_BASE64: 1724 hres = decode_base64(This->data, ppStream); 1725 break; 1726 case IET_QP: 1727 hres = decode_qp(This->data, ppStream); 1728 break; 1729 default: 1730 FIXME("Decoding %d is not supported.\n", This->encoding); 1731 hres = S_FALSE; 1732 } 1733 if(ietEncoding != IET_BINARY) 1734 FIXME("Encoding %d is not supported.\n", ietEncoding); 1735 if(hres != S_FALSE) 1736 return hres; 1737 } 1738 1739 start.QuadPart = 0; 1740 hres = get_stream_size(This->data, &size); 1741 if(SUCCEEDED(hres)) 1742 hres = create_sub_stream(This->data, start, size, ppStream); 1743 return hres; 1744 } 1745 1746 static HRESULT WINAPI MimeBody_SetData( 1747 IMimeBody* iface, 1748 ENCODINGTYPE ietEncoding, 1749 LPCSTR pszPriType, 1750 LPCSTR pszSubType, 1751 REFIID riid, 1752 LPVOID pvObject) 1753 { 1754 MimeBody *This = impl_from_IMimeBody(iface); 1755 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType), 1756 debugstr_guid(riid), pvObject); 1757 1758 if(IsEqualIID(riid, &IID_IStream)) 1759 IStream_AddRef((IStream *)pvObject); 1760 else 1761 { 1762 FIXME("Unhandled object type %s\n", debugstr_guid(riid)); 1763 return E_INVALIDARG; 1764 } 1765 1766 if(This->data) 1767 release_data(&This->data_iid, This->data); 1768 1769 This->data_iid = *riid; 1770 This->data = pvObject; 1771 1772 IMimeBody_SetCurrentEncoding(iface, ietEncoding); 1773 1774 /* FIXME: Update the content type. 1775 If pszPriType == NULL use 'application' 1776 If pszSubType == NULL use 'octet-stream' */ 1777 1778 return S_OK; 1779 } 1780 1781 static HRESULT WINAPI MimeBody_EmptyData( 1782 IMimeBody* iface) 1783 { 1784 MimeBody *This = impl_from_IMimeBody(iface); 1785 FIXME("(%p)->() stub\n", This); 1786 return E_NOTIMPL; 1787 } 1788 1789 static HRESULT WINAPI MimeBody_CopyTo( 1790 IMimeBody* iface, 1791 IMimeBody* pBody) 1792 { 1793 MimeBody *This = impl_from_IMimeBody(iface); 1794 FIXME("(%p)->(%p) stub\n", This, pBody); 1795 return E_NOTIMPL; 1796 } 1797 1798 static HRESULT WINAPI MimeBody_GetTransmitInfo( 1799 IMimeBody* iface, 1800 LPTRANSMITINFO pTransmitInfo) 1801 { 1802 MimeBody *This = impl_from_IMimeBody(iface); 1803 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo); 1804 return E_NOTIMPL; 1805 } 1806 1807 static HRESULT WINAPI MimeBody_SaveToFile( 1808 IMimeBody* iface, 1809 ENCODINGTYPE ietEncoding, 1810 LPCSTR pszFilePath) 1811 { 1812 MimeBody *This = impl_from_IMimeBody(iface); 1813 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath)); 1814 return E_NOTIMPL; 1815 } 1816 1817 static HRESULT WINAPI MimeBody_GetHandle( 1818 IMimeBody* iface, 1819 LPHBODY phBody) 1820 { 1821 MimeBody *This = impl_from_IMimeBody(iface); 1822 TRACE("(%p)->(%p)\n", iface, phBody); 1823 1824 if(!phBody) 1825 return E_INVALIDARG; 1826 1827 *phBody = This->handle; 1828 return This->handle ? S_OK : MIME_E_NO_DATA; 1829 } 1830 1831 static IMimeBodyVtbl body_vtbl = 1832 { 1833 MimeBody_QueryInterface, 1834 MimeBody_AddRef, 1835 MimeBody_Release, 1836 MimeBody_GetClassID, 1837 MimeBody_IsDirty, 1838 MimeBody_Load, 1839 MimeBody_Save, 1840 MimeBody_GetSizeMax, 1841 MimeBody_InitNew, 1842 MimeBody_GetPropInfo, 1843 MimeBody_SetPropInfo, 1844 MimeBody_GetProp, 1845 MimeBody_SetProp, 1846 MimeBody_AppendProp, 1847 MimeBody_DeleteProp, 1848 MimeBody_CopyProps, 1849 MimeBody_MoveProps, 1850 MimeBody_DeleteExcept, 1851 MimeBody_QueryProp, 1852 MimeBody_GetCharset, 1853 MimeBody_SetCharset, 1854 MimeBody_GetParameters, 1855 MimeBody_IsContentType, 1856 MimeBody_BindToObject, 1857 MimeBody_Clone, 1858 MimeBody_SetOption, 1859 MimeBody_GetOption, 1860 MimeBody_EnumProps, 1861 MimeBody_IsType, 1862 MimeBody_SetDisplayName, 1863 MimeBody_GetDisplayName, 1864 MimeBody_GetOffsets, 1865 MimeBody_GetCurrentEncoding, 1866 MimeBody_SetCurrentEncoding, 1867 MimeBody_GetEstimatedSize, 1868 MimeBody_GetDataHere, 1869 MimeBody_GetData, 1870 MimeBody_SetData, 1871 MimeBody_EmptyData, 1872 MimeBody_CopyTo, 1873 MimeBody_GetTransmitInfo, 1874 MimeBody_SaveToFile, 1875 MimeBody_GetHandle 1876 }; 1877 1878 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets) 1879 { 1880 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart, 1881 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd); 1882 1883 body->body_offsets = *offsets; 1884 return S_OK; 1885 } 1886 1887 #define FIRST_CUSTOM_PROP_ID 0x100 1888 1889 static MimeBody *mimebody_create(void) 1890 { 1891 MimeBody *This; 1892 BODYOFFSETS body_offsets; 1893 1894 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 1895 if (!This) 1896 return NULL; 1897 1898 This->IMimeBody_iface.lpVtbl = &body_vtbl; 1899 This->ref = 1; 1900 This->handle = NULL; 1901 list_init(&This->headers); 1902 list_init(&This->new_props); 1903 This->next_prop_id = FIRST_CUSTOM_PROP_ID; 1904 This->content_pri_type = NULL; 1905 This->content_sub_type = NULL; 1906 This->encoding = IET_7BIT; 1907 This->data = NULL; 1908 This->data_iid = IID_NULL; 1909 1910 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0; 1911 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0; 1912 MimeBody_set_offsets(This, &body_offsets); 1913 1914 return This; 1915 } 1916 1917 HRESULT MimeBody_create(IUnknown *outer, void **ppv) 1918 { 1919 MimeBody *mb; 1920 1921 if(outer) 1922 return CLASS_E_NOAGGREGATION; 1923 1924 if ((mb = mimebody_create())) 1925 { 1926 *ppv = &mb->IMimeBody_iface; 1927 return S_OK; 1928 } 1929 else 1930 { 1931 *ppv = NULL; 1932 return E_OUTOFMEMORY; 1933 } 1934 } 1935 1936 typedef struct body_t 1937 { 1938 struct list entry; 1939 DWORD index; 1940 MimeBody *mime_body; 1941 1942 struct body_t *parent; 1943 struct list children; 1944 } body_t; 1945 1946 typedef struct MimeMessage 1947 { 1948 IMimeMessage IMimeMessage_iface; 1949 LONG ref; 1950 IStream *stream; 1951 1952 struct list body_tree; 1953 DWORD next_index; 1954 } MimeMessage; 1955 1956 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface) 1957 { 1958 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface); 1959 } 1960 1961 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv) 1962 { 1963 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 1964 1965 if (IsEqualIID(riid, &IID_IUnknown) || 1966 IsEqualIID(riid, &IID_IPersist) || 1967 IsEqualIID(riid, &IID_IPersistStreamInit) || 1968 IsEqualIID(riid, &IID_IMimeMessageTree) || 1969 IsEqualIID(riid, &IID_IMimeMessage)) 1970 { 1971 *ppv = iface; 1972 IMimeMessage_AddRef(iface); 1973 return S_OK; 1974 } 1975 1976 FIXME("no interface for %s\n", debugstr_guid(riid)); 1977 *ppv = NULL; 1978 return E_NOINTERFACE; 1979 } 1980 1981 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface) 1982 { 1983 MimeMessage *This = impl_from_IMimeMessage(iface); 1984 ULONG ref = InterlockedIncrement(&This->ref); 1985 1986 TRACE("(%p) ref=%d\n", This, ref); 1987 1988 return ref; 1989 } 1990 1991 static void empty_body_list(struct list *list) 1992 { 1993 body_t *body, *cursor2; 1994 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry) 1995 { 1996 empty_body_list(&body->children); 1997 list_remove(&body->entry); 1998 IMimeBody_Release(&body->mime_body->IMimeBody_iface); 1999 HeapFree(GetProcessHeap(), 0, body); 2000 } 2001 } 2002 2003 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface) 2004 { 2005 MimeMessage *This = impl_from_IMimeMessage(iface); 2006 ULONG ref = InterlockedDecrement(&This->ref); 2007 2008 TRACE("(%p) ref=%d\n", This, ref); 2009 2010 if (!ref) 2011 { 2012 empty_body_list(&This->body_tree); 2013 2014 if(This->stream) IStream_Release(This->stream); 2015 HeapFree(GetProcessHeap(), 0, This); 2016 } 2017 2018 return ref; 2019 } 2020 2021 /*** IPersist methods ***/ 2022 static HRESULT WINAPI MimeMessage_GetClassID( 2023 IMimeMessage *iface, 2024 CLSID *pClassID) 2025 { 2026 FIXME("(%p)->(%p)\n", iface, pClassID); 2027 return E_NOTIMPL; 2028 } 2029 2030 /*** IPersistStreamInit methods ***/ 2031 static HRESULT WINAPI MimeMessage_IsDirty( 2032 IMimeMessage *iface) 2033 { 2034 FIXME("(%p)->()\n", iface); 2035 return E_NOTIMPL; 2036 } 2037 2038 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent) 2039 { 2040 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body)); 2041 if(body) 2042 { 2043 body->mime_body = mime_body; 2044 body->index = index; 2045 list_init(&body->children); 2046 body->parent = parent; 2047 2048 mime_body->handle = UlongToHandle(body->index); 2049 } 2050 return body; 2051 } 2052 2053 typedef struct 2054 { 2055 struct list entry; 2056 BODYOFFSETS offsets; 2057 } offset_entry_t; 2058 2059 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets) 2060 { 2061 HRESULT hr; 2062 DWORD read, boundary_start; 2063 int boundary_len = strlen(boundary); 2064 char *buf, *ptr, *overlap; 2065 DWORD start = 0, overlap_no; 2066 offset_entry_t *cur_body = NULL; 2067 BOOL is_first_line = TRUE; 2068 ULARGE_INTEGER cur; 2069 LARGE_INTEGER zero; 2070 2071 list_init(body_offsets); 2072 2073 overlap_no = boundary_len + 5; 2074 2075 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1); 2076 2077 zero.QuadPart = 0; 2078 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur); 2079 start = cur.u.LowPart; 2080 2081 do { 2082 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read); 2083 if(FAILED(hr)) goto end; 2084 if(read == 0) break; 2085 overlap[read] = '\0'; 2086 2087 ptr = buf; 2088 while(1) { 2089 if(is_first_line) { 2090 is_first_line = FALSE; 2091 }else { 2092 ptr = strstr(ptr, "\r\n"); 2093 if(!ptr) 2094 break; 2095 ptr += 2; 2096 } 2097 2098 boundary_start = start + ptr - buf; 2099 2100 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) { 2101 ptr += boundary_len + 2; 2102 2103 if(*ptr == '\r' && *(ptr + 1) == '\n') 2104 { 2105 ptr += 2; 2106 if(cur_body) 2107 { 2108 cur_body->offsets.cbBodyEnd = boundary_start - 2; 2109 list_add_tail(body_offsets, &cur_body->entry); 2110 } 2111 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body)); 2112 cur_body->offsets.cbBoundaryStart = boundary_start; 2113 cur_body->offsets.cbHeaderStart = start + ptr - buf; 2114 } 2115 else if(*ptr == '-' && *(ptr + 1) == '-') 2116 { 2117 if(cur_body) 2118 { 2119 cur_body->offsets.cbBodyEnd = boundary_start - 2; 2120 list_add_tail(body_offsets, &cur_body->entry); 2121 goto end; 2122 } 2123 } 2124 } 2125 } 2126 2127 if(overlap == buf) /* 1st iteration */ 2128 { 2129 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no); 2130 overlap = buf + overlap_no; 2131 start += read - overlap_no; 2132 } 2133 else 2134 { 2135 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no); 2136 start += read; 2137 } 2138 } while(1); 2139 2140 end: 2141 HeapFree(GetProcessHeap(), 0, buf); 2142 return hr; 2143 } 2144 2145 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent) 2146 { 2147 ULARGE_INTEGER start, length; 2148 MimeBody *mime_body; 2149 HRESULT hr; 2150 body_t *body; 2151 LARGE_INTEGER pos; 2152 2153 pos.QuadPart = offset->cbHeaderStart; 2154 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL); 2155 2156 mime_body = mimebody_create(); 2157 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm); 2158 2159 pos.QuadPart = 0; 2160 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start); 2161 offset->cbBodyStart = start.QuadPart; 2162 if (parent) MimeBody_set_offsets(mime_body, offset); 2163 2164 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart; 2165 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data); 2166 mime_body->data_iid = IID_IStream; 2167 2168 body = new_body_entry(mime_body, msg->next_index++, parent); 2169 2170 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK) 2171 { 2172 MIMEPARAMINFO *param_info; 2173 ULONG count, i; 2174 IMimeAllocator *alloc; 2175 2176 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count, 2177 ¶m_info); 2178 if(hr != S_OK || count == 0) return body; 2179 2180 MimeOleGetAllocator(&alloc); 2181 2182 for(i = 0; i < count; i++) 2183 { 2184 if(!lstrcmpiA(param_info[i].pszName, "boundary")) 2185 { 2186 struct list offset_list; 2187 offset_entry_t *cur, *cursor2; 2188 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list); 2189 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry) 2190 { 2191 body_t *sub_body; 2192 2193 sub_body = create_sub_body(msg, pStm, &cur->offsets, body); 2194 list_add_tail(&body->children, &sub_body->entry); 2195 list_remove(&cur->entry); 2196 HeapFree(GetProcessHeap(), 0, cur); 2197 } 2198 break; 2199 } 2200 } 2201 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE); 2202 IMimeAllocator_Release(alloc); 2203 } 2204 return body; 2205 } 2206 2207 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm) 2208 { 2209 MimeMessage *This = impl_from_IMimeMessage(iface); 2210 body_t *root_body; 2211 BODYOFFSETS offsets; 2212 ULARGE_INTEGER cur; 2213 LARGE_INTEGER zero; 2214 2215 TRACE("(%p)->(%p)\n", iface, pStm); 2216 2217 if(This->stream) 2218 { 2219 FIXME("already loaded a message\n"); 2220 return E_FAIL; 2221 } 2222 2223 empty_body_list(&This->body_tree); 2224 2225 IStream_AddRef(pStm); 2226 This->stream = pStm; 2227 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0; 2228 offsets.cbBodyStart = offsets.cbBodyEnd = 0; 2229 2230 root_body = create_sub_body(This, pStm, &offsets, NULL); 2231 2232 zero.QuadPart = 0; 2233 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur); 2234 offsets.cbBodyEnd = cur.u.LowPart; 2235 MimeBody_set_offsets(root_body->mime_body, &offsets); 2236 2237 list_add_head(&This->body_tree, &root_body->entry); 2238 2239 return S_OK; 2240 } 2241 2242 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty) 2243 { 2244 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE"); 2245 return E_NOTIMPL; 2246 } 2247 2248 static HRESULT WINAPI MimeMessage_GetSizeMax( 2249 IMimeMessage *iface, 2250 ULARGE_INTEGER *pcbSize) 2251 { 2252 FIXME("(%p)->(%p)\n", iface, pcbSize); 2253 return E_NOTIMPL; 2254 } 2255 2256 static HRESULT WINAPI MimeMessage_InitNew( 2257 IMimeMessage *iface) 2258 { 2259 FIXME("(%p)->()\n", iface); 2260 return E_NOTIMPL; 2261 } 2262 2263 /*** IMimeMessageTree methods ***/ 2264 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream, 2265 DWORD dwFlags) 2266 { 2267 MimeMessage *This = impl_from_IMimeMessage(iface); 2268 2269 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags); 2270 2271 IStream_AddRef(This->stream); 2272 *ppStream = This->stream; 2273 return S_OK; 2274 } 2275 2276 static HRESULT WINAPI MimeMessage_GetMessageSize( 2277 IMimeMessage *iface, 2278 ULONG *pcbSize, 2279 DWORD dwFlags) 2280 { 2281 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags); 2282 return E_NOTIMPL; 2283 } 2284 2285 static HRESULT WINAPI MimeMessage_LoadOffsetTable( 2286 IMimeMessage *iface, 2287 IStream *pStream) 2288 { 2289 FIXME("(%p)->(%p)\n", iface, pStream); 2290 return E_NOTIMPL; 2291 } 2292 2293 static HRESULT WINAPI MimeMessage_SaveOffsetTable( 2294 IMimeMessage *iface, 2295 IStream *pStream, 2296 DWORD dwFlags) 2297 { 2298 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags); 2299 return E_NOTIMPL; 2300 } 2301 2302 2303 static HRESULT WINAPI MimeMessage_GetFlags( 2304 IMimeMessage *iface, 2305 DWORD *pdwFlags) 2306 { 2307 FIXME("(%p)->(%p)\n", iface, pdwFlags); 2308 return E_NOTIMPL; 2309 } 2310 2311 static HRESULT WINAPI MimeMessage_Commit( 2312 IMimeMessage *iface, 2313 DWORD dwFlags) 2314 { 2315 FIXME("(%p)->(0x%x)\n", iface, dwFlags); 2316 return S_OK; 2317 } 2318 2319 2320 static HRESULT WINAPI MimeMessage_HandsOffStorage( 2321 IMimeMessage *iface) 2322 { 2323 FIXME("(%p)->()\n", iface); 2324 return E_NOTIMPL; 2325 } 2326 2327 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body) 2328 { 2329 body_t *cur; 2330 HRESULT hr; 2331 2332 if(hbody == HBODY_ROOT) 2333 { 2334 *body = LIST_ENTRY(list_head(list), body_t, entry); 2335 return S_OK; 2336 } 2337 2338 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry) 2339 { 2340 if(cur->index == HandleToUlong(hbody)) 2341 { 2342 *body = cur; 2343 return S_OK; 2344 } 2345 hr = find_body(&cur->children, hbody, body); 2346 if(hr == S_OK) return S_OK; 2347 } 2348 return S_FALSE; 2349 } 2350 2351 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid, 2352 void **ppvObject) 2353 { 2354 MimeMessage *This = impl_from_IMimeMessage(iface); 2355 HRESULT hr; 2356 body_t *body; 2357 2358 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject); 2359 2360 hr = find_body(&This->body_tree, hBody, &body); 2361 2362 if(hr != S_OK) return hr; 2363 2364 if(IsEqualIID(riid, &IID_IMimeBody)) 2365 { 2366 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface); 2367 *ppvObject = &body->mime_body->IMimeBody_iface; 2368 return S_OK; 2369 } 2370 2371 return E_NOINTERFACE; 2372 } 2373 2374 static HRESULT WINAPI MimeMessage_SaveBody( 2375 IMimeMessage *iface, 2376 HBODY hBody, 2377 DWORD dwFlags, 2378 IStream *pStream) 2379 { 2380 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream); 2381 return E_NOTIMPL; 2382 } 2383 2384 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out) 2385 { 2386 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry); 2387 body_t *body; 2388 HRESULT hr; 2389 struct list *list; 2390 2391 if(location == IBL_ROOT) 2392 { 2393 *out = root; 2394 return S_OK; 2395 } 2396 2397 hr = find_body(&msg->body_tree, pivot, &body); 2398 2399 if(hr == S_OK) 2400 { 2401 switch(location) 2402 { 2403 case IBL_PARENT: 2404 if(body->parent) 2405 *out = body->parent; 2406 else 2407 hr = MIME_E_NOT_FOUND; 2408 break; 2409 2410 case IBL_FIRST: 2411 list = list_head(&body->children); 2412 if(list) 2413 *out = LIST_ENTRY(list, body_t, entry); 2414 else 2415 hr = MIME_E_NOT_FOUND; 2416 break; 2417 2418 case IBL_LAST: 2419 list = list_tail(&body->children); 2420 if(list) 2421 *out = LIST_ENTRY(list, body_t, entry); 2422 else 2423 hr = MIME_E_NOT_FOUND; 2424 break; 2425 2426 case IBL_NEXT: 2427 list = list_next(&body->parent->children, &body->entry); 2428 if(list) 2429 *out = LIST_ENTRY(list, body_t, entry); 2430 else 2431 hr = MIME_E_NOT_FOUND; 2432 break; 2433 2434 case IBL_PREVIOUS: 2435 list = list_prev(&body->parent->children, &body->entry); 2436 if(list) 2437 *out = LIST_ENTRY(list, body_t, entry); 2438 else 2439 hr = MIME_E_NOT_FOUND; 2440 break; 2441 2442 default: 2443 hr = E_FAIL; 2444 break; 2445 } 2446 } 2447 2448 return hr; 2449 } 2450 2451 2452 static HRESULT WINAPI MimeMessage_InsertBody( 2453 IMimeMessage *iface, 2454 BODYLOCATION location, 2455 HBODY hPivot, 2456 LPHBODY phBody) 2457 { 2458 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody); 2459 return E_NOTIMPL; 2460 } 2461 2462 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot, 2463 HBODY *phBody) 2464 { 2465 MimeMessage *This = impl_from_IMimeMessage(iface); 2466 body_t *body; 2467 HRESULT hr; 2468 2469 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody); 2470 2471 if(!phBody) 2472 return E_INVALIDARG; 2473 2474 *phBody = NULL; 2475 2476 hr = get_body(This, location, hPivot, &body); 2477 2478 if(hr == S_OK) *phBody = UlongToHandle(body->index); 2479 2480 return hr; 2481 } 2482 2483 static HRESULT WINAPI MimeMessage_DeleteBody( 2484 IMimeMessage *iface, 2485 HBODY hBody, 2486 DWORD dwFlags) 2487 { 2488 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags); 2489 return E_NOTIMPL; 2490 } 2491 2492 static HRESULT WINAPI MimeMessage_MoveBody( 2493 IMimeMessage *iface, 2494 HBODY hBody, 2495 BODYLOCATION location) 2496 { 2497 FIXME("(%p)->(%d)\n", iface, location); 2498 return E_NOTIMPL; 2499 } 2500 2501 static void count_children(body_t *body, boolean recurse, ULONG *count) 2502 { 2503 body_t *child; 2504 2505 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry) 2506 { 2507 (*count)++; 2508 if(recurse) count_children(child, recurse, count); 2509 } 2510 } 2511 2512 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse, 2513 ULONG *pcBodies) 2514 { 2515 HRESULT hr; 2516 MimeMessage *This = impl_from_IMimeMessage(iface); 2517 body_t *body; 2518 2519 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies); 2520 2521 hr = find_body(&This->body_tree, hParent, &body); 2522 if(hr != S_OK) return hr; 2523 2524 *pcBodies = 1; 2525 count_children(body, fRecurse, pcBodies); 2526 2527 return S_OK; 2528 } 2529 2530 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out) 2531 { 2532 struct list *ptr; 2533 HBODY next; 2534 2535 for (;;) 2536 { 2537 if (!body) ptr = list_head( &This->body_tree ); 2538 else 2539 { 2540 ptr = list_head( &body->children ); 2541 while (!ptr) 2542 { 2543 if (!body->parent) return MIME_E_NOT_FOUND; 2544 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent; 2545 } 2546 } 2547 2548 body = LIST_ENTRY( ptr, body_t, entry ); 2549 next = UlongToHandle( body->index ); 2550 find->dwReserved = body->index; 2551 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType, 2552 find->pszSubType) == S_OK) 2553 { 2554 *out = next; 2555 return S_OK; 2556 } 2557 } 2558 return MIME_E_NOT_FOUND; 2559 } 2560 2561 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody) 2562 { 2563 MimeMessage *This = impl_from_IMimeMessage(iface); 2564 2565 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody); 2566 2567 pFindBody->dwReserved = 0; 2568 return find_next(This, NULL, pFindBody, phBody); 2569 } 2570 2571 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody) 2572 { 2573 MimeMessage *This = impl_from_IMimeMessage(iface); 2574 body_t *body; 2575 HRESULT hr; 2576 2577 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody); 2578 2579 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body ); 2580 if (hr != S_OK) return MIME_E_NOT_FOUND; 2581 return find_next(This, body, pFindBody, phBody); 2582 } 2583 2584 static HRESULT WINAPI MimeMessage_ResolveURL( 2585 IMimeMessage *iface, 2586 HBODY hRelated, 2587 LPCSTR pszBase, 2588 LPCSTR pszURL, 2589 DWORD dwFlags, 2590 LPHBODY phBody) 2591 { 2592 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody); 2593 return E_NOTIMPL; 2594 } 2595 2596 static HRESULT WINAPI MimeMessage_ToMultipart( 2597 IMimeMessage *iface, 2598 HBODY hBody, 2599 LPCSTR pszSubType, 2600 LPHBODY phMultipart) 2601 { 2602 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart); 2603 return E_NOTIMPL; 2604 } 2605 2606 static HRESULT WINAPI MimeMessage_GetBodyOffsets( 2607 IMimeMessage *iface, 2608 HBODY hBody, 2609 LPBODYOFFSETS pOffsets) 2610 { 2611 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets); 2612 return E_NOTIMPL; 2613 } 2614 2615 static HRESULT WINAPI MimeMessage_GetCharset( 2616 IMimeMessage *iface, 2617 LPHCHARSET phCharset) 2618 { 2619 FIXME("(%p)->(%p)\n", iface, phCharset); 2620 *phCharset = NULL; 2621 return S_OK; 2622 } 2623 2624 static HRESULT WINAPI MimeMessage_SetCharset( 2625 IMimeMessage *iface, 2626 HCHARSET hCharset, 2627 CSETAPPLYTYPE applytype) 2628 { 2629 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype); 2630 return E_NOTIMPL; 2631 } 2632 2633 static HRESULT WINAPI MimeMessage_IsBodyType( 2634 IMimeMessage *iface, 2635 HBODY hBody, 2636 IMSGBODYTYPE bodytype) 2637 { 2638 HRESULT hr; 2639 IMimeBody *mime_body; 2640 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype); 2641 2642 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body); 2643 if(hr != S_OK) return hr; 2644 2645 hr = IMimeBody_IsType(mime_body, bodytype); 2646 MimeBody_Release(mime_body); 2647 return hr; 2648 } 2649 2650 static HRESULT WINAPI MimeMessage_IsContentType( 2651 IMimeMessage *iface, 2652 HBODY hBody, 2653 LPCSTR pszPriType, 2654 LPCSTR pszSubType) 2655 { 2656 HRESULT hr; 2657 IMimeBody *mime_body; 2658 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType), 2659 debugstr_a(pszSubType)); 2660 2661 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body); 2662 if(FAILED(hr)) return hr; 2663 2664 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType); 2665 IMimeBody_Release(mime_body); 2666 return hr; 2667 } 2668 2669 static HRESULT WINAPI MimeMessage_QueryBodyProp( 2670 IMimeMessage *iface, 2671 HBODY hBody, 2672 LPCSTR pszName, 2673 LPCSTR pszCriteria, 2674 boolean fSubString, 2675 boolean fCaseSensitive) 2676 { 2677 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE"); 2678 return E_NOTIMPL; 2679 } 2680 2681 static HRESULT WINAPI MimeMessage_GetBodyProp( 2682 IMimeMessage *iface, 2683 HBODY hBody, 2684 LPCSTR pszName, 2685 DWORD dwFlags, 2686 LPPROPVARIANT pValue) 2687 { 2688 HRESULT hr; 2689 IMimeBody *mime_body; 2690 2691 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue); 2692 2693 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body); 2694 if(hr != S_OK) return hr; 2695 2696 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue); 2697 IMimeBody_Release(mime_body); 2698 2699 return hr; 2700 } 2701 2702 static HRESULT WINAPI MimeMessage_SetBodyProp( 2703 IMimeMessage *iface, 2704 HBODY hBody, 2705 LPCSTR pszName, 2706 DWORD dwFlags, 2707 LPCPROPVARIANT pValue) 2708 { 2709 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue); 2710 return E_NOTIMPL; 2711 } 2712 2713 static HRESULT WINAPI MimeMessage_DeleteBodyProp( 2714 IMimeMessage *iface, 2715 HBODY hBody, 2716 LPCSTR pszName) 2717 { 2718 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName); 2719 return E_NOTIMPL; 2720 } 2721 2722 static HRESULT WINAPI MimeMessage_SetOption( 2723 IMimeMessage *iface, 2724 const TYPEDID oid, 2725 LPCPROPVARIANT pValue) 2726 { 2727 HRESULT hr = S_OK; 2728 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue); 2729 2730 /* Message ID is checked before type. 2731 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later. 2732 */ 2733 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64)) 2734 { 2735 WARN("oid (%08x) out of range\n", oid); 2736 return MIME_E_INVALID_OPTION_ID; 2737 } 2738 2739 if(pValue->vt != TYPEDID_TYPE(oid)) 2740 { 2741 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid); 2742 return S_OK; 2743 } 2744 2745 switch(oid) 2746 { 2747 case OID_HIDE_TNEF_ATTACHMENTS: 2748 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal); 2749 break; 2750 case OID_SHOW_MACBINARY: 2751 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal); 2752 break; 2753 case OID_SAVEBODY_KEEPBOUNDARY: 2754 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal); 2755 break; 2756 case OID_CLEANUP_TREE_ON_SAVE: 2757 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal); 2758 break; 2759 default: 2760 FIXME("Unhandled oid %08x\n", oid); 2761 hr = MIME_E_INVALID_OPTION_ID; 2762 } 2763 2764 return hr; 2765 } 2766 2767 static HRESULT WINAPI MimeMessage_GetOption( 2768 IMimeMessage *iface, 2769 const TYPEDID oid, 2770 LPPROPVARIANT pValue) 2771 { 2772 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue); 2773 return E_NOTIMPL; 2774 } 2775 2776 /*** IMimeMessage methods ***/ 2777 static HRESULT WINAPI MimeMessage_CreateWebPage( 2778 IMimeMessage *iface, 2779 IStream *pRootStm, 2780 LPWEBPAGEOPTIONS pOptions, 2781 IMimeMessageCallback *pCallback, 2782 IMoniker **ppMoniker) 2783 { 2784 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker); 2785 *ppMoniker = NULL; 2786 return E_NOTIMPL; 2787 } 2788 2789 static HRESULT WINAPI MimeMessage_GetProp( 2790 IMimeMessage *iface, 2791 LPCSTR pszName, 2792 DWORD dwFlags, 2793 LPPROPVARIANT pValue) 2794 { 2795 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue); 2796 return E_NOTIMPL; 2797 } 2798 2799 static HRESULT WINAPI MimeMessage_SetProp( 2800 IMimeMessage *iface, 2801 LPCSTR pszName, 2802 DWORD dwFlags, 2803 LPCPROPVARIANT pValue) 2804 { 2805 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue); 2806 return E_NOTIMPL; 2807 } 2808 2809 static HRESULT WINAPI MimeMessage_DeleteProp( 2810 IMimeMessage *iface, 2811 LPCSTR pszName) 2812 { 2813 FIXME("(%p)->(%s)\n", iface, pszName); 2814 return E_NOTIMPL; 2815 } 2816 2817 static HRESULT WINAPI MimeMessage_QueryProp( 2818 IMimeMessage *iface, 2819 LPCSTR pszName, 2820 LPCSTR pszCriteria, 2821 boolean fSubString, 2822 boolean fCaseSensitive) 2823 { 2824 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE"); 2825 return E_NOTIMPL; 2826 } 2827 2828 static HRESULT WINAPI MimeMessage_GetTextBody( 2829 IMimeMessage *iface, 2830 DWORD dwTxtType, 2831 ENCODINGTYPE ietEncoding, 2832 IStream **pStream, 2833 LPHBODY phBody) 2834 { 2835 HRESULT hr; 2836 HBODY hbody; 2837 FINDBODY find_struct; 2838 IMimeBody *mime_body; 2839 static char text[] = "text"; 2840 static char plain[] = "plain"; 2841 static char html[] = "html"; 2842 2843 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody); 2844 2845 find_struct.pszPriType = text; 2846 2847 switch(dwTxtType) 2848 { 2849 case TXT_PLAIN: 2850 find_struct.pszSubType = plain; 2851 break; 2852 case TXT_HTML: 2853 find_struct.pszSubType = html; 2854 break; 2855 default: 2856 return MIME_E_INVALID_TEXT_TYPE; 2857 } 2858 2859 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody); 2860 if(hr != S_OK) 2861 { 2862 TRACE("not found hr %08x\n", hr); 2863 *phBody = NULL; 2864 return hr; 2865 } 2866 2867 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body); 2868 2869 IMimeBody_GetData(mime_body, ietEncoding, pStream); 2870 *phBody = hbody; 2871 IMimeBody_Release(mime_body); 2872 return hr; 2873 } 2874 2875 static HRESULT WINAPI MimeMessage_SetTextBody( 2876 IMimeMessage *iface, 2877 DWORD dwTxtType, 2878 ENCODINGTYPE ietEncoding, 2879 HBODY hAlternative, 2880 IStream *pStream, 2881 LPHBODY phBody) 2882 { 2883 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody); 2884 return E_NOTIMPL; 2885 } 2886 2887 static HRESULT WINAPI MimeMessage_AttachObject( 2888 IMimeMessage *iface, 2889 REFIID riid, 2890 void *pvObject, 2891 LPHBODY phBody) 2892 { 2893 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody); 2894 return E_NOTIMPL; 2895 } 2896 2897 static HRESULT WINAPI MimeMessage_AttachFile( 2898 IMimeMessage *iface, 2899 LPCSTR pszFilePath, 2900 IStream *pstmFile, 2901 LPHBODY phBody) 2902 { 2903 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody); 2904 return E_NOTIMPL; 2905 } 2906 2907 static HRESULT WINAPI MimeMessage_AttachURL( 2908 IMimeMessage *iface, 2909 LPCSTR pszBase, 2910 LPCSTR pszURL, 2911 DWORD dwFlags, 2912 IStream *pstmURL, 2913 LPSTR *ppszCIDURL, 2914 LPHBODY phBody) 2915 { 2916 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody); 2917 return E_NOTIMPL; 2918 } 2919 2920 static HRESULT WINAPI MimeMessage_GetAttachments( 2921 IMimeMessage *iface, 2922 ULONG *pcAttach, 2923 LPHBODY *pprghAttach) 2924 { 2925 HRESULT hr; 2926 FINDBODY find_struct; 2927 HBODY hbody; 2928 LPHBODY array; 2929 ULONG size = 10; 2930 2931 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach); 2932 2933 *pcAttach = 0; 2934 array = CoTaskMemAlloc(size * sizeof(HBODY)); 2935 2936 find_struct.pszPriType = find_struct.pszSubType = NULL; 2937 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody); 2938 while(hr == S_OK) 2939 { 2940 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL); 2941 TRACE("IsCT rets %08x %d\n", hr, *pcAttach); 2942 if(hr != S_OK) 2943 { 2944 if(*pcAttach + 1 > size) 2945 { 2946 size *= 2; 2947 array = CoTaskMemRealloc(array, size * sizeof(HBODY)); 2948 } 2949 array[*pcAttach] = hbody; 2950 (*pcAttach)++; 2951 } 2952 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody); 2953 } 2954 2955 *pprghAttach = array; 2956 return S_OK; 2957 } 2958 2959 static HRESULT WINAPI MimeMessage_GetAddressTable( 2960 IMimeMessage *iface, 2961 IMimeAddressTable **ppTable) 2962 { 2963 FIXME("(%p)->(%p)\n", iface, ppTable); 2964 return E_NOTIMPL; 2965 } 2966 2967 static HRESULT WINAPI MimeMessage_GetSender( 2968 IMimeMessage *iface, 2969 LPADDRESSPROPS pAddress) 2970 { 2971 FIXME("(%p)->(%p)\n", iface, pAddress); 2972 return E_NOTIMPL; 2973 } 2974 2975 static HRESULT WINAPI MimeMessage_GetAddressTypes( 2976 IMimeMessage *iface, 2977 DWORD dwAdrTypes, 2978 DWORD dwProps, 2979 LPADDRESSLIST pList) 2980 { 2981 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList); 2982 return E_NOTIMPL; 2983 } 2984 2985 static HRESULT WINAPI MimeMessage_GetAddressFormat( 2986 IMimeMessage *iface, 2987 DWORD dwAdrTypes, 2988 ADDRESSFORMAT format, 2989 LPSTR *ppszFormat) 2990 { 2991 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat); 2992 return E_NOTIMPL; 2993 } 2994 2995 static HRESULT WINAPI MimeMessage_EnumAddressTypes( 2996 IMimeMessage *iface, 2997 DWORD dwAdrTypes, 2998 DWORD dwProps, 2999 IMimeEnumAddressTypes **ppEnum) 3000 { 3001 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum); 3002 return E_NOTIMPL; 3003 } 3004 3005 static HRESULT WINAPI MimeMessage_SplitMessage( 3006 IMimeMessage *iface, 3007 ULONG cbMaxPart, 3008 IMimeMessageParts **ppParts) 3009 { 3010 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts); 3011 return E_NOTIMPL; 3012 } 3013 3014 static HRESULT WINAPI MimeMessage_GetRootMoniker( 3015 IMimeMessage *iface, 3016 IMoniker **ppMoniker) 3017 { 3018 FIXME("(%p)->(%p)\n", iface, ppMoniker); 3019 return E_NOTIMPL; 3020 } 3021 3022 static const IMimeMessageVtbl MimeMessageVtbl = 3023 { 3024 MimeMessage_QueryInterface, 3025 MimeMessage_AddRef, 3026 MimeMessage_Release, 3027 MimeMessage_GetClassID, 3028 MimeMessage_IsDirty, 3029 MimeMessage_Load, 3030 MimeMessage_Save, 3031 MimeMessage_GetSizeMax, 3032 MimeMessage_InitNew, 3033 MimeMessage_GetMessageSource, 3034 MimeMessage_GetMessageSize, 3035 MimeMessage_LoadOffsetTable, 3036 MimeMessage_SaveOffsetTable, 3037 MimeMessage_GetFlags, 3038 MimeMessage_Commit, 3039 MimeMessage_HandsOffStorage, 3040 MimeMessage_BindToObject, 3041 MimeMessage_SaveBody, 3042 MimeMessage_InsertBody, 3043 MimeMessage_GetBody, 3044 MimeMessage_DeleteBody, 3045 MimeMessage_MoveBody, 3046 MimeMessage_CountBodies, 3047 MimeMessage_FindFirst, 3048 MimeMessage_FindNext, 3049 MimeMessage_ResolveURL, 3050 MimeMessage_ToMultipart, 3051 MimeMessage_GetBodyOffsets, 3052 MimeMessage_GetCharset, 3053 MimeMessage_SetCharset, 3054 MimeMessage_IsBodyType, 3055 MimeMessage_IsContentType, 3056 MimeMessage_QueryBodyProp, 3057 MimeMessage_GetBodyProp, 3058 MimeMessage_SetBodyProp, 3059 MimeMessage_DeleteBodyProp, 3060 MimeMessage_SetOption, 3061 MimeMessage_GetOption, 3062 MimeMessage_CreateWebPage, 3063 MimeMessage_GetProp, 3064 MimeMessage_SetProp, 3065 MimeMessage_DeleteProp, 3066 MimeMessage_QueryProp, 3067 MimeMessage_GetTextBody, 3068 MimeMessage_SetTextBody, 3069 MimeMessage_AttachObject, 3070 MimeMessage_AttachFile, 3071 MimeMessage_AttachURL, 3072 MimeMessage_GetAttachments, 3073 MimeMessage_GetAddressTable, 3074 MimeMessage_GetSender, 3075 MimeMessage_GetAddressTypes, 3076 MimeMessage_GetAddressFormat, 3077 MimeMessage_EnumAddressTypes, 3078 MimeMessage_SplitMessage, 3079 MimeMessage_GetRootMoniker, 3080 }; 3081 3082 HRESULT MimeMessage_create(IUnknown *outer, void **obj) 3083 { 3084 MimeMessage *This; 3085 MimeBody *mime_body; 3086 body_t *root_body; 3087 3088 TRACE("(%p, %p)\n", outer, obj); 3089 3090 if (outer) 3091 { 3092 FIXME("outer unknown not supported yet\n"); 3093 return E_NOTIMPL; 3094 } 3095 3096 *obj = NULL; 3097 3098 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 3099 if (!This) return E_OUTOFMEMORY; 3100 3101 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl; 3102 This->ref = 1; 3103 This->stream = NULL; 3104 list_init(&This->body_tree); 3105 This->next_index = 1; 3106 3107 mime_body = mimebody_create(); 3108 root_body = new_body_entry(mime_body, This->next_index++, NULL); 3109 list_add_head(&This->body_tree, &root_body->entry); 3110 3111 *obj = &This->IMimeMessage_iface; 3112 return S_OK; 3113 } 3114 3115 /*********************************************************************** 3116 * MimeOleCreateMessage (INETCOMM.@) 3117 */ 3118 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage) 3119 { 3120 TRACE("(%p, %p)\n", pUnkOuter, ppMessage); 3121 return MimeMessage_create(NULL, (void **)ppMessage); 3122 } 3123 3124 /*********************************************************************** 3125 * MimeOleSetCompatMode (INETCOMM.@) 3126 */ 3127 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode) 3128 { 3129 FIXME("(0x%x)\n", dwMode); 3130 return S_OK; 3131 } 3132 3133 /*********************************************************************** 3134 * MimeOleCreateVirtualStream (INETCOMM.@) 3135 */ 3136 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream) 3137 { 3138 HRESULT hr; 3139 FIXME("(%p)\n", ppStream); 3140 3141 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream); 3142 return hr; 3143 } 3144 3145 typedef struct MimeSecurity 3146 { 3147 IMimeSecurity IMimeSecurity_iface; 3148 LONG ref; 3149 } MimeSecurity; 3150 3151 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface) 3152 { 3153 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface); 3154 } 3155 3156 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv) 3157 { 3158 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 3159 3160 if (IsEqualIID(riid, &IID_IUnknown) || 3161 IsEqualIID(riid, &IID_IMimeSecurity)) 3162 { 3163 *ppv = iface; 3164 IMimeSecurity_AddRef(iface); 3165 return S_OK; 3166 } 3167 3168 FIXME("no interface for %s\n", debugstr_guid(riid)); 3169 *ppv = NULL; 3170 return E_NOINTERFACE; 3171 } 3172 3173 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface) 3174 { 3175 MimeSecurity *This = impl_from_IMimeSecurity(iface); 3176 LONG ref = InterlockedIncrement(&This->ref); 3177 3178 TRACE("(%p) ref=%d\n", This, ref); 3179 3180 return ref; 3181 } 3182 3183 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface) 3184 { 3185 MimeSecurity *This = impl_from_IMimeSecurity(iface); 3186 LONG ref = InterlockedDecrement(&This->ref); 3187 3188 TRACE("(%p) ref=%d\n", This, ref); 3189 3190 if (!ref) 3191 HeapFree(GetProcessHeap(), 0, This); 3192 3193 return ref; 3194 } 3195 3196 static HRESULT WINAPI MimeSecurity_InitNew( 3197 IMimeSecurity* iface) 3198 { 3199 FIXME("(%p)->(): stub\n", iface); 3200 return S_OK; 3201 } 3202 3203 static HRESULT WINAPI MimeSecurity_CheckInit( 3204 IMimeSecurity* iface) 3205 { 3206 FIXME("(%p)->(): stub\n", iface); 3207 return E_NOTIMPL; 3208 } 3209 3210 static HRESULT WINAPI MimeSecurity_EncodeMessage( 3211 IMimeSecurity* iface, 3212 IMimeMessageTree* pTree, 3213 DWORD dwFlags) 3214 { 3215 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags); 3216 return E_NOTIMPL; 3217 } 3218 3219 static HRESULT WINAPI MimeSecurity_EncodeBody( 3220 IMimeSecurity* iface, 3221 IMimeMessageTree* pTree, 3222 HBODY hEncodeRoot, 3223 DWORD dwFlags) 3224 { 3225 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags); 3226 return E_NOTIMPL; 3227 } 3228 3229 static HRESULT WINAPI MimeSecurity_DecodeMessage( 3230 IMimeSecurity* iface, 3231 IMimeMessageTree* pTree, 3232 DWORD dwFlags) 3233 { 3234 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags); 3235 return E_NOTIMPL; 3236 } 3237 3238 static HRESULT WINAPI MimeSecurity_DecodeBody( 3239 IMimeSecurity* iface, 3240 IMimeMessageTree* pTree, 3241 HBODY hDecodeRoot, 3242 DWORD dwFlags) 3243 { 3244 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags); 3245 return E_NOTIMPL; 3246 } 3247 3248 static HRESULT WINAPI MimeSecurity_EnumCertificates( 3249 IMimeSecurity* iface, 3250 HCAPICERTSTORE hc, 3251 DWORD dwUsage, 3252 PCX509CERT pPrev, 3253 PCX509CERT* ppCert) 3254 { 3255 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert); 3256 return E_NOTIMPL; 3257 } 3258 3259 static HRESULT WINAPI MimeSecurity_GetCertificateName( 3260 IMimeSecurity* iface, 3261 const PCX509CERT pX509Cert, 3262 const CERTNAMETYPE cn, 3263 LPSTR* ppszName) 3264 { 3265 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName); 3266 return E_NOTIMPL; 3267 } 3268 3269 static HRESULT WINAPI MimeSecurity_GetMessageType( 3270 IMimeSecurity* iface, 3271 const HWND hwndParent, 3272 IMimeBody* pBody, 3273 DWORD* pdwSecType) 3274 { 3275 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType); 3276 return E_NOTIMPL; 3277 } 3278 3279 static HRESULT WINAPI MimeSecurity_GetCertData( 3280 IMimeSecurity* iface, 3281 const PCX509CERT pX509Cert, 3282 const CERTDATAID dataid, 3283 LPPROPVARIANT pValue) 3284 { 3285 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue); 3286 return E_NOTIMPL; 3287 } 3288 3289 3290 static const IMimeSecurityVtbl MimeSecurityVtbl = 3291 { 3292 MimeSecurity_QueryInterface, 3293 MimeSecurity_AddRef, 3294 MimeSecurity_Release, 3295 MimeSecurity_InitNew, 3296 MimeSecurity_CheckInit, 3297 MimeSecurity_EncodeMessage, 3298 MimeSecurity_EncodeBody, 3299 MimeSecurity_DecodeMessage, 3300 MimeSecurity_DecodeBody, 3301 MimeSecurity_EnumCertificates, 3302 MimeSecurity_GetCertificateName, 3303 MimeSecurity_GetMessageType, 3304 MimeSecurity_GetCertData 3305 }; 3306 3307 HRESULT MimeSecurity_create(IUnknown *outer, void **obj) 3308 { 3309 MimeSecurity *This; 3310 3311 *obj = NULL; 3312 3313 if (outer) return CLASS_E_NOAGGREGATION; 3314 3315 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 3316 if (!This) return E_OUTOFMEMORY; 3317 3318 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl; 3319 This->ref = 1; 3320 3321 *obj = &This->IMimeSecurity_iface; 3322 return S_OK; 3323 } 3324 3325 /*********************************************************************** 3326 * MimeOleCreateSecurity (INETCOMM.@) 3327 */ 3328 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity) 3329 { 3330 return MimeSecurity_create(NULL, (void **)ppSecurity); 3331 } 3332 3333 static HRESULT WINAPI MimeAlloc_QueryInterface( 3334 IMimeAllocator* iface, 3335 REFIID riid, 3336 void **obj) 3337 { 3338 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); 3339 3340 if (IsEqualIID(riid, &IID_IUnknown) || 3341 IsEqualIID(riid, &IID_IMalloc) || 3342 IsEqualIID(riid, &IID_IMimeAllocator)) 3343 { 3344 *obj = iface; 3345 IMimeAllocator_AddRef(iface); 3346 return S_OK; 3347 } 3348 3349 FIXME("no interface for %s\n", debugstr_guid(riid)); 3350 *obj = NULL; 3351 return E_NOINTERFACE; 3352 } 3353 3354 static ULONG WINAPI MimeAlloc_AddRef( 3355 IMimeAllocator* iface) 3356 { 3357 return 2; 3358 } 3359 3360 static ULONG WINAPI MimeAlloc_Release( 3361 IMimeAllocator* iface) 3362 { 3363 return 1; 3364 } 3365 3366 static LPVOID WINAPI MimeAlloc_Alloc( 3367 IMimeAllocator* iface, 3368 SIZE_T cb) 3369 { 3370 return CoTaskMemAlloc(cb); 3371 } 3372 3373 static LPVOID WINAPI MimeAlloc_Realloc( 3374 IMimeAllocator* iface, 3375 LPVOID pv, 3376 SIZE_T cb) 3377 { 3378 return CoTaskMemRealloc(pv, cb); 3379 } 3380 3381 static void WINAPI MimeAlloc_Free( 3382 IMimeAllocator* iface, 3383 LPVOID pv) 3384 { 3385 CoTaskMemFree(pv); 3386 } 3387 3388 static SIZE_T WINAPI MimeAlloc_GetSize( 3389 IMimeAllocator* iface, 3390 LPVOID pv) 3391 { 3392 FIXME("stub\n"); 3393 return 0; 3394 } 3395 3396 static int WINAPI MimeAlloc_DidAlloc( 3397 IMimeAllocator* iface, 3398 LPVOID pv) 3399 { 3400 FIXME("stub\n"); 3401 return 0; 3402 } 3403 3404 static void WINAPI MimeAlloc_HeapMinimize( 3405 IMimeAllocator* iface) 3406 { 3407 FIXME("stub\n"); 3408 return; 3409 } 3410 3411 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray( 3412 IMimeAllocator* iface, 3413 ULONG cParams, 3414 LPMIMEPARAMINFO prgParam, 3415 boolean fFreeArray) 3416 { 3417 ULONG i; 3418 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray); 3419 3420 for(i = 0; i < cParams; i++) 3421 { 3422 IMimeAllocator_Free(iface, prgParam[i].pszName); 3423 IMimeAllocator_Free(iface, prgParam[i].pszData); 3424 } 3425 if(fFreeArray) IMimeAllocator_Free(iface, prgParam); 3426 return S_OK; 3427 } 3428 3429 static HRESULT WINAPI MimeAlloc_FreeAddressList( 3430 IMimeAllocator* iface, 3431 LPADDRESSLIST pList) 3432 { 3433 FIXME("stub\n"); 3434 return E_NOTIMPL; 3435 } 3436 3437 static HRESULT WINAPI MimeAlloc_FreeAddressProps( 3438 IMimeAllocator* iface, 3439 LPADDRESSPROPS pAddress) 3440 { 3441 FIXME("stub\n"); 3442 return E_NOTIMPL; 3443 } 3444 3445 static HRESULT WINAPI MimeAlloc_ReleaseObjects( 3446 IMimeAllocator* iface, 3447 ULONG cObjects, 3448 IUnknown **prgpUnknown, 3449 boolean fFreeArray) 3450 { 3451 FIXME("stub\n"); 3452 return E_NOTIMPL; 3453 } 3454 3455 3456 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray( 3457 IMimeAllocator* iface, 3458 ULONG cRows, 3459 LPENUMHEADERROW prgRow, 3460 boolean fFreeArray) 3461 { 3462 FIXME("stub\n"); 3463 return E_NOTIMPL; 3464 } 3465 3466 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray( 3467 IMimeAllocator* iface, 3468 ULONG cProps, 3469 LPENUMPROPERTY prgProp, 3470 boolean fFreeArray) 3471 { 3472 FIXME("stub\n"); 3473 return E_NOTIMPL; 3474 } 3475 3476 static HRESULT WINAPI MimeAlloc_FreeThumbprint( 3477 IMimeAllocator* iface, 3478 THUMBBLOB *pthumbprint) 3479 { 3480 FIXME("stub\n"); 3481 return E_NOTIMPL; 3482 } 3483 3484 3485 static HRESULT WINAPI MimeAlloc_PropVariantClear( 3486 IMimeAllocator* iface, 3487 LPPROPVARIANT pProp) 3488 { 3489 FIXME("stub\n"); 3490 return E_NOTIMPL; 3491 } 3492 3493 static IMimeAllocatorVtbl mime_alloc_vtbl = 3494 { 3495 MimeAlloc_QueryInterface, 3496 MimeAlloc_AddRef, 3497 MimeAlloc_Release, 3498 MimeAlloc_Alloc, 3499 MimeAlloc_Realloc, 3500 MimeAlloc_Free, 3501 MimeAlloc_GetSize, 3502 MimeAlloc_DidAlloc, 3503 MimeAlloc_HeapMinimize, 3504 MimeAlloc_FreeParamInfoArray, 3505 MimeAlloc_FreeAddressList, 3506 MimeAlloc_FreeAddressProps, 3507 MimeAlloc_ReleaseObjects, 3508 MimeAlloc_FreeEnumHeaderRowArray, 3509 MimeAlloc_FreeEnumPropertyArray, 3510 MimeAlloc_FreeThumbprint, 3511 MimeAlloc_PropVariantClear 3512 }; 3513 3514 static IMimeAllocator mime_allocator = 3515 { 3516 &mime_alloc_vtbl 3517 }; 3518 3519 HRESULT MimeAllocator_create(IUnknown *outer, void **obj) 3520 { 3521 if(outer) return CLASS_E_NOAGGREGATION; 3522 3523 *obj = &mime_allocator; 3524 return S_OK; 3525 } 3526 3527 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc) 3528 { 3529 return MimeAllocator_create(NULL, (void**)alloc); 3530 } 3531 3532 HRESULT VirtualStream_create(IUnknown *outer, void **obj) 3533 { 3534 FIXME("(%p, %p)\n", outer, obj); 3535 3536 *obj = NULL; 3537 if (outer) return CLASS_E_NOAGGREGATION; 3538 3539 return MimeOleCreateVirtualStream((IStream **)obj); 3540 } 3541 3542 /* IMimePropertySchema Interface */ 3543 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out) 3544 { 3545 propschema *This = impl_from_IMimePropertySchema(iface); 3546 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out); 3547 3548 *out = NULL; 3549 3550 if (IsEqualIID(riid, &IID_IUnknown) || 3551 IsEqualIID(riid, &IID_IMimePropertySchema)) 3552 { 3553 *out = iface; 3554 } 3555 else 3556 { 3557 FIXME("no interface for %s\n", debugstr_guid(riid)); 3558 return E_NOINTERFACE; 3559 } 3560 3561 IMimePropertySchema_AddRef(iface); 3562 return S_OK; 3563 } 3564 3565 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface) 3566 { 3567 propschema *This = impl_from_IMimePropertySchema(iface); 3568 LONG ref = InterlockedIncrement(&This->ref); 3569 3570 TRACE("(%p) ref=%d\n", This, ref); 3571 3572 return ref; 3573 } 3574 3575 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface) 3576 { 3577 propschema *This = impl_from_IMimePropertySchema(iface); 3578 LONG ref = InterlockedDecrement(&This->ref); 3579 3580 TRACE("(%p) ref=%d\n", This, ref); 3581 3582 if (!ref) 3583 { 3584 HeapFree(GetProcessHeap(), 0, This); 3585 } 3586 3587 return ref; 3588 } 3589 3590 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags, 3591 DWORD rownumber, VARTYPE vtdefault, DWORD *propid) 3592 { 3593 propschema *This = impl_from_IMimePropertySchema(iface); 3594 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid); 3595 return E_NOTIMPL; 3596 } 3597 3598 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags, 3599 DWORD rownumber, VARTYPE vtdefault) 3600 { 3601 propschema *This = impl_from_IMimePropertySchema(iface); 3602 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault); 3603 return S_OK; 3604 } 3605 3606 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid) 3607 { 3608 propschema *This = impl_from_IMimePropertySchema(iface); 3609 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid); 3610 return E_NOTIMPL; 3611 } 3612 3613 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name) 3614 { 3615 propschema *This = impl_from_IMimePropertySchema(iface); 3616 FIXME("(%p)->(%d, %p) stub\n", This, propid, name); 3617 return E_NOTIMPL; 3618 } 3619 3620 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype) 3621 { 3622 propschema *This = impl_from_IMimePropertySchema(iface); 3623 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype); 3624 return E_NOTIMPL; 3625 } 3626 3627 static IMimePropertySchemaVtbl prop_schema_vtbl = 3628 { 3629 propschema_QueryInterface, 3630 propschema_AddRef, 3631 propschema_Release, 3632 propschema_RegisterProperty, 3633 propschema_ModifyProperty, 3634 propschema_GetPropertyId, 3635 propschema_GetPropertyName, 3636 propschema_RegisterAddressType 3637 }; 3638 3639 3640 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema) 3641 { 3642 propschema *This; 3643 3644 TRACE("(%p) stub\n", schema); 3645 3646 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 3647 if (!This) 3648 return E_OUTOFMEMORY; 3649 3650 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl; 3651 This->ref = 1; 3652 3653 *schema = &This->IMimePropertySchema_iface; 3654 3655 return S_OK; 3656 } 3657 3658 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type, 3659 ADDRESSFORMAT addr_format, WCHAR **address) 3660 { 3661 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address); 3662 3663 return E_NOTIMPL; 3664 } 3665 3666 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 3667 { 3668 FIXME("(%s %p)\n", debugstr_guid(riid), ppv); 3669 *ppv = NULL; 3670 return E_NOINTERFACE; 3671 } 3672 3673 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface) 3674 { 3675 TRACE("\n"); 3676 return 2; 3677 } 3678 3679 static ULONG WINAPI mime_obj_Release(IUnknown *iface) 3680 { 3681 TRACE("\n"); 3682 return 1; 3683 } 3684 3685 static const IUnknownVtbl mime_obj_vtbl = { 3686 mime_obj_QueryInterface, 3687 mime_obj_AddRef, 3688 mime_obj_Release 3689 }; 3690 3691 static IUnknown mime_obj = { &mime_obj_vtbl }; 3692 3693 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding, 3694 REFIID riid, void **out, IMoniker **moniker_new) 3695 { 3696 WCHAR *display_name, *mhtml_url; 3697 size_t len; 3698 HRESULT hres; 3699 3700 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'}; 3701 3702 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new); 3703 3704 if(!IsEqualGUID(&IID_IUnknown, riid)) { 3705 FIXME("Unsupported riid %s\n", debugstr_guid(riid)); 3706 return E_NOINTERFACE; 3707 } 3708 3709 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name); 3710 if(FAILED(hres)) 3711 return hres; 3712 3713 TRACE("display name %s\n", debugstr_w(display_name)); 3714 3715 len = strlenW(display_name); 3716 mhtml_url = heap_alloc((len+1)*sizeof(WCHAR) + sizeof(mhtml_prefixW)); 3717 if(!mhtml_url) 3718 return E_OUTOFMEMORY; 3719 3720 memcpy(mhtml_url, mhtml_prefixW, sizeof(mhtml_prefixW)); 3721 strcpyW(mhtml_url + sizeof(mhtml_prefixW)/sizeof(WCHAR), display_name); 3722 HeapFree(GetProcessHeap(), 0, display_name); 3723 3724 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new); 3725 heap_free(mhtml_url); 3726 if(FAILED(hres)) 3727 return hres; 3728 3729 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */ 3730 *out = &mime_obj; 3731 return S_OK; 3732 } 3733