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