inetcomm: Implement IMimeInternational_GetDefaultCharset.
[wine] / dlls / inetcomm / mimeintl.c
1 /*
2  * MIME OLE International interface
3  *
4  * Copyright 2008 Huw Davies for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #define COBJMACROS
22 #define NONAMELESSUNION
23
24 #include <stdarg.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "objbase.h"
32 #include "ole2.h"
33 #include "mimeole.h"
34 #include "mlang.h"
35
36 #include "wine/list.h"
37 #include "wine/debug.h"
38
39 #include "inetcomm_private.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(inetcomm);
42
43 typedef struct
44 {
45     struct list entry;
46     INETCSETINFO cs_info;
47 } charset_entry;
48
49 typedef struct
50 {
51     const IMimeInternationalVtbl *lpVtbl;
52     LONG refs;
53     CRITICAL_SECTION cs;
54
55     struct list charsets;
56     LONG next_charset_handle;
57     HCHARSET default_charset;
58 } internat;
59
60 static inline internat *impl_from_IMimeInternational( IMimeInternational *iface )
61 {
62     return (internat *)((char*)iface - FIELD_OFFSET(internat, lpVtbl));
63 }
64
65 static inline HRESULT get_mlang(IMultiLanguage **ml)
66 {
67     return CoCreateInstance(&CLSID_CMultiLanguage, NULL,  CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER,
68                             &IID_IMultiLanguage, (void **)ml);
69 }
70
71 static HRESULT WINAPI MimeInternat_QueryInterface( IMimeInternational *iface, REFIID riid, LPVOID *ppobj )
72 {
73     if (IsEqualGUID(riid, &IID_IUnknown) ||
74         IsEqualGUID(riid, &IID_IMimeInternational))
75     {
76         IMimeInternational_AddRef( iface );
77         *ppobj = iface;
78         return S_OK;
79     }
80
81     FIXME("interface %s not implemented\n", debugstr_guid(riid));
82     return E_NOINTERFACE;
83 }
84
85 static ULONG WINAPI MimeInternat_AddRef( IMimeInternational *iface )
86 {
87     internat *This = impl_from_IMimeInternational( iface );
88     return InterlockedIncrement(&This->refs);
89 }
90
91 static ULONG WINAPI MimeInternat_Release( IMimeInternational *iface )
92 {
93     internat *This = impl_from_IMimeInternational( iface );
94     ULONG refs;
95
96     refs = InterlockedDecrement(&This->refs);
97     if (!refs)
98     {
99         charset_entry *charset, *cursor2;
100
101         LIST_FOR_EACH_ENTRY_SAFE(charset, cursor2, &This->charsets, charset_entry, entry)
102         {
103             list_remove(&charset->entry);
104             HeapFree(GetProcessHeap(), 0, charset);
105         }
106         HeapFree(GetProcessHeap(), 0, This);
107     }
108
109     return refs;
110 }
111
112 static HRESULT WINAPI MimeInternat_SetDefaultCharset(IMimeInternational *iface, HCHARSET hCharset)
113 {
114     FIXME("stub\n");
115     return E_NOTIMPL;
116 }
117
118 static HRESULT WINAPI MimeInternat_GetDefaultCharset(IMimeInternational *iface, LPHCHARSET phCharset)
119 {
120     internat *This = impl_from_IMimeInternational( iface );
121     HRESULT hr = S_OK;
122
123     TRACE("(%p)->(%p)\n", iface, phCharset);
124
125     if(This->default_charset == NULL)
126     {
127         HCHARSET hcs;
128         hr = IMimeInternational_GetCodePageCharset(iface, GetACP(), CHARSET_BODY, &hcs);
129         if(SUCCEEDED(hr))
130             InterlockedCompareExchangePointer(&This->default_charset, hcs, NULL);
131     }
132     *phCharset = This->default_charset;
133
134     return hr;
135 }
136
137 static HRESULT mlang_getcodepageinfo(UINT cp, MIMECPINFO *mlang_cp_info)
138 {
139     HRESULT hr;
140     IMultiLanguage *ml;
141
142     hr = get_mlang(&ml);
143
144     if(SUCCEEDED(hr))
145     {
146         hr = IMultiLanguage_GetCodePageInfo(ml, cp, mlang_cp_info);
147         IMultiLanguage_Release(ml);
148     }
149     return hr;
150 }
151
152 static HRESULT WINAPI MimeInternat_GetCodePageCharset(IMimeInternational *iface, CODEPAGEID cpiCodePage,
153                                                       CHARSETTYPE ctCsetType,
154                                                       LPHCHARSET phCharset)
155 {
156     HRESULT hr;
157     MIMECPINFO mlang_cp_info;
158
159     TRACE("(%p)->(%d, %d, %p)\n", iface, cpiCodePage, ctCsetType, phCharset);
160
161     *phCharset = NULL;
162
163     if(ctCsetType < CHARSET_BODY || ctCsetType > CHARSET_WEB)
164         return MIME_E_INVALID_CHARSET_TYPE;
165
166     hr = mlang_getcodepageinfo(cpiCodePage, &mlang_cp_info);
167     if(SUCCEEDED(hr))
168     {
169         const WCHAR *charset_nameW = NULL;
170         char *charset_name;
171         DWORD len;
172
173         switch(ctCsetType)
174         {
175         case CHARSET_BODY:
176             charset_nameW = mlang_cp_info.wszBodyCharset;
177             break;
178         case CHARSET_HEADER:
179             charset_nameW = mlang_cp_info.wszHeaderCharset;
180             break;
181         case CHARSET_WEB:
182             charset_nameW = mlang_cp_info.wszWebCharset;
183             break;
184         }
185         len = WideCharToMultiByte(CP_ACP, 0, charset_nameW, -1, NULL, 0, NULL, NULL);
186         charset_name = HeapAlloc(GetProcessHeap(), 0, len);
187         WideCharToMultiByte(CP_ACP, 0, charset_nameW, -1, charset_name, len, NULL, NULL);
188         hr = IMimeInternational_FindCharset(iface, charset_name, phCharset);
189         HeapFree(GetProcessHeap(), 0, charset_name);
190     }
191     return hr;
192 }
193
194 static HRESULT mlang_getcsetinfo(const char *charset, MIMECSETINFO *mlang_info)
195 {
196     DWORD len = MultiByteToWideChar(CP_ACP, 0, charset, -1, NULL, 0);
197     BSTR bstr = SysAllocStringLen(NULL, len - 1);
198     HRESULT hr;
199     IMultiLanguage *ml;
200
201     MultiByteToWideChar(CP_ACP, 0, charset, -1, bstr, len);
202
203     hr = get_mlang(&ml);
204
205     if(SUCCEEDED(hr))
206     {
207         hr = IMultiLanguage_GetCharsetInfo(ml, bstr, mlang_info);
208         IMultiLanguage_Release(ml);
209     }
210     SysFreeString(bstr);
211     if(FAILED(hr)) hr = MIME_E_NOT_FOUND;
212     return hr;
213 }
214
215 static HCHARSET add_charset(struct list *list, MIMECSETINFO *mlang_info, HCHARSET handle)
216 {
217     charset_entry *charset = HeapAlloc(GetProcessHeap(), 0, sizeof(*charset));
218
219     WideCharToMultiByte(CP_ACP, 0, mlang_info->wszCharset, -1,
220                         charset->cs_info.szName, sizeof(charset->cs_info.szName), NULL, NULL);
221     charset->cs_info.cpiWindows = mlang_info->uiCodePage;
222     charset->cs_info.cpiInternet = mlang_info->uiInternetEncoding;
223     charset->cs_info.hCharset = handle;
224     charset->cs_info.dwReserved1 = 0;
225     list_add_head(list, &charset->entry);
226
227     return charset->cs_info.hCharset;
228 }
229
230 static HRESULT WINAPI MimeInternat_FindCharset(IMimeInternational *iface, LPCSTR pszCharset,
231                                                LPHCHARSET phCharset)
232 {
233     internat *This = impl_from_IMimeInternational( iface );
234     HRESULT hr = MIME_E_NOT_FOUND;
235     charset_entry *charset;
236
237     TRACE("(%p)->(%s, %p)\n", iface, debugstr_a(pszCharset), phCharset);
238
239     *phCharset = NULL;
240
241     EnterCriticalSection(&This->cs);
242
243     LIST_FOR_EACH_ENTRY(charset, &This->charsets, charset_entry, entry)
244     {
245         if(!strcmp(charset->cs_info.szName, pszCharset))
246         {
247             *phCharset = charset->cs_info.hCharset;
248             hr = S_OK;
249             break;
250         }
251     }
252
253     if(hr == MIME_E_NOT_FOUND)
254     {
255         MIMECSETINFO mlang_info;
256
257         LeaveCriticalSection(&This->cs);
258         hr = mlang_getcsetinfo(pszCharset, &mlang_info);
259         EnterCriticalSection(&This->cs);
260
261         if(SUCCEEDED(hr))
262             *phCharset = add_charset(&This->charsets, &mlang_info,
263                                      (HCHARSET)InterlockedIncrement(&This->next_charset_handle));
264     }
265
266     LeaveCriticalSection(&This->cs);
267     return hr;
268 }
269
270 static HRESULT WINAPI MimeInternat_GetCharsetInfo(IMimeInternational *iface, HCHARSET hCharset,
271                                                   LPINETCSETINFO pCsetInfo)
272 {
273     internat *This = impl_from_IMimeInternational( iface );
274     HRESULT hr = MIME_E_INVALID_HANDLE;
275     charset_entry *charset;
276
277     TRACE("(%p)->(%p, %p)\n", iface, hCharset, pCsetInfo);
278
279     EnterCriticalSection(&This->cs);
280
281     LIST_FOR_EACH_ENTRY(charset, &This->charsets, charset_entry, entry)
282     {
283         if(charset->cs_info.hCharset ==  hCharset)
284         {
285             *pCsetInfo = charset->cs_info;
286             hr = S_OK;
287             break;
288         }
289     }
290
291     LeaveCriticalSection(&This->cs);
292
293     return hr;
294 }
295
296 static HRESULT WINAPI MimeInternat_GetCodePageInfo(IMimeInternational *iface, CODEPAGEID cpiCodePage,
297                                                    LPCODEPAGEINFO pCodePageInfo)
298 {
299     FIXME("stub\n");
300     return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI MimeInternat_DecodeHeader(IMimeInternational *iface, HCHARSET hCharset,
304                                                 LPCSTR pszData,
305                                                 LPPROPVARIANT pDecoded,
306                                                 LPRFC1522INFO pRfc1522Info)
307 {
308     FIXME("stub\n");
309     return E_NOTIMPL;
310 }
311
312 static HRESULT WINAPI MimeInternat_EncodeHeader(IMimeInternational *iface, HCHARSET hCharset,
313                                                 LPPROPVARIANT pData,
314                                                 LPSTR *ppszEncoded,
315                                                 LPRFC1522INFO pRfc1522Info)
316 {
317     FIXME("stub\n");
318     return E_NOTIMPL;
319 }
320
321 static HRESULT WINAPI MimeInternat_ConvertBuffer(IMimeInternational *iface, CODEPAGEID cpiSource,
322                                                  CODEPAGEID cpiDest,
323                                                  LPBLOB pIn,
324                                                  LPBLOB pOut,
325                                                  ULONG *pcbRead)
326 {
327     FIXME("stub\n");
328     return E_NOTIMPL;
329 }
330
331 static HRESULT WINAPI MimeInternat_ConvertString(IMimeInternational *iface, CODEPAGEID cpiSource,
332                                                  CODEPAGEID cpiDest,
333                                                  LPPROPVARIANT pIn,
334                                                  LPPROPVARIANT pOut)
335 {
336     FIXME("stub\n");
337     return E_NOTIMPL;
338 }
339
340 static HRESULT WINAPI MimeInternat_MLANG_ConvertInetReset(IMimeInternational *iface)
341 {
342     FIXME("stub\n");
343     return E_NOTIMPL;
344 }
345
346 static HRESULT WINAPI MimeInternat_MLANG_ConvertInetString(IMimeInternational *iface, CODEPAGEID cpiSource,
347                                                            CODEPAGEID cpiDest,
348                                                            LPCSTR pSource,
349                                                            int *pnSizeOfSource,
350                                                            LPSTR pDestination,
351                                                            int *pnDstSize)
352 {
353     FIXME("stub\n");
354     return E_NOTIMPL;
355 }
356
357 static HRESULT WINAPI MimeInternat_Rfc1522Decode(IMimeInternational *iface, LPCSTR pszValue,
358                                                  LPCSTR pszCharset,
359                                                  ULONG cchmax,
360                                                  LPSTR *ppszDecoded)
361 {
362     FIXME("stub\n");
363     return E_NOTIMPL;
364 }
365
366 static HRESULT WINAPI MimeInternat_Rfc1522Encode(IMimeInternational *iface, LPCSTR pszValue,
367                                                  HCHARSET hCharset,
368                                                  LPSTR *ppszEncoded)
369 {
370     FIXME("stub\n");
371     return E_NOTIMPL;
372 }
373
374 static IMimeInternationalVtbl mime_internat_vtbl =
375 {
376     MimeInternat_QueryInterface,
377     MimeInternat_AddRef,
378     MimeInternat_Release,
379     MimeInternat_SetDefaultCharset,
380     MimeInternat_GetDefaultCharset,
381     MimeInternat_GetCodePageCharset,
382     MimeInternat_FindCharset,
383     MimeInternat_GetCharsetInfo,
384     MimeInternat_GetCodePageInfo,
385     MimeInternat_DecodeHeader,
386     MimeInternat_EncodeHeader,
387     MimeInternat_ConvertBuffer,
388     MimeInternat_ConvertString,
389     MimeInternat_MLANG_ConvertInetReset,
390     MimeInternat_MLANG_ConvertInetString,
391     MimeInternat_Rfc1522Decode,
392     MimeInternat_Rfc1522Encode
393 };
394
395 static internat *global_internat;
396
397 HRESULT MimeInternational_Construct(IMimeInternational **internat)
398 {
399     global_internat = HeapAlloc(GetProcessHeap(), 0, sizeof(*global_internat));
400     global_internat->lpVtbl = &mime_internat_vtbl;
401     global_internat->refs = 0;
402     InitializeCriticalSection(&global_internat->cs);
403
404     list_init(&global_internat->charsets);
405     global_internat->next_charset_handle = 0;
406     global_internat->default_charset = NULL;
407
408     *internat = (IMimeInternational*)&global_internat->lpVtbl;
409
410     IMimeInternational_AddRef(*internat);
411     return S_OK;
412 }
413
414 HRESULT WINAPI MimeOleGetInternat(IMimeInternational **internat)
415 {
416     TRACE("(%p)\n", internat);
417
418     *internat = (IMimeInternational *)&global_internat->lpVtbl;
419     IMimeInternational_AddRef(*internat);
420     return S_OK;
421 }