Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-winehq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-winehq
Commits
3f2d5d7f
Commit
3f2d5d7f
authored
Aug 19, 2005
by
Mike McCormack
Committed by
Alexandre Julliard
Aug 19, 2005
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Store the component information in a standard Wine list.
parent
602f0c10
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
88 additions
and
43 deletions
+88
-43
action.c
dlls/msi/action.c
+57
-33
action.h
dlls/msi/action.h
+10
-2
helpers.c
dlls/msi/helpers.c
+21
-8
No files found.
dlls/msi/action.c
View file @
3f2d5d7f
...
@@ -1016,18 +1016,29 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row)
...
@@ -1016,18 +1016,29 @@ static int load_component(MSIPACKAGE* package, MSIRECORD * row)
typedef
struct
{
typedef
struct
{
MSIPACKAGE
*
package
;
MSIPACKAGE
*
package
;
INT
index
;
INT
index
;
INT
cnt
;
}
_ilfs
;
}
_ilfs
;
static
UINT
add_feature_component
(
MSIFEATURE
*
feature
,
int
index
)
{
ComponentList
*
cl
;
cl
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
*
cl
)
);
if
(
!
cl
)
return
ERROR_NOT_ENOUGH_MEMORY
;
cl
->
component
=
index
;
list_add_tail
(
feature
->
Components
,
&
cl
->
entry
);
return
ERROR_SUCCESS
;
}
static
UINT
iterate_component_check
(
MSIRECORD
*
row
,
LPVOID
param
)
static
UINT
iterate_component_check
(
MSIRECORD
*
row
,
LPVOID
param
)
{
{
_ilfs
*
ilfs
=
(
_ilfs
*
)
param
;
_ilfs
*
ilfs
=
(
_ilfs
*
)
param
;
INT
c_indx
;
INT
c_indx
;
c_indx
=
load_component
(
ilfs
->
package
,
row
);
c_indx
=
load_component
(
ilfs
->
package
,
row
);
add_feature_component
(
&
ilfs
->
package
->
features
[
ilfs
->
index
],
c_indx
);
ilfs
->
package
->
features
[
ilfs
->
index
].
Components
[
ilfs
->
cnt
]
=
c_indx
;
ilfs
->
package
->
features
[
ilfs
->
index
].
ComponentCount
++
;
TRACE
(
"Loaded new component to index %i
\n
"
,
c_indx
);
TRACE
(
"Loaded new component to index %i
\n
"
,
c_indx
);
return
ERROR_SUCCESS
;
return
ERROR_SUCCESS
;
...
@@ -1039,7 +1050,6 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
...
@@ -1039,7 +1050,6 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
LPCWSTR
component
;
LPCWSTR
component
;
DWORD
rc
;
DWORD
rc
;
INT
c_indx
;
INT
c_indx
;
INT
cnt
=
ilfs
->
package
->
features
[
ilfs
->
index
].
ComponentCount
;
MSIQUERY
*
view
;
MSIQUERY
*
view
;
static
const
WCHAR
Query
[]
=
static
const
WCHAR
Query
[]
=
{
'S'
,
'E'
,
'L'
,
'E'
,
'C'
,
'T'
,
' '
,
'*'
,
' '
,
'F'
,
'R'
,
'O'
,
'M'
,
' '
,
{
'S'
,
'E'
,
'L'
,
'E'
,
'C'
,
'T'
,
' '
,
'*'
,
' '
,
'F'
,
'R'
,
'O'
,
'M'
,
' '
,
...
@@ -1056,8 +1066,7 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
...
@@ -1056,8 +1066,7 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
{
{
TRACE
(
"Component %s already loaded at %i
\n
"
,
debugstr_w
(
component
),
TRACE
(
"Component %s already loaded at %i
\n
"
,
debugstr_w
(
component
),
c_indx
);
c_indx
);
ilfs
->
package
->
features
[
ilfs
->
index
].
Components
[
cnt
]
=
c_indx
;
add_feature_component
(
&
ilfs
->
package
->
features
[
ilfs
->
index
],
c_indx
);
ilfs
->
package
->
features
[
ilfs
->
index
].
ComponentCount
++
;
return
ERROR_SUCCESS
;
return
ERROR_SUCCESS
;
}
}
...
@@ -1065,7 +1074,6 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
...
@@ -1065,7 +1074,6 @@ static UINT iterate_load_featurecomponents(MSIRECORD *row, LPVOID param)
if
(
rc
!=
ERROR_SUCCESS
)
if
(
rc
!=
ERROR_SUCCESS
)
return
ERROR_SUCCESS
;
return
ERROR_SUCCESS
;
ilfs
->
cnt
=
cnt
;
rc
=
MSI_IterateRecords
(
view
,
NULL
,
iterate_component_check
,
ilfs
);
rc
=
MSI_IterateRecords
(
view
,
NULL
,
iterate_component_check
,
ilfs
);
msiobj_release
(
&
view
->
hdr
);
msiobj_release
(
&
view
->
hdr
);
...
@@ -1102,6 +1110,14 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
...
@@ -1102,6 +1110,14 @@ static UINT load_feature(MSIRECORD * row, LPVOID param)
memset
(
&
package
->
features
[
index
],
0
,
sizeof
(
MSIFEATURE
));
memset
(
&
package
->
features
[
index
],
0
,
sizeof
(
MSIFEATURE
));
/*
* Can't use struct list in features because the address keeps changing
* due to the above HeapReAlloc, so allocate a struct list instead
*/
package
->
features
[
index
].
Components
=
HeapAlloc
(
GetProcessHeap
(),
0
,
sizeof
(
struct
list
)
);
list_init
(
package
->
features
[
index
].
Components
);
sz
=
IDENTIFIER_SIZE
;
sz
=
IDENTIFIER_SIZE
;
MSI_RecordGetStringW
(
row
,
1
,
package
->
features
[
index
].
Feature
,
&
sz
);
MSI_RecordGetStringW
(
row
,
1
,
package
->
features
[
index
].
Feature
,
&
sz
);
...
@@ -1421,12 +1437,14 @@ static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
...
@@ -1421,12 +1437,14 @@ static void ACTION_UpdateInstallStates(MSIPACKAGE *package)
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
{
{
ComponentList
*
cl
;
INSTALLSTATE
res
=
-
10
;
INSTALLSTATE
res
=
-
10
;
int
j
;
for
(
j
=
0
;
j
<
package
->
features
[
i
].
ComponentCount
;
j
++
)
LIST_FOR_EACH_ENTRY
(
cl
,
package
->
features
[
i
].
Components
,
ComponentList
,
entry
)
{
{
MSICOMPONENT
*
component
=
&
package
->
components
[
package
->
features
[
i
].
MSICOMPONENT
*
component
=
&
package
->
components
[
cl
->
component
];
Components
[
j
]];
if
(
res
==
-
10
)
if
(
res
==
-
10
)
res
=
component
->
Installed
;
res
=
component
->
Installed
;
else
else
...
@@ -1497,7 +1515,6 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
...
@@ -1497,7 +1515,6 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
LPWSTR
level
;
LPWSTR
level
;
INT
install_level
;
INT
install_level
;
DWORD
i
;
DWORD
i
;
INT
j
;
static
const
WCHAR
szlevel
[]
=
static
const
WCHAR
szlevel
[]
=
{
'I'
,
'N'
,
'S'
,
'T'
,
'A'
,
'L'
,
'L'
,
'L'
,
'E'
,
'V'
,
'E'
,
'L'
,
0
};
{
'I'
,
'N'
,
'S'
,
'T'
,
'A'
,
'L'
,
'L'
,
'L'
,
'E'
,
'V'
,
'E'
,
'L'
,
0
};
static
const
WCHAR
szAddLocal
[]
=
static
const
WCHAR
szAddLocal
[]
=
...
@@ -1590,14 +1607,15 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
...
@@ -1590,14 +1607,15 @@ static UINT SetFeatureStates(MSIPACKAGE *package)
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
{
{
MSIFEATURE
*
feature
=
&
package
->
features
[
i
];
MSIFEATURE
*
feature
=
&
package
->
features
[
i
];
ComponentList
*
cl
;
TRACE
(
"Examining Feature %s (Installed %i, Action %i, Request %i)
\n
"
,
TRACE
(
"Examining Feature %s (Installed %i, Action %i, Request %i)
\n
"
,
debugstr_w
(
feature
->
Feature
),
feature
->
Installed
,
feature
->
Action
,
debugstr_w
(
feature
->
Feature
),
feature
->
Installed
,
feature
->
Action
,
feature
->
ActionRequest
);
feature
->
ActionRequest
);
for
(
j
=
0
;
j
<
feature
->
ComponentCount
;
j
++
)
LIST_FOR_EACH_ENTRY
(
cl
,
feature
->
Components
,
ComponentList
,
entry
)
{
{
MSICOMPONENT
*
component
=
&
package
->
components
[
MSICOMPONENT
*
component
=
&
package
->
components
[
cl
->
component
];
feature
->
Components
[
j
]];
if
(
!
component
->
Enabled
)
if
(
!
component
->
Enabled
)
{
{
...
@@ -2435,27 +2453,30 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
...
@@ -2435,27 +2453,30 @@ static void ACTION_RefCountComponent( MSIPACKAGE* package, UINT index)
/* increment counts */
/* increment counts */
for
(
j
=
0
;
j
<
package
->
loaded_features
;
j
++
)
for
(
j
=
0
;
j
<
package
->
loaded_features
;
j
++
)
{
{
int
i
;
ComponentList
*
cl
;
if
(
!
ACTION_VerifyFeatureForAction
(
package
,
j
,
INSTALLSTATE_LOCAL
))
if
(
!
ACTION_VerifyFeatureForAction
(
package
,
j
,
INSTALLSTATE_LOCAL
))
continue
;
continue
;
for
(
i
=
0
;
i
<
package
->
features
[
j
].
ComponentCount
;
i
++
)
LIST_FOR_EACH_ENTRY
(
cl
,
package
->
features
[
j
].
Components
,
ComponentList
,
entry
)
{
{
if
(
package
->
features
[
j
].
Components
[
i
]
==
index
)
if
(
cl
->
component
==
index
)
count
++
;
count
++
;
}
}
}
}
/* decrement counts */
/* decrement counts */
for
(
j
=
0
;
j
<
package
->
loaded_features
;
j
++
)
for
(
j
=
0
;
j
<
package
->
loaded_features
;
j
++
)
{
{
int
i
;
ComponentList
*
cl
;
if
(
!
ACTION_VerifyFeatureForAction
(
package
,
j
,
INSTALLSTATE_ABSENT
))
if
(
!
ACTION_VerifyFeatureForAction
(
package
,
j
,
INSTALLSTATE_ABSENT
))
continue
;
continue
;
for
(
i
=
0
;
i
<
package
->
features
[
j
].
ComponentCount
;
i
++
)
LIST_FOR_EACH_ENTRY
(
cl
,
package
->
features
[
j
].
Components
,
ComponentList
,
entry
)
{
{
if
(
package
->
features
[
j
].
Components
[
i
]
==
index
)
if
(
cl
->
component
==
index
)
count
--
;
count
--
;
}
}
}
}
...
@@ -3324,9 +3345,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
...
@@ -3324,9 +3345,9 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
/* here the guids are base 85 encoded */
/* here the guids are base 85 encoded */
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
for
(
i
=
0
;
i
<
package
->
loaded_features
;
i
++
)
{
{
ComponentList
*
cl
;
LPWSTR
data
=
NULL
;
LPWSTR
data
=
NULL
;
GUID
clsid
;
GUID
clsid
;
int
j
;
INT
size
;
INT
size
;
BOOL
absent
=
FALSE
;
BOOL
absent
=
FALSE
;
...
@@ -3335,26 +3356,29 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
...
@@ -3335,26 +3356,29 @@ static UINT ACTION_PublishFeatures(MSIPACKAGE *package)
!
ACTION_VerifyFeatureForAction
(
package
,
i
,
INSTALLSTATE_ADVERTISED
))
!
ACTION_VerifyFeatureForAction
(
package
,
i
,
INSTALLSTATE_ADVERTISED
))
absent
=
TRUE
;
absent
=
TRUE
;
size
=
package
->
features
[
i
].
ComponentCount
*
21
;
size
=
1
;
size
+=
1
;
LIST_FOR_EACH_ENTRY
(
cl
,
package
->
features
[
i
].
Components
,
ComponentList
,
entry
)
{
size
+=
21
;
}
if
(
package
->
features
[
i
].
Feature_Parent
[
0
])
if
(
package
->
features
[
i
].
Feature_Parent
[
0
])
size
+=
strlenW
(
package
->
features
[
i
].
Feature_Parent
)
+
2
;
size
+=
strlenW
(
package
->
features
[
i
].
Feature_Parent
)
+
2
;
data
=
HeapAlloc
(
GetProcessHeap
(),
0
,
size
*
sizeof
(
WCHAR
));
data
=
HeapAlloc
(
GetProcessHeap
(),
0
,
size
*
sizeof
(
WCHAR
));
data
[
0
]
=
0
;
data
[
0
]
=
0
;
for
(
j
=
0
;
j
<
package
->
features
[
i
].
ComponentCount
;
j
++
)
LIST_FOR_EACH_ENTRY
(
cl
,
package
->
features
[
i
].
Components
,
ComponentList
,
entry
)
{
{
MSICOMPONENT
*
component
=
&
package
->
components
[
cl
->
component
];
WCHAR
buf
[
21
];
WCHAR
buf
[
21
];
memset
(
buf
,
0
,
sizeof
(
buf
));
memset
(
buf
,
0
,
sizeof
(
buf
));
if
(
package
->
components
if
(
component
->
ComponentId
[
0
]
)
[
package
->
features
[
i
].
Components
[
j
]].
ComponentId
[
0
]
!=
0
)
{
{
TRACE
(
"From %s
\n
"
,
debugstr_w
(
component
->
ComponentId
));
TRACE
(
"From %s
\n
"
,
debugstr_w
(
package
->
components
CLSIDFromString
(
component
->
ComponentId
,
&
clsid
);
[
package
->
features
[
i
].
Components
[
j
]].
ComponentId
));
CLSIDFromString
(
package
->
components
[
package
->
features
[
i
].
Components
[
j
]].
ComponentId
,
&
clsid
);
encode_base85_guid
(
&
clsid
,
buf
);
encode_base85_guid
(
&
clsid
,
buf
);
TRACE
(
"to %s
\n
"
,
debugstr_w
(
buf
));
TRACE
(
"to %s
\n
"
,
debugstr_w
(
buf
));
strcatW
(
data
,
buf
);
strcatW
(
data
,
buf
);
...
...
dlls/msi/action.h
View file @
3f2d5d7f
...
@@ -18,6 +18,8 @@
...
@@ -18,6 +18,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
*/
#include "wine/list.h"
#define IDENTIFIER_SIZE 96
#define IDENTIFIER_SIZE 96
typedef
struct
tagMSIFEATURE
typedef
struct
tagMSIFEATURE
...
@@ -35,8 +37,8 @@ typedef struct tagMSIFEATURE
...
@@ -35,8 +37,8 @@ typedef struct tagMSIFEATURE
INSTALLSTATE
ActionRequest
;
INSTALLSTATE
ActionRequest
;
INSTALLSTATE
Action
;
INSTALLSTATE
Action
;
INT
ComponentCount
;
struct
list
*
Components
;
INT
Components
[
1024
];
/* yes hardcoded limit.... I am bad */
INT
Cost
;
INT
Cost
;
}
MSIFEATURE
;
}
MSIFEATURE
;
...
@@ -61,6 +63,12 @@ typedef struct tagMSICOMPONENT
...
@@ -61,6 +63,12 @@ typedef struct tagMSICOMPONENT
LPWSTR
AdvertiseString
;
LPWSTR
AdvertiseString
;
}
MSICOMPONENT
;
}
MSICOMPONENT
;
typedef
struct
tagComponentList
{
struct
list
entry
;
int
component
;
}
ComponentList
;
typedef
struct
tagMSIFOLDER
typedef
struct
tagMSIFOLDER
{
{
LPWSTR
Directory
;
LPWSTR
Directory
;
...
...
dlls/msi/helpers.c
View file @
3f2d5d7f
...
@@ -457,14 +457,23 @@ static void remove_tracked_tempfiles(MSIPACKAGE* package)
...
@@ -457,14 +457,23 @@ static void remove_tracked_tempfiles(MSIPACKAGE* package)
void
ACTION_free_package_structures
(
MSIPACKAGE
*
package
)
void
ACTION_free_package_structures
(
MSIPACKAGE
*
package
)
{
{
INT
i
;
INT
i
;
struct
list
*
item
,
*
cursor
;
TRACE
(
"Freeing package action data
\n
"
);
TRACE
(
"Freeing package action data
\n
"
);
remove_tracked_tempfiles
(
package
);
remove_tracked_tempfiles
(
package
);
/* No dynamic buffers in features */
if
(
package
->
features
)
if
(
package
->
features
&&
package
->
loaded_features
>
0
)
{
LIST_FOR_EACH_SAFE
(
item
,
cursor
,
package
->
features
->
Components
)
{
ComponentList
*
cl
=
LIST_ENTRY
(
item
,
ComponentList
,
entry
);
list_remove
(
&
cl
->
entry
);
HeapFree
(
GetProcessHeap
(),
0
,
cl
);
}
HeapFree
(
GetProcessHeap
(),
0
,
package
->
features
->
Components
);
HeapFree
(
GetProcessHeap
(),
0
,
package
->
features
);
HeapFree
(
GetProcessHeap
(),
0
,
package
->
features
);
}
for
(
i
=
0
;
i
<
package
->
loaded_folders
;
i
++
)
for
(
i
=
0
;
i
<
package
->
loaded_folders
;
i
++
)
{
{
...
@@ -847,6 +856,7 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
...
@@ -847,6 +856,7 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
int
i
;
int
i
;
INSTALLSTATE
newstate
;
INSTALLSTATE
newstate
;
MSIFEATURE
*
feature
;
MSIFEATURE
*
feature
;
ComponentList
*
cl
;
i
=
get_loaded_feature
(
package
,
szFeature
);
i
=
get_loaded_feature
(
package
,
szFeature
);
if
(
i
<
0
)
if
(
i
<
0
)
...
@@ -855,9 +865,9 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
...
@@ -855,9 +865,9 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
feature
=
&
package
->
features
[
i
];
feature
=
&
package
->
features
[
i
];
newstate
=
feature
->
ActionRequest
;
newstate
=
feature
->
ActionRequest
;
for
(
i
=
0
;
i
<
feature
->
ComponentCount
;
i
++
)
LIST_FOR_EACH_ENTRY
(
cl
,
feature
->
Components
,
ComponentList
,
entry
)
{
{
MSICOMPONENT
*
component
=
&
package
->
components
[
feature
->
Components
[
i
]
];
MSICOMPONENT
*
component
=
&
package
->
components
[
cl
->
component
];
TRACE
(
"MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)
\n
"
,
TRACE
(
"MODIFYING(%i): Component %s (Installed %i, Action %i, Request %i)
\n
"
,
newstate
,
debugstr_w
(
component
->
Component
),
component
->
Installed
,
newstate
,
debugstr_w
(
component
->
Component
),
component
->
Installed
,
...
@@ -874,7 +884,8 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
...
@@ -874,7 +884,8 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
}
}
else
else
{
{
int
j
,
k
;
int
j
;
ComponentList
*
clist
;
component
->
ActionRequest
=
newstate
;
component
->
ActionRequest
=
newstate
;
component
->
Action
=
newstate
;
component
->
Action
=
newstate
;
...
@@ -885,9 +896,10 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
...
@@ -885,9 +896,10 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
component
->
ActionRequest
!=
INSTALLSTATE_LOCAL
;
component
->
ActionRequest
!=
INSTALLSTATE_LOCAL
;
j
++
)
j
++
)
{
{
for
(
k
=
0
;
k
<
package
->
features
[
j
].
ComponentCount
;
k
++
)
LIST_FOR_EACH_ENTRY
(
clist
,
package
->
features
[
j
].
Components
,
if
(
package
->
features
[
j
].
Components
[
k
]
==
ComponentList
,
entry
)
feature
->
Components
[
i
]
)
{
if
(
clist
->
component
==
cl
->
component
)
{
{
if
(
package
->
features
[
j
].
ActionRequest
==
if
(
package
->
features
[
j
].
ActionRequest
==
INSTALLSTATE_LOCAL
)
INSTALLSTATE_LOCAL
)
...
@@ -901,6 +913,7 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
...
@@ -901,6 +913,7 @@ void ACTION_UpdateComponentStates(MSIPACKAGE *package, LPCWSTR szFeature)
}
}
}
}
}
}
}
TRACE
(
"Result (%i): Component %s (Installed %i, Action %i, Request %i)
\n
"
,
TRACE
(
"Result (%i): Component %s (Installed %i, Action %i, Request %i)
\n
"
,
newstate
,
debugstr_w
(
component
->
Component
),
component
->
Installed
,
newstate
,
debugstr_w
(
component
->
Component
),
component
->
Installed
,
component
->
Action
,
component
->
ActionRequest
);
component
->
Action
,
component
->
ActionRequest
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment