|  | /* | 
|  | * MIME OLE International interface | 
|  | * | 
|  | * Copyright 2008 Huw Davies for CodeWeavers | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #define COBJMACROS | 
|  | #define NONAMELESSUNION | 
|  |  | 
|  | #include <stdarg.h> | 
|  | #include <stdio.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "winnls.h" | 
|  | #include "objbase.h" | 
|  | #include "ole2.h" | 
|  | #include "mimeole.h" | 
|  | #include "mlang.h" | 
|  |  | 
|  | #include "wine/list.h" | 
|  | #include "wine/unicode.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "inetcomm_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(inetcomm); | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | struct list entry; | 
|  | INETCSETINFO cs_info; | 
|  | } charset_entry; | 
|  |  | 
|  | typedef struct | 
|  | { | 
|  | const IMimeInternationalVtbl *lpVtbl; | 
|  | LONG refs; | 
|  | CRITICAL_SECTION cs; | 
|  |  | 
|  | struct list charsets; | 
|  | LONG next_charset_handle; | 
|  | HCHARSET default_charset; | 
|  | } internat; | 
|  |  | 
|  | static inline internat *impl_from_IMimeInternational( IMimeInternational *iface ) | 
|  | { | 
|  | return (internat *)((char*)iface - FIELD_OFFSET(internat, lpVtbl)); | 
|  | } | 
|  |  | 
|  | static inline HRESULT get_mlang(IMultiLanguage **ml) | 
|  | { | 
|  | return CoCreateInstance(&CLSID_CMultiLanguage, NULL,  CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER, | 
|  | &IID_IMultiLanguage, (void **)ml); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_QueryInterface( IMimeInternational *iface, REFIID riid, LPVOID *ppobj ) | 
|  | { | 
|  | if (IsEqualGUID(riid, &IID_IUnknown) || | 
|  | IsEqualGUID(riid, &IID_IMimeInternational)) | 
|  | { | 
|  | IMimeInternational_AddRef( iface ); | 
|  | *ppobj = iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | FIXME("interface %s not implemented\n", debugstr_guid(riid)); | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI MimeInternat_AddRef( IMimeInternational *iface ) | 
|  | { | 
|  | internat *This = impl_from_IMimeInternational( iface ); | 
|  | return InterlockedIncrement(&This->refs); | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI MimeInternat_Release( IMimeInternational *iface ) | 
|  | { | 
|  | internat *This = impl_from_IMimeInternational( iface ); | 
|  | ULONG refs; | 
|  |  | 
|  | refs = InterlockedDecrement(&This->refs); | 
|  | if (!refs) | 
|  | { | 
|  | charset_entry *charset, *cursor2; | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY_SAFE(charset, cursor2, &This->charsets, charset_entry, entry) | 
|  | { | 
|  | list_remove(&charset->entry); | 
|  | HeapFree(GetProcessHeap(), 0, charset); | 
|  | } | 
|  | HeapFree(GetProcessHeap(), 0, This); | 
|  | } | 
|  |  | 
|  | return refs; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_SetDefaultCharset(IMimeInternational *iface, HCHARSET hCharset) | 
|  | { | 
|  | internat *This = impl_from_IMimeInternational( iface ); | 
|  |  | 
|  | TRACE("(%p)->(%p)\n", iface, hCharset); | 
|  |  | 
|  | if(hCharset == NULL) return E_INVALIDARG; | 
|  | /* FIXME check hCharset is valid */ | 
|  |  | 
|  | InterlockedExchangePointer(&This->default_charset, hCharset); | 
|  |  | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_GetDefaultCharset(IMimeInternational *iface, LPHCHARSET phCharset) | 
|  | { | 
|  | internat *This = impl_from_IMimeInternational( iface ); | 
|  | HRESULT hr = S_OK; | 
|  |  | 
|  | TRACE("(%p)->(%p)\n", iface, phCharset); | 
|  |  | 
|  | if(This->default_charset == NULL) | 
|  | { | 
|  | HCHARSET hcs; | 
|  | hr = IMimeInternational_GetCodePageCharset(iface, GetACP(), CHARSET_BODY, &hcs); | 
|  | if(SUCCEEDED(hr)) | 
|  | InterlockedCompareExchangePointer(&This->default_charset, hcs, NULL); | 
|  | } | 
|  | *phCharset = This->default_charset; | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT mlang_getcodepageinfo(UINT cp, MIMECPINFO *mlang_cp_info) | 
|  | { | 
|  | HRESULT hr; | 
|  | IMultiLanguage *ml; | 
|  |  | 
|  | hr = get_mlang(&ml); | 
|  |  | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = IMultiLanguage_GetCodePageInfo(ml, cp, mlang_cp_info); | 
|  | IMultiLanguage_Release(ml); | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_GetCodePageCharset(IMimeInternational *iface, CODEPAGEID cpiCodePage, | 
|  | CHARSETTYPE ctCsetType, | 
|  | LPHCHARSET phCharset) | 
|  | { | 
|  | HRESULT hr; | 
|  | MIMECPINFO mlang_cp_info; | 
|  |  | 
|  | TRACE("(%p)->(%d, %d, %p)\n", iface, cpiCodePage, ctCsetType, phCharset); | 
|  |  | 
|  | *phCharset = NULL; | 
|  |  | 
|  | hr = mlang_getcodepageinfo(cpiCodePage, &mlang_cp_info); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | const WCHAR *charset_nameW = NULL; | 
|  | char *charset_name; | 
|  | DWORD len; | 
|  |  | 
|  | switch(ctCsetType) | 
|  | { | 
|  | case CHARSET_BODY: | 
|  | charset_nameW = mlang_cp_info.wszBodyCharset; | 
|  | break; | 
|  | case CHARSET_HEADER: | 
|  | charset_nameW = mlang_cp_info.wszHeaderCharset; | 
|  | break; | 
|  | case CHARSET_WEB: | 
|  | charset_nameW = mlang_cp_info.wszWebCharset; | 
|  | break; | 
|  | default: | 
|  | return MIME_E_INVALID_CHARSET_TYPE; | 
|  | } | 
|  | len = WideCharToMultiByte(CP_ACP, 0, charset_nameW, -1, NULL, 0, NULL, NULL); | 
|  | charset_name = HeapAlloc(GetProcessHeap(), 0, len); | 
|  | WideCharToMultiByte(CP_ACP, 0, charset_nameW, -1, charset_name, len, NULL, NULL); | 
|  | hr = IMimeInternational_FindCharset(iface, charset_name, phCharset); | 
|  | HeapFree(GetProcessHeap(), 0, charset_name); | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT mlang_getcsetinfo(const char *charset, MIMECSETINFO *mlang_info) | 
|  | { | 
|  | DWORD len = MultiByteToWideChar(CP_ACP, 0, charset, -1, NULL, 0); | 
|  | BSTR bstr = SysAllocStringLen(NULL, len - 1); | 
|  | HRESULT hr; | 
|  | IMultiLanguage *ml; | 
|  |  | 
|  | MultiByteToWideChar(CP_ACP, 0, charset, -1, bstr, len); | 
|  |  | 
|  | hr = get_mlang(&ml); | 
|  |  | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = IMultiLanguage_GetCharsetInfo(ml, bstr, mlang_info); | 
|  | IMultiLanguage_Release(ml); | 
|  | } | 
|  | SysFreeString(bstr); | 
|  | if(FAILED(hr)) hr = MIME_E_NOT_FOUND; | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HCHARSET add_charset(struct list *list, MIMECSETINFO *mlang_info, HCHARSET handle) | 
|  | { | 
|  | charset_entry *charset = HeapAlloc(GetProcessHeap(), 0, sizeof(*charset)); | 
|  |  | 
|  | WideCharToMultiByte(CP_ACP, 0, mlang_info->wszCharset, -1, | 
|  | charset->cs_info.szName, sizeof(charset->cs_info.szName), NULL, NULL); | 
|  | charset->cs_info.cpiWindows = mlang_info->uiCodePage; | 
|  | charset->cs_info.cpiInternet = mlang_info->uiInternetEncoding; | 
|  | charset->cs_info.hCharset = handle; | 
|  | charset->cs_info.dwReserved1 = 0; | 
|  | list_add_head(list, &charset->entry); | 
|  |  | 
|  | return charset->cs_info.hCharset; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_FindCharset(IMimeInternational *iface, LPCSTR pszCharset, | 
|  | LPHCHARSET phCharset) | 
|  | { | 
|  | internat *This = impl_from_IMimeInternational( iface ); | 
|  | HRESULT hr = MIME_E_NOT_FOUND; | 
|  | charset_entry *charset; | 
|  |  | 
|  | TRACE("(%p)->(%s, %p)\n", iface, debugstr_a(pszCharset), phCharset); | 
|  |  | 
|  | *phCharset = NULL; | 
|  |  | 
|  | EnterCriticalSection(&This->cs); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(charset, &This->charsets, charset_entry, entry) | 
|  | { | 
|  | if(!lstrcmpiA(charset->cs_info.szName, pszCharset)) | 
|  | { | 
|  | *phCharset = charset->cs_info.hCharset; | 
|  | hr = S_OK; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if(hr == MIME_E_NOT_FOUND) | 
|  | { | 
|  | MIMECSETINFO mlang_info; | 
|  |  | 
|  | LeaveCriticalSection(&This->cs); | 
|  | hr = mlang_getcsetinfo(pszCharset, &mlang_info); | 
|  | EnterCriticalSection(&This->cs); | 
|  |  | 
|  | if(SUCCEEDED(hr)) | 
|  | *phCharset = add_charset(&This->charsets, &mlang_info, | 
|  | (HCHARSET)InterlockedIncrement(&This->next_charset_handle)); | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection(&This->cs); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_GetCharsetInfo(IMimeInternational *iface, HCHARSET hCharset, | 
|  | LPINETCSETINFO pCsetInfo) | 
|  | { | 
|  | internat *This = impl_from_IMimeInternational( iface ); | 
|  | HRESULT hr = MIME_E_INVALID_HANDLE; | 
|  | charset_entry *charset; | 
|  |  | 
|  | TRACE("(%p)->(%p, %p)\n", iface, hCharset, pCsetInfo); | 
|  |  | 
|  | EnterCriticalSection(&This->cs); | 
|  |  | 
|  | LIST_FOR_EACH_ENTRY(charset, &This->charsets, charset_entry, entry) | 
|  | { | 
|  | if(charset->cs_info.hCharset ==  hCharset) | 
|  | { | 
|  | *pCsetInfo = charset->cs_info; | 
|  | hr = S_OK; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | LeaveCriticalSection(&This->cs); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_GetCodePageInfo(IMimeInternational *iface, CODEPAGEID cpiCodePage, | 
|  | LPCODEPAGEINFO pCodePageInfo) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_CanConvertCodePages(IMimeInternational *iface, CODEPAGEID cpiSource, | 
|  | CODEPAGEID cpiDest) | 
|  | { | 
|  | HRESULT hr; | 
|  | IMultiLanguage *ml; | 
|  |  | 
|  | TRACE("(%p)->(%d, %d)\n", iface, cpiSource, cpiDest); | 
|  |  | 
|  | /* Could call mlang.IsConvertINetStringAvailable() to avoid the COM overhead if need be. */ | 
|  |  | 
|  | hr = get_mlang(&ml); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = IMultiLanguage_IsConvertible(ml, cpiSource, cpiDest); | 
|  | IMultiLanguage_Release(ml); | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_DecodeHeader(IMimeInternational *iface, HCHARSET hCharset, | 
|  | LPCSTR pszData, | 
|  | LPPROPVARIANT pDecoded, | 
|  | LPRFC1522INFO pRfc1522Info) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_EncodeHeader(IMimeInternational *iface, HCHARSET hCharset, | 
|  | LPPROPVARIANT pData, | 
|  | LPSTR *ppszEncoded, | 
|  | LPRFC1522INFO pRfc1522Info) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_ConvertBuffer(IMimeInternational *iface, CODEPAGEID cpiSource, | 
|  | CODEPAGEID cpiDest, LPBLOB pIn, LPBLOB pOut, | 
|  | ULONG *pcbRead) | 
|  | { | 
|  | HRESULT hr; | 
|  | IMultiLanguage *ml; | 
|  |  | 
|  | TRACE("(%p)->(%d, %d, %p, %p, %p)\n", iface, cpiSource, cpiDest, pIn, pOut, pcbRead); | 
|  |  | 
|  | *pcbRead = 0; | 
|  | pOut->cbSize = 0; | 
|  |  | 
|  | /* Could call mlang.ConvertINetString() to avoid the COM overhead if need be. */ | 
|  |  | 
|  | hr = get_mlang(&ml); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | DWORD mode = 0; | 
|  | UINT in_size = pIn->cbSize, out_size; | 
|  |  | 
|  | hr = IMultiLanguage_ConvertString(ml, &mode, cpiSource, cpiDest, pIn->pBlobData, &in_size, | 
|  | NULL, &out_size); | 
|  | if(hr == S_OK) /* S_FALSE means the conversion could not be performed */ | 
|  | { | 
|  | pOut->pBlobData = CoTaskMemAlloc(out_size); | 
|  | if(!pOut->pBlobData) | 
|  | hr = E_OUTOFMEMORY; | 
|  | else | 
|  | { | 
|  | mode = 0; | 
|  | in_size = pIn->cbSize; | 
|  | hr = IMultiLanguage_ConvertString(ml, &mode, cpiSource, cpiDest, pIn->pBlobData, &in_size, | 
|  | pOut->pBlobData, &out_size); | 
|  |  | 
|  | if(hr == S_OK) | 
|  | { | 
|  | *pcbRead = in_size; | 
|  | pOut->cbSize = out_size; | 
|  | } | 
|  | else | 
|  | CoTaskMemFree(pOut->pBlobData); | 
|  | } | 
|  | } | 
|  | IMultiLanguage_Release(ml); | 
|  | } | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_ConvertString(IMimeInternational *iface, CODEPAGEID cpiSource, | 
|  | CODEPAGEID cpiDest, LPPROPVARIANT pIn, | 
|  | LPPROPVARIANT pOut) | 
|  | { | 
|  | HRESULT hr; | 
|  | int src_len; | 
|  | IMultiLanguage *ml; | 
|  |  | 
|  | TRACE("(%p)->(%d, %d, %p %p)\n", iface, cpiSource, cpiDest, pIn, pOut); | 
|  |  | 
|  | switch(pIn->vt) | 
|  | { | 
|  | case VT_LPSTR: | 
|  | if(cpiSource == CP_UNICODE) cpiSource = GetACP(); | 
|  | src_len = strlen(pIn->u.pszVal); | 
|  | break; | 
|  | case VT_LPWSTR: | 
|  | cpiSource = CP_UNICODE; | 
|  | src_len = strlenW(pIn->u.pwszVal) * sizeof(WCHAR); | 
|  | break; | 
|  | default: | 
|  | return E_INVALIDARG; | 
|  | } | 
|  |  | 
|  | hr = get_mlang(&ml); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | DWORD mode = 0; | 
|  | UINT in_size = src_len, out_size; | 
|  |  | 
|  | hr = IMultiLanguage_ConvertString(ml, &mode, cpiSource, cpiDest, (BYTE*)pIn->u.pszVal, &in_size, | 
|  | NULL, &out_size); | 
|  | if(hr == S_OK) /* S_FALSE means the conversion could not be performed */ | 
|  | { | 
|  | out_size += (cpiDest == CP_UNICODE) ? sizeof(WCHAR) : sizeof(char); | 
|  |  | 
|  | pOut->u.pszVal = CoTaskMemAlloc(out_size); | 
|  | if(!pOut->u.pszVal) | 
|  | hr = E_OUTOFMEMORY; | 
|  | else | 
|  | { | 
|  | mode = 0; | 
|  | in_size = src_len; | 
|  | hr = IMultiLanguage_ConvertString(ml, &mode, cpiSource, cpiDest, (BYTE*)pIn->u.pszVal, &in_size, | 
|  | (BYTE*)pOut->u.pszVal, &out_size); | 
|  |  | 
|  | if(hr == S_OK) | 
|  | { | 
|  | if(cpiDest == CP_UNICODE) | 
|  | { | 
|  | pOut->u.pwszVal[out_size / sizeof(WCHAR)] = 0; | 
|  | pOut->vt = VT_LPWSTR; | 
|  | } | 
|  | else | 
|  | { | 
|  | pOut->u.pszVal[out_size] = '\0'; | 
|  | pOut->vt = VT_LPSTR; | 
|  | } | 
|  | } | 
|  | else | 
|  | CoTaskMemFree(pOut->u.pszVal); | 
|  | } | 
|  | } | 
|  | IMultiLanguage_Release(ml); | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_MLANG_ConvertInetReset(IMimeInternational *iface) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_MLANG_ConvertInetString(IMimeInternational *iface, CODEPAGEID cpiSource, | 
|  | CODEPAGEID cpiDest, | 
|  | LPCSTR pSource, | 
|  | int *pnSizeOfSource, | 
|  | LPSTR pDestination, | 
|  | int *pnDstSize) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_Rfc1522Decode(IMimeInternational *iface, LPCSTR pszValue, | 
|  | LPSTR pszCharset, | 
|  | ULONG cchmax, | 
|  | LPSTR *ppszDecoded) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI MimeInternat_Rfc1522Encode(IMimeInternational *iface, LPCSTR pszValue, | 
|  | HCHARSET hCharset, | 
|  | LPSTR *ppszEncoded) | 
|  | { | 
|  | FIXME("stub\n"); | 
|  | return E_NOTIMPL; | 
|  | } | 
|  |  | 
|  | static IMimeInternationalVtbl mime_internat_vtbl = | 
|  | { | 
|  | MimeInternat_QueryInterface, | 
|  | MimeInternat_AddRef, | 
|  | MimeInternat_Release, | 
|  | MimeInternat_SetDefaultCharset, | 
|  | MimeInternat_GetDefaultCharset, | 
|  | MimeInternat_GetCodePageCharset, | 
|  | MimeInternat_FindCharset, | 
|  | MimeInternat_GetCharsetInfo, | 
|  | MimeInternat_GetCodePageInfo, | 
|  | MimeInternat_CanConvertCodePages, | 
|  | MimeInternat_DecodeHeader, | 
|  | MimeInternat_EncodeHeader, | 
|  | MimeInternat_ConvertBuffer, | 
|  | MimeInternat_ConvertString, | 
|  | MimeInternat_MLANG_ConvertInetReset, | 
|  | MimeInternat_MLANG_ConvertInetString, | 
|  | MimeInternat_Rfc1522Decode, | 
|  | MimeInternat_Rfc1522Encode | 
|  | }; | 
|  |  | 
|  | static internat *global_internat; | 
|  |  | 
|  | HRESULT MimeInternational_Construct(IMimeInternational **internat) | 
|  | { | 
|  | global_internat = HeapAlloc(GetProcessHeap(), 0, sizeof(*global_internat)); | 
|  | global_internat->lpVtbl = &mime_internat_vtbl; | 
|  | global_internat->refs = 0; | 
|  | InitializeCriticalSection(&global_internat->cs); | 
|  |  | 
|  | list_init(&global_internat->charsets); | 
|  | global_internat->next_charset_handle = 0; | 
|  | global_internat->default_charset = NULL; | 
|  |  | 
|  | *internat = (IMimeInternational*)&global_internat->lpVtbl; | 
|  |  | 
|  | IMimeInternational_AddRef(*internat); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI MimeOleGetInternat(IMimeInternational **internat) | 
|  | { | 
|  | TRACE("(%p)\n", internat); | 
|  |  | 
|  | *internat = (IMimeInternational *)&global_internat->lpVtbl; | 
|  | IMimeInternational_AddRef(*internat); | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI MimeOleFindCharset(LPCSTR name, LPHCHARSET charset) | 
|  | { | 
|  | IMimeInternational *internat; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%s, %p)\n", debugstr_a(name), charset); | 
|  |  | 
|  | hr = MimeOleGetInternat(&internat); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = IMimeInternational_FindCharset(internat, name, charset); | 
|  | IMimeInternational_Release(internat); | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI MimeOleGetCharsetInfo(HCHARSET hCharset, LPINETCSETINFO pCsetInfo) | 
|  | { | 
|  | IMimeInternational *internat; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p, %p)\n", hCharset, pCsetInfo); | 
|  |  | 
|  | hr = MimeOleGetInternat(&internat); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = IMimeInternational_GetCharsetInfo(internat, hCharset, pCsetInfo); | 
|  | IMimeInternational_Release(internat); | 
|  | } | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | HRESULT WINAPI MimeOleGetDefaultCharset(LPHCHARSET charset) | 
|  | { | 
|  | IMimeInternational *internat; | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("(%p)\n", charset); | 
|  |  | 
|  | hr = MimeOleGetInternat(&internat); | 
|  | if(SUCCEEDED(hr)) | 
|  | { | 
|  | hr = IMimeInternational_GetDefaultCharset(internat, charset); | 
|  | IMimeInternational_Release(internat); | 
|  | } | 
|  | return hr; | 
|  | } |