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