Browse code

freshclamwrap draft

aCaB authored on 2010/09/22 02:01:32
Showing 6 changed files
... ...
@@ -66,6 +66,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libclamunrar_iface", "libcl
66 66
 EndProject
67 67
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "clamav-for-windows", "clamav-for-windows.vcxproj", "{127CBFE6-B8AE-4422-AFFB-61F80A7C8D18}"
68 68
 EndProject
69
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "freshclamwrap", "freshclamwrap.vcxproj", "{366C2DCE-777A-43EE-96DC-C530E67E7B32}"
70
+EndProject
69 71
 Global
70 72
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
71 73
 		Debug|Win32 = Debug|Win32
... ...
@@ -198,6 +200,10 @@ Global
198 198
 		{127CBFE6-B8AE-4422-AFFB-61F80A7C8D18}.Debug|x64.ActiveCfg = Debug|x64
199 199
 		{127CBFE6-B8AE-4422-AFFB-61F80A7C8D18}.Release|Win32.ActiveCfg = Release|Win32
200 200
 		{127CBFE6-B8AE-4422-AFFB-61F80A7C8D18}.Release|x64.ActiveCfg = Release|x64
201
+		{366C2DCE-777A-43EE-96DC-C530E67E7B32}.Debug|Win32.ActiveCfg = Debug|Win32
202
+		{366C2DCE-777A-43EE-96DC-C530E67E7B32}.Debug|x64.ActiveCfg = Debug|Win32
203
+		{366C2DCE-777A-43EE-96DC-C530E67E7B32}.Release|Win32.ActiveCfg = Release|Win32
204
+		{366C2DCE-777A-43EE-96DC-C530E67E7B32}.Release|x64.ActiveCfg = Release|Win32
201 205
 	EndGlobalSection
202 206
 	GlobalSection(SolutionProperties) = preSolution
203 207
 		HideSolutionNode = FALSE
204 208
new file mode 100644
... ...
@@ -0,0 +1,101 @@
0
+<?xml version="1.0" encoding="utf-8"?>
1
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
2
+  <ItemGroup Label="ProjectConfigurations">
3
+    <ProjectConfiguration Include="Debug|Win32">
4
+      <Configuration>Debug</Configuration>
5
+      <Platform>Win32</Platform>
6
+    </ProjectConfiguration>
7
+    <ProjectConfiguration Include="Release|Win32">
8
+      <Configuration>Release</Configuration>
9
+      <Platform>Win32</Platform>
10
+    </ProjectConfiguration>
11
+  </ItemGroup>
12
+  <ItemGroup>
13
+    <ClCompile Include="freshclamwrap\flog.c" />
14
+    <ClCompile Include="freshclamwrap\freshclamwrap.c" />
15
+  </ItemGroup>
16
+  <PropertyGroup Label="Globals">
17
+    <ProjectGuid>{366C2DCE-777A-43EE-96DC-C530E67E7B32}</ProjectGuid>
18
+    <Keyword>Win32Proj</Keyword>
19
+    <RootNamespace>freshclamwrap</RootNamespace>
20
+  </PropertyGroup>
21
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
22
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
23
+    <ConfigurationType>Application</ConfigurationType>
24
+    <UseDebugLibraries>true</UseDebugLibraries>
25
+    <CharacterSet>MultiByte</CharacterSet>
26
+  </PropertyGroup>
27
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
28
+    <ConfigurationType>Application</ConfigurationType>
29
+    <UseDebugLibraries>false</UseDebugLibraries>
30
+    <WholeProgramOptimization>true</WholeProgramOptimization>
31
+    <CharacterSet>MultiByte</CharacterSet>
32
+  </PropertyGroup>
33
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
34
+  <ImportGroup Label="ExtensionSettings">
35
+  </ImportGroup>
36
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
37
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
38
+  </ImportGroup>
39
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
40
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
41
+  </ImportGroup>
42
+  <PropertyGroup Label="UserMacros" />
43
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
44
+    <LinkIncremental>true</LinkIncremental>
45
+    <OutDir>$(SolutionDir)$(PlatformName)\$(Configuration)\</OutDir>
46
+    <IntDir>$(SolutionDir)build\$(PlatformName)\$(ProjectName)\$(Configuration)\</IntDir>
47
+  </PropertyGroup>
48
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
49
+    <LinkIncremental>false</LinkIncremental>
50
+    <OutDir>$(SolutionDir)$(PlatformName)\$(Configuration)\</OutDir>
51
+    <IntDir>$(SolutionDir)build\$(PlatformName)\$(ProjectName)\$(Configuration)\</IntDir>
52
+  </PropertyGroup>
53
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
54
+    <ClCompile>
55
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
56
+      <WarningLevel>Level3</WarningLevel>
57
+      <Optimization>Disabled</Optimization>
58
+      <PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
59
+      <PrecompiledHeaderFile>
60
+      </PrecompiledHeaderFile>
61
+      <PrecompiledHeaderOutputFile>
62
+      </PrecompiledHeaderOutputFile>
63
+      <AdditionalIncludeDirectories>"$(SolutionDir)";"$(SolutionDir)..\libclamav";"$(SolutionDir)compat";"$(SolutionDir).."</AdditionalIncludeDirectories>
64
+      <CompileAs>CompileAsC</CompileAs>
65
+      <DisableSpecificWarnings>4996</DisableSpecificWarnings>
66
+    </ClCompile>
67
+    <Link>
68
+      <SubSystem>Windows</SubSystem>
69
+      <GenerateDebugInformation>true</GenerateDebugInformation>
70
+      <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
71
+    </Link>
72
+  </ItemDefinitionGroup>
73
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
74
+    <ClCompile>
75
+      <WarningLevel>Level3</WarningLevel>
76
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
77
+      <Optimization>MaxSpeed</Optimization>
78
+      <FunctionLevelLinking>true</FunctionLevelLinking>
79
+      <IntrinsicFunctions>true</IntrinsicFunctions>
80
+      <PreprocessorDefinitions>WIN32;WIN32_LEAN_AND_MEAN;HAVE_CONFIG_H;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
81
+      <PrecompiledHeaderFile>
82
+      </PrecompiledHeaderFile>
83
+      <PrecompiledHeaderOutputFile>
84
+      </PrecompiledHeaderOutputFile>
85
+      <AdditionalIncludeDirectories>"$(SolutionDir)";"$(SolutionDir)..\libclamav";"$(SolutionDir)compat";"$(SolutionDir).."</AdditionalIncludeDirectories>
86
+      <CompileAs>CompileAsC</CompileAs>
87
+      <DisableSpecificWarnings>4996</DisableSpecificWarnings>
88
+    </ClCompile>
89
+    <Link>
90
+      <SubSystem>Windows</SubSystem>
91
+      <GenerateDebugInformation>true</GenerateDebugInformation>
92
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
93
+      <OptimizeReferences>true</OptimizeReferences>
94
+      <AdditionalDependencies>kernel32.lib;%(AdditionalDependencies)</AdditionalDependencies>
95
+    </Link>
96
+  </ItemDefinitionGroup>
97
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
98
+  <ImportGroup Label="ExtensionTargets">
99
+  </ImportGroup>
100
+</Project>
0 101
\ No newline at end of file
1 102
new file mode 100644
... ...
@@ -0,0 +1,49 @@
0
+/*
1
+ * Copyright (C) 2010 Sourcefire, Inc.
2
+ * Authors: aCaB <acab@clamav.net>
3
+ *
4
+ * This library is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License version 2.1 as published by the Free Software Foundation.
7
+ *
8
+ * This library is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with this library; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
16
+ * USA
17
+ */
18
+
19
+#ifndef _CLUPDATE_H
20
+#define _CLUPDATE_H
21
+
22
+// Possible states during update
23
+typedef enum _AV_UPD_STATE
24
+{
25
+	UPD_CHECK,
26
+	UPD_NEWER_FOUND,
27
+	UPD_NONE,
28
+	UPD_DOWNLOAD_BEGIN,
29
+	UPD_DOWNLOAD_COMPLETE,
30
+	UPD_PAUSE,
31
+	UPD_ABORT,
32
+	UPD_DONE,
33
+	UPD_INSTALL_BEGIN,
34
+	UPD_INSTALL_COMPLETE,
35
+	UPD_FILE_BEGIN,
36
+	UPD_FILE_COMPLETE,
37
+}AV_UPD_STATE;
38
+
39
+typedef struct _AV_UPD_STATUS
40
+{
41
+	int state;                      // AV_UPD_STATE                                                        
42
+	int status;						// 0 -> Success, anything else failure
43
+	int totalSize;					// total bytes to download
44
+	int downloadedSize;				// bytes downloaded so far
45
+	int totalFiles;					// incase there update happens with multiple files
46
+}AV_UPD_STATUS, *PAV_UPD_STATUS;
47
+
48
+#endif /* _CLUPDATE_H */
0 49
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+/*
1
+ * Copyright (C) 2010 Sourcefire, Inc.
2
+ * Authors: aCaB <acab@clamav.net>
3
+ *
4
+ * This library is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License version 2.1 as published by the Free Software Foundation.
7
+ *
8
+ * This library is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with this library; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
16
+ * USA
17
+ */
18
+
19
+#include <windows.h>
20
+#include <stdio.h>
21
+
22
+#include "flog.h"
23
+
24
+static HANDLE logh;
25
+
26
+void flog_open(const char *path) {
27
+    logh = CreateFile(path, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
28
+    SetFilePointer(logh, 0, NULL, FILE_END);
29
+    flog("Log file initialized");
30
+}
31
+
32
+void flog(const char *fmt, ...) {
33
+    char buf[4096];
34
+    SYSTEMTIME t;
35
+    DWORD x;
36
+    va_list ap;
37
+
38
+    GetLocalTime(&t);
39
+    _snprintf(buf, sizeof(buf), "%04u-%02u-%02u %02u:%02u:%02u - ", t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
40
+    WriteFile(logh, buf, strlen(buf), &x, NULL);
41
+    va_start(ap, fmt);
42
+    vsnprintf(buf, sizeof(buf), fmt, ap);
43
+    va_end(ap);
44
+    WriteFile(logh, buf, strlen(buf), &x, NULL);
45
+    WriteFile(logh, "\r\n", 2, &x, NULL);
46
+}
47
+
48
+void flog_close(void) {
49
+    flog("Log file closed");
50
+    CloseHandle(logh);
51
+}
0 52
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+/*
1
+ * Copyright (C) 2010 Sourcefire, Inc.
2
+ * Authors: aCaB <acab@clamav.net>
3
+ *
4
+ * This library is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License version 2.1 as published by the Free Software Foundation.
7
+ *
8
+ * This library is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with this library; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
16
+ * USA
17
+ */
18
+
19
+#ifndef __FLOG_H
20
+#define __FLOG_H
21
+
22
+void flog_open(path);
23
+void flog(const char *fmt, ...);
24
+void flog_close(void);
25
+
26
+#endif
0 27
new file mode 100644
... ...
@@ -0,0 +1,286 @@
0
+/*
1
+ * Copyright (C) 2010 Sourcefire, Inc.
2
+ * Authors: aCaB <acab@clamav.net>
3
+ *
4
+ * This library is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License version 2.1 as published by the Free Software Foundation.
7
+ *
8
+ * This library is distributed in the hope that it will be useful,
9
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11
+ * Lesser General Public License for more details.
12
+ *
13
+ * You should have received a copy of the GNU Lesser General Public
14
+ * License along with this library; if not, write to the Free Software
15
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
16
+ * USA
17
+ */
18
+
19
+#include <windows.h>
20
+#include <string.h>
21
+#include <stdio.h>
22
+
23
+#include "clupdate.h"
24
+#include "flog.h"
25
+
26
+struct my_f {
27
+    HANDLE h;
28
+    char buf[1024];
29
+    char *next;
30
+    unsigned int len;
31
+};
32
+
33
+static void init_myf(struct my_f *f, HANDLE h) {
34
+    f->next = f->buf;
35
+    f->len = 0;
36
+    f->h = h;
37
+}
38
+
39
+static char *my_fgets(struct my_f *f) {
40
+    int stripping = 0;
41
+    char *cur = f->next;
42
+    while(1) {
43
+	if(!f->len) {
44
+	    if(f->next == &f->buf[sizeof(f->buf)-1]) {
45
+		if(cur == f->buf) {
46
+		    *f->next = '\0';
47
+		    f->next = f->buf;
48
+		    return f->buf;
49
+		}
50
+		memmove(f->buf, cur, f->next - cur);
51
+		f->next -= cur - f->buf;
52
+		cur = f->buf;
53
+	    }
54
+	    if(!ReadFile(f->h, f->next, sizeof(f->buf) - 1 - (f->next - f->buf), &f->len, NULL))
55
+		return NULL;
56
+	    if(!f->len) {
57
+		*f->next = '\0';
58
+		return cur != f->next ? cur : NULL;
59
+	    }
60
+	    continue;
61
+	}
62
+	if(*f->next == '\n' || *f->next == '\r') {
63
+	    *f->next = '\0';
64
+	    stripping = 1;
65
+	} else if(stripping)
66
+	    return cur;
67
+	f->len--;
68
+	f->next++;
69
+    }
70
+}
71
+
72
+
73
+static void send_pipe(HANDLE pipe, AV_UPD_STATUS *updstatus, int state, int fail) {
74
+    DWORD got;
75
+
76
+const char *phases[] = {
77
+    "UPD_CHECK",
78
+    "UPD_NEWER_FOUND",
79
+    "UPD_NONE",
80
+    "UPD_DOWNLOAD_BEGIN",
81
+    "UPD_DOWNLOAD_COMPLETE",
82
+    "UPD_PAUSE",
83
+    "UPD_ABORT",
84
+    "UPD_DONE",
85
+    "UPD_INSTALL_BEGIN",
86
+    "UPD_INSTALL_COMPLETE",
87
+    "UPD_FILE_BEGIN",
88
+    "UPD_FILE_COMPLETE"
89
+    };
90
+
91
+    flog("SEND: state: %s - status: %s", (unsigned int)state < sizeof(phases) / sizeof(*phases) ? phases[state] : "INVALID", fail ? "fail" : "success");
92
+    updstatus->state = state;
93
+    updstatus->status = fail;
94
+    if(!WriteFile(pipe, updstatus, sizeof(*updstatus), &got, NULL))
95
+	flog("WARNING: cannot write to pipe");
96
+}
97
+
98
+#define SENDFAIL_AND_QUIT(phase)	    \
99
+    do {				    \
100
+	send_pipe(updpipe, &st, (phase), 1);\
101
+	CloseHandle(updpipe);		    \
102
+	flog_close();		    \
103
+	return 1;			    \
104
+    } while(0)
105
+
106
+#define SENDOK(phase)			    \
107
+    do {				    \
108
+	send_pipe(updpipe, &st, (phase), 0);\
109
+    } while(0)
110
+
111
+enum fresh_states {
112
+    FRESH_PRE,
113
+    FRESH_IDLE,
114
+    FRESH_DOWN
115
+};
116
+
117
+const char *fstates[] = {
118
+    "FRESH_PRE",
119
+    "FRESH_IDLE",
120
+    "FRESH_DOWN"
121
+};
122
+
123
+static void log_state(enum fresh_states s) {
124
+    flog("state is now: %s", (s < FRESH_PRE || s > FRESH_DOWN) ? "INVALID" : fstates[s]);
125
+}
126
+
127
+#define FRESH_PRE_START_S "ClamAV update process started at "
128
+#define FRESH_DOWN_S "Downloading "
129
+#define FRESH_UPDATED_S " updated (version: "
130
+#define FRESH_UPTODATE_S " is up to date "
131
+#define FRESH_DONE_S "Database updated "
132
+
133
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
134
+    HANDLE cld_r, cld_w2, cld_w, updpipe;
135
+    PROCESS_INFORMATION pinfo;
136
+    STARTUPINFO sinfo;
137
+    enum fresh_states fstate = FRESH_PRE;
138
+    AV_UPD_STATUS st = {UPD_CHECK, 0, 100, 0, 3};
139
+    DWORD dw;
140
+    struct my_f spam;
141
+    char buf[4096], command[8192], *ptr;
142
+    int updated_files = 0;
143
+    wchar_t *cmdl = GetCommandLineW();
144
+
145
+//    DebugBreak();
146
+
147
+    /* Locate myself */
148
+    dw = GetModuleFileName(NULL, buf, sizeof(buf));
149
+    if(!dw || dw >= sizeof(buf)-2)
150
+	return 1;
151
+    ptr = strrchr(buf, '\\');
152
+    if(!ptr)
153
+	return 1;
154
+    *ptr = '\0';
155
+
156
+    /* Log file */
157
+    _snprintf(command, sizeof(command)-1, "%s\\update.log", buf);
158
+    command[sizeof(command)-1] = '\0';
159
+    flog_open(command);
160
+
161
+    _snprintf(command, sizeof(command)-1, "freshclam.exe --stdout --config-file=\"%s\\freshclam.conf\" --datadir=\"%s\"", buf, buf);
162
+    command[sizeof(command)-1] = '\0';
163
+
164
+    /* Connect to master */
165
+    updpipe = CreateFile("\\\\.\\pipe\\IMMUNET_AVUPDATE", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
166
+    if(updpipe == INVALID_HANDLE_VALUE) {
167
+	flog("ERROR: failed to connect pipe");
168
+	flog_close();
169
+	return 1;
170
+    }
171
+    dw = PIPE_READMODE_MESSAGE;
172
+    if(!SetNamedPipeHandleState(updpipe, &dw, NULL, NULL)) {
173
+	CloseHandle(updpipe);
174
+	flog("ERROR: failed to set pipe to message mode");
175
+    	flog_close();
176
+	return 1;
177
+    }
178
+
179
+    /* Make pipe for freshclam stdio */
180
+    if(!CreatePipe(&cld_r, &cld_w, NULL, 0)) {
181
+	flog("ERROR: failed to create pipe");
182
+	SENDFAIL_AND_QUIT(UPD_CHECK);
183
+    }
184
+
185
+    if(!DuplicateHandle(GetCurrentProcess(), cld_w, GetCurrentProcess(), &cld_w2, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
186
+	CloseHandle(cld_r);
187
+	CloseHandle(cld_w);
188
+	flog("ERROR: failed to duplicate pipe");
189
+	SENDFAIL_AND_QUIT(UPD_CHECK);
190
+    }
191
+    CloseHandle(cld_w);
192
+
193
+    /* init my_fgets */
194
+    init_myf(&spam, cld_r);
195
+
196
+    /* Redir freshclam stdio */
197
+    memset(&sinfo, 0, sizeof(sinfo));
198
+    sinfo.cb = sizeof(sinfo);
199
+    sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
200
+    sinfo.hStdOutput = cld_w2;
201
+    sinfo.hStdError = cld_w2;
202
+    sinfo.dwFlags = STARTF_FORCEOFFFEEDBACK|STARTF_USESTDHANDLES;
203
+    if(!CreateProcess(NULL, command, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, buf, &sinfo, &pinfo)) {
204
+	CloseHandle(cld_w2);
205
+	CloseHandle(cld_r);
206
+	flog("ERROR: failed to execute '%s'", command);
207
+	SENDFAIL_AND_QUIT(UPD_CHECK);
208
+    }
209
+    CloseHandle(pinfo.hThread);
210
+    CloseHandle(cld_w2);
211
+
212
+    flog("Executing '%s'", command);
213
+    log_state(fstate);
214
+    /* Spam parsing */
215
+    while(1) {
216
+	char *buf;
217
+	buf = my_fgets(&spam);
218
+	flog("GOT: %s", buf);
219
+	if(!buf)
220
+	    break;
221
+	if(!strncmp(buf, "WARNING: ", 9))
222
+	    continue;
223
+	if(fstate == FRESH_PRE && !strncmp(buf, FRESH_PRE_START_S, sizeof(FRESH_PRE_START_S)-1)) {
224
+	    SENDOK(UPD_CHECK);
225
+	    fstate = FRESH_IDLE;
226
+	    log_state(fstate);
227
+	    continue;
228
+	}
229
+	if(fstate == FRESH_IDLE) {
230
+	    if(!strncmp(buf, FRESH_DOWN_S, sizeof(FRESH_DOWN_S)-1)) {
231
+		if(!updated_files) {
232
+		    SENDOK(UPD_NEWER_FOUND);
233
+		    SENDOK(UPD_DOWNLOAD_BEGIN);
234
+		}
235
+		updated_files++;
236
+		SENDOK(UPD_FILE_BEGIN);
237
+		fstate = FRESH_DOWN;
238
+		log_state(fstate);
239
+		continue;
240
+	    }
241
+	    if(strstr(buf, FRESH_UPTODATE_S))
242
+		continue;
243
+	    if(!strncmp(buf, FRESH_DONE_S, sizeof(FRESH_DONE_S) - 1))
244
+		continue;
245
+	}
246
+	if(fstate == FRESH_DOWN) {
247
+	    if(strstr(buf, FRESH_UPDATED_S)) {
248
+		SENDOK(UPD_FILE_COMPLETE);
249
+		fstate = FRESH_IDLE;
250
+		log_state(fstate);
251
+		continue;
252
+	    }
253
+	    if(strlen(buf) > sizeof(FRESH_DOWN_S)-1 && strstr(buf, FRESH_DOWN_S)) 
254
+		continue;
255
+	}
256
+	break;
257
+    }
258
+    CloseHandle(cld_r);
259
+    WaitForSingleObject(pinfo.hProcess, 30*1000);
260
+    if(!GetExitCodeProcess(pinfo.hProcess, &dw)) {
261
+	CloseHandle(pinfo.hProcess);
262
+	flog("ERROR: failed to retrieve freshclam return code");
263
+	SENDFAIL_AND_QUIT(st.state);
264
+    }
265
+    CloseHandle(pinfo.hProcess);
266
+    if(dw) {
267
+	flog("ERROR: freshclam exitted with %u\n", dw);
268
+	SENDFAIL_AND_QUIT(st.state);
269
+    }
270
+    if(fstate != FRESH_IDLE) {
271
+	flog("ERROR: freshclam exited with %u\n", dw);
272
+	SENDFAIL_AND_QUIT(st.state);
273
+    }
274
+
275
+    /* Send complete fin seq */
276
+    if(updated_files) {
277
+	SENDOK(UPD_DOWNLOAD_COMPLETE);
278
+	SENDOK(UPD_INSTALL_BEGIN);
279
+	SENDOK(UPD_INSTALL_COMPLETE);
280
+	SENDOK(UPD_DONE);
281
+    } else
282
+	SENDOK(UPD_NONE);
283
+    flog_close();
284
+    return 0;
285
+}