Added MIME type checking to ResProtocol::Start.
[wine] / dlls / msi / source.c
1 /*
2  * Implementation of the Microsoft Installer (msi.dll)
3  *
4  * Copyright 2005 Aric Stewart 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winreg.h"
29 #include "winnls.h"
30 #include "shlwapi.h"
31 #include "wine/debug.h"
32 #include "msi.h"
33 #include "msiquery.h"
34 #include "msipriv.h"
35 #include "wincrypt.h"
36 #include "winver.h"
37 #include "winuser.h"
38 #include "wine/unicode.h"
39 #include "action.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msi);
42
43 /*
44  * These apis are defined in MSI 3.0
45  */
46
47 typedef struct tagMediaInfo
48 {
49     LPWSTR  path;
50     WCHAR   szIndex[10];
51     WCHAR   type;
52 } media_info;
53
54 static UINT OpenSourceKey(LPCWSTR szProduct, HKEY* key, BOOL user, BOOL create)
55 {
56     HKEY rootkey = 0; 
57     UINT rc; 
58     static const WCHAR szSourceList[] = {'S','o','u','r','c','e','L','i','s','t',0};
59
60     if (user)
61         rc = MSIREG_OpenUserProductsKey(szProduct, &rootkey, create);
62     else
63         rc = MSIREG_OpenProductsKey(szProduct, &rootkey, create);
64
65     if (rc)
66         return rc;
67
68     if (create)
69         rc = RegCreateKeyW(rootkey, szSourceList, key);
70     else
71         rc = RegOpenKeyW(rootkey,szSourceList, key); 
72
73     return rc;
74 }
75
76 static UINT OpenMediaSubkey(HKEY rootkey, HKEY *key, BOOL create)
77 {
78     UINT rc;
79     static const WCHAR media[] = {'M','e','d','i','a',0};
80
81     if (create)
82         rc = RegCreateKeyW(rootkey, media, key);
83     else
84         rc = RegOpenKeyW(rootkey,media, key); 
85
86     return rc;
87 }
88
89 static UINT OpenNetworkSubkey(HKEY rootkey, HKEY *key, BOOL create)
90 {
91     UINT rc;
92     static const WCHAR net[] = {'N','e','t',0};
93
94     if (create)
95         rc = RegCreateKeyW(rootkey, net, key);
96     else
97         rc = RegOpenKeyW(rootkey, net, key); 
98
99     return rc;
100 }
101
102 static UINT OpenURLSubkey(HKEY rootkey, HKEY *key, BOOL create)
103 {
104     UINT rc;
105     static const WCHAR URL[] = {'U','R','L',0};
106
107     if (create)
108         rc = RegCreateKeyW(rootkey, URL, key);
109     else
110         rc = RegOpenKeyW(rootkey, URL, key); 
111
112     return rc;
113 }
114
115
116 static UINT find_given_source(HKEY key, LPCWSTR szSource, media_info *ss)
117 {
118     DWORD index = 0;
119     WCHAR szIndex[10];
120     DWORD size;
121     DWORD val_size;
122     LPWSTR val;
123     UINT rc = ERROR_SUCCESS;
124
125     while (rc == ERROR_SUCCESS)
126     {
127         val = NULL;
128         val_size = 0;
129         rc = RegEnumValueW(key, index, szIndex, &size, NULL, NULL, NULL, &val_size);
130         if (rc != ERROR_NO_MORE_ITEMS)
131         {
132             val = HeapAlloc(GetProcessHeap(),0,val_size);
133             RegEnumValueW(key, index, szIndex, &size, NULL, NULL, (LPBYTE)val, 
134                 &val_size);
135             if (lstrcmpiW(szSource,val)==0)
136             {
137                 ss->path = val;
138                 strcpyW(ss->szIndex,szIndex);
139                 break;
140             }
141             else
142                 strcpyW(ss->szIndex,szIndex);
143
144             HeapFree(GetProcessHeap(),0,val);
145             index ++;
146         }
147     }
148     return rc;
149 }
150
151 /******************************************************************
152  *  MsiSourceListGetInfoW   (MSI.@)
153  */
154 UINT WINAPI MsiSourceListGetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
155                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
156                                    LPCWSTR szProperty, LPWSTR szValue, 
157                                    LPDWORD pcchValue) 
158 {
159     HKEY sourcekey;
160     UINT rc;
161
162     TRACE("%s %s\n", debugstr_w(szProduct), debugstr_w(szProperty));
163
164     if (!szProduct || lstrlenW(szProduct) > 39)
165         return ERROR_INVALID_PARAMETER;
166
167     if (szValue && !pcchValue)
168         return ERROR_INVALID_PARAMETER;
169     
170     if (dwOptions == MSICODE_PATCH)
171     {
172         FIXME("Unhandled options MSICODE_PATCH\n");
173         return ERROR_FUNCTION_FAILED;
174     }
175     
176     if (szUserSid)
177         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
178
179     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
180         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
181
182     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
183         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, FALSE);
184     else
185         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, FALSE);
186
187     if (rc != ERROR_SUCCESS)
188         return ERROR_UNKNOWN_PRODUCT;
189
190     if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
191     {
192         HKEY key;
193         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
194         if (rc == ERROR_SUCCESS)
195             rc = RegQueryValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW,
196                     0, 0, (LPBYTE)szValue, pcchValue);
197         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
198             rc = ERROR_UNKNOWN_PROPERTY;
199         RegCloseKey(key);
200     }
201     else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) ==0)
202     {
203         HKEY key;
204         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
205         if (rc == ERROR_SUCCESS)
206             rc = RegQueryValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0, 0,
207                     (LPBYTE)szValue, pcchValue);
208         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
209             rc = ERROR_UNKNOWN_PROPERTY;
210         RegCloseKey(key);
211     }
212     else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
213     {
214         LPWSTR buffer;
215         DWORD size = 0;
216
217         RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
218                 NULL, &size);
219         if (size == 0)
220             rc = ERROR_UNKNOWN_PROPERTY;
221         else
222         {
223             LPWSTR ptr;
224             buffer = HeapAlloc(GetProcessHeap(),0,size);
225             rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
226                     0, 0, (LPBYTE)buffer,&size); 
227             ptr = strchrW(buffer,';');
228             if (ptr) ptr = strchrW(ptr+1,';');
229             if (!ptr)
230                 rc = ERROR_UNKNOWN_PROPERTY;
231             else
232             {
233                 ptr ++;
234                 lstrcpynW(szValue, ptr, *pcchValue);
235                 if (lstrlenW(ptr) > *pcchValue)
236                 {
237                     *pcchValue = lstrlenW(ptr)+1;
238                     rc = ERROR_MORE_DATA;
239                 }
240                 else
241                     rc = ERROR_SUCCESS;
242             }
243             HeapFree(GetProcessHeap(),0,buffer);
244         }
245     }
246     else if (strcmpW(INSTALLPROPERTY_LASTUSEDTYPEW, szProperty)==0)
247     {
248         LPWSTR buffer;
249         DWORD size = 0;
250
251         RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 0,
252                 NULL, &size);
253         if (size == 0)
254             rc = ERROR_UNKNOWN_PROPERTY;
255         else
256         {
257             buffer = HeapAlloc(GetProcessHeap(),0,size);
258             rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW,
259                     0, 0, (LPBYTE)buffer,&size); 
260             if (*pcchValue < 1)
261             {
262                 rc = ERROR_MORE_DATA;
263                 *pcchValue = 1;
264             }
265             else
266             {
267                 szValue[0] = buffer[0];
268                 rc = ERROR_SUCCESS;
269             }
270             HeapFree(GetProcessHeap(),0,buffer);
271         }
272     }
273     else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
274     {
275         rc = RegQueryValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0, 0, 
276                 (LPBYTE)szValue, pcchValue);
277         if (rc != ERROR_SUCCESS && rc != ERROR_MORE_DATA)
278             rc = ERROR_UNKNOWN_PROPERTY;
279     }
280     else
281     {
282         FIXME("Unknown property %s\n",debugstr_w(szProperty));
283         rc = ERROR_UNKNOWN_PROPERTY;
284     }
285
286     RegCloseKey(sourcekey);
287     return rc;
288 }
289
290 /******************************************************************
291  *  MsiSourceListSetInfoW   (MSI.@)
292  */
293 UINT WINAPI MsiSourceListSetInfoW( LPCWSTR szProduct, LPCWSTR szUserSid,
294                                    MSIINSTALLCONTEXT dwContext, DWORD dwOptions,
295                                    LPCWSTR szProperty, LPCWSTR szValue)
296 {
297     HKEY sourcekey;
298     UINT rc;
299
300     TRACE("%s %s %x %lx %s %s\n", debugstr_w(szProduct), debugstr_w(szUserSid), 
301             dwContext, dwOptions, debugstr_w(szProperty), debugstr_w(szValue));
302
303     if (!szProduct || lstrlenW(szProduct) > 39)
304         return ERROR_INVALID_PARAMETER;
305
306     if (dwOptions & MSICODE_PATCH)
307     {
308         FIXME("Unhandled options MSICODE_PATCH\n");
309         return ERROR_FUNCTION_FAILED;
310     }
311     
312     if (szUserSid)
313         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
314
315     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
316         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
317
318     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
319         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
320     else
321         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
322
323     if (rc != ERROR_SUCCESS)
324         return ERROR_UNKNOWN_PRODUCT;
325
326
327     if (strcmpW(szProperty, INSTALLPROPERTY_MEDIAPACKAGEPATHW) == 0)
328     {
329         HKEY key;
330         DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
331         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
332         if (rc == ERROR_SUCCESS)
333             rc = RegSetValueExW(key, INSTALLPROPERTY_MEDIAPACKAGEPATHW, 0,
334                     REG_SZ, (LPBYTE)szValue, size);
335         if (rc != ERROR_SUCCESS)
336             rc = ERROR_UNKNOWN_PROPERTY;
337         RegCloseKey(key);
338     }
339     else if (strcmpW(szProperty, INSTALLPROPERTY_DISKPROMPTW) == 0)
340     {
341         HKEY key;
342         DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
343         rc = OpenMediaSubkey(sourcekey, &key, FALSE);
344         if (rc == ERROR_SUCCESS)
345             rc = RegSetValueExW(key, INSTALLPROPERTY_DISKPROMPTW, 0,
346                     REG_SZ, (LPBYTE)szValue, size);
347         if (rc != ERROR_SUCCESS)
348             rc = ERROR_UNKNOWN_PROPERTY;
349         RegCloseKey(key);
350     }
351     else if (strcmpW(szProperty, INSTALLPROPERTY_LASTUSEDSOURCEW)==0)
352     {
353         LPWSTR buffer = NULL;
354         DWORD size;
355         WCHAR typechar = 'n';
356         static const WCHAR LastUsedSource_Fmt[] = {'%','c',';','%','i',';','%','s',0};
357
358         /* make sure the source is registered */
359         MsiSourceListAddSourceExW(szProduct, szUserSid, dwContext, 
360                 dwOptions, szValue, 0); 
361
362         if (dwOptions & MSISOURCETYPE_NETWORK)
363             typechar = 'n';
364         else if (dwOptions & MSISOURCETYPE_URL)
365             typechar = 'u';
366         else if (dwOptions & MSISOURCETYPE_MEDIA)
367             typechar = 'm';
368         else 
369             ERR("Unknown source type! 0x%lx\n",dwOptions);
370         
371         size = (lstrlenW(szValue)+5)*sizeof(WCHAR);
372         buffer = HeapAlloc(GetProcessHeap(),0,size);
373         sprintfW(buffer, LastUsedSource_Fmt, typechar, 1, szValue);
374         rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_LASTUSEDSOURCEW, 0, 
375                 REG_EXPAND_SZ, (LPBYTE)buffer, size);
376         if (rc != ERROR_SUCCESS)
377             rc = ERROR_UNKNOWN_PROPERTY;
378         HeapFree( GetProcessHeap(), 0, buffer );
379     }
380     else if (strcmpW(INSTALLPROPERTY_PACKAGENAMEW, szProperty)==0)
381     {
382         DWORD size = lstrlenW(szValue)*sizeof(WCHAR);
383         rc = RegSetValueExW(sourcekey, INSTALLPROPERTY_PACKAGENAMEW, 0,
384                 REG_SZ, (LPBYTE)szValue, size);
385         if (rc != ERROR_SUCCESS)
386             rc = ERROR_UNKNOWN_PROPERTY;
387     }
388     else
389     {
390         FIXME("Unknown property %s\n",debugstr_w(szProperty));
391         rc = ERROR_UNKNOWN_PROPERTY;
392     }
393
394     RegCloseKey(sourcekey);
395     return rc;
396
397 }
398
399 /******************************************************************
400  *  MsiSourceListAddSourceExW (MSI.@)
401  */
402 UINT WINAPI MsiSourceListAddSourceExW( LPCWSTR szProduct, LPCWSTR szUserSid,
403         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, LPCWSTR szSource, 
404         DWORD dwIndex)
405 {
406     HKEY sourcekey;
407     HKEY typekey;
408     UINT rc;
409     media_info source_struct;
410    
411     TRACE("%s, %s, %x, %lx, %s, %li\n", debugstr_w(szProduct), 
412             debugstr_w(szUserSid), dwContext, dwOptions, debugstr_w(szSource), 
413             dwIndex);
414     
415     if (!szProduct)
416         return ERROR_INVALID_PARAMETER;
417
418     if (!szSource)
419         return ERROR_INVALID_PARAMETER;
420
421     if (dwOptions & MSICODE_PATCH)
422     {
423         FIXME("Unhandled options MSICODE_PATCH\n");
424         return ERROR_FUNCTION_FAILED;
425     }
426
427     if (szUserSid)
428         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
429
430     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
431         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
432
433     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
434         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
435     else
436         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
437
438     if (rc != ERROR_SUCCESS)
439         return ERROR_UNKNOWN_PRODUCT;
440
441     if (dwOptions & MSISOURCETYPE_NETWORK)
442         rc = OpenNetworkSubkey(sourcekey, &typekey, TRUE);
443     else if (dwOptions & MSISOURCETYPE_URL)
444         rc = OpenURLSubkey(sourcekey, &typekey, TRUE);
445     else
446     {
447         ERR("unknown media type: %08lx\n", dwOptions);
448         RegCloseKey(sourcekey);
449         return ERROR_FUNCTION_FAILED;
450     }
451
452     source_struct.szIndex[0] = 0;
453     if (find_given_source(typekey, szSource, &source_struct)==ERROR_SUCCESS)
454     {
455         DWORD current_index = atoiW(source_struct.szIndex);
456         /* found the source */
457         if (dwIndex > 0 && current_index != dwIndex)
458             FIXME("Need to reorder the sources!\n");
459     }
460     else
461     {
462         DWORD current_index = 0;
463         static const WCHAR fmt[] = {'%','i',0};
464         DWORD size = lstrlenW(szSource)*sizeof(WCHAR);
465
466         if (source_struct.szIndex[0])
467             current_index = atoiW(source_struct.szIndex);
468         /* new source */
469         if (dwIndex > 0 && dwIndex < current_index)
470             FIXME("Need to reorder the sources!\n");
471
472         current_index ++;
473         sprintfW(source_struct.szIndex,fmt,current_index);
474         rc = RegSetValueExW(typekey, source_struct.szIndex, 0, REG_EXPAND_SZ, 
475                 (LPBYTE)szSource, size);
476     }
477
478     RegCloseKey(typekey);
479     RegCloseKey(sourcekey);
480     return rc;
481 }
482
483 /******************************************************************
484  *  MsiSourceListAddMediaDisk(MSI.@)
485  */
486 UINT WINAPI MsiSourceListAddMediaDiskW(LPCWSTR szProduct, LPCWSTR szUserSid, 
487         MSIINSTALLCONTEXT dwContext, DWORD dwOptions, DWORD dwDiskId, 
488         LPCWSTR szVolumeLabel, LPCWSTR szDiskPrompt)
489 {
490     HKEY sourcekey;
491     HKEY mediakey;
492     UINT rc;
493     WCHAR szIndex[10];
494     static const WCHAR fmt[] = {'%','i',0};
495     static const WCHAR disk_fmt[] = {'%','s',';','%','s',0};
496     static const WCHAR empty[1] = {0};
497     LPCWSTR pt1,pt2;
498     LPWSTR buffer;
499     DWORD size;
500
501     TRACE("%s %s %x %lx %li %s %s\n", debugstr_w(szProduct), 
502             debugstr_w(szUserSid), dwContext, dwOptions, dwDiskId, 
503             debugstr_w(szVolumeLabel), debugstr_w(szDiskPrompt)); 
504
505     if (!szProduct || lstrlenW(szProduct) > 39)
506         return ERROR_INVALID_PARAMETER;
507
508     if (dwOptions & MSICODE_PATCH)
509     {
510         FIXME("Unhandled options MSICODE_PATCH\n");
511         return ERROR_FUNCTION_FAILED;
512     }
513     
514     if (szUserSid)
515         FIXME("Unhandled UserSid %s\n",debugstr_w(szUserSid));
516
517     if (dwContext == MSIINSTALLCONTEXT_USERUNMANAGED)
518         FIXME("Unknown context MSIINSTALLCONTEXT_USERUNMANAGED\n");
519
520     if (dwContext == MSIINSTALLCONTEXT_MACHINE)
521         rc = OpenSourceKey(szProduct, &sourcekey, FALSE, TRUE);
522     else
523         rc = OpenSourceKey(szProduct, &sourcekey, TRUE, TRUE);
524
525     if (rc != ERROR_SUCCESS)
526         return ERROR_UNKNOWN_PRODUCT;
527
528     OpenMediaSubkey(sourcekey,&mediakey,TRUE);
529
530     sprintfW(szIndex,fmt,dwDiskId);
531
532     size = 2;
533     if (szVolumeLabel)
534     {
535         size +=lstrlenW(szVolumeLabel);
536         pt1 = szVolumeLabel;
537     }
538     else
539         pt1 = empty;
540     if (szDiskPrompt)
541     {
542         size +=lstrlenW(szDiskPrompt);
543         pt2 = szDiskPrompt;
544     }
545     else
546         pt2 = empty;
547
548     size *=sizeof(WCHAR);
549
550     buffer = HeapAlloc(GetProcessHeap(),0,size);
551     sprintfW(buffer,disk_fmt,pt1,pt2);
552
553     RegSetValueExW(mediakey, szIndex, 0, REG_SZ, (LPBYTE)buffer, size);
554     HeapFree( GetProcessHeap(), 0, buffer );
555
556     RegCloseKey(sourcekey);
557     RegCloseKey(mediakey);
558
559     return ERROR_SUCCESS;
560 }