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 "wine/winternl.h" 31 #include "winuser.h" 32 #include "objbase.h" 33 #include "ole2.h" 34 #include "mimeole.h" 35 #ifdef __REACTOS__ 36 #include <winreg.h> 37 #endif 38 #include "propvarutil.h" 39 40 #include "wine/heap.h" 41 #include "wine/list.h" 42 #include "wine/debug.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(!_strnicmp(encoding, "base64", -1)) 772 body->encoding = IET_BASE64; 773 else if(!_strnicmp(encoding, "quoted-printable", -1)) 774 body->encoding = IET_QP; 775 else if(!_strnicmp(encoding, "7bit", -1)) 776 body->encoding = IET_7BIT; 777 else if(!_strnicmp(encoding, "8bit", -1)) 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 free_header(header_t *header) 826 { 827 list_remove(&header->entry); 828 PropVariantClear(&header->value); 829 empty_param_list(&header->params); 830 heap_free(header); 831 } 832 833 static void empty_header_list(struct list *list) 834 { 835 header_t *header, *cursor2; 836 837 LIST_FOR_EACH_ENTRY_SAFE(header, cursor2, list, header_t, entry) 838 { 839 free_header(header); 840 } 841 } 842 843 static void empty_new_prop_list(struct list *list) 844 { 845 property_list_entry_t *prop, *cursor2; 846 847 LIST_FOR_EACH_ENTRY_SAFE(prop, cursor2, list, property_list_entry_t, entry) 848 { 849 list_remove(&prop->entry); 850 HeapFree(GetProcessHeap(), 0, (char *)prop->prop.name); 851 HeapFree(GetProcessHeap(), 0, prop); 852 } 853 } 854 855 static void release_data(REFIID riid, void *data) 856 { 857 if(!data) return; 858 859 if(IsEqualIID(riid, &IID_IStream)) 860 IStream_Release((IStream *)data); 861 else 862 FIXME("Unhandled data format %s\n", debugstr_guid(riid)); 863 } 864 865 static HRESULT find_prop(MimeBody *body, const char *name, header_t **prop) 866 { 867 header_t *header; 868 869 *prop = NULL; 870 871 LIST_FOR_EACH_ENTRY(header, &body->headers, header_t, entry) 872 { 873 if(ISPIDSTR(name)) 874 { 875 if(STRTOPID(name) == header->prop->id) 876 { 877 *prop = header; 878 return S_OK; 879 } 880 } 881 else if(!lstrcmpiA(name, header->prop->name)) 882 { 883 *prop = header; 884 return S_OK; 885 } 886 } 887 888 return MIME_E_NOT_FOUND; 889 } 890 891 static const property_t *find_default_prop(const char *name) 892 { 893 const property_t *prop_def = NULL; 894 895 for(prop_def = default_props; prop_def->name; prop_def++) 896 { 897 if(ISPIDSTR(name)) 898 { 899 if(STRTOPID(name) == prop_def->id) 900 { 901 break; 902 } 903 } 904 else if(!lstrcmpiA(name, prop_def->name)) 905 { 906 break; 907 } 908 } 909 910 if(prop_def->id) 911 TRACE("%s: found match with default property id %d\n", prop_def->name, prop_def->id); 912 else 913 prop_def = NULL; 914 915 return prop_def; 916 } 917 918 static HRESULT WINAPI MimeBody_QueryInterface(IMimeBody* iface, 919 REFIID riid, 920 void** ppvObject) 921 { 922 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppvObject); 923 924 *ppvObject = NULL; 925 926 if (IsEqualIID(riid, &IID_IUnknown) || 927 IsEqualIID(riid, &IID_IPersist) || 928 IsEqualIID(riid, &IID_IPersistStreamInit) || 929 IsEqualIID(riid, &IID_IMimePropertySet) || 930 IsEqualIID(riid, &IID_IMimeBody)) 931 { 932 *ppvObject = iface; 933 } 934 935 if(*ppvObject) 936 { 937 IUnknown_AddRef((IUnknown*)*ppvObject); 938 return S_OK; 939 } 940 941 FIXME("no interface for %s\n", debugstr_guid(riid)); 942 return E_NOINTERFACE; 943 } 944 945 static ULONG WINAPI MimeBody_AddRef(IMimeBody *iface) 946 { 947 MimeBody *This = impl_from_IMimeBody(iface); 948 LONG ref = InterlockedIncrement(&This->ref); 949 950 TRACE("(%p) ref=%d\n", This, ref); 951 952 return ref; 953 } 954 955 static ULONG WINAPI MimeBody_Release(IMimeBody *iface) 956 { 957 MimeBody *This = impl_from_IMimeBody(iface); 958 LONG ref = InterlockedDecrement(&This->ref); 959 960 TRACE("(%p) ref=%d\n", This, ref); 961 962 if (!ref) 963 { 964 empty_header_list(&This->headers); 965 empty_new_prop_list(&This->new_props); 966 967 HeapFree(GetProcessHeap(), 0, This->content_pri_type); 968 HeapFree(GetProcessHeap(), 0, This->content_sub_type); 969 970 release_data(&This->data_iid, This->data); 971 972 HeapFree(GetProcessHeap(), 0, This); 973 } 974 975 return ref; 976 } 977 978 static HRESULT WINAPI MimeBody_GetClassID( 979 IMimeBody* iface, 980 CLSID* pClassID) 981 { 982 MimeBody *This = impl_from_IMimeBody(iface); 983 984 TRACE("(%p)->(%p)\n", This, pClassID); 985 986 if(!pClassID) 987 return E_INVALIDARG; 988 989 *pClassID = IID_IMimeBody; 990 return S_OK; 991 } 992 993 static HRESULT WINAPI MimeBody_IsDirty( 994 IMimeBody* iface) 995 { 996 MimeBody *This = impl_from_IMimeBody(iface); 997 FIXME("(%p)->() stub\n", This); 998 return E_NOTIMPL; 999 } 1000 1001 static HRESULT WINAPI MimeBody_Load(IMimeBody *iface, IStream *pStm) 1002 { 1003 MimeBody *This = impl_from_IMimeBody(iface); 1004 TRACE("(%p)->(%p)\n", This, pStm); 1005 return parse_headers(This, pStm); 1006 } 1007 1008 static HRESULT WINAPI MimeBody_Save(IMimeBody *iface, IStream *pStm, BOOL fClearDirty) 1009 { 1010 MimeBody *This = impl_from_IMimeBody(iface); 1011 FIXME("(%p)->(%p, %d)\n", This, pStm, fClearDirty); 1012 return E_NOTIMPL; 1013 } 1014 1015 static HRESULT WINAPI MimeBody_GetSizeMax( 1016 IMimeBody* iface, 1017 ULARGE_INTEGER* pcbSize) 1018 { 1019 MimeBody *This = impl_from_IMimeBody(iface); 1020 FIXME("(%p)->(%p) stub\n", This, pcbSize); 1021 return E_NOTIMPL; 1022 } 1023 1024 static HRESULT WINAPI MimeBody_InitNew( 1025 IMimeBody* iface) 1026 { 1027 MimeBody *This = impl_from_IMimeBody(iface); 1028 TRACE("(%p)->()\n", This); 1029 return S_OK; 1030 } 1031 1032 static HRESULT WINAPI MimeBody_GetPropInfo( 1033 IMimeBody* iface, 1034 LPCSTR pszName, 1035 LPMIMEPROPINFO pInfo) 1036 { 1037 MimeBody *This = impl_from_IMimeBody(iface); 1038 header_t *header; 1039 HRESULT hr; 1040 DWORD supported = PIM_PROPID | PIM_VTDEFAULT; 1041 1042 TRACE("(%p)->(%s, %p) semi-stub\n", This, debugstr_a(pszName), pInfo); 1043 1044 if(!pszName || !pInfo) 1045 return E_INVALIDARG; 1046 1047 TRACE("mask 0x%04x\n", pInfo->dwMask); 1048 1049 if(pInfo->dwMask & ~supported) 1050 FIXME("Unsupported mask flags 0x%04x\n", pInfo->dwMask & ~supported); 1051 1052 hr = find_prop(This, pszName, &header); 1053 if(hr == S_OK) 1054 { 1055 if(pInfo->dwMask & PIM_CHARSET) 1056 pInfo->hCharset = 0; 1057 if(pInfo->dwMask & PIM_FLAGS) 1058 pInfo->dwFlags = 0x00000000; 1059 if(pInfo->dwMask & PIM_ROWNUMBER) 1060 pInfo->dwRowNumber = 0; 1061 if(pInfo->dwMask & PIM_ENCODINGTYPE) 1062 pInfo->ietEncoding = 0; 1063 if(pInfo->dwMask & PIM_VALUES) 1064 pInfo->cValues = 0; 1065 if(pInfo->dwMask & PIM_PROPID) 1066 pInfo->dwPropId = header->prop->id; 1067 if(pInfo->dwMask & PIM_VTDEFAULT) 1068 pInfo->vtDefault = header->prop->default_vt; 1069 if(pInfo->dwMask & PIM_VTCURRENT) 1070 pInfo->vtCurrent = 0; 1071 } 1072 1073 return hr; 1074 } 1075 1076 static HRESULT WINAPI MimeBody_SetPropInfo( 1077 IMimeBody* iface, 1078 LPCSTR pszName, 1079 LPCMIMEPROPINFO pInfo) 1080 { 1081 MimeBody *This = impl_from_IMimeBody(iface); 1082 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(pszName), pInfo); 1083 return E_NOTIMPL; 1084 } 1085 1086 static HRESULT WINAPI MimeBody_GetProp( 1087 IMimeBody* iface, 1088 LPCSTR pszName, 1089 DWORD dwFlags, 1090 LPPROPVARIANT pValue) 1091 { 1092 MimeBody *This = impl_from_IMimeBody(iface); 1093 header_t *header; 1094 HRESULT hr; 1095 1096 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue); 1097 1098 if(!pszName || !pValue) 1099 return E_INVALIDARG; 1100 1101 if(!ISPIDSTR(pszName) && !lstrcmpiA(pszName, "att:pri-content-type")) 1102 { 1103 PropVariantClear(pValue); 1104 pValue->vt = VT_LPSTR; 1105 pValue->u.pszVal = strdupA(This->content_pri_type); 1106 return S_OK; 1107 } 1108 1109 hr = find_prop(This, pszName, &header); 1110 if(hr == S_OK) 1111 { 1112 TRACE("type %d->%d\n", header->value.vt, pValue->vt); 1113 1114 hr = PropVariantChangeType(pValue, &header->value, 0, pValue->vt); 1115 if(FAILED(hr)) 1116 FIXME("Conversion not currently supported (%d->%d)\n", header->value.vt, pValue->vt); 1117 } 1118 1119 return hr; 1120 } 1121 1122 static HRESULT WINAPI MimeBody_SetProp( 1123 IMimeBody* iface, 1124 LPCSTR pszName, 1125 DWORD dwFlags, 1126 LPCPROPVARIANT pValue) 1127 { 1128 MimeBody *This = impl_from_IMimeBody(iface); 1129 header_t *header; 1130 HRESULT hr; 1131 1132 TRACE("(%p)->(%s, 0x%x, %p)\n", This, debugstr_a(pszName), dwFlags, pValue); 1133 1134 if(!pszName || !pValue) 1135 return E_INVALIDARG; 1136 1137 hr = find_prop(This, pszName, &header); 1138 if(hr != S_OK) 1139 { 1140 property_list_entry_t *prop_entry; 1141 const property_t *prop = NULL; 1142 1143 LIST_FOR_EACH_ENTRY(prop_entry, &This->new_props, property_list_entry_t, entry) 1144 { 1145 if(ISPIDSTR(pszName)) 1146 { 1147 if(STRTOPID(pszName) == prop_entry->prop.id) 1148 { 1149 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id); 1150 prop = &prop_entry->prop; 1151 break; 1152 } 1153 } 1154 else if(!lstrcmpiA(pszName, prop_entry->prop.name)) 1155 { 1156 TRACE("Found match with already added new property id %d\n", prop_entry->prop.id); 1157 prop = &prop_entry->prop; 1158 break; 1159 } 1160 } 1161 1162 header = HeapAlloc(GetProcessHeap(), 0, sizeof(*header)); 1163 if(!header) 1164 return E_OUTOFMEMORY; 1165 1166 if(!prop) 1167 { 1168 const property_t *prop_def = NULL; 1169 prop_entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*prop_entry)); 1170 if(!prop_entry) 1171 { 1172 HeapFree(GetProcessHeap(), 0, header); 1173 return E_OUTOFMEMORY; 1174 } 1175 1176 prop_def = find_default_prop(pszName); 1177 if(prop_def) 1178 { 1179 prop_entry->prop.name = strdupA(prop_def->name); 1180 prop_entry->prop.id = prop_def->id; 1181 } 1182 else 1183 { 1184 if(ISPIDSTR(pszName)) 1185 { 1186 HeapFree(GetProcessHeap(), 0, prop_entry); 1187 HeapFree(GetProcessHeap(), 0, header); 1188 return MIME_E_NOT_FOUND; 1189 } 1190 1191 prop_entry->prop.name = strdupA(pszName); 1192 prop_entry->prop.id = This->next_prop_id++; 1193 } 1194 1195 prop_entry->prop.flags = 0; 1196 prop_entry->prop.default_vt = pValue->vt; 1197 list_add_tail(&This->new_props, &prop_entry->entry); 1198 prop = &prop_entry->prop; 1199 TRACE("Allocating new prop id %d\n", prop_entry->prop.id); 1200 } 1201 1202 header->prop = prop; 1203 PropVariantInit(&header->value); 1204 list_init(&header->params); 1205 list_add_tail(&This->headers, &header->entry); 1206 } 1207 1208 PropVariantCopy(&header->value, pValue); 1209 1210 return S_OK; 1211 } 1212 1213 static HRESULT WINAPI MimeBody_AppendProp( 1214 IMimeBody* iface, 1215 LPCSTR pszName, 1216 DWORD dwFlags, 1217 LPPROPVARIANT pValue) 1218 { 1219 MimeBody *This = impl_from_IMimeBody(iface); 1220 FIXME("(%p)->(%s, 0x%x, %p) stub\n", This, debugstr_a(pszName), dwFlags, pValue); 1221 return E_NOTIMPL; 1222 } 1223 1224 static HRESULT WINAPI MimeBody_DeleteProp( 1225 IMimeBody* iface, 1226 LPCSTR pszName) 1227 { 1228 MimeBody *This = impl_from_IMimeBody(iface); 1229 header_t *cursor; 1230 BOOL found; 1231 1232 TRACE("(%p)->(%s) stub\n", This, debugstr_a(pszName)); 1233 1234 LIST_FOR_EACH_ENTRY(cursor, &This->headers, header_t, entry) 1235 { 1236 if(ISPIDSTR(pszName)) 1237 found = STRTOPID(pszName) == cursor->prop->id; 1238 else 1239 found = !lstrcmpiA(pszName, cursor->prop->name); 1240 1241 if(found) 1242 { 1243 free_header(cursor); 1244 return S_OK; 1245 } 1246 } 1247 1248 return MIME_E_NOT_FOUND; 1249 } 1250 1251 static HRESULT WINAPI MimeBody_CopyProps( 1252 IMimeBody* iface, 1253 ULONG cNames, 1254 LPCSTR* prgszName, 1255 IMimePropertySet* pPropertySet) 1256 { 1257 MimeBody *This = impl_from_IMimeBody(iface); 1258 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet); 1259 return E_NOTIMPL; 1260 } 1261 1262 static HRESULT WINAPI MimeBody_MoveProps( 1263 IMimeBody* iface, 1264 ULONG cNames, 1265 LPCSTR* prgszName, 1266 IMimePropertySet* pPropertySet) 1267 { 1268 MimeBody *This = impl_from_IMimeBody(iface); 1269 FIXME("(%p)->(%d, %p, %p) stub\n", This, cNames, prgszName, pPropertySet); 1270 return E_NOTIMPL; 1271 } 1272 1273 static HRESULT WINAPI MimeBody_DeleteExcept( 1274 IMimeBody* iface, 1275 ULONG cNames, 1276 LPCSTR* prgszName) 1277 { 1278 MimeBody *This = impl_from_IMimeBody(iface); 1279 FIXME("(%p)->(%d, %p) stub\n", This, cNames, prgszName); 1280 return E_NOTIMPL; 1281 } 1282 1283 static HRESULT WINAPI MimeBody_QueryProp( 1284 IMimeBody* iface, 1285 LPCSTR pszName, 1286 LPCSTR pszCriteria, 1287 boolean fSubString, 1288 boolean fCaseSensitive) 1289 { 1290 MimeBody *This = impl_from_IMimeBody(iface); 1291 FIXME("(%p)->(%s, %s, %d, %d) stub\n", This, debugstr_a(pszName), debugstr_a(pszCriteria), fSubString, fCaseSensitive); 1292 return E_NOTIMPL; 1293 } 1294 1295 static HRESULT WINAPI MimeBody_GetCharset( 1296 IMimeBody* iface, 1297 LPHCHARSET phCharset) 1298 { 1299 MimeBody *This = impl_from_IMimeBody(iface); 1300 FIXME("(%p)->(%p) stub\n", This, phCharset); 1301 *phCharset = NULL; 1302 return S_OK; 1303 } 1304 1305 static HRESULT WINAPI MimeBody_SetCharset( 1306 IMimeBody* iface, 1307 HCHARSET hCharset, 1308 CSETAPPLYTYPE applytype) 1309 { 1310 MimeBody *This = impl_from_IMimeBody(iface); 1311 FIXME("(%p)->(%p, %d) stub\n", This, hCharset, applytype); 1312 return E_NOTIMPL; 1313 } 1314 1315 static HRESULT WINAPI MimeBody_GetParameters( 1316 IMimeBody* iface, 1317 LPCSTR pszName, 1318 ULONG* pcParams, 1319 LPMIMEPARAMINFO* pprgParam) 1320 { 1321 MimeBody *This = impl_from_IMimeBody(iface); 1322 HRESULT hr; 1323 header_t *header; 1324 1325 TRACE("(%p)->(%s, %p, %p)\n", iface, debugstr_a(pszName), pcParams, pprgParam); 1326 1327 *pprgParam = NULL; 1328 *pcParams = 0; 1329 1330 hr = find_prop(This, pszName, &header); 1331 if(hr != S_OK) return hr; 1332 1333 *pcParams = list_count(&header->params); 1334 if(*pcParams) 1335 { 1336 IMimeAllocator *alloc; 1337 param_t *param; 1338 MIMEPARAMINFO *info; 1339 1340 MimeOleGetAllocator(&alloc); 1341 1342 *pprgParam = info = IMimeAllocator_Alloc(alloc, *pcParams * sizeof(**pprgParam)); 1343 LIST_FOR_EACH_ENTRY(param, &header->params, param_t, entry) 1344 { 1345 int len; 1346 1347 len = strlen(param->name) + 1; 1348 info->pszName = IMimeAllocator_Alloc(alloc, len); 1349 memcpy(info->pszName, param->name, len); 1350 len = strlen(param->value) + 1; 1351 info->pszData = IMimeAllocator_Alloc(alloc, len); 1352 memcpy(info->pszData, param->value, len); 1353 info++; 1354 } 1355 IMimeAllocator_Release(alloc); 1356 } 1357 return S_OK; 1358 } 1359 1360 static HRESULT WINAPI MimeBody_IsContentType( 1361 IMimeBody* iface, 1362 LPCSTR pszPriType, 1363 LPCSTR pszSubType) 1364 { 1365 MimeBody *This = impl_from_IMimeBody(iface); 1366 1367 TRACE("(%p)->(%s, %s)\n", This, debugstr_a(pszPriType), debugstr_a(pszSubType)); 1368 if(pszPriType) 1369 { 1370 const char *pri = This->content_pri_type; 1371 if(!pri) pri = "text"; 1372 if(lstrcmpiA(pri, pszPriType)) return S_FALSE; 1373 } 1374 1375 if(pszSubType) 1376 { 1377 const char *sub = This->content_sub_type; 1378 if(!sub) sub = "plain"; 1379 if(lstrcmpiA(sub, pszSubType)) return S_FALSE; 1380 } 1381 1382 return S_OK; 1383 } 1384 1385 static HRESULT WINAPI MimeBody_BindToObject( 1386 IMimeBody* iface, 1387 REFIID riid, 1388 void** ppvObject) 1389 { 1390 MimeBody *This = impl_from_IMimeBody(iface); 1391 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_guid(riid), ppvObject); 1392 return E_NOTIMPL; 1393 } 1394 1395 static HRESULT WINAPI MimeBody_Clone( 1396 IMimeBody* iface, 1397 IMimePropertySet** ppPropertySet) 1398 { 1399 MimeBody *This = impl_from_IMimeBody(iface); 1400 FIXME("(%p)->(%p) stub\n", This, ppPropertySet); 1401 return E_NOTIMPL; 1402 } 1403 1404 static HRESULT WINAPI MimeBody_SetOption( 1405 IMimeBody* iface, 1406 const TYPEDID oid, 1407 LPCPROPVARIANT pValue) 1408 { 1409 MimeBody *This = impl_from_IMimeBody(iface); 1410 HRESULT hr = E_NOTIMPL; 1411 TRACE("(%p)->(%08x, %p)\n", This, oid, pValue); 1412 1413 if(pValue->vt != TYPEDID_TYPE(oid)) 1414 { 1415 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid); 1416 return E_INVALIDARG; 1417 } 1418 1419 switch(oid) 1420 { 1421 case OID_SECURITY_HWND_OWNER: 1422 FIXME("OID_SECURITY_HWND_OWNER (value %08x): ignoring\n", pValue->u.ulVal); 1423 hr = S_OK; 1424 break; 1425 case OID_TRANSMIT_BODY_ENCODING: 1426 FIXME("OID_TRANSMIT_BODY_ENCODING (value %08x): ignoring\n", pValue->u.ulVal); 1427 hr = S_OK; 1428 break; 1429 default: 1430 FIXME("Unhandled oid %08x\n", oid); 1431 } 1432 1433 return hr; 1434 } 1435 1436 static HRESULT WINAPI MimeBody_GetOption( 1437 IMimeBody* iface, 1438 const TYPEDID oid, 1439 LPPROPVARIANT pValue) 1440 { 1441 MimeBody *This = impl_from_IMimeBody(iface); 1442 FIXME("(%p)->(%08x, %p): stub\n", This, oid, pValue); 1443 return E_NOTIMPL; 1444 } 1445 1446 static HRESULT WINAPI MimeBody_EnumProps( 1447 IMimeBody* iface, 1448 DWORD dwFlags, 1449 IMimeEnumProperties** ppEnum) 1450 { 1451 MimeBody *This = impl_from_IMimeBody(iface); 1452 FIXME("(%p)->(0x%x, %p) stub\n", This, dwFlags, ppEnum); 1453 return E_NOTIMPL; 1454 } 1455 1456 static HRESULT WINAPI MimeBody_IsType( 1457 IMimeBody* iface, 1458 IMSGBODYTYPE bodytype) 1459 { 1460 MimeBody *This = impl_from_IMimeBody(iface); 1461 1462 TRACE("(%p)->(%d)\n", This, bodytype); 1463 switch(bodytype) 1464 { 1465 case IBT_EMPTY: 1466 return This->data ? S_FALSE : S_OK; 1467 default: 1468 FIXME("Unimplemented bodytype %d - returning S_OK\n", bodytype); 1469 } 1470 return S_OK; 1471 } 1472 1473 static HRESULT WINAPI MimeBody_SetDisplayName( 1474 IMimeBody* iface, 1475 LPCSTR pszDisplay) 1476 { 1477 MimeBody *This = impl_from_IMimeBody(iface); 1478 FIXME("(%p)->(%s) stub\n", This, debugstr_a(pszDisplay)); 1479 return E_NOTIMPL; 1480 } 1481 1482 static HRESULT WINAPI MimeBody_GetDisplayName( 1483 IMimeBody* iface, 1484 LPSTR* ppszDisplay) 1485 { 1486 MimeBody *This = impl_from_IMimeBody(iface); 1487 FIXME("(%p)->(%p) stub\n", This, ppszDisplay); 1488 return E_NOTIMPL; 1489 } 1490 1491 static HRESULT WINAPI MimeBody_GetOffsets( 1492 IMimeBody* iface, 1493 LPBODYOFFSETS pOffsets) 1494 { 1495 MimeBody *This = impl_from_IMimeBody(iface); 1496 TRACE("(%p)->(%p)\n", This, pOffsets); 1497 1498 *pOffsets = This->body_offsets; 1499 1500 if(This->body_offsets.cbBodyEnd == 0) return MIME_E_NO_DATA; 1501 return S_OK; 1502 } 1503 1504 static HRESULT WINAPI MimeBody_GetCurrentEncoding( 1505 IMimeBody* iface, 1506 ENCODINGTYPE* pietEncoding) 1507 { 1508 MimeBody *This = impl_from_IMimeBody(iface); 1509 1510 TRACE("(%p)->(%p)\n", This, pietEncoding); 1511 1512 *pietEncoding = This->encoding; 1513 return S_OK; 1514 } 1515 1516 static HRESULT WINAPI MimeBody_SetCurrentEncoding( 1517 IMimeBody* iface, 1518 ENCODINGTYPE ietEncoding) 1519 { 1520 MimeBody *This = impl_from_IMimeBody(iface); 1521 1522 TRACE("(%p)->(%d)\n", This, ietEncoding); 1523 1524 This->encoding = ietEncoding; 1525 return S_OK; 1526 } 1527 1528 static HRESULT WINAPI MimeBody_GetEstimatedSize( 1529 IMimeBody* iface, 1530 ENCODINGTYPE ietEncoding, 1531 ULONG* pcbSize) 1532 { 1533 MimeBody *This = impl_from_IMimeBody(iface); 1534 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pcbSize); 1535 return E_NOTIMPL; 1536 } 1537 1538 static HRESULT WINAPI MimeBody_GetDataHere( 1539 IMimeBody* iface, 1540 ENCODINGTYPE ietEncoding, 1541 IStream* pStream) 1542 { 1543 MimeBody *This = impl_from_IMimeBody(iface); 1544 FIXME("(%p)->(%d, %p) stub\n", This, ietEncoding, pStream); 1545 return E_NOTIMPL; 1546 } 1547 1548 static const signed char base64_decode_table[] = 1549 { 1550 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x00 */ 1551 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 0x10 */ 1552 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, /* 0x20 */ 1553 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, /* 0x30 */ 1554 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40 */ 1555 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, /* 0x50 */ 1556 -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60 */ 1557 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 /* 0x70 */ 1558 }; 1559 1560 static HRESULT decode_base64(IStream *input, IStream **ret_stream) 1561 { 1562 const unsigned char *ptr, *end; 1563 unsigned char buf[1024]; 1564 LARGE_INTEGER pos; 1565 unsigned char *ret; 1566 unsigned char in[4]; 1567 IStream *output; 1568 DWORD size; 1569 int n = 0; 1570 HRESULT hres; 1571 1572 pos.QuadPart = 0; 1573 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL); 1574 if(FAILED(hres)) 1575 return hres; 1576 1577 hres = CreateStreamOnHGlobal(NULL, TRUE, &output); 1578 if(FAILED(hres)) 1579 return hres; 1580 1581 while(1) { 1582 hres = IStream_Read(input, buf, sizeof(buf), &size); 1583 if(FAILED(hres) || !size) 1584 break; 1585 1586 ptr = ret = buf; 1587 end = buf + size; 1588 1589 while(1) { 1590 /* skip invalid chars */ 1591 while(ptr < end && (*ptr >= ARRAY_SIZE(base64_decode_table) 1592 || base64_decode_table[*ptr] == -1)) 1593 ptr++; 1594 if(ptr == end) 1595 break; 1596 1597 in[n++] = base64_decode_table[*ptr++]; 1598 switch(n) { 1599 case 2: 1600 *ret++ = in[0] << 2 | in[1] >> 4; 1601 continue; 1602 case 3: 1603 *ret++ = in[1] << 4 | in[2] >> 2; 1604 continue; 1605 case 4: 1606 *ret++ = ((in[2] << 6) & 0xc0) | in[3]; 1607 n = 0; 1608 } 1609 } 1610 1611 if(ret > buf) { 1612 hres = IStream_Write(output, buf, ret - buf, NULL); 1613 if(FAILED(hres)) 1614 break; 1615 } 1616 } 1617 1618 if(SUCCEEDED(hres)) 1619 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL); 1620 if(FAILED(hres)) { 1621 IStream_Release(output); 1622 return hres; 1623 } 1624 1625 *ret_stream = output; 1626 return S_OK; 1627 } 1628 1629 static int hex_digit(char c) 1630 { 1631 if('0' <= c && c <= '9') 1632 return c - '0'; 1633 if('A' <= c && c <= 'F') 1634 return c - 'A' + 10; 1635 if('a' <= c && c <= 'f') 1636 return c - 'a' + 10; 1637 return -1; 1638 } 1639 1640 static HRESULT decode_qp(IStream *input, IStream **ret_stream) 1641 { 1642 const unsigned char *ptr, *end; 1643 unsigned char *ret, prev = 0; 1644 unsigned char buf[1024]; 1645 LARGE_INTEGER pos; 1646 IStream *output; 1647 DWORD size; 1648 int n = -1; 1649 HRESULT hres; 1650 1651 pos.QuadPart = 0; 1652 hres = IStream_Seek(input, pos, STREAM_SEEK_SET, NULL); 1653 if(FAILED(hres)) 1654 return hres; 1655 1656 hres = CreateStreamOnHGlobal(NULL, TRUE, &output); 1657 if(FAILED(hres)) 1658 return hres; 1659 1660 while(1) { 1661 hres = IStream_Read(input, buf, sizeof(buf), &size); 1662 if(FAILED(hres) || !size) 1663 break; 1664 1665 ptr = ret = buf; 1666 end = buf + size; 1667 1668 while(ptr < end) { 1669 unsigned char byte = *ptr++; 1670 1671 switch(n) { 1672 case -1: 1673 if(byte == '=') 1674 n = 0; 1675 else 1676 *ret++ = byte; 1677 continue; 1678 case 0: 1679 prev = byte; 1680 n = 1; 1681 continue; 1682 case 1: 1683 if(prev != '\r' || byte != '\n') { 1684 int h1 = hex_digit(prev), h2 = hex_digit(byte); 1685 if(h1 != -1 && h2 != -1) 1686 *ret++ = (h1 << 4) | h2; 1687 else 1688 *ret++ = '='; 1689 } 1690 n = -1; 1691 continue; 1692 } 1693 } 1694 1695 if(ret > buf) { 1696 hres = IStream_Write(output, buf, ret - buf, NULL); 1697 if(FAILED(hres)) 1698 break; 1699 } 1700 } 1701 1702 if(SUCCEEDED(hres)) 1703 hres = IStream_Seek(output, pos, STREAM_SEEK_SET, NULL); 1704 if(FAILED(hres)) { 1705 IStream_Release(output); 1706 return hres; 1707 } 1708 1709 *ret_stream = output; 1710 return S_OK; 1711 } 1712 1713 static HRESULT WINAPI MimeBody_GetData( 1714 IMimeBody* iface, 1715 ENCODINGTYPE ietEncoding, 1716 IStream** ppStream) 1717 { 1718 MimeBody *This = impl_from_IMimeBody(iface); 1719 ULARGE_INTEGER start, size; 1720 HRESULT hres; 1721 1722 TRACE("(%p)->(%d %p)\n", This, ietEncoding, ppStream); 1723 1724 if(This->encoding != ietEncoding) { 1725 switch(This->encoding) { 1726 case IET_BASE64: 1727 hres = decode_base64(This->data, ppStream); 1728 break; 1729 case IET_QP: 1730 hres = decode_qp(This->data, ppStream); 1731 break; 1732 default: 1733 FIXME("Decoding %d is not supported.\n", This->encoding); 1734 hres = S_FALSE; 1735 } 1736 if(ietEncoding != IET_BINARY) 1737 FIXME("Encoding %d is not supported.\n", ietEncoding); 1738 if(hres != S_FALSE) 1739 return hres; 1740 } 1741 1742 start.QuadPart = 0; 1743 hres = get_stream_size(This->data, &size); 1744 if(SUCCEEDED(hres)) 1745 hres = create_sub_stream(This->data, start, size, ppStream); 1746 return hres; 1747 } 1748 1749 static HRESULT WINAPI MimeBody_SetData( 1750 IMimeBody* iface, 1751 ENCODINGTYPE ietEncoding, 1752 LPCSTR pszPriType, 1753 LPCSTR pszSubType, 1754 REFIID riid, 1755 LPVOID pvObject) 1756 { 1757 MimeBody *This = impl_from_IMimeBody(iface); 1758 TRACE("(%p)->(%d, %s, %s, %s %p)\n", This, ietEncoding, debugstr_a(pszPriType), debugstr_a(pszSubType), 1759 debugstr_guid(riid), pvObject); 1760 1761 if(IsEqualIID(riid, &IID_IStream)) 1762 IStream_AddRef((IStream *)pvObject); 1763 else 1764 { 1765 FIXME("Unhandled object type %s\n", debugstr_guid(riid)); 1766 return E_INVALIDARG; 1767 } 1768 1769 if(This->data) 1770 release_data(&This->data_iid, This->data); 1771 1772 This->data_iid = *riid; 1773 This->data = pvObject; 1774 1775 IMimeBody_SetCurrentEncoding(iface, ietEncoding); 1776 1777 /* FIXME: Update the content type. 1778 If pszPriType == NULL use 'application' 1779 If pszSubType == NULL use 'octet-stream' */ 1780 1781 return S_OK; 1782 } 1783 1784 static HRESULT WINAPI MimeBody_EmptyData( 1785 IMimeBody* iface) 1786 { 1787 MimeBody *This = impl_from_IMimeBody(iface); 1788 FIXME("(%p)->() stub\n", This); 1789 return E_NOTIMPL; 1790 } 1791 1792 static HRESULT WINAPI MimeBody_CopyTo( 1793 IMimeBody* iface, 1794 IMimeBody* pBody) 1795 { 1796 MimeBody *This = impl_from_IMimeBody(iface); 1797 FIXME("(%p)->(%p) stub\n", This, pBody); 1798 return E_NOTIMPL; 1799 } 1800 1801 static HRESULT WINAPI MimeBody_GetTransmitInfo( 1802 IMimeBody* iface, 1803 LPTRANSMITINFO pTransmitInfo) 1804 { 1805 MimeBody *This = impl_from_IMimeBody(iface); 1806 FIXME("(%p)->(%p) stub\n", This, pTransmitInfo); 1807 return E_NOTIMPL; 1808 } 1809 1810 static HRESULT WINAPI MimeBody_SaveToFile( 1811 IMimeBody* iface, 1812 ENCODINGTYPE ietEncoding, 1813 LPCSTR pszFilePath) 1814 { 1815 MimeBody *This = impl_from_IMimeBody(iface); 1816 FIXME("(%p)->(%d, %s) stub\n", This, ietEncoding, debugstr_a(pszFilePath)); 1817 return E_NOTIMPL; 1818 } 1819 1820 static HRESULT WINAPI MimeBody_GetHandle( 1821 IMimeBody* iface, 1822 LPHBODY phBody) 1823 { 1824 MimeBody *This = impl_from_IMimeBody(iface); 1825 TRACE("(%p)->(%p)\n", iface, phBody); 1826 1827 if(!phBody) 1828 return E_INVALIDARG; 1829 1830 *phBody = This->handle; 1831 return This->handle ? S_OK : MIME_E_NO_DATA; 1832 } 1833 1834 static IMimeBodyVtbl body_vtbl = 1835 { 1836 MimeBody_QueryInterface, 1837 MimeBody_AddRef, 1838 MimeBody_Release, 1839 MimeBody_GetClassID, 1840 MimeBody_IsDirty, 1841 MimeBody_Load, 1842 MimeBody_Save, 1843 MimeBody_GetSizeMax, 1844 MimeBody_InitNew, 1845 MimeBody_GetPropInfo, 1846 MimeBody_SetPropInfo, 1847 MimeBody_GetProp, 1848 MimeBody_SetProp, 1849 MimeBody_AppendProp, 1850 MimeBody_DeleteProp, 1851 MimeBody_CopyProps, 1852 MimeBody_MoveProps, 1853 MimeBody_DeleteExcept, 1854 MimeBody_QueryProp, 1855 MimeBody_GetCharset, 1856 MimeBody_SetCharset, 1857 MimeBody_GetParameters, 1858 MimeBody_IsContentType, 1859 MimeBody_BindToObject, 1860 MimeBody_Clone, 1861 MimeBody_SetOption, 1862 MimeBody_GetOption, 1863 MimeBody_EnumProps, 1864 MimeBody_IsType, 1865 MimeBody_SetDisplayName, 1866 MimeBody_GetDisplayName, 1867 MimeBody_GetOffsets, 1868 MimeBody_GetCurrentEncoding, 1869 MimeBody_SetCurrentEncoding, 1870 MimeBody_GetEstimatedSize, 1871 MimeBody_GetDataHere, 1872 MimeBody_GetData, 1873 MimeBody_SetData, 1874 MimeBody_EmptyData, 1875 MimeBody_CopyTo, 1876 MimeBody_GetTransmitInfo, 1877 MimeBody_SaveToFile, 1878 MimeBody_GetHandle 1879 }; 1880 1881 static HRESULT MimeBody_set_offsets(MimeBody *body, const BODYOFFSETS *offsets) 1882 { 1883 TRACE("setting offsets to %d, %d, %d, %d\n", offsets->cbBoundaryStart, 1884 offsets->cbHeaderStart, offsets->cbBodyStart, offsets->cbBodyEnd); 1885 1886 body->body_offsets = *offsets; 1887 return S_OK; 1888 } 1889 1890 #define FIRST_CUSTOM_PROP_ID 0x100 1891 1892 static MimeBody *mimebody_create(void) 1893 { 1894 MimeBody *This; 1895 BODYOFFSETS body_offsets; 1896 1897 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 1898 if (!This) 1899 return NULL; 1900 1901 This->IMimeBody_iface.lpVtbl = &body_vtbl; 1902 This->ref = 1; 1903 This->handle = NULL; 1904 list_init(&This->headers); 1905 list_init(&This->new_props); 1906 This->next_prop_id = FIRST_CUSTOM_PROP_ID; 1907 This->content_pri_type = NULL; 1908 This->content_sub_type = NULL; 1909 This->encoding = IET_7BIT; 1910 This->data = NULL; 1911 This->data_iid = IID_NULL; 1912 1913 body_offsets.cbBoundaryStart = body_offsets.cbHeaderStart = 0; 1914 body_offsets.cbBodyStart = body_offsets.cbBodyEnd = 0; 1915 MimeBody_set_offsets(This, &body_offsets); 1916 1917 return This; 1918 } 1919 1920 HRESULT MimeBody_create(IUnknown *outer, void **ppv) 1921 { 1922 MimeBody *mb; 1923 1924 if(outer) 1925 return CLASS_E_NOAGGREGATION; 1926 1927 if ((mb = mimebody_create())) 1928 { 1929 *ppv = &mb->IMimeBody_iface; 1930 return S_OK; 1931 } 1932 else 1933 { 1934 *ppv = NULL; 1935 return E_OUTOFMEMORY; 1936 } 1937 } 1938 1939 typedef struct body_t 1940 { 1941 struct list entry; 1942 DWORD index; 1943 MimeBody *mime_body; 1944 1945 struct body_t *parent; 1946 struct list children; 1947 } body_t; 1948 1949 typedef struct MimeMessage 1950 { 1951 IMimeMessage IMimeMessage_iface; 1952 LONG ref; 1953 IStream *stream; 1954 1955 struct list body_tree; 1956 DWORD next_index; 1957 } MimeMessage; 1958 1959 static inline MimeMessage *impl_from_IMimeMessage(IMimeMessage *iface) 1960 { 1961 return CONTAINING_RECORD(iface, MimeMessage, IMimeMessage_iface); 1962 } 1963 1964 static HRESULT WINAPI MimeMessage_QueryInterface(IMimeMessage *iface, REFIID riid, void **ppv) 1965 { 1966 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 1967 1968 if (IsEqualIID(riid, &IID_IUnknown) || 1969 IsEqualIID(riid, &IID_IPersist) || 1970 IsEqualIID(riid, &IID_IPersistStreamInit) || 1971 IsEqualIID(riid, &IID_IMimeMessageTree) || 1972 IsEqualIID(riid, &IID_IMimeMessage)) 1973 { 1974 *ppv = iface; 1975 IMimeMessage_AddRef(iface); 1976 return S_OK; 1977 } 1978 1979 FIXME("no interface for %s\n", debugstr_guid(riid)); 1980 *ppv = NULL; 1981 return E_NOINTERFACE; 1982 } 1983 1984 static ULONG WINAPI MimeMessage_AddRef(IMimeMessage *iface) 1985 { 1986 MimeMessage *This = impl_from_IMimeMessage(iface); 1987 ULONG ref = InterlockedIncrement(&This->ref); 1988 1989 TRACE("(%p) ref=%d\n", This, ref); 1990 1991 return ref; 1992 } 1993 1994 static void empty_body_list(struct list *list) 1995 { 1996 body_t *body, *cursor2; 1997 LIST_FOR_EACH_ENTRY_SAFE(body, cursor2, list, body_t, entry) 1998 { 1999 empty_body_list(&body->children); 2000 list_remove(&body->entry); 2001 IMimeBody_Release(&body->mime_body->IMimeBody_iface); 2002 HeapFree(GetProcessHeap(), 0, body); 2003 } 2004 } 2005 2006 static ULONG WINAPI MimeMessage_Release(IMimeMessage *iface) 2007 { 2008 MimeMessage *This = impl_from_IMimeMessage(iface); 2009 ULONG ref = InterlockedDecrement(&This->ref); 2010 2011 TRACE("(%p) ref=%d\n", This, ref); 2012 2013 if (!ref) 2014 { 2015 empty_body_list(&This->body_tree); 2016 2017 if(This->stream) IStream_Release(This->stream); 2018 HeapFree(GetProcessHeap(), 0, This); 2019 } 2020 2021 return ref; 2022 } 2023 2024 /*** IPersist methods ***/ 2025 static HRESULT WINAPI MimeMessage_GetClassID( 2026 IMimeMessage *iface, 2027 CLSID *pClassID) 2028 { 2029 FIXME("(%p)->(%p)\n", iface, pClassID); 2030 return E_NOTIMPL; 2031 } 2032 2033 /*** IPersistStreamInit methods ***/ 2034 static HRESULT WINAPI MimeMessage_IsDirty( 2035 IMimeMessage *iface) 2036 { 2037 FIXME("(%p)->()\n", iface); 2038 return E_NOTIMPL; 2039 } 2040 2041 static body_t *new_body_entry(MimeBody *mime_body, DWORD index, body_t *parent) 2042 { 2043 body_t *body = HeapAlloc(GetProcessHeap(), 0, sizeof(*body)); 2044 if(body) 2045 { 2046 body->mime_body = mime_body; 2047 body->index = index; 2048 list_init(&body->children); 2049 body->parent = parent; 2050 2051 mime_body->handle = UlongToHandle(body->index); 2052 } 2053 return body; 2054 } 2055 2056 typedef struct 2057 { 2058 struct list entry; 2059 BODYOFFSETS offsets; 2060 } offset_entry_t; 2061 2062 static HRESULT create_body_offset_list(IStream *stm, const char *boundary, struct list *body_offsets) 2063 { 2064 HRESULT hr; 2065 DWORD read, boundary_start; 2066 int boundary_len = strlen(boundary); 2067 char *buf, *ptr, *overlap; 2068 DWORD start = 0, overlap_no; 2069 offset_entry_t *cur_body = NULL; 2070 BOOL is_first_line = TRUE; 2071 ULARGE_INTEGER cur; 2072 LARGE_INTEGER zero; 2073 2074 list_init(body_offsets); 2075 2076 overlap_no = boundary_len + 5; 2077 2078 overlap = buf = HeapAlloc(GetProcessHeap(), 0, overlap_no + PARSER_BUF_SIZE + 1); 2079 2080 zero.QuadPart = 0; 2081 hr = IStream_Seek(stm, zero, STREAM_SEEK_CUR, &cur); 2082 start = cur.u.LowPart; 2083 2084 do { 2085 hr = IStream_Read(stm, overlap, PARSER_BUF_SIZE, &read); 2086 if(FAILED(hr)) goto end; 2087 if(read == 0) break; 2088 overlap[read] = '\0'; 2089 2090 ptr = buf; 2091 while(1) { 2092 if(is_first_line) { 2093 is_first_line = FALSE; 2094 }else { 2095 ptr = strstr(ptr, "\r\n"); 2096 if(!ptr) 2097 break; 2098 ptr += 2; 2099 } 2100 2101 boundary_start = start + ptr - buf; 2102 2103 if(*ptr == '-' && *(ptr + 1) == '-' && !memcmp(ptr + 2, boundary, boundary_len)) { 2104 ptr += boundary_len + 2; 2105 2106 if(*ptr == '\r' && *(ptr + 1) == '\n') 2107 { 2108 ptr += 2; 2109 if(cur_body) 2110 { 2111 cur_body->offsets.cbBodyEnd = boundary_start - 2; 2112 list_add_tail(body_offsets, &cur_body->entry); 2113 } 2114 cur_body = HeapAlloc(GetProcessHeap(), 0, sizeof(*cur_body)); 2115 cur_body->offsets.cbBoundaryStart = boundary_start; 2116 cur_body->offsets.cbHeaderStart = start + ptr - buf; 2117 } 2118 else if(*ptr == '-' && *(ptr + 1) == '-') 2119 { 2120 if(cur_body) 2121 { 2122 cur_body->offsets.cbBodyEnd = boundary_start - 2; 2123 list_add_tail(body_offsets, &cur_body->entry); 2124 goto end; 2125 } 2126 } 2127 } 2128 } 2129 2130 if(overlap == buf) /* 1st iteration */ 2131 { 2132 memmove(buf, buf + PARSER_BUF_SIZE - overlap_no, overlap_no); 2133 overlap = buf + overlap_no; 2134 start += read - overlap_no; 2135 } 2136 else 2137 { 2138 memmove(buf, buf + PARSER_BUF_SIZE, overlap_no); 2139 start += read; 2140 } 2141 } while(1); 2142 2143 end: 2144 HeapFree(GetProcessHeap(), 0, buf); 2145 return hr; 2146 } 2147 2148 static body_t *create_sub_body(MimeMessage *msg, IStream *pStm, BODYOFFSETS *offset, body_t *parent) 2149 { 2150 ULARGE_INTEGER start, length; 2151 MimeBody *mime_body; 2152 HRESULT hr; 2153 body_t *body; 2154 LARGE_INTEGER pos; 2155 2156 pos.QuadPart = offset->cbHeaderStart; 2157 IStream_Seek(pStm, pos, STREAM_SEEK_SET, NULL); 2158 2159 mime_body = mimebody_create(); 2160 IMimeBody_Load(&mime_body->IMimeBody_iface, pStm); 2161 2162 pos.QuadPart = 0; 2163 hr = IStream_Seek(pStm, pos, STREAM_SEEK_CUR, &start); 2164 offset->cbBodyStart = start.QuadPart; 2165 if (parent) MimeBody_set_offsets(mime_body, offset); 2166 2167 length.QuadPart = offset->cbBodyEnd - offset->cbBodyStart; 2168 create_sub_stream(pStm, start, length, (IStream**)&mime_body->data); 2169 mime_body->data_iid = IID_IStream; 2170 2171 body = new_body_entry(mime_body, msg->next_index++, parent); 2172 2173 if(IMimeBody_IsContentType(&mime_body->IMimeBody_iface, "multipart", NULL) == S_OK) 2174 { 2175 MIMEPARAMINFO *param_info; 2176 ULONG count, i; 2177 IMimeAllocator *alloc; 2178 2179 hr = IMimeBody_GetParameters(&mime_body->IMimeBody_iface, "Content-Type", &count, 2180 ¶m_info); 2181 if(hr != S_OK || count == 0) return body; 2182 2183 MimeOleGetAllocator(&alloc); 2184 2185 for(i = 0; i < count; i++) 2186 { 2187 if(!lstrcmpiA(param_info[i].pszName, "boundary")) 2188 { 2189 struct list offset_list; 2190 offset_entry_t *cur, *cursor2; 2191 hr = create_body_offset_list(pStm, param_info[i].pszData, &offset_list); 2192 LIST_FOR_EACH_ENTRY_SAFE(cur, cursor2, &offset_list, offset_entry_t, entry) 2193 { 2194 body_t *sub_body; 2195 2196 sub_body = create_sub_body(msg, pStm, &cur->offsets, body); 2197 list_add_tail(&body->children, &sub_body->entry); 2198 list_remove(&cur->entry); 2199 HeapFree(GetProcessHeap(), 0, cur); 2200 } 2201 break; 2202 } 2203 } 2204 IMimeAllocator_FreeParamInfoArray(alloc, count, param_info, TRUE); 2205 IMimeAllocator_Release(alloc); 2206 } 2207 return body; 2208 } 2209 2210 static HRESULT WINAPI MimeMessage_Load(IMimeMessage *iface, IStream *pStm) 2211 { 2212 MimeMessage *This = impl_from_IMimeMessage(iface); 2213 body_t *root_body; 2214 BODYOFFSETS offsets; 2215 ULARGE_INTEGER cur; 2216 LARGE_INTEGER zero; 2217 2218 TRACE("(%p)->(%p)\n", iface, pStm); 2219 2220 if(This->stream) 2221 { 2222 FIXME("already loaded a message\n"); 2223 return E_FAIL; 2224 } 2225 2226 empty_body_list(&This->body_tree); 2227 2228 IStream_AddRef(pStm); 2229 This->stream = pStm; 2230 offsets.cbBoundaryStart = offsets.cbHeaderStart = 0; 2231 offsets.cbBodyStart = offsets.cbBodyEnd = 0; 2232 2233 root_body = create_sub_body(This, pStm, &offsets, NULL); 2234 2235 zero.QuadPart = 0; 2236 IStream_Seek(pStm, zero, STREAM_SEEK_END, &cur); 2237 offsets.cbBodyEnd = cur.u.LowPart; 2238 MimeBody_set_offsets(root_body->mime_body, &offsets); 2239 2240 list_add_head(&This->body_tree, &root_body->entry); 2241 2242 return S_OK; 2243 } 2244 2245 static HRESULT WINAPI MimeMessage_Save(IMimeMessage *iface, IStream *pStm, BOOL fClearDirty) 2246 { 2247 FIXME("(%p)->(%p, %s)\n", iface, pStm, fClearDirty ? "TRUE" : "FALSE"); 2248 return E_NOTIMPL; 2249 } 2250 2251 static HRESULT WINAPI MimeMessage_GetSizeMax( 2252 IMimeMessage *iface, 2253 ULARGE_INTEGER *pcbSize) 2254 { 2255 FIXME("(%p)->(%p)\n", iface, pcbSize); 2256 return E_NOTIMPL; 2257 } 2258 2259 static HRESULT WINAPI MimeMessage_InitNew( 2260 IMimeMessage *iface) 2261 { 2262 FIXME("(%p)->()\n", iface); 2263 return E_NOTIMPL; 2264 } 2265 2266 /*** IMimeMessageTree methods ***/ 2267 static HRESULT WINAPI MimeMessage_GetMessageSource(IMimeMessage *iface, IStream **ppStream, 2268 DWORD dwFlags) 2269 { 2270 MimeMessage *This = impl_from_IMimeMessage(iface); 2271 2272 FIXME("(%p)->(%p, 0x%x)\n", iface, ppStream, dwFlags); 2273 2274 IStream_AddRef(This->stream); 2275 *ppStream = This->stream; 2276 return S_OK; 2277 } 2278 2279 static HRESULT WINAPI MimeMessage_GetMessageSize( 2280 IMimeMessage *iface, 2281 ULONG *pcbSize, 2282 DWORD dwFlags) 2283 { 2284 FIXME("(%p)->(%p, 0x%x)\n", iface, pcbSize, dwFlags); 2285 return E_NOTIMPL; 2286 } 2287 2288 static HRESULT WINAPI MimeMessage_LoadOffsetTable( 2289 IMimeMessage *iface, 2290 IStream *pStream) 2291 { 2292 FIXME("(%p)->(%p)\n", iface, pStream); 2293 return E_NOTIMPL; 2294 } 2295 2296 static HRESULT WINAPI MimeMessage_SaveOffsetTable( 2297 IMimeMessage *iface, 2298 IStream *pStream, 2299 DWORD dwFlags) 2300 { 2301 FIXME("(%p)->(%p, 0x%x)\n", iface, pStream, dwFlags); 2302 return E_NOTIMPL; 2303 } 2304 2305 2306 static HRESULT WINAPI MimeMessage_GetFlags( 2307 IMimeMessage *iface, 2308 DWORD *pdwFlags) 2309 { 2310 FIXME("(%p)->(%p)\n", iface, pdwFlags); 2311 return E_NOTIMPL; 2312 } 2313 2314 static HRESULT WINAPI MimeMessage_Commit( 2315 IMimeMessage *iface, 2316 DWORD dwFlags) 2317 { 2318 FIXME("(%p)->(0x%x)\n", iface, dwFlags); 2319 return S_OK; 2320 } 2321 2322 2323 static HRESULT WINAPI MimeMessage_HandsOffStorage( 2324 IMimeMessage *iface) 2325 { 2326 FIXME("(%p)->()\n", iface); 2327 return E_NOTIMPL; 2328 } 2329 2330 static HRESULT find_body(struct list *list, HBODY hbody, body_t **body) 2331 { 2332 body_t *cur; 2333 HRESULT hr; 2334 2335 if(hbody == HBODY_ROOT) 2336 { 2337 *body = LIST_ENTRY(list_head(list), body_t, entry); 2338 return S_OK; 2339 } 2340 2341 LIST_FOR_EACH_ENTRY(cur, list, body_t, entry) 2342 { 2343 if(cur->index == HandleToUlong(hbody)) 2344 { 2345 *body = cur; 2346 return S_OK; 2347 } 2348 hr = find_body(&cur->children, hbody, body); 2349 if(hr == S_OK) return S_OK; 2350 } 2351 return S_FALSE; 2352 } 2353 2354 static HRESULT WINAPI MimeMessage_BindToObject(IMimeMessage *iface, const HBODY hBody, REFIID riid, 2355 void **ppvObject) 2356 { 2357 MimeMessage *This = impl_from_IMimeMessage(iface); 2358 HRESULT hr; 2359 body_t *body; 2360 2361 TRACE("(%p)->(%p, %s, %p)\n", iface, hBody, debugstr_guid(riid), ppvObject); 2362 2363 hr = find_body(&This->body_tree, hBody, &body); 2364 2365 if(hr != S_OK) return hr; 2366 2367 if(IsEqualIID(riid, &IID_IMimeBody)) 2368 { 2369 IMimeBody_AddRef(&body->mime_body->IMimeBody_iface); 2370 *ppvObject = &body->mime_body->IMimeBody_iface; 2371 return S_OK; 2372 } 2373 2374 return E_NOINTERFACE; 2375 } 2376 2377 static HRESULT WINAPI MimeMessage_SaveBody( 2378 IMimeMessage *iface, 2379 HBODY hBody, 2380 DWORD dwFlags, 2381 IStream *pStream) 2382 { 2383 FIXME("(%p)->(%p, 0x%x, %p)\n", iface, hBody, dwFlags, pStream); 2384 return E_NOTIMPL; 2385 } 2386 2387 static HRESULT get_body(MimeMessage *msg, BODYLOCATION location, HBODY pivot, body_t **out) 2388 { 2389 body_t *root = LIST_ENTRY(list_head(&msg->body_tree), body_t, entry); 2390 body_t *body; 2391 HRESULT hr; 2392 struct list *list; 2393 2394 if(location == IBL_ROOT) 2395 { 2396 *out = root; 2397 return S_OK; 2398 } 2399 2400 hr = find_body(&msg->body_tree, pivot, &body); 2401 2402 if(hr == S_OK) 2403 { 2404 switch(location) 2405 { 2406 case IBL_PARENT: 2407 if(body->parent) 2408 *out = body->parent; 2409 else 2410 hr = MIME_E_NOT_FOUND; 2411 break; 2412 2413 case IBL_FIRST: 2414 list = list_head(&body->children); 2415 if(list) 2416 *out = LIST_ENTRY(list, body_t, entry); 2417 else 2418 hr = MIME_E_NOT_FOUND; 2419 break; 2420 2421 case IBL_LAST: 2422 list = list_tail(&body->children); 2423 if(list) 2424 *out = LIST_ENTRY(list, body_t, entry); 2425 else 2426 hr = MIME_E_NOT_FOUND; 2427 break; 2428 2429 case IBL_NEXT: 2430 list = list_next(&body->parent->children, &body->entry); 2431 if(list) 2432 *out = LIST_ENTRY(list, body_t, entry); 2433 else 2434 hr = MIME_E_NOT_FOUND; 2435 break; 2436 2437 case IBL_PREVIOUS: 2438 list = list_prev(&body->parent->children, &body->entry); 2439 if(list) 2440 *out = LIST_ENTRY(list, body_t, entry); 2441 else 2442 hr = MIME_E_NOT_FOUND; 2443 break; 2444 2445 default: 2446 hr = E_FAIL; 2447 break; 2448 } 2449 } 2450 2451 return hr; 2452 } 2453 2454 2455 static HRESULT WINAPI MimeMessage_InsertBody( 2456 IMimeMessage *iface, 2457 BODYLOCATION location, 2458 HBODY hPivot, 2459 LPHBODY phBody) 2460 { 2461 FIXME("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody); 2462 return E_NOTIMPL; 2463 } 2464 2465 static HRESULT WINAPI MimeMessage_GetBody(IMimeMessage *iface, BODYLOCATION location, HBODY hPivot, 2466 HBODY *phBody) 2467 { 2468 MimeMessage *This = impl_from_IMimeMessage(iface); 2469 body_t *body; 2470 HRESULT hr; 2471 2472 TRACE("(%p)->(%d, %p, %p)\n", iface, location, hPivot, phBody); 2473 2474 if(!phBody) 2475 return E_INVALIDARG; 2476 2477 *phBody = NULL; 2478 2479 hr = get_body(This, location, hPivot, &body); 2480 2481 if(hr == S_OK) *phBody = UlongToHandle(body->index); 2482 2483 return hr; 2484 } 2485 2486 static HRESULT WINAPI MimeMessage_DeleteBody( 2487 IMimeMessage *iface, 2488 HBODY hBody, 2489 DWORD dwFlags) 2490 { 2491 FIXME("(%p)->(%p, %08x)\n", iface, hBody, dwFlags); 2492 return E_NOTIMPL; 2493 } 2494 2495 static HRESULT WINAPI MimeMessage_MoveBody( 2496 IMimeMessage *iface, 2497 HBODY hBody, 2498 BODYLOCATION location) 2499 { 2500 FIXME("(%p)->(%d)\n", iface, location); 2501 return E_NOTIMPL; 2502 } 2503 2504 static void count_children(body_t *body, boolean recurse, ULONG *count) 2505 { 2506 body_t *child; 2507 2508 LIST_FOR_EACH_ENTRY(child, &body->children, body_t, entry) 2509 { 2510 (*count)++; 2511 if(recurse) count_children(child, recurse, count); 2512 } 2513 } 2514 2515 static HRESULT WINAPI MimeMessage_CountBodies(IMimeMessage *iface, HBODY hParent, boolean fRecurse, 2516 ULONG *pcBodies) 2517 { 2518 HRESULT hr; 2519 MimeMessage *This = impl_from_IMimeMessage(iface); 2520 body_t *body; 2521 2522 TRACE("(%p)->(%p, %s, %p)\n", iface, hParent, fRecurse ? "TRUE" : "FALSE", pcBodies); 2523 2524 hr = find_body(&This->body_tree, hParent, &body); 2525 if(hr != S_OK) return hr; 2526 2527 *pcBodies = 1; 2528 count_children(body, fRecurse, pcBodies); 2529 2530 return S_OK; 2531 } 2532 2533 static HRESULT find_next(MimeMessage *This, body_t *body, FINDBODY *find, HBODY *out) 2534 { 2535 struct list *ptr; 2536 HBODY next; 2537 2538 for (;;) 2539 { 2540 if (!body) ptr = list_head( &This->body_tree ); 2541 else 2542 { 2543 ptr = list_head( &body->children ); 2544 while (!ptr) 2545 { 2546 if (!body->parent) return MIME_E_NOT_FOUND; 2547 if (!(ptr = list_next( &body->parent->children, &body->entry ))) body = body->parent; 2548 } 2549 } 2550 2551 body = LIST_ENTRY( ptr, body_t, entry ); 2552 next = UlongToHandle( body->index ); 2553 find->dwReserved = body->index; 2554 if (IMimeBody_IsContentType(&body->mime_body->IMimeBody_iface, find->pszPriType, 2555 find->pszSubType) == S_OK) 2556 { 2557 *out = next; 2558 return S_OK; 2559 } 2560 } 2561 return MIME_E_NOT_FOUND; 2562 } 2563 2564 static HRESULT WINAPI MimeMessage_FindFirst(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody) 2565 { 2566 MimeMessage *This = impl_from_IMimeMessage(iface); 2567 2568 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody); 2569 2570 pFindBody->dwReserved = 0; 2571 return find_next(This, NULL, pFindBody, phBody); 2572 } 2573 2574 static HRESULT WINAPI MimeMessage_FindNext(IMimeMessage *iface, FINDBODY *pFindBody, HBODY *phBody) 2575 { 2576 MimeMessage *This = impl_from_IMimeMessage(iface); 2577 body_t *body; 2578 HRESULT hr; 2579 2580 TRACE("(%p)->(%p, %p)\n", iface, pFindBody, phBody); 2581 2582 hr = find_body( &This->body_tree, UlongToHandle( pFindBody->dwReserved ), &body ); 2583 if (hr != S_OK) return MIME_E_NOT_FOUND; 2584 return find_next(This, body, pFindBody, phBody); 2585 } 2586 2587 static HRESULT WINAPI MimeMessage_ResolveURL( 2588 IMimeMessage *iface, 2589 HBODY hRelated, 2590 LPCSTR pszBase, 2591 LPCSTR pszURL, 2592 DWORD dwFlags, 2593 LPHBODY phBody) 2594 { 2595 FIXME("(%p)->(%p, %s, %s, 0x%x, %p)\n", iface, hRelated, pszBase, pszURL, dwFlags, phBody); 2596 return E_NOTIMPL; 2597 } 2598 2599 static HRESULT WINAPI MimeMessage_ToMultipart( 2600 IMimeMessage *iface, 2601 HBODY hBody, 2602 LPCSTR pszSubType, 2603 LPHBODY phMultipart) 2604 { 2605 FIXME("(%p)->(%p, %s, %p)\n", iface, hBody, pszSubType, phMultipart); 2606 return E_NOTIMPL; 2607 } 2608 2609 static HRESULT WINAPI MimeMessage_GetBodyOffsets( 2610 IMimeMessage *iface, 2611 HBODY hBody, 2612 LPBODYOFFSETS pOffsets) 2613 { 2614 FIXME("(%p)->(%p, %p)\n", iface, hBody, pOffsets); 2615 return E_NOTIMPL; 2616 } 2617 2618 static HRESULT WINAPI MimeMessage_GetCharset( 2619 IMimeMessage *iface, 2620 LPHCHARSET phCharset) 2621 { 2622 FIXME("(%p)->(%p)\n", iface, phCharset); 2623 *phCharset = NULL; 2624 return S_OK; 2625 } 2626 2627 static HRESULT WINAPI MimeMessage_SetCharset( 2628 IMimeMessage *iface, 2629 HCHARSET hCharset, 2630 CSETAPPLYTYPE applytype) 2631 { 2632 FIXME("(%p)->(%p, %d)\n", iface, hCharset, applytype); 2633 return E_NOTIMPL; 2634 } 2635 2636 static HRESULT WINAPI MimeMessage_IsBodyType( 2637 IMimeMessage *iface, 2638 HBODY hBody, 2639 IMSGBODYTYPE bodytype) 2640 { 2641 HRESULT hr; 2642 IMimeBody *mime_body; 2643 TRACE("(%p)->(%p, %d)\n", iface, hBody, bodytype); 2644 2645 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body); 2646 if(hr != S_OK) return hr; 2647 2648 hr = IMimeBody_IsType(mime_body, bodytype); 2649 MimeBody_Release(mime_body); 2650 return hr; 2651 } 2652 2653 static HRESULT WINAPI MimeMessage_IsContentType( 2654 IMimeMessage *iface, 2655 HBODY hBody, 2656 LPCSTR pszPriType, 2657 LPCSTR pszSubType) 2658 { 2659 HRESULT hr; 2660 IMimeBody *mime_body; 2661 TRACE("(%p)->(%p, %s, %s)\n", iface, hBody, debugstr_a(pszPriType), 2662 debugstr_a(pszSubType)); 2663 2664 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body); 2665 if(FAILED(hr)) return hr; 2666 2667 hr = IMimeBody_IsContentType(mime_body, pszPriType, pszSubType); 2668 IMimeBody_Release(mime_body); 2669 return hr; 2670 } 2671 2672 static HRESULT WINAPI MimeMessage_QueryBodyProp( 2673 IMimeMessage *iface, 2674 HBODY hBody, 2675 LPCSTR pszName, 2676 LPCSTR pszCriteria, 2677 boolean fSubString, 2678 boolean fCaseSensitive) 2679 { 2680 FIXME("(%p)->(%p, %s, %s, %s, %s)\n", iface, hBody, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE"); 2681 return E_NOTIMPL; 2682 } 2683 2684 static HRESULT WINAPI MimeMessage_GetBodyProp( 2685 IMimeMessage *iface, 2686 HBODY hBody, 2687 LPCSTR pszName, 2688 DWORD dwFlags, 2689 LPPROPVARIANT pValue) 2690 { 2691 HRESULT hr; 2692 IMimeBody *mime_body; 2693 2694 TRACE("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue); 2695 2696 hr = IMimeMessage_BindToObject(iface, hBody, &IID_IMimeBody, (void**)&mime_body); 2697 if(hr != S_OK) return hr; 2698 2699 hr = IMimeBody_GetProp(mime_body, pszName, dwFlags, pValue); 2700 IMimeBody_Release(mime_body); 2701 2702 return hr; 2703 } 2704 2705 static HRESULT WINAPI MimeMessage_SetBodyProp( 2706 IMimeMessage *iface, 2707 HBODY hBody, 2708 LPCSTR pszName, 2709 DWORD dwFlags, 2710 LPCPROPVARIANT pValue) 2711 { 2712 FIXME("(%p)->(%p, %s, 0x%x, %p)\n", iface, hBody, pszName, dwFlags, pValue); 2713 return E_NOTIMPL; 2714 } 2715 2716 static HRESULT WINAPI MimeMessage_DeleteBodyProp( 2717 IMimeMessage *iface, 2718 HBODY hBody, 2719 LPCSTR pszName) 2720 { 2721 FIXME("(%p)->(%p, %s)\n", iface, hBody, pszName); 2722 return E_NOTIMPL; 2723 } 2724 2725 static HRESULT WINAPI MimeMessage_SetOption( 2726 IMimeMessage *iface, 2727 const TYPEDID oid, 2728 LPCPROPVARIANT pValue) 2729 { 2730 HRESULT hr = S_OK; 2731 TRACE("(%p)->(%08x, %p)\n", iface, oid, pValue); 2732 2733 /* Message ID is checked before type. 2734 * OID 0x4D -> 0x56 and 0x58 aren't defined but will filtered out later. 2735 */ 2736 if(TYPEDID_ID(oid) < TYPEDID_ID(OID_ALLOW_8BIT_HEADER) || TYPEDID_ID(oid) > TYPEDID_ID(OID_SECURITY_2KEY_CERT_BAG_64)) 2737 { 2738 WARN("oid (%08x) out of range\n", oid); 2739 return MIME_E_INVALID_OPTION_ID; 2740 } 2741 2742 if(pValue->vt != TYPEDID_TYPE(oid)) 2743 { 2744 WARN("Called with vartype %04x and oid %08x\n", pValue->vt, oid); 2745 return S_OK; 2746 } 2747 2748 switch(oid) 2749 { 2750 case OID_HIDE_TNEF_ATTACHMENTS: 2751 FIXME("OID_HIDE_TNEF_ATTACHMENTS (value %d): ignoring\n", pValue->u.boolVal); 2752 break; 2753 case OID_SHOW_MACBINARY: 2754 FIXME("OID_SHOW_MACBINARY (value %d): ignoring\n", pValue->u.boolVal); 2755 break; 2756 case OID_SAVEBODY_KEEPBOUNDARY: 2757 FIXME("OID_SAVEBODY_KEEPBOUNDARY (value %d): ignoring\n", pValue->u.boolVal); 2758 break; 2759 case OID_CLEANUP_TREE_ON_SAVE: 2760 FIXME("OID_CLEANUP_TREE_ON_SAVE (value %d): ignoring\n", pValue->u.boolVal); 2761 break; 2762 default: 2763 FIXME("Unhandled oid %08x\n", oid); 2764 hr = MIME_E_INVALID_OPTION_ID; 2765 } 2766 2767 return hr; 2768 } 2769 2770 static HRESULT WINAPI MimeMessage_GetOption( 2771 IMimeMessage *iface, 2772 const TYPEDID oid, 2773 LPPROPVARIANT pValue) 2774 { 2775 FIXME("(%p)->(%08x, %p)\n", iface, oid, pValue); 2776 return E_NOTIMPL; 2777 } 2778 2779 /*** IMimeMessage methods ***/ 2780 static HRESULT WINAPI MimeMessage_CreateWebPage( 2781 IMimeMessage *iface, 2782 IStream *pRootStm, 2783 LPWEBPAGEOPTIONS pOptions, 2784 IMimeMessageCallback *pCallback, 2785 IMoniker **ppMoniker) 2786 { 2787 FIXME("(%p)->(%p, %p, %p, %p)\n", iface, pRootStm, pOptions, pCallback, ppMoniker); 2788 *ppMoniker = NULL; 2789 return E_NOTIMPL; 2790 } 2791 2792 static HRESULT WINAPI MimeMessage_GetProp( 2793 IMimeMessage *iface, 2794 LPCSTR pszName, 2795 DWORD dwFlags, 2796 LPPROPVARIANT pValue) 2797 { 2798 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue); 2799 return E_NOTIMPL; 2800 } 2801 2802 static HRESULT WINAPI MimeMessage_SetProp( 2803 IMimeMessage *iface, 2804 LPCSTR pszName, 2805 DWORD dwFlags, 2806 LPCPROPVARIANT pValue) 2807 { 2808 FIXME("(%p)->(%s, 0x%x, %p)\n", iface, pszName, dwFlags, pValue); 2809 return E_NOTIMPL; 2810 } 2811 2812 static HRESULT WINAPI MimeMessage_DeleteProp( 2813 IMimeMessage *iface, 2814 LPCSTR pszName) 2815 { 2816 FIXME("(%p)->(%s)\n", iface, pszName); 2817 return E_NOTIMPL; 2818 } 2819 2820 static HRESULT WINAPI MimeMessage_QueryProp( 2821 IMimeMessage *iface, 2822 LPCSTR pszName, 2823 LPCSTR pszCriteria, 2824 boolean fSubString, 2825 boolean fCaseSensitive) 2826 { 2827 FIXME("(%p)->(%s, %s, %s, %s)\n", iface, pszName, pszCriteria, fSubString ? "TRUE" : "FALSE", fCaseSensitive ? "TRUE" : "FALSE"); 2828 return E_NOTIMPL; 2829 } 2830 2831 static HRESULT WINAPI MimeMessage_GetTextBody( 2832 IMimeMessage *iface, 2833 DWORD dwTxtType, 2834 ENCODINGTYPE ietEncoding, 2835 IStream **pStream, 2836 LPHBODY phBody) 2837 { 2838 HRESULT hr; 2839 HBODY hbody; 2840 FINDBODY find_struct; 2841 IMimeBody *mime_body; 2842 static char text[] = "text"; 2843 static char plain[] = "plain"; 2844 static char html[] = "html"; 2845 2846 TRACE("(%p)->(%d, %d, %p, %p)\n", iface, dwTxtType, ietEncoding, pStream, phBody); 2847 2848 find_struct.pszPriType = text; 2849 2850 switch(dwTxtType) 2851 { 2852 case TXT_PLAIN: 2853 find_struct.pszSubType = plain; 2854 break; 2855 case TXT_HTML: 2856 find_struct.pszSubType = html; 2857 break; 2858 default: 2859 return MIME_E_INVALID_TEXT_TYPE; 2860 } 2861 2862 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody); 2863 if(hr != S_OK) 2864 { 2865 TRACE("not found hr %08x\n", hr); 2866 *phBody = NULL; 2867 return hr; 2868 } 2869 2870 IMimeMessage_BindToObject(iface, hbody, &IID_IMimeBody, (void**)&mime_body); 2871 2872 IMimeBody_GetData(mime_body, ietEncoding, pStream); 2873 *phBody = hbody; 2874 IMimeBody_Release(mime_body); 2875 return hr; 2876 } 2877 2878 static HRESULT WINAPI MimeMessage_SetTextBody( 2879 IMimeMessage *iface, 2880 DWORD dwTxtType, 2881 ENCODINGTYPE ietEncoding, 2882 HBODY hAlternative, 2883 IStream *pStream, 2884 LPHBODY phBody) 2885 { 2886 FIXME("(%p)->(%d, %d, %p, %p, %p)\n", iface, dwTxtType, ietEncoding, hAlternative, pStream, phBody); 2887 return E_NOTIMPL; 2888 } 2889 2890 static HRESULT WINAPI MimeMessage_AttachObject( 2891 IMimeMessage *iface, 2892 REFIID riid, 2893 void *pvObject, 2894 LPHBODY phBody) 2895 { 2896 FIXME("(%p)->(%s, %p, %p)\n", iface, debugstr_guid(riid), pvObject, phBody); 2897 return E_NOTIMPL; 2898 } 2899 2900 static HRESULT WINAPI MimeMessage_AttachFile( 2901 IMimeMessage *iface, 2902 LPCSTR pszFilePath, 2903 IStream *pstmFile, 2904 LPHBODY phBody) 2905 { 2906 FIXME("(%p)->(%s, %p, %p)\n", iface, pszFilePath, pstmFile, phBody); 2907 return E_NOTIMPL; 2908 } 2909 2910 static HRESULT WINAPI MimeMessage_AttachURL( 2911 IMimeMessage *iface, 2912 LPCSTR pszBase, 2913 LPCSTR pszURL, 2914 DWORD dwFlags, 2915 IStream *pstmURL, 2916 LPSTR *ppszCIDURL, 2917 LPHBODY phBody) 2918 { 2919 FIXME("(%p)->(%s, %s, 0x%x, %p, %p, %p)\n", iface, pszBase, pszURL, dwFlags, pstmURL, ppszCIDURL, phBody); 2920 return E_NOTIMPL; 2921 } 2922 2923 static HRESULT WINAPI MimeMessage_GetAttachments( 2924 IMimeMessage *iface, 2925 ULONG *pcAttach, 2926 LPHBODY *pprghAttach) 2927 { 2928 HRESULT hr; 2929 FINDBODY find_struct; 2930 HBODY hbody; 2931 LPHBODY array; 2932 ULONG size = 10; 2933 2934 TRACE("(%p)->(%p, %p)\n", iface, pcAttach, pprghAttach); 2935 2936 *pcAttach = 0; 2937 array = CoTaskMemAlloc(size * sizeof(HBODY)); 2938 2939 find_struct.pszPriType = find_struct.pszSubType = NULL; 2940 hr = IMimeMessage_FindFirst(iface, &find_struct, &hbody); 2941 while(hr == S_OK) 2942 { 2943 hr = IMimeMessage_IsContentType(iface, hbody, "multipart", NULL); 2944 TRACE("IsCT rets %08x %d\n", hr, *pcAttach); 2945 if(hr != S_OK) 2946 { 2947 if(*pcAttach + 1 > size) 2948 { 2949 size *= 2; 2950 array = CoTaskMemRealloc(array, size * sizeof(HBODY)); 2951 } 2952 array[*pcAttach] = hbody; 2953 (*pcAttach)++; 2954 } 2955 hr = IMimeMessage_FindNext(iface, &find_struct, &hbody); 2956 } 2957 2958 *pprghAttach = array; 2959 return S_OK; 2960 } 2961 2962 static HRESULT WINAPI MimeMessage_GetAddressTable( 2963 IMimeMessage *iface, 2964 IMimeAddressTable **ppTable) 2965 { 2966 FIXME("(%p)->(%p)\n", iface, ppTable); 2967 return E_NOTIMPL; 2968 } 2969 2970 static HRESULT WINAPI MimeMessage_GetSender( 2971 IMimeMessage *iface, 2972 LPADDRESSPROPS pAddress) 2973 { 2974 FIXME("(%p)->(%p)\n", iface, pAddress); 2975 return E_NOTIMPL; 2976 } 2977 2978 static HRESULT WINAPI MimeMessage_GetAddressTypes( 2979 IMimeMessage *iface, 2980 DWORD dwAdrTypes, 2981 DWORD dwProps, 2982 LPADDRESSLIST pList) 2983 { 2984 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, pList); 2985 return E_NOTIMPL; 2986 } 2987 2988 static HRESULT WINAPI MimeMessage_GetAddressFormat( 2989 IMimeMessage *iface, 2990 DWORD dwAdrTypes, 2991 ADDRESSFORMAT format, 2992 LPSTR *ppszFormat) 2993 { 2994 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, format, ppszFormat); 2995 return E_NOTIMPL; 2996 } 2997 2998 static HRESULT WINAPI MimeMessage_EnumAddressTypes( 2999 IMimeMessage *iface, 3000 DWORD dwAdrTypes, 3001 DWORD dwProps, 3002 IMimeEnumAddressTypes **ppEnum) 3003 { 3004 FIXME("(%p)->(%d, %d, %p)\n", iface, dwAdrTypes, dwProps, ppEnum); 3005 return E_NOTIMPL; 3006 } 3007 3008 static HRESULT WINAPI MimeMessage_SplitMessage( 3009 IMimeMessage *iface, 3010 ULONG cbMaxPart, 3011 IMimeMessageParts **ppParts) 3012 { 3013 FIXME("(%p)->(%d, %p)\n", iface, cbMaxPart, ppParts); 3014 return E_NOTIMPL; 3015 } 3016 3017 static HRESULT WINAPI MimeMessage_GetRootMoniker( 3018 IMimeMessage *iface, 3019 IMoniker **ppMoniker) 3020 { 3021 FIXME("(%p)->(%p)\n", iface, ppMoniker); 3022 return E_NOTIMPL; 3023 } 3024 3025 static const IMimeMessageVtbl MimeMessageVtbl = 3026 { 3027 MimeMessage_QueryInterface, 3028 MimeMessage_AddRef, 3029 MimeMessage_Release, 3030 MimeMessage_GetClassID, 3031 MimeMessage_IsDirty, 3032 MimeMessage_Load, 3033 MimeMessage_Save, 3034 MimeMessage_GetSizeMax, 3035 MimeMessage_InitNew, 3036 MimeMessage_GetMessageSource, 3037 MimeMessage_GetMessageSize, 3038 MimeMessage_LoadOffsetTable, 3039 MimeMessage_SaveOffsetTable, 3040 MimeMessage_GetFlags, 3041 MimeMessage_Commit, 3042 MimeMessage_HandsOffStorage, 3043 MimeMessage_BindToObject, 3044 MimeMessage_SaveBody, 3045 MimeMessage_InsertBody, 3046 MimeMessage_GetBody, 3047 MimeMessage_DeleteBody, 3048 MimeMessage_MoveBody, 3049 MimeMessage_CountBodies, 3050 MimeMessage_FindFirst, 3051 MimeMessage_FindNext, 3052 MimeMessage_ResolveURL, 3053 MimeMessage_ToMultipart, 3054 MimeMessage_GetBodyOffsets, 3055 MimeMessage_GetCharset, 3056 MimeMessage_SetCharset, 3057 MimeMessage_IsBodyType, 3058 MimeMessage_IsContentType, 3059 MimeMessage_QueryBodyProp, 3060 MimeMessage_GetBodyProp, 3061 MimeMessage_SetBodyProp, 3062 MimeMessage_DeleteBodyProp, 3063 MimeMessage_SetOption, 3064 MimeMessage_GetOption, 3065 MimeMessage_CreateWebPage, 3066 MimeMessage_GetProp, 3067 MimeMessage_SetProp, 3068 MimeMessage_DeleteProp, 3069 MimeMessage_QueryProp, 3070 MimeMessage_GetTextBody, 3071 MimeMessage_SetTextBody, 3072 MimeMessage_AttachObject, 3073 MimeMessage_AttachFile, 3074 MimeMessage_AttachURL, 3075 MimeMessage_GetAttachments, 3076 MimeMessage_GetAddressTable, 3077 MimeMessage_GetSender, 3078 MimeMessage_GetAddressTypes, 3079 MimeMessage_GetAddressFormat, 3080 MimeMessage_EnumAddressTypes, 3081 MimeMessage_SplitMessage, 3082 MimeMessage_GetRootMoniker, 3083 }; 3084 3085 HRESULT MimeMessage_create(IUnknown *outer, void **obj) 3086 { 3087 MimeMessage *This; 3088 MimeBody *mime_body; 3089 body_t *root_body; 3090 3091 TRACE("(%p, %p)\n", outer, obj); 3092 3093 if (outer) 3094 { 3095 FIXME("outer unknown not supported yet\n"); 3096 return E_NOTIMPL; 3097 } 3098 3099 *obj = NULL; 3100 3101 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 3102 if (!This) return E_OUTOFMEMORY; 3103 3104 This->IMimeMessage_iface.lpVtbl = &MimeMessageVtbl; 3105 This->ref = 1; 3106 This->stream = NULL; 3107 list_init(&This->body_tree); 3108 This->next_index = 1; 3109 3110 mime_body = mimebody_create(); 3111 root_body = new_body_entry(mime_body, This->next_index++, NULL); 3112 list_add_head(&This->body_tree, &root_body->entry); 3113 3114 *obj = &This->IMimeMessage_iface; 3115 return S_OK; 3116 } 3117 3118 /*********************************************************************** 3119 * MimeOleCreateMessage (INETCOMM.@) 3120 */ 3121 HRESULT WINAPI MimeOleCreateMessage(IUnknown *pUnkOuter, IMimeMessage **ppMessage) 3122 { 3123 TRACE("(%p, %p)\n", pUnkOuter, ppMessage); 3124 return MimeMessage_create(NULL, (void **)ppMessage); 3125 } 3126 3127 /*********************************************************************** 3128 * MimeOleSetCompatMode (INETCOMM.@) 3129 */ 3130 HRESULT WINAPI MimeOleSetCompatMode(DWORD dwMode) 3131 { 3132 FIXME("(0x%x)\n", dwMode); 3133 return S_OK; 3134 } 3135 3136 /*********************************************************************** 3137 * MimeOleCreateVirtualStream (INETCOMM.@) 3138 */ 3139 HRESULT WINAPI MimeOleCreateVirtualStream(IStream **ppStream) 3140 { 3141 HRESULT hr; 3142 FIXME("(%p)\n", ppStream); 3143 3144 hr = CreateStreamOnHGlobal(NULL, TRUE, ppStream); 3145 return hr; 3146 } 3147 3148 typedef struct MimeSecurity 3149 { 3150 IMimeSecurity IMimeSecurity_iface; 3151 LONG ref; 3152 } MimeSecurity; 3153 3154 static inline MimeSecurity *impl_from_IMimeSecurity(IMimeSecurity *iface) 3155 { 3156 return CONTAINING_RECORD(iface, MimeSecurity, IMimeSecurity_iface); 3157 } 3158 3159 static HRESULT WINAPI MimeSecurity_QueryInterface(IMimeSecurity *iface, REFIID riid, void **ppv) 3160 { 3161 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv); 3162 3163 if (IsEqualIID(riid, &IID_IUnknown) || 3164 IsEqualIID(riid, &IID_IMimeSecurity)) 3165 { 3166 *ppv = iface; 3167 IMimeSecurity_AddRef(iface); 3168 return S_OK; 3169 } 3170 3171 FIXME("no interface for %s\n", debugstr_guid(riid)); 3172 *ppv = NULL; 3173 return E_NOINTERFACE; 3174 } 3175 3176 static ULONG WINAPI MimeSecurity_AddRef(IMimeSecurity *iface) 3177 { 3178 MimeSecurity *This = impl_from_IMimeSecurity(iface); 3179 LONG ref = InterlockedIncrement(&This->ref); 3180 3181 TRACE("(%p) ref=%d\n", This, ref); 3182 3183 return ref; 3184 } 3185 3186 static ULONG WINAPI MimeSecurity_Release(IMimeSecurity *iface) 3187 { 3188 MimeSecurity *This = impl_from_IMimeSecurity(iface); 3189 LONG ref = InterlockedDecrement(&This->ref); 3190 3191 TRACE("(%p) ref=%d\n", This, ref); 3192 3193 if (!ref) 3194 HeapFree(GetProcessHeap(), 0, This); 3195 3196 return ref; 3197 } 3198 3199 static HRESULT WINAPI MimeSecurity_InitNew( 3200 IMimeSecurity* iface) 3201 { 3202 FIXME("(%p)->(): stub\n", iface); 3203 return S_OK; 3204 } 3205 3206 static HRESULT WINAPI MimeSecurity_CheckInit( 3207 IMimeSecurity* iface) 3208 { 3209 FIXME("(%p)->(): stub\n", iface); 3210 return E_NOTIMPL; 3211 } 3212 3213 static HRESULT WINAPI MimeSecurity_EncodeMessage( 3214 IMimeSecurity* iface, 3215 IMimeMessageTree* pTree, 3216 DWORD dwFlags) 3217 { 3218 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags); 3219 return E_NOTIMPL; 3220 } 3221 3222 static HRESULT WINAPI MimeSecurity_EncodeBody( 3223 IMimeSecurity* iface, 3224 IMimeMessageTree* pTree, 3225 HBODY hEncodeRoot, 3226 DWORD dwFlags) 3227 { 3228 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hEncodeRoot, dwFlags); 3229 return E_NOTIMPL; 3230 } 3231 3232 static HRESULT WINAPI MimeSecurity_DecodeMessage( 3233 IMimeSecurity* iface, 3234 IMimeMessageTree* pTree, 3235 DWORD dwFlags) 3236 { 3237 FIXME("(%p)->(%p, %08x): stub\n", iface, pTree, dwFlags); 3238 return E_NOTIMPL; 3239 } 3240 3241 static HRESULT WINAPI MimeSecurity_DecodeBody( 3242 IMimeSecurity* iface, 3243 IMimeMessageTree* pTree, 3244 HBODY hDecodeRoot, 3245 DWORD dwFlags) 3246 { 3247 FIXME("(%p)->(%p, %p, %08x): stub\n", iface, pTree, hDecodeRoot, dwFlags); 3248 return E_NOTIMPL; 3249 } 3250 3251 static HRESULT WINAPI MimeSecurity_EnumCertificates( 3252 IMimeSecurity* iface, 3253 HCAPICERTSTORE hc, 3254 DWORD dwUsage, 3255 PCX509CERT pPrev, 3256 PCX509CERT* ppCert) 3257 { 3258 FIXME("(%p)->(%p, %08x, %p, %p): stub\n", iface, hc, dwUsage, pPrev, ppCert); 3259 return E_NOTIMPL; 3260 } 3261 3262 static HRESULT WINAPI MimeSecurity_GetCertificateName( 3263 IMimeSecurity* iface, 3264 const PCX509CERT pX509Cert, 3265 const CERTNAMETYPE cn, 3266 LPSTR* ppszName) 3267 { 3268 FIXME("(%p)->(%p, %08x, %p): stub\n", iface, pX509Cert, cn, ppszName); 3269 return E_NOTIMPL; 3270 } 3271 3272 static HRESULT WINAPI MimeSecurity_GetMessageType( 3273 IMimeSecurity* iface, 3274 const HWND hwndParent, 3275 IMimeBody* pBody, 3276 DWORD* pdwSecType) 3277 { 3278 FIXME("(%p)->(%p, %p, %p): stub\n", iface, hwndParent, pBody, pdwSecType); 3279 return E_NOTIMPL; 3280 } 3281 3282 static HRESULT WINAPI MimeSecurity_GetCertData( 3283 IMimeSecurity* iface, 3284 const PCX509CERT pX509Cert, 3285 const CERTDATAID dataid, 3286 LPPROPVARIANT pValue) 3287 { 3288 FIXME("(%p)->(%p, %x, %p): stub\n", iface, pX509Cert, dataid, pValue); 3289 return E_NOTIMPL; 3290 } 3291 3292 3293 static const IMimeSecurityVtbl MimeSecurityVtbl = 3294 { 3295 MimeSecurity_QueryInterface, 3296 MimeSecurity_AddRef, 3297 MimeSecurity_Release, 3298 MimeSecurity_InitNew, 3299 MimeSecurity_CheckInit, 3300 MimeSecurity_EncodeMessage, 3301 MimeSecurity_EncodeBody, 3302 MimeSecurity_DecodeMessage, 3303 MimeSecurity_DecodeBody, 3304 MimeSecurity_EnumCertificates, 3305 MimeSecurity_GetCertificateName, 3306 MimeSecurity_GetMessageType, 3307 MimeSecurity_GetCertData 3308 }; 3309 3310 HRESULT MimeSecurity_create(IUnknown *outer, void **obj) 3311 { 3312 MimeSecurity *This; 3313 3314 *obj = NULL; 3315 3316 if (outer) return CLASS_E_NOAGGREGATION; 3317 3318 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 3319 if (!This) return E_OUTOFMEMORY; 3320 3321 This->IMimeSecurity_iface.lpVtbl = &MimeSecurityVtbl; 3322 This->ref = 1; 3323 3324 *obj = &This->IMimeSecurity_iface; 3325 return S_OK; 3326 } 3327 3328 /*********************************************************************** 3329 * MimeOleCreateSecurity (INETCOMM.@) 3330 */ 3331 HRESULT WINAPI MimeOleCreateSecurity(IMimeSecurity **ppSecurity) 3332 { 3333 return MimeSecurity_create(NULL, (void **)ppSecurity); 3334 } 3335 3336 static HRESULT WINAPI MimeAlloc_QueryInterface( 3337 IMimeAllocator* iface, 3338 REFIID riid, 3339 void **obj) 3340 { 3341 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), obj); 3342 3343 if (IsEqualIID(riid, &IID_IUnknown) || 3344 IsEqualIID(riid, &IID_IMalloc) || 3345 IsEqualIID(riid, &IID_IMimeAllocator)) 3346 { 3347 *obj = iface; 3348 IMimeAllocator_AddRef(iface); 3349 return S_OK; 3350 } 3351 3352 FIXME("no interface for %s\n", debugstr_guid(riid)); 3353 *obj = NULL; 3354 return E_NOINTERFACE; 3355 } 3356 3357 static ULONG WINAPI MimeAlloc_AddRef( 3358 IMimeAllocator* iface) 3359 { 3360 return 2; 3361 } 3362 3363 static ULONG WINAPI MimeAlloc_Release( 3364 IMimeAllocator* iface) 3365 { 3366 return 1; 3367 } 3368 3369 static LPVOID WINAPI MimeAlloc_Alloc( 3370 IMimeAllocator* iface, 3371 SIZE_T cb) 3372 { 3373 return CoTaskMemAlloc(cb); 3374 } 3375 3376 static LPVOID WINAPI MimeAlloc_Realloc( 3377 IMimeAllocator* iface, 3378 LPVOID pv, 3379 SIZE_T cb) 3380 { 3381 return CoTaskMemRealloc(pv, cb); 3382 } 3383 3384 static void WINAPI MimeAlloc_Free( 3385 IMimeAllocator* iface, 3386 LPVOID pv) 3387 { 3388 CoTaskMemFree(pv); 3389 } 3390 3391 static SIZE_T WINAPI MimeAlloc_GetSize( 3392 IMimeAllocator* iface, 3393 LPVOID pv) 3394 { 3395 FIXME("stub\n"); 3396 return 0; 3397 } 3398 3399 static int WINAPI MimeAlloc_DidAlloc( 3400 IMimeAllocator* iface, 3401 LPVOID pv) 3402 { 3403 FIXME("stub\n"); 3404 return 0; 3405 } 3406 3407 static void WINAPI MimeAlloc_HeapMinimize( 3408 IMimeAllocator* iface) 3409 { 3410 FIXME("stub\n"); 3411 return; 3412 } 3413 3414 static HRESULT WINAPI MimeAlloc_FreeParamInfoArray( 3415 IMimeAllocator* iface, 3416 ULONG cParams, 3417 LPMIMEPARAMINFO prgParam, 3418 boolean fFreeArray) 3419 { 3420 ULONG i; 3421 TRACE("(%p)->(%d, %p, %d)\n", iface, cParams, prgParam, fFreeArray); 3422 3423 for(i = 0; i < cParams; i++) 3424 { 3425 IMimeAllocator_Free(iface, prgParam[i].pszName); 3426 IMimeAllocator_Free(iface, prgParam[i].pszData); 3427 } 3428 if(fFreeArray) IMimeAllocator_Free(iface, prgParam); 3429 return S_OK; 3430 } 3431 3432 static HRESULT WINAPI MimeAlloc_FreeAddressList( 3433 IMimeAllocator* iface, 3434 LPADDRESSLIST pList) 3435 { 3436 FIXME("stub\n"); 3437 return E_NOTIMPL; 3438 } 3439 3440 static HRESULT WINAPI MimeAlloc_FreeAddressProps( 3441 IMimeAllocator* iface, 3442 LPADDRESSPROPS pAddress) 3443 { 3444 FIXME("stub\n"); 3445 return E_NOTIMPL; 3446 } 3447 3448 static HRESULT WINAPI MimeAlloc_ReleaseObjects( 3449 IMimeAllocator* iface, 3450 ULONG cObjects, 3451 IUnknown **prgpUnknown, 3452 boolean fFreeArray) 3453 { 3454 FIXME("stub\n"); 3455 return E_NOTIMPL; 3456 } 3457 3458 3459 static HRESULT WINAPI MimeAlloc_FreeEnumHeaderRowArray( 3460 IMimeAllocator* iface, 3461 ULONG cRows, 3462 LPENUMHEADERROW prgRow, 3463 boolean fFreeArray) 3464 { 3465 FIXME("stub\n"); 3466 return E_NOTIMPL; 3467 } 3468 3469 static HRESULT WINAPI MimeAlloc_FreeEnumPropertyArray( 3470 IMimeAllocator* iface, 3471 ULONG cProps, 3472 LPENUMPROPERTY prgProp, 3473 boolean fFreeArray) 3474 { 3475 FIXME("stub\n"); 3476 return E_NOTIMPL; 3477 } 3478 3479 static HRESULT WINAPI MimeAlloc_FreeThumbprint( 3480 IMimeAllocator* iface, 3481 THUMBBLOB *pthumbprint) 3482 { 3483 FIXME("stub\n"); 3484 return E_NOTIMPL; 3485 } 3486 3487 3488 static HRESULT WINAPI MimeAlloc_PropVariantClear( 3489 IMimeAllocator* iface, 3490 LPPROPVARIANT pProp) 3491 { 3492 FIXME("stub\n"); 3493 return E_NOTIMPL; 3494 } 3495 3496 static IMimeAllocatorVtbl mime_alloc_vtbl = 3497 { 3498 MimeAlloc_QueryInterface, 3499 MimeAlloc_AddRef, 3500 MimeAlloc_Release, 3501 MimeAlloc_Alloc, 3502 MimeAlloc_Realloc, 3503 MimeAlloc_Free, 3504 MimeAlloc_GetSize, 3505 MimeAlloc_DidAlloc, 3506 MimeAlloc_HeapMinimize, 3507 MimeAlloc_FreeParamInfoArray, 3508 MimeAlloc_FreeAddressList, 3509 MimeAlloc_FreeAddressProps, 3510 MimeAlloc_ReleaseObjects, 3511 MimeAlloc_FreeEnumHeaderRowArray, 3512 MimeAlloc_FreeEnumPropertyArray, 3513 MimeAlloc_FreeThumbprint, 3514 MimeAlloc_PropVariantClear 3515 }; 3516 3517 static IMimeAllocator mime_allocator = 3518 { 3519 &mime_alloc_vtbl 3520 }; 3521 3522 HRESULT MimeAllocator_create(IUnknown *outer, void **obj) 3523 { 3524 if(outer) return CLASS_E_NOAGGREGATION; 3525 3526 *obj = &mime_allocator; 3527 return S_OK; 3528 } 3529 3530 HRESULT WINAPI MimeOleGetAllocator(IMimeAllocator **alloc) 3531 { 3532 return MimeAllocator_create(NULL, (void**)alloc); 3533 } 3534 3535 HRESULT VirtualStream_create(IUnknown *outer, void **obj) 3536 { 3537 FIXME("(%p, %p)\n", outer, obj); 3538 3539 *obj = NULL; 3540 if (outer) return CLASS_E_NOAGGREGATION; 3541 3542 return MimeOleCreateVirtualStream((IStream **)obj); 3543 } 3544 3545 /* IMimePropertySchema Interface */ 3546 static HRESULT WINAPI propschema_QueryInterface(IMimePropertySchema *iface, REFIID riid, void **out) 3547 { 3548 propschema *This = impl_from_IMimePropertySchema(iface); 3549 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), out); 3550 3551 *out = NULL; 3552 3553 if (IsEqualIID(riid, &IID_IUnknown) || 3554 IsEqualIID(riid, &IID_IMimePropertySchema)) 3555 { 3556 *out = iface; 3557 } 3558 else 3559 { 3560 FIXME("no interface for %s\n", debugstr_guid(riid)); 3561 return E_NOINTERFACE; 3562 } 3563 3564 IMimePropertySchema_AddRef(iface); 3565 return S_OK; 3566 } 3567 3568 static ULONG WINAPI propschema_AddRef(IMimePropertySchema *iface) 3569 { 3570 propschema *This = impl_from_IMimePropertySchema(iface); 3571 LONG ref = InterlockedIncrement(&This->ref); 3572 3573 TRACE("(%p) ref=%d\n", This, ref); 3574 3575 return ref; 3576 } 3577 3578 static ULONG WINAPI propschema_Release(IMimePropertySchema *iface) 3579 { 3580 propschema *This = impl_from_IMimePropertySchema(iface); 3581 LONG ref = InterlockedDecrement(&This->ref); 3582 3583 TRACE("(%p) ref=%d\n", This, ref); 3584 3585 if (!ref) 3586 { 3587 HeapFree(GetProcessHeap(), 0, This); 3588 } 3589 3590 return ref; 3591 } 3592 3593 static HRESULT WINAPI propschema_RegisterProperty(IMimePropertySchema *iface, const char *name, DWORD flags, 3594 DWORD rownumber, VARTYPE vtdefault, DWORD *propid) 3595 { 3596 propschema *This = impl_from_IMimePropertySchema(iface); 3597 FIXME("(%p)->(%s, %x, %d, %d, %p) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault, propid); 3598 return E_NOTIMPL; 3599 } 3600 3601 static HRESULT WINAPI propschema_ModifyProperty(IMimePropertySchema *iface, const char *name, DWORD flags, 3602 DWORD rownumber, VARTYPE vtdefault) 3603 { 3604 propschema *This = impl_from_IMimePropertySchema(iface); 3605 FIXME("(%p)->(%s, %x, %d, %d) stub\n", This, debugstr_a(name), flags, rownumber, vtdefault); 3606 return S_OK; 3607 } 3608 3609 static HRESULT WINAPI propschema_GetPropertyId(IMimePropertySchema *iface, const char *name, DWORD *propid) 3610 { 3611 propschema *This = impl_from_IMimePropertySchema(iface); 3612 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), propid); 3613 return E_NOTIMPL; 3614 } 3615 3616 static HRESULT WINAPI propschema_GetPropertyName(IMimePropertySchema *iface, DWORD propid, char **name) 3617 { 3618 propschema *This = impl_from_IMimePropertySchema(iface); 3619 FIXME("(%p)->(%d, %p) stub\n", This, propid, name); 3620 return E_NOTIMPL; 3621 } 3622 3623 static HRESULT WINAPI propschema_RegisterAddressType(IMimePropertySchema *iface, const char *name, DWORD *adrtype) 3624 { 3625 propschema *This = impl_from_IMimePropertySchema(iface); 3626 FIXME("(%p)->(%s, %p) stub\n", This, debugstr_a(name), adrtype); 3627 return E_NOTIMPL; 3628 } 3629 3630 static IMimePropertySchemaVtbl prop_schema_vtbl = 3631 { 3632 propschema_QueryInterface, 3633 propschema_AddRef, 3634 propschema_Release, 3635 propschema_RegisterProperty, 3636 propschema_ModifyProperty, 3637 propschema_GetPropertyId, 3638 propschema_GetPropertyName, 3639 propschema_RegisterAddressType 3640 }; 3641 3642 3643 HRESULT WINAPI MimeOleGetPropertySchema(IMimePropertySchema **schema) 3644 { 3645 propschema *This; 3646 3647 TRACE("(%p) stub\n", schema); 3648 3649 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 3650 if (!This) 3651 return E_OUTOFMEMORY; 3652 3653 This->IMimePropertySchema_iface.lpVtbl = &prop_schema_vtbl; 3654 This->ref = 1; 3655 3656 *schema = &This->IMimePropertySchema_iface; 3657 3658 return S_OK; 3659 } 3660 3661 HRESULT WINAPI MimeGetAddressFormatW(REFIID riid, void *object, DWORD addr_type, 3662 ADDRESSFORMAT addr_format, WCHAR **address) 3663 { 3664 FIXME("(%s, %p, %d, %d, %p) stub\n", debugstr_guid(riid), object, addr_type, addr_format, address); 3665 3666 return E_NOTIMPL; 3667 } 3668 3669 static HRESULT WINAPI mime_obj_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) 3670 { 3671 FIXME("(%s %p)\n", debugstr_guid(riid), ppv); 3672 *ppv = NULL; 3673 return E_NOINTERFACE; 3674 } 3675 3676 static ULONG WINAPI mime_obj_AddRef(IUnknown *iface) 3677 { 3678 TRACE("\n"); 3679 return 2; 3680 } 3681 3682 static ULONG WINAPI mime_obj_Release(IUnknown *iface) 3683 { 3684 TRACE("\n"); 3685 return 1; 3686 } 3687 3688 static const IUnknownVtbl mime_obj_vtbl = { 3689 mime_obj_QueryInterface, 3690 mime_obj_AddRef, 3691 mime_obj_Release 3692 }; 3693 3694 static IUnknown mime_obj = { &mime_obj_vtbl }; 3695 3696 HRESULT WINAPI MimeOleObjectFromMoniker(BINDF bindf, IMoniker *moniker, IBindCtx *binding, 3697 REFIID riid, void **out, IMoniker **moniker_new) 3698 { 3699 WCHAR *display_name, *mhtml_url; 3700 size_t len; 3701 HRESULT hres; 3702 3703 static const WCHAR mhtml_prefixW[] = {'m','h','t','m','l',':'}; 3704 3705 WARN("(0x%08x, %p, %p, %s, %p, %p) semi-stub\n", bindf, moniker, binding, debugstr_guid(riid), out, moniker_new); 3706 3707 if(!IsEqualGUID(&IID_IUnknown, riid)) { 3708 FIXME("Unsupported riid %s\n", debugstr_guid(riid)); 3709 return E_NOINTERFACE; 3710 } 3711 3712 hres = IMoniker_GetDisplayName(moniker, NULL, NULL, &display_name); 3713 if(FAILED(hres)) 3714 return hres; 3715 3716 TRACE("display name %s\n", debugstr_w(display_name)); 3717 3718 len = lstrlenW(display_name); 3719 mhtml_url = heap_alloc((len+1)*sizeof(WCHAR) + sizeof(mhtml_prefixW)); 3720 if(!mhtml_url) 3721 return E_OUTOFMEMORY; 3722 3723 memcpy(mhtml_url, mhtml_prefixW, sizeof(mhtml_prefixW)); 3724 lstrcpyW(mhtml_url + ARRAY_SIZE(mhtml_prefixW), display_name); 3725 HeapFree(GetProcessHeap(), 0, display_name); 3726 3727 hres = CreateURLMoniker(NULL, mhtml_url, moniker_new); 3728 heap_free(mhtml_url); 3729 if(FAILED(hres)) 3730 return hres; 3731 3732 /* FIXME: We most likely should start binding here and return something more meaningful as mime object. */ 3733 *out = &mime_obj; 3734 return S_OK; 3735 } 3736