riched20: COM cleanup for the ITextSelection iface.
[wine] / dlls / inetcpl.cpl / security.c
1 /*
2  * Internet control panel applet: security propsheet
3  *
4  * Copyright 2011 Detlef Riekenberg
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
22 #define COBJMACROS
23 #define CONST_VTABLE
24 #define NONAMELESSUNION
25
26 #include <stdarg.h>
27 #include <windef.h>
28 #include <winbase.h>
29 #include <winuser.h>
30 #include <prsht.h>
31 #include "commctrl.h"
32
33 #include "ole2.h"
34 #include "urlmon.h"
35 #include "initguid.h"
36 #include "winreg.h"
37 #include "shlwapi.h"
38
39 #include "inetcpl.h"
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(inetcpl);
43
44 typedef struct secdlg_data_s {
45     HWND hsec;  /* security propsheet */
46     HWND hlv;   /* listview */
47     HWND htb;   /* trackbar */
48     IInternetSecurityManager *sec_mgr;
49     IInternetZoneManager *zone_mgr;
50     DWORD zone_enumerator;
51     DWORD num_zones;
52     ZONEATTRIBUTES *zone_attr;
53     DWORD *zones;
54     DWORD *levels;
55     HIMAGELIST himages;
56     DWORD last_lv_index;
57     DWORD last_level;
58 } secdlg_data;
59
60 #define NUM_TRACKBAR_POS 5
61
62 static WCHAR spaceW[] = {' ',0};
63 static DWORD url_templates[] = {URLTEMPLATE_CUSTOM,
64                                 URLTEMPLATE_LOW,
65                                 URLTEMPLATE_MEDLOW,
66                                 URLTEMPLATE_MEDIUM,
67                                 URLTEMPLATE_MEDHIGH,
68                                 URLTEMPLATE_HIGH};
69
70 /*********************************************************************
71  * index_from_urltemplate [internal]
72  *
73  */
74 static DWORD index_from_urltemplate(URLTEMPLATE value)
75 {
76
77     DWORD index = sizeof(url_templates) / sizeof(url_templates[0]);
78
79     while((index > 0) && (url_templates[index-1] != value))
80         index--;
81
82     index--; /* table entries are 0 based */
83     if (!index && value)
84         FIXME("URLTEMPLATE 0x%x not supported\n", value);
85
86     TRACE("URLTEMPLATE 0x%08x=> Level %d\n", value, index);
87     return index;
88 }
89
90 /*********************************************************************
91  * update_security_level [internal]
92  *
93  */
94 static void update_security_level(secdlg_data *sd, DWORD lv_index, DWORD tb_index)
95 {
96     WCHAR name[512];
97     DWORD current_index;
98
99     TRACE("(%p, lv_index: %u, tb_index: %u)\n", sd, lv_index, tb_index);
100
101     if ((sd->levels[lv_index] != sd->last_level) || (tb_index > 0)) {
102         /* show or hide the trackbar */
103         if (!sd->levels[lv_index] || !sd->last_level)
104             ShowWindow(sd->htb, sd->levels[lv_index] ? SW_NORMAL : SW_HIDE);
105
106         current_index = (tb_index > 0) ? tb_index : index_from_urltemplate(sd->levels[lv_index]);
107
108         name[0] = 0;
109         LoadStringW(hcpl, IDS_SEC_LEVEL0 + current_index, name, sizeof(name)/sizeof(name[0]));
110         TRACE("new level #%d: %s\n", current_index, debugstr_w(name));
111         SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL), name);
112
113         name[0] = 0;
114         LoadStringW(hcpl, IDS_SEC_LEVEL0_INFO + (current_index * 0x10), name, sizeof(name)/sizeof(name[0]));
115         TRACE("new level info: %s\n", debugstr_w(name));
116         SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_LEVEL_INFO), name);
117
118         if (current_index)
119             SendMessageW(sd->htb, TBM_SETPOS, TRUE, NUM_TRACKBAR_POS - current_index);
120
121         sd->last_level = sd->levels[lv_index];
122
123     }
124 }
125
126 /*********************************************************************
127  * update_zone_info [internal]
128  *
129  */
130 static void update_zone_info(secdlg_data *sd, DWORD lv_index)
131 {
132     ZONEATTRIBUTES *za = &sd->zone_attr[lv_index];
133     WCHAR name[MAX_PATH];
134     DWORD len;
135
136     SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_ZONE_INFO), za->szDescription);
137
138     name[0] = ' ';
139     name[1] = 0;
140
141     LoadStringW(hcpl, IDS_SEC_SETTINGS, &name[1], sizeof(name)/sizeof(name[0]) - 3);
142     len = lstrlenW(name);
143     lstrcpynW(&name[len], za->szDisplayName, sizeof(name)/sizeof(name[0]) - len - 3);
144     lstrcatW(name, spaceW);
145
146     TRACE("new title: %s\n", debugstr_w(name));
147     SetWindowTextW(GetDlgItem(sd->hsec, IDC_SEC_GROUP), name);
148
149     update_security_level(sd, lv_index, 0);
150     sd->last_lv_index = lv_index;
151 }
152
153 /*********************************************************************
154  * add_zone_to_listview [internal]
155  *
156  */
157 static void add_zone_to_listview(secdlg_data *sd, DWORD *pindex, DWORD zone)
158 {
159     DWORD lv_index = *pindex;
160     ZONEATTRIBUTES *za = &sd->zone_attr[lv_index];
161     LVITEMW lvitem;
162     HRESULT hr;
163     INT iconid = 0;
164     HMODULE hdll = NULL;
165     WCHAR * ptr;
166     HICON icon;
167
168     TRACE("item %d (zone %d)\n", lv_index, zone);
169
170     sd->zones[lv_index] = zone;
171
172     memset(&lvitem, 0, sizeof(LVITEMW));
173     memset(za, 0, sizeof(ZONEATTRIBUTES));
174     za->cbSize = sizeof(ZONEATTRIBUTES);
175     hr = IInternetZoneManager_GetZoneAttributes(sd->zone_mgr, zone, za);
176     if (SUCCEEDED(hr)) {
177         TRACE("displayname: %s\n", debugstr_w(za->szDisplayName));
178         TRACE("description: %s\n", debugstr_w(za->szDescription));
179         TRACE("minlevel: 0x%x, recommended: 0x%x, current: 0x%x (flags: 0x%x)\n", za->dwTemplateMinLevel,
180              za->dwTemplateRecommended, za->dwTemplateCurrentLevel, za->dwFlags);
181
182         if (za->dwFlags & ZAFLAGS_NO_UI ) {
183             TRACE("item %d (zone %d): UI disabled for %s\n", lv_index, zone, debugstr_w(za->szDisplayName));
184             return;
185         }
186
187         sd->levels[lv_index] = za->dwTemplateCurrentLevel;
188
189         lvitem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM;
190         lvitem.iItem = lv_index;
191         lvitem.iSubItem = 0;
192         lvitem.pszText = za->szDisplayName;
193         lvitem.lParam = (LPARAM) zone;
194
195         /* format is "filename.ext#iconid" */
196         ptr = StrChrW(za->szIconPath, '#');
197         if (ptr) {
198             *ptr = 0;
199             ptr++;
200             iconid = StrToIntW(ptr);
201             hdll = LoadLibraryExW(za->szIconPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
202             TRACE("%p: icon #%d from %s\n", hdll, iconid, debugstr_w(za->szIconPath));
203
204             icon = LoadImageW(hdll, MAKEINTRESOURCEW(iconid), IMAGE_ICON, GetSystemMetrics(SM_CXICON),
205                               GetSystemMetrics(SM_CYICON), LR_SHARED);
206
207             if (!icon) {
208                 FIXME("item %d (zone %d): missing icon #%d in %s\n", lv_index, zone, iconid, debugstr_w(za->szIconPath));
209             }
210
211             /* the failure result (NULL) from LoadImageW let ImageList_AddIcon fail
212                with -1, which is reused in ListView_InsertItemW to disable the image */
213             lvitem.iImage = ImageList_AddIcon(sd->himages, icon);
214         }
215         else
216             FIXME("item %d (zone %d): malformed szIconPath %s\n", lv_index, zone, debugstr_w(za->szIconPath));
217
218         if (ListView_InsertItemW(sd->hlv, &lvitem) >= 0) {
219             /* activate first item in the listview */
220             if (! lv_index) {
221                 lvitem.state = LVIS_FOCUSED | LVIS_SELECTED;
222                 lvitem.stateMask = LVIS_FOCUSED | LVIS_SELECTED;
223                 SendMessageW(sd->hlv, LVM_SETITEMSTATE, 0, (LPARAM) &lvitem);
224                 sd->last_level = ~0;
225                 update_zone_info(sd, lv_index);
226             }
227             (*pindex)++;
228         }
229         FreeLibrary(hdll);
230     }
231     else
232         FIXME("item %d (zone %d): GetZoneAttributes failed with 0x%x\n", lv_index, zone, hr);
233 }
234
235 /*********************************************************************
236  * security_cleanup_zones [internal]
237  *
238  */
239 static void security_cleanup_zones(secdlg_data *sd)
240 {
241     if (sd->zone_enumerator) {
242         IInternetZoneManager_DestroyZoneEnumerator(sd->zone_mgr, sd->zone_enumerator);
243     }
244
245     if (sd->zone_mgr) {
246         IInternetZoneManager_Release(sd->zone_mgr);
247     }
248
249     if (sd->sec_mgr) {
250         IInternetSecurityManager_Release(sd->sec_mgr);
251     }
252 }
253
254 /*********************************************************************
255  * security_enum_zones [internal]
256  *
257  */
258 static HRESULT security_enum_zones(secdlg_data * sd)
259 {
260     HRESULT hr;
261
262     hr = CoInternetCreateSecurityManager(NULL, &sd->sec_mgr, 0);
263     if (SUCCEEDED(hr)) {
264         hr = CoInternetCreateZoneManager(NULL, &sd->zone_mgr, 0);
265         if (SUCCEEDED(hr)) {
266             hr = IInternetZoneManager_CreateZoneEnumerator(sd->zone_mgr, &sd->zone_enumerator, &sd->num_zones, 0);
267         }
268     }
269     return hr;
270 }
271
272 /*********************************************************************
273  * security_on_destroy [internal]
274  *
275  * handle WM_NCDESTROY
276  *
277  */
278 static INT_PTR security_on_destroy(secdlg_data * sd)
279 {
280     TRACE("(%p)\n", sd);
281
282     heap_free(sd->zone_attr);
283     heap_free(sd->zones);
284     if (sd->himages) {
285         SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, 0);
286         ImageList_Destroy(sd->himages);
287     }
288
289     security_cleanup_zones(sd);
290     SetWindowLongPtrW(sd->hsec, DWLP_USER, 0);
291     heap_free(sd);
292     return TRUE;
293 }
294
295 /*********************************************************************
296  * security_on_initdialog [internal]
297  *
298  * handle WM_INITDIALOG
299  *
300  */
301 static INT_PTR security_on_initdialog(HWND hsec)
302 {
303     secdlg_data *sd;
304     HRESULT hr;
305     DWORD current_zone;
306     DWORD lv_index = 0;
307     DWORD i;
308
309     sd = heap_alloc_zero(sizeof(secdlg_data));
310     SetWindowLongPtrW(hsec, DWLP_USER, (LONG_PTR) sd);
311     if (!sd) {
312         return FALSE;
313     }
314
315     sd->hsec = hsec;
316     sd->hlv = GetDlgItem(hsec, IDC_SEC_LISTVIEW);
317     sd->htb = GetDlgItem(hsec, IDC_SEC_TRACKBAR);
318
319     EnableWindow(sd->htb, FALSE); /* not changeable yet */
320
321     TRACE("(%p)   (data: %p, listview: %p, trackbar: %p)\n", hsec, sd, sd->hlv, sd->htb);
322
323     SendMessageW(sd->htb, TBM_SETRANGE, FALSE, MAKELONG(0, NUM_TRACKBAR_POS - 1));
324     SendMessageW(sd->htb, TBM_SETTICFREQ, 1, 0 );
325
326     /* Create the image lists for the listview */
327     sd->himages = ImageList_Create(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CYICON), ILC_COLOR32 | ILC_MASK, 1, 1);
328
329     TRACE("using imagelist: %p\n", sd->himages);
330     if (!sd->himages) {
331         ERR("ImageList_Create failed!\n");
332         return FALSE;
333     }
334     SendMessageW(sd->hlv, LVM_SETIMAGELIST, LVSIL_NORMAL, (LPARAM)sd->himages);
335
336     hr = security_enum_zones(sd);
337     if (FAILED(hr)) {
338         ERR("got 0x%x\n", hr);
339         security_on_destroy(sd);
340         return FALSE;
341     }
342
343     TRACE("found %d zones\n", sd->num_zones);
344
345     /* remember ZONEATTRIBUTES for a listview entry */
346     sd->zone_attr = heap_alloc(sizeof(ZONEATTRIBUTES) * sd->num_zones);
347     if (!sd->zone_attr) {
348         security_on_destroy(sd);
349         return FALSE;
350     }
351
352     /* remember zone number and current security level for a listview entry */
353     sd->zones = heap_alloc((sizeof(DWORD) + sizeof(DWORD)) * sd->num_zones);
354     if (!sd->zones) {
355         security_on_destroy(sd);
356         return FALSE;
357     }
358     sd->levels = &sd->zones[sd->num_zones];
359
360     /* use the same order as visible with native inetcpl.cpl */
361     add_zone_to_listview(sd, &lv_index, URLZONE_INTERNET);
362     add_zone_to_listview(sd, &lv_index, URLZONE_INTRANET);
363     add_zone_to_listview(sd, &lv_index, URLZONE_TRUSTED);
364     add_zone_to_listview(sd, &lv_index, URLZONE_UNTRUSTED);
365
366     for (i = 0; i < sd->num_zones; i++)
367     {
368         hr = IInternetZoneManager_GetZoneAt(sd->zone_mgr, sd->zone_enumerator, i, &current_zone);
369         if (SUCCEEDED(hr) && (current_zone != (DWORD)URLZONE_INVALID)) {
370             if (!current_zone || (current_zone > URLZONE_UNTRUSTED)) {
371                 add_zone_to_listview(sd, &lv_index, current_zone);
372             }
373         }
374     }
375     return TRUE;
376 }
377
378 /*********************************************************************
379  * security_on_notify [internal]
380  *
381  * handle WM_NOTIFY
382  *
383  */
384 static INT_PTR security_on_notify(secdlg_data *sd, WPARAM wparam, LPARAM lparam)
385 {
386     NMLISTVIEW *nm;
387
388     nm = (NMLISTVIEW *) lparam;
389     switch (nm->hdr.code)
390     {
391         case LVN_ITEMCHANGED:
392             TRACE("LVN_ITEMCHANGED (0x%lx, 0x%lx) from %p with code: %d (item: %d, uNewState: %u)\n",
393                     wparam, lparam, nm->hdr.hwndFrom, nm->hdr.code, nm->iItem, nm->uNewState);
394             if ((nm->uNewState & LVIS_SELECTED) == LVIS_SELECTED) {
395                 update_zone_info(sd, nm->iItem);
396             }
397             break;
398
399         case PSN_APPLY:
400             TRACE("PSN_APPLY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam,
401                     nm->hdr.hwndFrom, nm->hdr.code);
402             break;
403
404         default:
405             TRACE("WM_NOTIFY (0x%lx, 0x%lx) from %p with code: %d\n", wparam, lparam,
406                     nm->hdr.hwndFrom, nm->hdr.code);
407
408     }
409     return FALSE;
410 }
411
412 /*********************************************************************
413  * security_dlgproc [internal]
414  *
415  */
416 INT_PTR CALLBACK security_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
417 {
418     secdlg_data *sd;
419
420     if (msg == WM_INITDIALOG) {
421         return security_on_initdialog(hwnd);
422     }
423
424     sd = (secdlg_data *)GetWindowLongPtrW(hwnd, DWLP_USER);
425     if (sd) {
426         switch (msg)
427         {
428             case WM_NOTIFY:
429                 return security_on_notify(sd, wparam, lparam);
430
431             case WM_NCDESTROY:
432                 return security_on_destroy(sd);
433
434             default:
435                 /* do not flood the log */
436                 if ((msg == WM_SETCURSOR) || (msg == WM_NCHITTEST) ||
437                     (msg == WM_MOUSEMOVE) || (msg == WM_MOUSEACTIVATE) || (msg == WM_PARENTNOTIFY))
438                     return FALSE;
439
440                 TRACE("(%p, 0x%08x/%03d, 0x%08lx, 0x%08lx)\n", hwnd, msg, msg, wparam, lparam);
441         }
442     }
443     return FALSE;
444 }