Merge lp:~psiphon-inc/psiphon/psiphon-1.6 into lp:psiphon

Proposed by مندس جرثومي
Status: Needs review
Proposed branch: lp:~psiphon-inc/psiphon/psiphon-1.6
Merge into: lp:psiphon
Diff against target: 30229 lines (+29308/-0)
170 files modified
appWeb/CONFIGURE_DEBUG.TXT (+5/-0)
appWeb/CONFIGURE_RELEASE.TXT (+5/-0)
appWeb/openSslModule.cpp (+896/-0)
appWeb/thread.cpp (+768/-0)
appweb.cnf (+27/-0)
bake-w32.bat (+1/-0)
changes.txt (+99/-0)
common/CppSQLite3.cpp (+1383/-0)
common/CppSQLite3.h (+270/-0)
common/SHA1.cpp (+282/-0)
common/SHA1.h (+150/-0)
common/SetupInfo.cpp (+512/-0)
common/SetupInfo.h (+110/-0)
common/User.cpp (+598/-0)
common/User.h (+94/-0)
common/bookmarks.cpp (+213/-0)
common/bookmarks.h (+30/-0)
common/convert.cpp (+176/-0)
common/convert.h (+47/-0)
common/cookies.cpp (+947/-0)
common/cookies.h (+73/-0)
common/logDetails.cpp (+252/-0)
common/logDetails.h (+70/-0)
common/parsedUrl.cpp (+312/-0)
common/parsedUrl.h (+78/-0)
common/sessions.cpp (+134/-0)
common/sessions.h (+29/-0)
common/sqlite3.h (+1161/-0)
common/strfunc.cpp (+109/-0)
common/strfunc.h (+39/-0)
common/timefunc.h (+21/-0)
common/tracer.cpp (+89/-0)
common/tracer.h (+39/-0)
html/en/errors/403.html (+15/-0)
html/en/errors/404.html (+15/-0)
html/en/errors/504.html (+15/-0)
html/en/index.tpl.html (+1/-0)
html/en/language.ini (+1/-0)
html/en/login.tpl.html (+62/-0)
html/en/login_err_db_insert_sess.tpl.html (+62/-0)
html/en/login_err_db_update_sess.tpl.html (+62/-0)
html/en/login_err_no_match.tpl.html (+62/-0)
html/en/login_err_pwd.tpl.html (+62/-0)
html/en/login_err_user.tpl.html (+62/-0)
html/en/main.tpl.html (+15/-0)
html/en/reset_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_conf_fail_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_conf_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_cur_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_db_update.tpl.html (+66/-0)
html/en/reset_pwd_err_new_pwd.tpl.html (+66/-0)
html/en/reset_pwd_err_no_match.tpl.html (+66/-0)
html/en/reset_pwd_err_user.tpl.html (+66/-0)
html/en/reset_pwd_success.tpl.html (+27/-0)
html/en/topbar.tpl.html (+511/-0)
html/fr/errors/403.html (+15/-0)
html/fr/errors/404.html (+15/-0)
html/fr/errors/504.html (+15/-0)
html/fr/index.tpl.html (+1/-0)
html/fr/language.ini (+1/-0)
html/fr/login.tpl.html (+62/-0)
html/fr/login_err_db_insert_sess.tpl.html (+62/-0)
html/fr/login_err_db_update_sess.tpl.html (+62/-0)
html/fr/login_err_no_match.tpl.html (+62/-0)
html/fr/login_err_pwd.tpl.html (+62/-0)
html/fr/login_err_user.tpl.html (+62/-0)
html/fr/main.tpl.html (+15/-0)
html/fr/reset_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_conf_fail_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_conf_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_cur_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_db_update.tpl.html (+66/-0)
html/fr/reset_pwd_err_new_pwd.tpl.html (+66/-0)
html/fr/reset_pwd_err_no_match.tpl.html (+66/-0)
html/fr/reset_pwd_err_user.tpl.html (+66/-0)
html/fr/reset_pwd_success.tpl.html (+27/-0)
html/fr/topbar.tpl.html (+511/-0)
html/fr/topbar_text.tpl.html (+461/-0)
html/ru/language.ini (+1/-0)
html/ru/login.tpl.html (+62/-0)
html/ru/login_err_db_insert_sess.tpl.html (+62/-0)
html/ru/login_err_db_update_sess.tpl.html (+62/-0)
html/ru/login_err_no_match.tpl.html (+62/-0)
html/ru/login_err_pwd.tpl.html (+62/-0)
html/ru/login_err_user.tpl.html (+62/-0)
html/ru/reset_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_conf_fail_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_conf_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_cur_pwd.tpl.html (+66/-0)
html/ru/reset_pwd_err_db_update.tpl.html (+66/-0)
html/ru/reset_pwd_err_new_pwd.tpl.html (+67/-0)
html/ru/reset_pwd_err_no_match.tpl.html (+66/-0)
html/ru/reset_pwd_err_user.tpl.html (+66/-0)
html/ru/reset_pwd_success.tpl.html (+27/-0)
html/ru/topbar.tpl.html (+517/-0)
install-ubuntu.txt (+98/-0)
install-w32.txt (+111/-0)
installer.aip (+221/-0)
mime.types (+110/-0)
psiphon.bkl (+296/-0)
psiphonHandler/CSSFlexLexer.h (+24/-0)
psiphonHandler/CSSLexer.l (+61/-0)
psiphonHandler/FlexLexer.h (+202/-0)
psiphonHandler/HTMLFlexLexer.h (+24/-0)
psiphonHandler/HTMLlexer.l (+315/-0)
psiphonHandler/lex.CSS.cpp (+1451/-0)
psiphonHandler/lex.HTML.cpp (+1852/-0)
psiphonHandler/myclient.cpp (+1084/-0)
psiphonHandler/myclient.h (+239/-0)
psiphonHandler/psiphonContFilter.cpp (+394/-0)
psiphonHandler/psiphonContFilter.h (+84/-0)
psiphonHandler/psiphonHandler.cpp (+1797/-0)
psiphonHandler/psiphonHandler.def (+3/-0)
psiphonHandler/psiphonHandler.h (+204/-0)
psiphonHandler/psiphonUrl.cpp (+293/-0)
psiphonHandler/psiphonUrl.h (+49/-0)
psiphonHandler/psiphonUtils.cpp (+390/-0)
psiphonHandler/psiphonUtils.h (+55/-0)
psiphonHandler/tokensDefs.h (+48/-0)
psiphonPanel/CertDlg.cpp (+309/-0)
psiphonPanel/CertDlg.h (+64/-0)
psiphonPanel/CodeCountry.cpp (+266/-0)
psiphonPanel/CodeCountry.h (+30/-0)
psiphonPanel/DownloadEvent.cpp (+96/-0)
psiphonPanel/DownloadEvent.h (+168/-0)
psiphonPanel/DownloadFile.cpp (+167/-0)
psiphonPanel/DownloadFile.h (+80/-0)
psiphonPanel/GetIP.cpp (+101/-0)
psiphonPanel/GetIP.h (+23/-0)
psiphonPanel/LinkDlg.cpp (+302/-0)
psiphonPanel/LinkDlg.h (+63/-0)
psiphonPanel/ListCtrlSort.cpp (+88/-0)
psiphonPanel/ListCtrlSort.h (+74/-0)
psiphonPanel/LogDlg.cpp (+223/-0)
psiphonPanel/LogDlg.h (+61/-0)
psiphonPanel/PrefDlg.cpp (+121/-0)
psiphonPanel/PrefDlg.h (+45/-0)
psiphonPanel/PsiphonApp.cpp (+99/-0)
psiphonPanel/PsiphonApp.h (+43/-0)
psiphonPanel/PsiphonDlg.cpp (+574/-0)
psiphonPanel/PsiphonDlg.h (+99/-0)
psiphonPanel/PsiphonLog.cpp (+51/-0)
psiphonPanel/PsiphonLog.h (+39/-0)
psiphonPanel/PsiphonNameDlg.cpp (+133/-0)
psiphonPanel/PsiphonNameDlg.h (+42/-0)
psiphonPanel/Server.cpp (+215/-0)
psiphonPanel/Server.h (+80/-0)
psiphonPanel/SetupDlg.cpp (+123/-0)
psiphonPanel/SetupDlg.h (+61/-0)
psiphonPanel/UpdateDlg.cpp (+292/-0)
psiphonPanel/UpdateDlg.h (+59/-0)
psiphonPanel/UserDetailsDlg.cpp (+230/-0)
psiphonPanel/UserDetailsDlg.h (+46/-0)
psiphonPanel/UserDlg.cpp (+336/-0)
psiphonPanel/UserDlg.h (+69/-0)
psiphonPanel/cert.cpp (+102/-0)
psiphonPanel/cert.h (+22/-0)
psiphonPanel/psiphonoff.xpm (+189/-0)
psiphonPanel/psiphonon.xpm (+189/-0)
psiphonPanel/resources.h (+33/-0)
psiphonPanel/sessionAccess.cpp (+172/-0)
psiphonPanel/sessionAccess.h (+35/-0)
psiphonPanel/stdwx.cpp (+19/-0)
psiphonPanel/stdwx.h (+53/-0)
psiphonPanel/taskbaricon.cpp (+91/-0)
psiphonPanel/taskbaricon.h (+39/-0)
psiphonPanel/update.cpp (+79/-0)
psiphonPanel/update.h (+20/-0)
psiphonPanel/wxPsiphon.rc (+23/-0)
userlicense.txt (+39/-0)
To merge this branch: bzr merge lp:~psiphon-inc/psiphon/psiphon-1.6
Reviewer Review Type Date Requested Status
Psiphon Inc. Pending
Review via email: mp+83096@code.launchpad.net
To post a comment you must log in.

Unmerged revisions

1. By jamyang <email address hidden>

psiphon-1.6

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.DS_Store'
2Binary files .DS_Store 1970-01-01 00:00:00 +0000 and .DS_Store 2011-11-23 01:01:25 +0000 differ
3=== added directory 'appWeb'
4=== added file 'appWeb/CONFIGURE_DEBUG.TXT'
5--- appWeb/CONFIGURE_DEBUG.TXT 1970-01-01 00:00:00 +0000
6+++ appWeb/CONFIGURE_DEBUG.TXT 2011-11-23 01:01:25 +0000
7@@ -0,0 +1,5 @@
8+./configure --reset
9+./configure --disable-samples --without-upload --without-xdb --disable-test --type=DEBUG \
10+--with-openssl=loadable \
11+--with-openssl-dir=../../openssl \
12+--with-openssl-libs="ssl crypto"
13\ No newline at end of file
14
15=== added file 'appWeb/CONFIGURE_RELEASE.TXT'
16--- appWeb/CONFIGURE_RELEASE.TXT 1970-01-01 00:00:00 +0000
17+++ appWeb/CONFIGURE_RELEASE.TXT 2011-11-23 01:01:25 +0000
18@@ -0,0 +1,5 @@
19+./configure --reset
20+./configure --disable-samples --without-upload --without-xdb --disable-test --type=RELEASE \
21+--with-openssl=loadable \
22+--with-openssl-dir=../../openssl \
23+--with-openssl-libs="ssl crypto"
24\ No newline at end of file
25
26=== added file 'appWeb/openSslModule.cpp'
27--- appWeb/openSslModule.cpp 1970-01-01 00:00:00 +0000
28+++ appWeb/openSslModule.cpp 2011-11-23 01:01:25 +0000
29@@ -0,0 +1,896 @@
30+///
31+/// @file openSslModule.cpp
32+/// @brief Support for secure sockets via OpenSSL
33+/// @overview This module integrates support for OpenSSL into AppWeb
34+/// via a dynamically loadable module.
35+//
36+/////////////////////////////////// Copyright //////////////////////////////////
37+//
38+// @copy default
39+//
40+// Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
41+// Copyright (c) Michael O'Brien, 1994-2006. All Rights Reserved.
42+//
43+// This software is distributed under commercial and open source licenses.
44+// You may use the GPL open source license described below or you may acquire
45+// a commercial license from Mbedthis Software. You agree to be fully bound
46+// by the terms of either license. Consult the LICENSE.TXT distributed with
47+// this software for full details.
48+//
49+// This software is open source; you can redistribute it and/or modify it
50+// under the terms of the GNU General Public License as published by the
51+// Free Software Foundation; either version 2 of the License, or (at your
52+// option) any later version. See the GNU General Public License for more
53+// details at: http://www.mbedthis.com/downloads/gplLicense.html
54+//
55+// This program is distributed WITHOUT ANY WARRANTY; without even the
56+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
57+//
58+// This GPL license does NOT permit incorporating this software into
59+// proprietary programs. If you are unable to comply with the GPL, you must
60+// acquire a commercial license to use this software. Commercial licenses
61+// for this software and support services are available from Mbedthis
62+// Software at http://www.mbedthis.com
63+//
64+// @end
65+//
66+////////////////////////////////// Includes ////////////////////////////////////
67+
68+#include "openSslModule.h"
69+
70+//////////////////////////////////// Locals ////////////////////////////////////
71+#if BLD_FEATURE_OPENSSL_MODULE
72+
73+#include "openSslDh.h"
74+
75+#if BLD_FEATURE_MULTITHREAD
76+static MprMutex **locks;
77+static int numLocks;
78+#endif
79+
80+////////////////////////////// Forward Declarations ////////////////////////////
81+
82+#if BLD_FEATURE_MULTITHREAD
83+static DynLock *sslCreateDynLock(const char *file, int line);
84+static void sslDynLock(int mode, DynLock *dl, const char *file, int line);
85+static void sslDestroyDynLock(DynLock *dl, const char *file, int line);
86+static void sslStaticLock(int mode, int n, const char *file, int line);
87+static ulong sslThreadId();
88+#endif
89+
90+static int configureCertificates(SSL_CTX *ctx, char *key, char *cert);
91+static RSA *rsaCallback(SSL *ssl, int isExport, int keyLength);
92+static DH *dhCallback(SSL *ssl, int isExport, int keyLength);
93+static int verifyX509Certificate(int ok, X509_STORE_CTX *ctx);
94+
95+//////////////////////////////////// Locals ////////////////////////////////////
96+
97+static MaOpenSslModule *openSslModule;
98+static MaOpenSslProvider *openSslProvider;
99+
100+////////////////////////////////////////////////////////////////////////////////
101+/////////////////////////////// MaOpenSslModule ////////////////////////////////
102+////////////////////////////////////////////////////////////////////////////////
103+
104+int mprOpenSslInit(void *handle)
105+{
106+ if (maGetHttp() == 0) {
107+ return MPR_ERR_NOT_INITIALIZED;
108+ }
109+ new MaOpenSslModule(handle);
110+ return 0;
111+}
112+
113+////////////////////////////////////////////////////////////////////////////////
114+
115+MaOpenSslModule::MaOpenSslModule(void *handle) : MaModule("openSsl", handle)
116+{
117+ openSslModule = this;
118+ openSslProvider = new MaOpenSslProvider("openSsl");
119+}
120+
121+////////////////////////////////////////////////////////////////////////////////
122+
123+MaOpenSslModule::~MaOpenSslModule()
124+{
125+ delete openSslProvider;
126+}
127+
128+////////////////////////////////////////////////////////////////////////////////
129+//
130+// This is called from Http::start after all the modules are loaded.
131+// The code here is global for this handler and is not required per handler
132+// instance.
133+//
134+int MaOpenSslModule::start()
135+{
136+ RandBuf randBuf;
137+ static int once = 0;
138+
139+ //
140+ // Depending on the order in the configuration file, we will get called
141+ // by the module mechanism and by OpenSslConfig::start(). But we only
142+ // want to run once.
143+ //
144+ if (once++ > 0) {
145+ return 0;
146+ }
147+ randBuf.pid = getpid();
148+ randBuf.time = time(0);
149+ randBuf.msec = mprGetTime(0);
150+ RAND_seed((void*) &randBuf, sizeof(randBuf));
151+
152+#if SOLARIS || LINUX || MACOSX
153+ mprLog(6, "OpenSsl: Before calling RAND_load_file\n");
154+ RAND_load_file("/dev/urandom", 256);
155+ mprLog(6, "OpenSsl: After calling RAND_load_file\n");
156+#endif
157+
158+#if BLD_FEATURE_MULTITHREAD
159+ numLocks = CRYPTO_num_locks();
160+ locks = (MprMutex**) mprMalloc(numLocks * sizeof(MprMutex*));
161+ for (int i = 0; i < numLocks; i++) {
162+ locks[i] = new MprMutex();
163+ }
164+ CRYPTO_set_id_callback(sslThreadId);
165+ CRYPTO_set_locking_callback(sslStaticLock);
166+
167+ CRYPTO_set_dynlock_create_callback(sslCreateDynLock);
168+ CRYPTO_set_dynlock_destroy_callback(sslDestroyDynLock);
169+ CRYPTO_set_dynlock_lock_callback(sslDynLock);
170+#endif
171+
172+#if WIN
173+ // _fmode=_O_BINARY;
174+ // CRYPTO_malloc_init();
175+ // SSLC_add_all_algorithms();
176+#else
177+ OpenSSL_add_all_algorithms();
178+#endif
179+
180+ SSL_library_init();
181+ return 0;
182+}
183+
184+////////////////////////////////////////////////////////////////////////////////
185+
186+void MaOpenSslModule::stop()
187+{
188+#if BLD_FEATURE_MULTITHREAD
189+ int i;
190+
191+ if (locks) {
192+ for (i = 0; i < numLocks; i++) {
193+ delete locks[i];
194+ }
195+ mprFree(locks);
196+ locks = 0;
197+ numLocks = 0;
198+
199+ CRYPTO_set_id_callback(0);
200+ CRYPTO_set_locking_callback(0);
201+
202+ CRYPTO_set_dynlock_create_callback(0);
203+ CRYPTO_set_dynlock_destroy_callback(0);
204+ CRYPTO_set_dynlock_lock_callback(0);
205+ }
206+#endif
207+}
208+
209+////////////////////////////////////////////////////////////////////////////////
210+/////////////////////////////// MaOpenSslProvider //////////////////////////////
211+////////////////////////////////////////////////////////////////////////////////
212+//
213+// The SSL provider class implements and decouples the interface between
214+// AppWeb and any SSL stack.
215+//
216+
217+MaOpenSslProvider::MaOpenSslProvider(char *name) : MaSslProvider(name)
218+{
219+}
220+
221+////////////////////////////////////////////////////////////////////////////////
222+
223+MaOpenSslProvider::~MaOpenSslProvider()
224+{
225+}
226+
227+////////////////////////////////////////////////////////////////////////////////
228+
229+MaSslConfig *MaOpenSslProvider::newConfig(MaHost *host)
230+{
231+ return new MaOpenSslConfig(host);
232+}
233+
234+////////////////////////////////////////////////////////////////////////////////
235+//////////////////////////////// MaOpenSslConfig ///////////////////////////////
236+////////////////////////////////////////////////////////////////////////////////
237+//
238+// An instance is created for each SSL server
239+//
240+
241+MaOpenSslConfig::MaOpenSslConfig(MaHost *host) : MaSslConfig(host)
242+{
243+ context = 0;
244+ dhKey512 = 0;
245+ dhKey1024 = 0;
246+ rsaKey512 = 0;
247+ rsaKey1024 = 0;
248+}
249+
250+////////////////////////////////////////////////////////////////////////////////
251+
252+MaOpenSslConfig::~MaOpenSslConfig()
253+{
254+ if (context != 0) {
255+ SSL_CTX_free(context);
256+ }
257+ if (rsaKey512) {
258+ RSA_free(rsaKey512);
259+ }
260+ if (rsaKey1024) {
261+ RSA_free(rsaKey1024);
262+ }
263+ if (dhKey512) {
264+ DH_free(dhKey512);
265+ }
266+ if (dhKey1024) {
267+ DH_free(dhKey1024);
268+ }
269+}
270+
271+////////////////////////////////////////////////////////////////////////////////
272+//
273+// This method is called to open listening sockets using this SslConfig setup.
274+//
275+
276+MprSocket *MaOpenSslConfig::newSocket()
277+{
278+ MaOpenSslSocket *socket;
279+
280+ socket = new MaOpenSslSocket(this);
281+
282+ return (MprSocket*) socket;
283+}
284+
285+////////////////////////////////////////////////////////////////////////////////
286+//
287+// This is started for each SSL connection. With Keep-alive this may service
288+// many requests.
289+//
290+
291+int MaOpenSslConfig::start()
292+{
293+ SSL_METHOD *meth;
294+ char *hostName;
295+
296+ if (keyFile == 0) {
297+ mprError(MPR_L, MPR_LOG, "Cant start SSL: missing key file");
298+ return MPR_ERR_CANT_INITIALIZE;
299+ }
300+ if (certFile == 0) {
301+ mprError(MPR_L, MPR_LOG, "Cant start SSL: missing certificate file");
302+ return MPR_ERR_CANT_INITIALIZE;
303+ }
304+
305+ //
306+ // Depending on the order in the configuration file, we may get called
307+ // by sslModule::start() before OpenSslModule::start has run. So we
308+ // must initialize here.
309+ //
310+ openSslModule->start();
311+
312+ hostName = host->getName();
313+
314+ if (protocols == MPR_HTTP_PROTO_SSLV2) {
315+ meth = SSLv2_server_method();
316+ } else {
317+ meth = SSLv23_server_method();
318+ }
319+ context = SSL_CTX_new(meth);
320+ mprAssert(context);
321+ if (context == 0) {
322+ mprError(MPR_L, MPR_LOG, "Unable to create SSL context");
323+ return MPR_ERR_CANT_CREATE;
324+ }
325+
326+ SSL_CTX_set_app_data(context, (void*) this);
327+ SSL_CTX_set_quiet_shutdown(context, 1);
328+ SSL_CTX_sess_set_cache_size(context, 512);
329+
330+ //
331+ // Configure the certificate for this host
332+ //
333+ if (configureCertificates(context, keyFile, certFile) != 0) {
334+ SSL_CTX_free(context);
335+ context = 0;
336+ return MPR_ERR_CANT_INITIALIZE;
337+ }
338+
339+ mprLog(4, "SSL: %s: Using ciphers %s\n", hostName, ciphers);
340+ SSL_CTX_set_cipher_list(context, ciphers);
341+
342+ //
343+ // Configure the client verification certificate locations
344+ //
345+ if (verifyClient) {
346+ if (caFile == 0 && caPath == 0) {
347+ mprError(MPR_L, MPR_LOG,
348+ "Must define CA certificates if using client verification");
349+ SSL_CTX_free(context);
350+ context = 0;
351+ return MPR_ERR_BAD_STATE;
352+ }
353+ if (caFile || caPath) {
354+ if ((!SSL_CTX_load_verify_locations(context, caFile, caPath)) ||
355+ (!SSL_CTX_set_default_verify_paths(context))) {
356+ mprError(MPR_L, MPR_LOG,
357+ "Unable to set certificate locations");
358+ SSL_CTX_free(context);
359+ context = 0;
360+ return MPR_ERR_CANT_ACCESS;
361+ }
362+ if (caFile) {
363+ STACK_OF(X509_NAME) *certNames;
364+ certNames = SSL_load_client_CA_file(caFile);
365+ if (certNames == 0) {
366+ } else {
367+ //
368+ // Define the list of CA certificates to send to the client
369+ // before they send their client certificate for validation
370+ //
371+ SSL_CTX_set_client_CA_list(context, certNames);
372+ }
373+ }
374+ }
375+ mprLog(4, "SSL: %s: is verifying client connections\n", hostName);
376+ if (caFile) {
377+ mprLog(4, "SSL: %s: Using certificates from %s\n", hostName,
378+ caFile);
379+ } else if (caPath) {
380+ mprLog(4, "SSL: %s: Using certificates from directory %s\n",
381+ hostName, caPath);
382+ }
383+ SSL_CTX_set_verify(context,
384+ SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
385+ verifyX509Certificate);
386+ SSL_CTX_set_verify_depth(context, verifyDepth);
387+
388+ } else {
389+ SSL_CTX_set_verify(context, SSL_VERIFY_NONE, verifyX509Certificate);
390+ }
391+
392+ //
393+ // Define callbacks
394+ //
395+ SSL_CTX_set_tmp_rsa_callback(context, rsaCallback);
396+ SSL_CTX_set_tmp_dh_callback(context, dhCallback);
397+
398+ //
399+ // Enable all buggy client work-arounds
400+ //
401+ SSL_CTX_set_options(context, SSL_OP_ALL);
402+
403+ //
404+ // Select the required protocols
405+ //
406+ if (!(protocols & MPR_HTTP_PROTO_SSLV2)) {
407+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv2);
408+ mprLog(4, "SSL: %s: Disabling SSLv2\n", hostName);
409+ }
410+ if (!(protocols & MPR_HTTP_PROTO_SSLV3)) {
411+ SSL_CTX_set_options(context, SSL_OP_NO_SSLv3);
412+ mprLog(4, "SSL: %s: Disabling SSLv3\n", hostName);
413+ }
414+ if (!(protocols & MPR_HTTP_PROTO_TLSV1)) {
415+ SSL_CTX_set_options(context, SSL_OP_NO_TLSv1);
416+ mprLog(4, "SSL: %s: Disabling TLSv1\n", hostName);
417+ }
418+
419+ //
420+ // Ensure we generate a new private key for each connection
421+ //
422+ SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
423+
424+ //
425+ // Pre-generate some keys that are slow to compute
426+ //
427+ rsaKey512 = RSA_generate_key(512, RSA_F4, 0, 0);
428+ rsaKey1024 = RSA_generate_key(1024, RSA_F4, 0, 0);
429+
430+ dhKey512 = get_dh512();
431+ dhKey1024 = get_dh1024();
432+
433+ return 0;
434+}
435+
436+////////////////////////////////////////////////////////////////////////////////
437+
438+void MaOpenSslConfig::stop()
439+{
440+}
441+
442+////////////////////////////////////////////////////////////////////////////////
443+
444+SSL_CTX *MaOpenSslConfig::getContext()
445+{
446+ return context;
447+}
448+
449+////////////////////////////////////////////////////////////////////////////////
450+
451+///
452+/// Called to verify X509 client certificates
453+///
454+static int verifyX509Certificate(int ok, X509_STORE_CTX *xContext)
455+{
456+ X509 *cert;
457+ SSL *ssl;
458+ MaOpenSslSocket *sslSocket;
459+ MaOpenSslConfig *config;
460+ char subject[260], issuer[260], peer[260];
461+ int error, depth;
462+
463+ subject[0] = issuer[0] = '\0';
464+
465+ ssl = (SSL*) X509_STORE_CTX_get_app_data(xContext);
466+ sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl);
467+ config = (MaOpenSslConfig*) sslSocket->getConfig();
468+
469+ cert = X509_STORE_CTX_get_current_cert(xContext);
470+ depth = X509_STORE_CTX_get_error_depth(xContext);
471+ error = X509_STORE_CTX_get_error(xContext);
472+
473+ if (X509_NAME_oneline(X509_get_subject_name(cert), subject,
474+ sizeof(subject) - 1) < 0) {
475+ ok = 0;
476+ }
477+ //
478+ // FUTURE -- should compare subject name and host name. Need smart compare
479+ //
480+ if (X509_NAME_oneline(X509_get_issuer_name(xContext->current_cert), issuer,
481+ sizeof(issuer) - 1) < 0) {
482+ ok = 0;
483+ }
484+ if (X509_NAME_get_text_by_NID(X509_get_subject_name(xContext->current_cert),
485+ NID_commonName, peer, sizeof(peer) - 1) < 0) {
486+ ok = 0;
487+ }
488+
489+ //
490+ // Customizers: add your own code here to validate client certificates
491+ //
492+ if (ok && config->verifyDepth < depth) {
493+ if (error == 0) {
494+ error = X509_V_ERR_CERT_CHAIN_TOO_LONG;
495+ }
496+ ok = 0;
497+ }
498+
499+ if (error != 0) {
500+ mprAssert(!ok);
501+ }
502+
503+#if UNUSED
504+ switch (error) {
505+ case X509_V_ERR_CERT_HAS_EXPIRED:
506+ case X509_V_ERR_CERT_NOT_YET_VALID:
507+ case X509_V_ERR_CERT_REJECTED:
508+ case X509_V_ERR_CERT_SIGNATURE_FAILURE:
509+ case X509_V_ERR_CERT_UNTRUSTED:
510+ case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
511+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
512+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
513+ case X509_V_ERR_INVALID_CA:
514+ case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
515+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
516+ default:
517+ ok = 0;
518+ break;
519+ }
520+#endif
521+
522+ if (!ok) {
523+ mprLog(0, "SSL: Certification failed: subject %s\n", subject);
524+ mprLog(4, "SSL: Issuer: %s\n", issuer);
525+ mprLog(4, "SSL: Peer: %s\n", peer);
526+ mprLog(4, "SSL: Error: %d: %s\n", error,
527+ X509_verify_cert_error_string(error));
528+
529+ } else {
530+ mprLog(0, "SSL: Certificate verified: subject %s\n", subject);
531+ mprLog(4, "SSL: Issuer: %s\n", issuer);
532+ mprLog(4, "SSL: Peer: %s\n", peer);
533+ }
534+ return ok;
535+}
536+
537+////////////////////////////////////////////////////////////////////////////////
538+
539+///
540+/// Configure the SSL certificate information
541+///
542+
543+static int configureCertificates(SSL_CTX *ctx, char *key, char *cert)
544+{
545+ mprAssert(ctx);
546+ mprAssert(cert);
547+
548+ if (cert == 0) {
549+ return 0;
550+ }
551+
552+ if (SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM) <= 0){
553+ mprError(MPR_L, MPR_LOG, "Can't define certificate file: %s", cert);
554+ return -1;
555+ }
556+
557+ key = (key == 0) ? cert : key;
558+ if (SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM) <= 0) {
559+ mprError(MPR_L, MPR_LOG, "Can't define private key file: %s", key);
560+ return -1;
561+ }
562+
563+ if (!SSL_CTX_check_private_key(ctx)) {
564+ mprError(MPR_L, MPR_LOG, "Check of private key file failed: %s", key);
565+ return -1;
566+ }
567+ return 0;
568+}
569+
570+////////////////////////////////////////////////////////////////////////////////
571+//////////////////////////////// MaOpenSslSocket ///////////////////////////////
572+////////////////////////////////////////////////////////////////////////////////
573+
574+MaOpenSslSocket::MaOpenSslSocket(MaOpenSslConfig *config) : MaSslSocket(config)
575+{
576+ ssl = 0;
577+ bio = 0;
578+ context = config->getContext();
579+}
580+
581+////////////////////////////////////////////////////////////////////////////////
582+
583+MaOpenSslSocket::~MaOpenSslSocket()
584+{
585+ mprAssert(ssl == 0);
586+ mprAssert(bio == 0);
587+}
588+
589+////////////////////////////////////////////////////////////////////////////////
590+//
591+// Called to accept new connections. When a new connection arrives, this
592+// method is called to create a new socket object using the same SSL "config"
593+// as the listening socket.
594+//
595+
596+MprSocket *MaOpenSslSocket::newSocket()
597+{
598+ MaOpenSslSocket *socket;
599+
600+ socket = new MaOpenSslSocket((MaOpenSslConfig*) config);
601+
602+ return (MprSocket*) socket;
603+}
604+
605+////////////////////////////////////////////////////////////////////////////////
606+//
607+// initConnection is called on the first I/O on a new connection. It must
608+// setup the SSL structures ready to exchange data.
609+//
610+// Init connection must return -1 on errors. It must also be able to reject
611+// subsequent calls to read()/write(). On errors we leave bio == 0. This
612+// will cause any calls to read() to error.
613+//
614+
615+int MaOpenSslSocket::initConnection()
616+{
617+ BIO *bioSSL, *bioSock;
618+
619+ if (bio) {
620+ return 0;
621+ }
622+ bio = BIO_new(BIO_f_buffer());
623+ if (bio == 0) {
624+ return MPR_ERR_CANT_INITIALIZE;
625+ }
626+
627+ BIO_set_write_buffer_size(bio, 128);
628+ ssl = (SSL*) SSL_new(context);
629+ mprAssert(ssl);
630+ if (ssl == 0) {
631+ return MPR_ERR_CANT_INITIALIZE;
632+ }
633+ SSL_set_app_data(ssl, (void*) this);
634+
635+ SSL_set_session(ssl, 0);
636+ bioSSL = BIO_new(BIO_f_ssl());
637+ mprAssert(bioSSL);
638+
639+ bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
640+ mprAssert(bioSock);
641+
642+ SSL_set_bio(ssl, bioSock, bioSock);
643+ SSL_set_accept_state(ssl);
644+
645+ BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
646+ BIO_push(bio, bioSSL);
647+ return 0;
648+}
649+
650+////////////////////////////////////////////////////////////////////////////////
651+
652+bool MaOpenSslSocket::dispose()
653+{
654+ if (ssl) {
655+ SSL_set_shutdown(ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
656+ ssl = 0;
657+ }
658+ if (bio) {
659+ BIO_free_all(bio);
660+ bio = 0;
661+ }
662+
663+ //
664+ // Disposing a socket is a thread-safe way of calling a destructor. It
665+ // uses reference counting and will be deleted when the last reference
666+ // is released.
667+ //
668+ return this->MprSocket::dispose();
669+}
670+
671+////////////////////////////////////////////////////////////////////////////////
672+
673+void MaOpenSslSocket::close(int how)
674+{
675+ BIO_flush(bio);
676+ this->MprSocket::close(how);
677+}
678+
679+////////////////////////////////////////////////////////////////////////////////
680+//
681+// Write data. Return the number of bytes written or -1 on errors.
682+//
683+
684+int MaOpenSslSocket::write(char *buf, int len)
685+{
686+ int rc, written, totalWritten;
687+
688+ if (bio == 0 || ssl == 0 || len < 0) {
689+ return -1;
690+ }
691+ BIO_clear_retry_flags(bio);
692+ totalWritten = 0;
693+ do {
694+ written = BIO_write(bio, buf, len);
695+ mprLog(7, "written %d, len %d\n", written, len);
696+ if (written >= 0) {
697+ do {
698+ rc = BIO_flush(bio);
699+ mprLog(7, "BIO_flush rc %d\n", rc);
700+ if (rc > 0) {
701+ // Success
702+ break;
703+ }
704+ //
705+ // Nap to prevent busy waiting.
706+ //
707+ mprSleep(10);
708+ } while (rc <= 0 && BIO_should_retry(bio));
709+ totalWritten += written;
710+ buf += written;
711+ len -= written;
712+ }
713+ mprLog(7, "write: len %d, written %d, total %d, should_retry %d\n",
714+ len, written, totalWritten, BIO_should_retry(bio));
715+ } while (len > 0 && (written > 0 || BIO_should_retry(bio)));
716+
717+//AFF
718+ if(written < 0 && BIO_should_retry(bio) == 0)
719+ return -1;
720+//
721+
722+ return totalWritten;
723+}
724+
725+////////////////////////////////////////////////////////////////////////////////
726+
727+int MaOpenSslSocket::flush()
728+{
729+ return BIO_flush(bio);
730+}
731+
732+////////////////////////////////////////////////////////////////////////////////
733+
734+int MaOpenSslSocket::read(char *buf, int len)
735+{
736+ int rc;
737+
738+ if (bio == 0 || ssl == 0) {
739+ return -1;
740+ }
741+
742+ rc = BIO_read(bio, buf, len);
743+
744+#if DEBUG
745+ if (rc > 0 && !connTraced) {
746+ X509_NAME *xSubject;
747+ X509 *cert;
748+ char subject[260], issuer[260], peer[260];
749+
750+ mprLog(4, "%d: SSL Connected using: \"%s\"\n",
751+ sock, SSL_get_cipher(ssl));
752+
753+ cert = SSL_get_peer_certificate(ssl);
754+ if (cert == 0) {
755+ mprLog(4, "%d: SSL Details: client supplied no certificate\n",
756+ sock);
757+ } else {
758+ xSubject = X509_get_subject_name(cert);
759+ X509_NAME_oneline(xSubject, subject, sizeof(subject) -1);
760+ X509_NAME_oneline(X509_get_issuer_name(cert), issuer,
761+ sizeof(issuer) -1);
762+ X509_NAME_get_text_by_NID(xSubject, NID_commonName, peer,
763+ sizeof(peer) - 1);
764+ mprLog(4, "%d: SSL Subject %s\n", sock, subject);
765+ mprLog(4, "%d: SSL Issuer: %s\n", sock, issuer);
766+ mprLog(4, "%d: SSL Peer: %s\n", sock, peer);
767+ X509_free(cert);
768+ }
769+ connTraced = 1;
770+ }
771+#endif
772+
773+ if (rc > 0) {
774+ return rc;
775+
776+ } else if (rc == 0) {
777+ if (BIO_should_retry(bio)) {
778+ return 0;
779+ }
780+ flags |= MPR_SOCKET_EOF;
781+ return 0;
782+ }
783+ if (BIO_should_retry(bio)) {
784+ return 0;
785+ }
786+ return rc;
787+}
788+
789+////////////////////////////////////////////////////////////////////////////////
790+#if UNUSED
791+//
792+// Return true if end of file
793+//
794+
795+bool MaOpenSslSocket::getEof()
796+{
797+ bool rc;
798+
799+ rc = (BIO_eof(bio) != 0);
800+ return rc;
801+}
802+
803+#endif
804+
805+////////////////////////////////////////////////////////////////////////////////
806+#if BLD_FEATURE_MULTITHREAD
807+
808+static ulong sslThreadId()
809+{
810+ return (long) mprGetCurrentThread();
811+}
812+
813+////////////////////////////////////////////////////////////////////////////////
814+
815+static void sslStaticLock(int mode, int n, const char *file, int line)
816+{
817+ mprAssert(0 <= n && n < numLocks);
818+ if (mode & CRYPTO_LOCK) {
819+ locks[n]->lock();
820+ } else {
821+ locks[n]->unlock();
822+ }
823+}
824+
825+////////////////////////////////////////////////////////////////////////////////
826+
827+static DynLock *sslCreateDynLock(const char *file, int line)
828+{
829+ DynLock *dl;
830+
831+ dl = (DynLock*) mprMalloc(sizeof(DynLock));
832+ dl->mutex = new MprMutex();
833+ return dl;
834+}
835+
836+////////////////////////////////////////////////////////////////////////////////
837+
838+static void sslDestroyDynLock(DynLock *dl, const char *file, int line)
839+{
840+ delete dl->mutex;
841+ mprFree(dl);
842+}
843+
844+////////////////////////////////////////////////////////////////////////////////
845+
846+static void sslDynLock(int mode, DynLock *dl, const char *file, int line)
847+{
848+ if (mode & CRYPTO_LOCK) {
849+ dl->mutex->lock();
850+ } else {
851+ dl->mutex->unlock();
852+ }
853+}
854+
855+#endif // BLD_FEATURE_MULTITHREAD
856+////////////////////////////////////////////////////////////////////////////////
857+//
858+// Used for ephemeral RSA keys
859+//
860+
861+static RSA *rsaCallback(SSL *ssl, int isExport, int keyLength)
862+{
863+ MaOpenSslSocket *sslSocket;
864+ MaOpenSslConfig *config;
865+ RSA *key;
866+
867+ sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl);
868+ config = (MaOpenSslConfig*) sslSocket->getConfig();
869+
870+ key = 0;
871+ switch (keyLength) {
872+ case 512:
873+ key = config->rsaKey512;
874+ break;
875+
876+ case 1024:
877+ default:
878+ key = config->rsaKey1024;
879+ }
880+ return key;
881+}
882+
883+
884+////////////////////////////////////////////////////////////////////////////////
885+//
886+// Used for ephemeral DH keys
887+//
888+
889+static DH *dhCallback(SSL *ssl, int isExport, int keyLength)
890+{
891+ MaOpenSslSocket *sslSocket;
892+ MaOpenSslConfig *config;
893+ DH *key;
894+
895+ sslSocket = (MaOpenSslSocket*) SSL_get_app_data(ssl);
896+ config = (MaOpenSslConfig*) sslSocket->getConfig();
897+
898+ key = 0;
899+ switch (keyLength) {
900+ case 512:
901+ key = config->dhKey512;
902+ break;
903+
904+ case 1024:
905+ default:
906+ key = config->dhKey1024;
907+ }
908+ return key;
909+}
910+
911+////////////////////////////////////////////////////////////////////////////////
912+#else
913+void mprOpenSslModuleDummy() {}
914+
915+#endif // BLD_FEATURE_OPENSSL_MODULE
916+
917+//
918+// Local variables:
919+// tab-width: 4
920+// c-basic-offset: 4
921+// End:
922+// vim:tw=78
923+// vim600: sw=4 ts=4 fdm=marker
924+// vim<600: sw=4 ts=4
925+//
926
927=== added file 'appWeb/thread.cpp'
928--- appWeb/thread.cpp 1970-01-01 00:00:00 +0000
929+++ appWeb/thread.cpp 2011-11-23 01:01:25 +0000
930@@ -0,0 +1,768 @@
931+///
932+/// @file WIN/thread.cpp
933+/// @brief Primitive multi-threading support for Linux
934+/// @overview This module provides threading, mutex and condition
935+/// variable APIs for Windows.
936+//
937+////////////////////////////////// Copyright ///////////////////////////////////
938+//
939+// @copy default
940+//
941+// Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
942+// Copyright (c) Michael O'Brien, 1994-2006. All Rights Reserved.
943+//
944+// This software is distributed under commercial and open source licenses.
945+// You may use the GPL open source license described below or you may acquire
946+// a commercial license from Mbedthis Software. You agree to be fully bound
947+// by the terms of either license. Consult the LICENSE.TXT distributed with
948+// this software for full details.
949+//
950+// This software is open source; you can redistribute it and/or modify it
951+// under the terms of the GNU General Public License as published by the
952+// Free Software Foundation; either version 2 of the License, or (at your
953+// option) any later version. See the GNU General Public License for more
954+// details at: http://www.mbedthis.com/downloads/gplLicense.html
955+//
956+// This program is distributed WITHOUT ANY WARRANTY; without even the
957+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
958+//
959+// This GPL license does NOT permit incorporating this software into
960+// proprietary programs. If you are unable to comply with the GPL, you must
961+// acquire a commercial license to use this software. Commercial licenses
962+// for this software and support services are available from Mbedthis
963+// Software at http://www.mbedthis.com
964+//
965+// @end
966+//
967+////////////////////////////////// Includes ///////////////////////////////////
968+
969+#include "mpr/mpr.h"
970+
971+//////////////////////////////////// Locals ///////////////////////////////////
972+#if BLD_FEATURE_MULTITHREAD
973+
974+#if BLD_DEBUG
975+CRITICAL_SECTION debugCs;
976+static MprList mutexList;
977+static int numMutex = -1; // Must initialize to -1 (see addMutex)
978+MprList condList;
979+
980+#define DEBUG_TIME 0 // Spare[0] == time
981+#define DEBUG_ID 1 // Spare[1] == thread id
982+#endif
983+
984+//////////////////////////// Forward Declarations /////////////////////////////
985+
986+static uint __stdcall threadProcWrapper(void *arg);
987+
988+#if BLD_DEBUG
989+#if UNUSED
990+static void lockBuster(void *data, MprThread *tp);
991+#endif
992+static void removeMutex(MprMutex *mp);
993+static void addMutex(MprMutex *mp);
994+#endif
995+
996+///////////////////////////////////// Code ////////////////////////////////////
997+//
998+// Initialize thread service
999+//
1000+//
1001+
1002+MprThreadService::MprThreadService()
1003+{
1004+ mutex = new MprMutex();
1005+
1006+ //
1007+ // Don't actually create the thread. Just create a thread object for this
1008+ // main thread.
1009+ //
1010+ mainThread = new MprThread(MPR_NORMAL_PRIORITY, "main");
1011+ mainThread->setId(GetCurrentThreadId());
1012+
1013+ insertThread(mainThread);
1014+}
1015+
1016+///////////////////////////////////////////////////////////////////////////////
1017+//
1018+// Terminate the thread service
1019+//
1020+
1021+MprThreadService::~MprThreadService()
1022+{
1023+ delete mainThread;
1024+
1025+#if BLD_DEBUG
1026+ if (threads.getNumItems() > 0) {
1027+ mprError(MPR_L, MPR_LOG, "Exiting with %d thread(s) unfreed",
1028+ threads.getNumItems());
1029+ }
1030+ if (condList.getNumItems() > 0) {
1031+ mprError(MPR_L, MPR_LOG, "Exiting with %d cond var(s) unfreed",
1032+ condList.getNumItems());
1033+ }
1034+ //
1035+ // We allow one open mutex for the log service which has not yet shutdown,
1036+ // and one for the libmpr DLL (malloc), we also need one for our mutex
1037+ // is freed below.
1038+ //
1039+ if (mutexList.getNumItems() > 3) {
1040+ mprError(MPR_L, MPR_LOG, "Exiting with %d mutex(es) unfreed",
1041+ mutexList.getNumItems() - 3);
1042+ }
1043+#endif
1044+ delete mutex;
1045+}
1046+
1047+////////////////////////////////////////////////////////////////////////////////
1048+//
1049+// Add a thread to the list
1050+//
1051+
1052+void MprThreadService::insertThread(MprThread *tp)
1053+{
1054+ lock();
1055+ threads.insert(tp);
1056+ unlock();
1057+}
1058+
1059+////////////////////////////////////////////////////////////////////////////////
1060+//
1061+// Remove a thread from the list
1062+//
1063+
1064+void MprThreadService::removeThread(MprThread *tp)
1065+{
1066+ lock();
1067+ threads.remove(tp);
1068+ unlock();
1069+}
1070+
1071+////////////////////////////////////////////////////////////////////////////////
1072+//
1073+// Nothing to do
1074+//
1075+
1076+int MprThreadService::start()
1077+{
1078+#if BLD_DEBUG && UNUSED
1079+ MprThread *tp;
1080+
1081+ if (!mprGetDebugMode()) {
1082+ tp = new MprThread(lockBuster, MPR_LOW_PRIORITY, 0, "watch");
1083+ tp->start();
1084+ }
1085+#endif
1086+ return 0;
1087+}
1088+
1089+////////////////////////////////////////////////////////////////////////////////
1090+//
1091+// Nothing to do. We expect the threads to be self terminating.
1092+//
1093+
1094+int MprThreadService::stop(int timeout)
1095+{
1096+ //
1097+ // Wait until all threads (except main thread) have exited
1098+ //
1099+ while (threads.getNumItems() > 1 && timeout > 0) {
1100+ mprSleep(10);
1101+ timeout -= 10;
1102+ }
1103+ return 0;
1104+}
1105+
1106+////////////////////////////////////////////////////////////////////////////////
1107+//
1108+// Return the current thread object
1109+//
1110+
1111+MprThread *MprThreadService::getCurrentThread()
1112+{
1113+ MprThread *tp;
1114+ int id;
1115+
1116+ lock();
1117+ id = (int) GetCurrentThreadId();
1118+ tp = (MprThread*) threads.getFirst();
1119+ while (tp) {
1120+ if (tp->getId() == id) {
1121+ unlock();
1122+ return tp;
1123+ }
1124+ tp = (MprThread*) threads.getNext(tp);
1125+ }
1126+ unlock();
1127+ return 0;
1128+}
1129+
1130+////////////////////////////////////////////////////////////////////////////////
1131+////////////////////////////////// MprThread ///////////////////////////////////
1132+////////////////////////////////////////////////////////////////////////////////
1133+//
1134+// Create a main thread
1135+//
1136+
1137+MprThread::MprThread(int priority, char *name)
1138+{
1139+ osThreadId = 0;
1140+ pid = getpid();
1141+ threadHandle = 0;
1142+ this->priority = priority;
1143+ entry = 0;
1144+ data = 0;
1145+ this->name = mprStrdup(name);
1146+
1147+ mutex = new MprMutex();
1148+ //
1149+ // Inserted into the thread list in MprThreadService()
1150+ //
1151+}
1152+
1153+////////////////////////////////////////////////////////////////////////////////
1154+//
1155+// Create a thread
1156+//
1157+
1158+MprThread::MprThread(MprThreadProc entry, int priority, void *data,
1159+ char *name, int stackSize)
1160+{
1161+ osThreadId = 0;
1162+ pid = getpid();
1163+ threadHandle = 0;
1164+ this->priority = priority;
1165+ this->entry = entry;
1166+ this->data = data;
1167+ this->name = mprStrdup(name);
1168+
1169+ mutex = new MprMutex();
1170+ mpr->threadService->insertThread(this);
1171+}
1172+
1173+////////////////////////////////////////////////////////////////////////////////
1174+//
1175+// Destroy a thread
1176+//
1177+
1178+MprThread::~MprThread()
1179+{
1180+ lock();
1181+ mprLog(MPR_INFO, "Thread exiting %s (%x)\n", name, osThreadId);
1182+
1183+ mpr->threadService->removeThread(this);
1184+ mprFree(name);
1185+ if (threadHandle) {
1186+ CloseHandle(threadHandle);
1187+ }
1188+ delete mutex;
1189+}
1190+
1191+////////////////////////////////////////////////////////////////////////////////
1192+//
1193+// Start a thread
1194+//
1195+
1196+int MprThread::start()
1197+{
1198+ HANDLE h;
1199+ uint threadId;
1200+
1201+ lock();
1202+ h = (HANDLE) _beginthreadex(NULL, 0, threadProcWrapper, (void*) this,
1203+ 0, &threadId);
1204+ if (h == NULL) {
1205+ unlock();
1206+ return MPR_ERR_CANT_INITIALIZE;
1207+ }
1208+ osThreadId = (ulong) threadId;
1209+ threadHandle = (HANDLE) h;
1210+
1211+ setPriority(priority);
1212+ mprLog(MPR_INFO, "Created thread %s (%x)\n", name, threadId);
1213+ unlock();
1214+ return 0;
1215+}
1216+
1217+////////////////////////////////////////////////////////////////////////////////
1218+//
1219+// Thread entry function
1220+//
1221+
1222+static uint __stdcall threadProcWrapper(void *data)
1223+{
1224+//AFF gracefull crash, main app should exit
1225+#if BLD_DEBUG
1226+#else
1227+ try
1228+ {
1229+#endif
1230+ MprThread *tp;
1231+
1232+ tp = (MprThread*) data;
1233+ tp->threadProc();
1234+ delete tp;
1235+
1236+#if BLD_DEBUG
1237+#else
1238+ }
1239+ catch(...)
1240+ {
1241+ mprLog((char*)"ERROR: catch(...) threadProcWrapper crashed. terminating gracefully...");
1242+ mprGetMpr()->terminate(1);
1243+ }
1244+#endif
1245+
1246+ return 0;
1247+}
1248+
1249+////////////////////////////////////////////////////////////////////////////////
1250+//
1251+// Thread procedure
1252+//
1253+
1254+void MprThread::threadProc()
1255+{
1256+ osThreadId = GetCurrentThreadId();
1257+ pid = getpid();
1258+ (entry)(data, this);
1259+}
1260+
1261+////////////////////////////////////////////////////////////////////////////////
1262+
1263+void MprThread::setPriority(int newPriority)
1264+{
1265+ int osPri;
1266+
1267+ lock();
1268+ if (priority == newPriority) {
1269+ unlock();
1270+ return;
1271+ }
1272+
1273+ osPri = mapMprPriorityToOs(newPriority);
1274+ SetThreadPriority(threadHandle, osPri);
1275+ priority = newPriority;
1276+ unlock();
1277+}
1278+
1279+////////////////////////////////////////////////////////////////////////////////
1280+
1281+void MprThread::setId(int id)
1282+{
1283+ osThreadId = (ulong) id;
1284+}
1285+
1286+////////////////////////////////////////////////////////////////////////////////
1287+//
1288+// Map Mpr priority to Windows native priority. Windows priorities range from
1289+// -15 to +15 (zero is normal). Warning: +15 will not yield the CPU, -15 may
1290+// get starved. We should be very wary going above +11.
1291+//
1292+
1293+int MprThread::mapMprPriorityToOs(int mprPriority)
1294+{
1295+ mprAssert(mprPriority >= 0 && mprPriority <= 100);
1296+
1297+ if (mprPriority <= MPR_BACKGROUND_PRIORITY) {
1298+ return THREAD_PRIORITY_LOWEST;
1299+ } else if (mprPriority <= MPR_LOW_PRIORITY) {
1300+ return THREAD_PRIORITY_BELOW_NORMAL;
1301+ } else if (mprPriority <= MPR_NORMAL_PRIORITY) {
1302+ return THREAD_PRIORITY_NORMAL;
1303+ } else if (mprPriority <= MPR_HIGH_PRIORITY) {
1304+ return THREAD_PRIORITY_ABOVE_NORMAL;
1305+ } else {
1306+ return THREAD_PRIORITY_HIGHEST;
1307+ }
1308+}
1309+
1310+///////////////////////////////////////////////////////////////////////////////
1311+//
1312+// Map Windows priority to Mpr priority
1313+//
1314+
1315+int MprThread::mapOsPriorityToMpr(int nativePriority)
1316+{
1317+ int priority;
1318+
1319+ priority = (45 * nativePriority) + 50;
1320+ if (priority < 0) {
1321+ priority = 0;
1322+ }
1323+ if (priority >= 100) {
1324+ priority = 99;
1325+ }
1326+ return priority;
1327+}
1328+
1329+////////////////////////////////////////////////////////////////////////////////
1330+/////////////////////////////////// MprMutex ///////////////////////////////////
1331+////////////////////////////////////////////////////////////////////////////////
1332+//
1333+// Create a mutex
1334+//
1335+
1336+MprMutex::MprMutex()
1337+{
1338+ memset(&cs, 0, sizeof(cs));
1339+ InitializeCriticalSectionAndSpinCount(&cs, 5000);
1340+
1341+#if BLD_DEBUG
1342+ addMutex(this);
1343+ cs.DebugInfo->Spare[DEBUG_ID] = -1; // Thread ID goes here
1344+ cs.DebugInfo->Spare[DEBUG_TIME] = 0; // Time goes here
1345+#endif
1346+}
1347+
1348+///////////////////////////////////////////////////////////////////////////////
1349+//
1350+// Destroy a mutex. Must be locked on entrance.
1351+//
1352+
1353+MprMutex::~MprMutex()
1354+{
1355+ DeleteCriticalSection(&cs);
1356+#if BLD_DEBUG
1357+ removeMutex(this);
1358+#endif
1359+}
1360+
1361+///////////////////////////////////////////////////////////////////////////////
1362+//
1363+// Lock a mutex
1364+//
1365+
1366+void MprMutex::lock()
1367+{
1368+ EnterCriticalSection(&cs);
1369+
1370+#if BLD_DEBUG
1371+ mprAssert(cs.RecursionCount >= 0);
1372+ mprAssert(cs.RecursionCount < MPR_MAX_RECURSION);
1373+ mprAssert(cs.LockCount < MPR_MAX_BLOCKED_LOCKS);
1374+
1375+ cs.DebugInfo->Spare[DEBUG_ID] = (ulong) GetCurrentThreadId();
1376+ cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount();
1377+#endif
1378+}
1379+
1380+///////////////////////////////////////////////////////////////////////////////
1381+//
1382+// Try to lock a mutex. Do not block!
1383+//
1384+
1385+int MprMutex::tryLock()
1386+{
1387+ mprAssert(cs.RecursionCount >= 0);
1388+ if (TryEnterCriticalSection(&cs) == 0) {
1389+ return MPR_ERR_BUSY;
1390+ }
1391+#if BLD_DEBUG
1392+ cs.DebugInfo->Spare[DEBUG_ID] = (ulong) GetCurrentThreadId();
1393+ cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount();
1394+#endif
1395+ return 0;
1396+}
1397+
1398+///////////////////////////////////////////////////////////////////////////////
1399+//
1400+// Unlock a mutex. structure
1401+//
1402+
1403+void MprMutex::unlock()
1404+{
1405+#if BLD_DEBUG
1406+ mprAssert(cs.DebugInfo->Spare[DEBUG_ID] == (ulong) GetCurrentThreadId());
1407+ mprAssert(cs.RecursionCount > 0);
1408+ mprAssert(cs.RecursionCount < MPR_MAX_RECURSION);
1409+ mprAssert(cs.LockCount < MPR_MAX_LOCKS);
1410+ cs.DebugInfo->Spare[DEBUG_TIME] = GetTickCount();
1411+#endif
1412+ LeaveCriticalSection(&cs);
1413+}
1414+
1415+///////////////////////////////////////////////////////////////////////////////
1416+/////////////////////////////////// MprCond ////////////////////////////////////
1417+////////////////////////////////////////////////////////////////////////////////
1418+//
1419+// Create a condition variable for use by single or multiple waiters
1420+//
1421+
1422+MprCond::MprCond()
1423+{
1424+#if UNUSED
1425+ wakeAll = 0;
1426+ numWaiting = 0;
1427+#endif
1428+ triggered = 0;
1429+ mutex = new MprMutex();
1430+ cv = CreateEvent(NULL, FALSE, FALSE, NULL);
1431+}
1432+
1433+
1434+////////////////////////////////////////////////////////////////////////////////
1435+//
1436+// Destroy a condition variable
1437+//
1438+
1439+MprCond::~MprCond()
1440+{
1441+ mutex->lock();
1442+ CloseHandle(cv);
1443+ delete mutex;
1444+}
1445+
1446+////////////////////////////////////////////////////////////////////////////////
1447+//
1448+// Wait for the event to be triggered. Should only be used when there are
1449+// single waiters. If the event is already triggered, then it will return
1450+// immediately.
1451+//
1452+
1453+int MprCond::waitForCond(long timeout)
1454+{
1455+ if (timeout < 0) {
1456+ timeout = MAXINT;
1457+ }
1458+
1459+ if (WaitForSingleObject(cv, timeout) != WAIT_OBJECT_0) {
1460+ return -1;
1461+ }
1462+
1463+ //
1464+ // Reset the event
1465+ //
1466+ mutex->lock();
1467+ mprAssert(triggered != 0);
1468+ triggered = 0;
1469+ ResetEvent(cv);
1470+ mutex->unlock();
1471+
1472+ return 0;
1473+}
1474+
1475+////////////////////////////////////////////////////////////////////////////////
1476+#if UNUSED
1477+//
1478+// Wait for a condition variable to be signalled. Suitable for when there are
1479+// multiple waiters. It will work for single waiters, but is slower than
1480+// waitForCond() above. Depending on whether signalCond() or signalAll() is
1481+// used, a single waiter or multiple waiters may awake with one invocation of
1482+// signal. If the condition is already triggered, this routine will not block
1483+// for the first waiter. NOTE: the externalMutex must be defined and locked on
1484+// entry to this routine
1485+//
1486+
1487+int MprCond::multiWait(MprMutex *externalMutex, long timeout)
1488+{
1489+ int now, deadline;
1490+
1491+ if (timeout < 0) {
1492+ timeout = MAXINT;
1493+ }
1494+ now = mprGetTime(0);
1495+ deadline = now + timeout;
1496+
1497+ while (now <= deadline) {
1498+ mutex->lock();
1499+ numWaiting++;
1500+ mutex->unlock();
1501+
1502+ externalMutex->unlock();
1503+
1504+ if (WaitForSingleObject(cv, timeout) != WAIT_OBJECT_0) {
1505+ return -1;
1506+ }
1507+
1508+ mutex->lock();
1509+ --numWaiting;
1510+ if (wakeAll) {
1511+ //
1512+ // Last thread to awake must reset the event
1513+ //
1514+ if (numWaiting == 0) {
1515+ wakeAll = 0;
1516+ ResetEvent(cv);
1517+ }
1518+ mutex->unlock();
1519+ break;
1520+ }
1521+ if (triggered) {
1522+ triggered = 0;
1523+ ResetEvent(cv);
1524+ mutex->unlock();
1525+ break;
1526+ }
1527+ mutex->unlock();
1528+ now = mprGetTime(0);
1529+ }
1530+ externalMutex->lock();
1531+ return 0;
1532+}
1533+
1534+#endif
1535+////////////////////////////////////////////////////////////////////////////////
1536+//
1537+// Signal a condition and wakeup the waiter. Note: this may be called
1538+// prior to the waiter waiting.
1539+//
1540+
1541+void MprCond::signalCond()
1542+{
1543+ mutex->lock();
1544+ triggered = 1;
1545+#if UNUSED
1546+ wakeAll = 0;
1547+#endif
1548+ SetEvent(cv);
1549+ mutex->unlock();
1550+}
1551+
1552+///////////////////////////////////////////////////////////////////////////////
1553+#if UNUSED
1554+//
1555+// Signal all waiters. Note: this may be called prior to anyone waiting.
1556+//
1557+
1558+void MprCond::signalAll()
1559+{
1560+ mutex->lock();
1561+ triggered = 1;
1562+#if UNUSED
1563+ wakeAll = 1;
1564+#endif
1565+ SetEvent(cv);
1566+ mutex->unlock();
1567+}
1568+
1569+///////////////////////////////////////////////////////////////////////////////
1570+//
1571+// Use very carefully when you really know what you are doing. More dangerous
1572+// than it looks
1573+//
1574+
1575+void MprCond::reset()
1576+{
1577+ mutex->lock();
1578+ triggered = 0;
1579+#if UNUSED
1580+ wakeAll = 0;
1581+#endif
1582+ ResetEvent(cv);
1583+ mutex->unlock();
1584+}
1585+
1586+#endif
1587+///////////////////////////////////////////////////////////////////////////////
1588+////////////////////////////////////// Debug //////////////////////////////////
1589+///////////////////////////////////////////////////////////////////////////////
1590+#if BLD_DEBUG
1591+#if UNUSED
1592+
1593+static void lockBuster(void *data, MprThread *tp)
1594+{
1595+ MprMutex *mp;
1596+ int duration;
1597+ uint tid, whenLocked, ticks;
1598+
1599+ tid = (int) GetCurrentThreadId();
1600+ while (! mpr->isExiting()) {
1601+ if (numMutex > MPR_MAX_LOCKS) {
1602+ mprError(MPR_L, MPR_LOG, "Too many mutexes");
1603+ }
1604+
1605+ mp = (MprMutex*) mutexList.getFirst();
1606+ while (mp) {
1607+ whenLocked = mp->cs.DebugInfo->Spare[DEBUG_TIME];
1608+
1609+ if (mp->cs.RecursionCount > 0) {
1610+ ticks = GetTickCount();
1611+ if (ticks < whenLocked) {
1612+ duration = 0xFFFFFFFF - whenLocked + 1 + ticks;
1613+ } else {
1614+ duration = ticks - whenLocked;
1615+ }
1616+ if (duration > MPR_MAX_LOCK_TIME) {
1617+ mprError(MPR_L, MPR_LOG, "Mutex held too long");
1618+ // FUTURE -- could bust the lock here ... mp->unlock();
1619+ }
1620+ }
1621+ mp = (MprMutex*) mutexList.getNext(&mp->link);
1622+ }
1623+ mprSleep(500);
1624+ }
1625+}
1626+
1627+#endif // UNUSED
1628+///////////////////////////////////////////////////////////////////////////////
1629+//
1630+// Add this mutex to the list
1631+//
1632+
1633+static void addMutex(MprMutex *mp)
1634+{
1635+ //
1636+ // First time initialization
1637+ //
1638+ if (numMutex < 0) {
1639+ memset(&debugCs, 0, sizeof(debugCs));
1640+ InitializeCriticalSectionAndSpinCount(&debugCs, 4000);
1641+ }
1642+ EnterCriticalSection(&debugCs);
1643+ mutexList.insert(&mp->link);
1644+ numMutex++;
1645+ LeaveCriticalSection(&debugCs);
1646+}
1647+
1648+///////////////////////////////////////////////////////////////////////////////
1649+//
1650+// Remove this mutex from the list
1651+//
1652+
1653+static void removeMutex(MprMutex *mp)
1654+{
1655+ EnterCriticalSection(&debugCs);
1656+ numMutex--;
1657+ mutexList.remove(&mp->link);
1658+ LeaveCriticalSection(&debugCs);
1659+}
1660+
1661+///////////////////////////////////////////////////////////////////////////////
1662+//
1663+// Return the number of mutexes owned by this thread
1664+//
1665+
1666+int MprDebug::getMutexNum()
1667+{
1668+ MprMutex *mp;
1669+ int num;
1670+ uint tid;
1671+
1672+ tid = (uint) GetCurrentThreadId();
1673+
1674+ num = 0;
1675+ mp = (MprMutex*) mutexList.getFirst();
1676+ while (mp) {
1677+
1678+ if (mp->cs.DebugInfo->Spare[DEBUG_ID] == tid) {
1679+ num++;
1680+ }
1681+ mp = (MprMutex*) mutexList.getNext(&mp->link);
1682+ }
1683+ return num;
1684+}
1685+
1686+#endif // BLD_DEBUG
1687+#endif // BLD_FEATURE_MULTITHREAD
1688+///////////////////////////////////////////////////////////////////////////////
1689+
1690+//
1691+// Local variables:
1692+// tab-width: 4
1693+// c-basic-offset: 4
1694+// End:
1695+// vim:tw=78
1696+// vim600: sw=4 ts=4 fdm=marker
1697+// vim<600: sw=4 ts=4
1698+//
1699
1700=== added file 'appweb.cnf'
1701--- appweb.cnf 1970-01-01 00:00:00 +0000
1702+++ appweb.cnf 2011-11-23 01:01:25 +0000
1703@@ -0,0 +1,27 @@
1704+ServerRoot "."
1705+DocumentRoot "."
1706+
1707+LoadModulePath $SERVER_ROOT
1708+
1709+LoadModule psiphonHandler libpsiphonHandler
1710+LoadModule ssl libsslModule
1711+LoadModule openSsl libopenSslModule
1712+
1713+ThreadLimit 100
1714+KeepAlive on
1715+
1716+<VirtualHost *:*>
1717+ AddHandler psiphonHandler
1718+ DocumentRoot "."
1719+ SSLEngine on
1720+ SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
1721+ SSLProtocol ALL -SSLV2
1722+
1723+ SSLCertificateFile "$SERVER_ROOT/cert.pem"
1724+ SSLCertificateKeyFile "$SERVER_ROOT/key.pem"
1725+
1726+ <Location />
1727+ HttpChunking off
1728+ SetHandler psiphonHandler
1729+ </Location>
1730+</VirtualHost>
1731
1732=== added file 'bake-w32.bat'
1733--- bake-w32.bat 1970-01-01 00:00:00 +0000
1734+++ bake-w32.bat 2011-11-23 01:01:25 +0000
1735@@ -0,0 +1,1 @@
1736+bakefile -f msvc6prj psiphon.bkl
1737\ No newline at end of file
1738
1739=== added file 'changes.txt'
1740--- changes.txt 1970-01-01 00:00:00 +0000
1741+++ changes.txt 2011-11-23 01:01:25 +0000
1742@@ -0,0 +1,99 @@
1743+-------------------------------------------
1744+Changes in version 1.6 (09 Mar 2007)
1745+- added fingerprint to SSL certificate page
1746+- added update downloading
1747+- minor code revisions
1748+
1749+-------------------------------------------
1750+Changes in version 1.5 (09 Feb 2007)
1751+
1752+- fixed '100% CPU usage' bug
1753+- added psiphon will find available port if 443 is not
1754+- added double click on a link in the log window opens it in default browser
1755+- added column sorting
1756+- added status icons
1757+- added choise for "Get My IP" server
1758+- added SLL country combo sorting
1759+- changed System Tray icon to be always available
1760+- minor GUI revisions
1761+- minor code revisions
1762+
1763+-------------------------------------------
1764+Changes in version 1.4 (26 Jan 2007)
1765+
1766+- added minimize to task bar
1767+- added single bakefile file for both platforms(WIN, LINUX)
1768+- added detailed build instructions for both platforms
1769+- fixed compatibility with Shaw Secure
1770+- improved HTML entities decoding
1771+- minor code revisions
1772+
1773+-------------------------------------------
1774+Changes in version 1.3 (29 Dec 2006)
1775+
1776+Added:
1777+- HTML entities decoding in the HTML filter
1778+
1779+Changed:
1780+- Improved CSS filtering
1781+
1782+- Improved error handling
1783+
1784+- Limited user input
1785+
1786+- Delete user related info when delete user
1787+
1788+- Password overwrite bug fixed
1789+
1790+- Switched to prepared SQL statements throughout the code
1791+
1792+- Minor code revisions
1793+
1794+-------------------------------------------
1795+Changes in version 1.2 (15 Dec 2006)
1796+
1797+Added:
1798+- Custom SSL certificate
1799+
1800+- Log level persistence
1801+
1802+- Log can be disabled
1803+
1804+Changed:
1805+- Image on/off handling through "Javascript:void(0);" in order to avoid extra HTTP requests
1806+
1807+- Updated wxWidgets framework to 2.8
1808+
1809+- Updated Advanced Installer to 4.6
1810+
1811+- Fixed several buffer overflow vulnerabilities
1812+
1813+-------------------------------------------
1814+Changes in version 1.1 (8 Dec 2006)
1815+
1816+Added:
1817+- psiphon access is forbidden (HTTP 403) to domains that resolve to localhost or
1818+ private network
1819+
1820+- Multiple network interface cards support
1821+
1822+- Our own external IP detection service
1823+
1824+- Version check on startup
1825+
1826+- Users can toggle images on/off in the blue bar
1827+
1828+Changed:
1829+- URLs in HTTP requests to psiphon must be prepended with psiphonode name
1830+ set by psiphon admin at setup, i.e. https://<IP>:<port>/<psiphonode>/login/..,
1831+ https://<IP>:<port>/<psiphonode>/fetch/.. etc.
1832+
1833+- Replacement tags (<%varname%>) added in HTML templates.
1834+
1835+- wxWidgets HTTP headers are replaced with generic headers
1836+
1837+- New database design in order to minimize SQLite locking
1838+
1839+- GUI changes
1840+
1841+- Minor bug fixes
1842\ No newline at end of file
1843
1844=== added directory 'common'
1845=== added file 'common/CppSQLite3.cpp'
1846--- common/CppSQLite3.cpp 1970-01-01 00:00:00 +0000
1847+++ common/CppSQLite3.cpp 2011-11-23 01:01:25 +0000
1848@@ -0,0 +1,1383 @@
1849+////////////////////////////////////////////////////////////////////////////////
1850+// CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.
1851+//
1852+// Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com
1853+//
1854+// Permission to use, copy, modify, and distribute this software and its
1855+// documentation for any purpose, without fee, and without a written
1856+// agreement, is hereby granted, provided that the above copyright notice,
1857+// this paragraph and the following two paragraphs appear in all copies,
1858+// modifications, and distributions.
1859+//
1860+// IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,
1861+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
1862+// PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
1863+// EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1864+//
1865+// THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
1866+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
1867+// PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF
1868+// ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION
1869+// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
1870+//
1871+// V3.0 03/08/2004 -Initial Version for sqlite3
1872+//
1873+// V3.1 16/09/2004 -Implemented getXXXXField using sqlite3 functions
1874+// -Added CppSQLiteDB3::tableExists()
1875+////////////////////////////////////////////////////////////////////////////////
1876+#include "CppSQLite3.h"
1877+#include <cstdlib>
1878+
1879+// Named constant for passing to CppSQLite3Exception when passing it a string
1880+// that cannot be deleted.
1881+static const bool DONT_DELETE_MSG = false;
1882+
1883+////////////////////////////////////////////////////////////////////////////////
1884+// Prototypes for SQLite functions not included in SQLite DLL, but copied below
1885+// from SQLite encode.c
1886+////////////////////////////////////////////////////////////////////////////////
1887+int sqlite3_encode_binary(const unsigned char* in, int n, unsigned char* out);
1888+int sqlite3_decode_binary(const unsigned char* in, unsigned char* out);
1889+
1890+////////////////////////////////////////////////////////////////////////////////
1891+
1892+////////////////////////////////////////////////////////////////////////////////
1893+
1894+CppSQLite3Exception::CppSQLite3Exception(const int nErrCode, char* szErrMess, bool bDeleteMsg/*=true*/) : mnErrCode(nErrCode)
1895+{
1896+ mpszErrMess = sqlite3_mprintf("%s[%d]: %s", errorCodeAsString(nErrCode), nErrCode, szErrMess ? szErrMess : "");
1897+
1898+ if(bDeleteMsg && szErrMess)
1899+ {
1900+ sqlite3_free(szErrMess);
1901+ }
1902+}
1903+
1904+CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception& e) : mnErrCode(e.mnErrCode)
1905+{
1906+ mpszErrMess = 0;
1907+ if(e.mpszErrMess)
1908+ {
1909+ mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);
1910+ }
1911+}
1912+
1913+const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)
1914+{
1915+ switch(nErrCode)
1916+ {
1917+ case SQLITE_OK :
1918+ return "SQLITE_OK";
1919+ case SQLITE_ERROR :
1920+ return "SQLITE_ERROR";
1921+ case SQLITE_INTERNAL :
1922+ return "SQLITE_INTERNAL";
1923+ case SQLITE_PERM :
1924+ return "SQLITE_PERM";
1925+ case SQLITE_ABORT :
1926+ return "SQLITE_ABORT";
1927+ case SQLITE_BUSY :
1928+ return "SQLITE_BUSY";
1929+ case SQLITE_LOCKED :
1930+ return "SQLITE_LOCKED";
1931+ case SQLITE_NOMEM :
1932+ return "SQLITE_NOMEM";
1933+ case SQLITE_READONLY :
1934+ return "SQLITE_READONLY";
1935+ case SQLITE_INTERRUPT :
1936+ return "SQLITE_INTERRUPT";
1937+ case SQLITE_IOERR :
1938+ return "SQLITE_IOERR";
1939+ case SQLITE_CORRUPT :
1940+ return "SQLITE_CORRUPT";
1941+ case SQLITE_NOTFOUND :
1942+ return "SQLITE_NOTFOUND";
1943+ case SQLITE_FULL :
1944+ return "SQLITE_FULL";
1945+ case SQLITE_CANTOPEN :
1946+ return "SQLITE_CANTOPEN";
1947+ case SQLITE_PROTOCOL :
1948+ return "SQLITE_PROTOCOL";
1949+ case SQLITE_EMPTY :
1950+ return "SQLITE_EMPTY";
1951+ case SQLITE_SCHEMA :
1952+ return "SQLITE_SCHEMA";
1953+ case SQLITE_TOOBIG :
1954+ return "SQLITE_TOOBIG";
1955+ case SQLITE_CONSTRAINT :
1956+ return "SQLITE_CONSTRAINT";
1957+ case SQLITE_MISMATCH :
1958+ return "SQLITE_MISMATCH";
1959+ case SQLITE_MISUSE :
1960+ return "SQLITE_MISUSE";
1961+ case SQLITE_NOLFS :
1962+ return "SQLITE_NOLFS";
1963+ case SQLITE_AUTH :
1964+ return "SQLITE_AUTH";
1965+ case SQLITE_FORMAT :
1966+ return "SQLITE_FORMAT";
1967+ case SQLITE_RANGE :
1968+ return "SQLITE_RANGE";
1969+ case SQLITE_ROW :
1970+ return "SQLITE_ROW";
1971+ case SQLITE_DONE :
1972+ return "SQLITE_DONE";
1973+ case CPPSQLITE_ERROR :
1974+ return "CPPSQLITE_ERROR";
1975+ default:
1976+ return "UNKNOWN_ERROR";
1977+ }
1978+}
1979+
1980+CppSQLite3Exception::~CppSQLite3Exception()
1981+{
1982+ if(mpszErrMess)
1983+ {
1984+ sqlite3_free(mpszErrMess);
1985+ mpszErrMess = 0;
1986+ }
1987+}
1988+
1989+////////////////////////////////////////////////////////////////////////////////
1990+
1991+CppSQLite3Buffer::CppSQLite3Buffer()
1992+{
1993+ mpBuf = 0;
1994+}
1995+
1996+CppSQLite3Buffer::~CppSQLite3Buffer()
1997+{
1998+ clear();
1999+}
2000+
2001+void CppSQLite3Buffer::clear()
2002+{
2003+ if(mpBuf)
2004+ {
2005+ sqlite3_free(mpBuf);
2006+ mpBuf = 0;
2007+ }
2008+}
2009+
2010+const char* CppSQLite3Buffer::format(const char* szFormat, ...)
2011+{
2012+ clear();
2013+ va_list va;
2014+ va_start(va, szFormat);
2015+ mpBuf = sqlite3_vmprintf(szFormat, va);
2016+ va_end(va);
2017+ return mpBuf;
2018+}
2019+
2020+////////////////////////////////////////////////////////////////////////////////
2021+
2022+CppSQLite3Binary::CppSQLite3Binary() : mpBuf(0), mnBinaryLen(0), mnBufferLen(0), mnEncodedLen(0), mbEncoded(false)
2023+{
2024+}
2025+
2026+CppSQLite3Binary::~CppSQLite3Binary()
2027+{
2028+ clear();
2029+}
2030+
2031+void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)
2032+{
2033+ mpBuf = allocBuffer(nLen);
2034+ memcpy(mpBuf, pBuf, nLen);
2035+}
2036+
2037+void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)
2038+{
2039+ clear();
2040+
2041+ mnEncodedLen = strlen((const char*)pBuf);
2042+ mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator
2043+
2044+ mpBuf = (unsigned char*)malloc(mnBufferLen);
2045+
2046+ if(!mpBuf)
2047+ {
2048+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot allocate memory", DONT_DELETE_MSG);
2049+ }
2050+
2051+ memcpy(mpBuf, pBuf, mnBufferLen);
2052+ mbEncoded = true;
2053+}
2054+
2055+const unsigned char* CppSQLite3Binary::getEncoded()
2056+{
2057+ if(!mbEncoded)
2058+ {
2059+ unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);
2060+ memcpy(ptmp, mpBuf, mnBinaryLen);
2061+ mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);
2062+ free(ptmp);
2063+ mbEncoded = true;
2064+ }
2065+
2066+ return mpBuf;
2067+}
2068+
2069+const unsigned char* CppSQLite3Binary::getBinary()
2070+{
2071+ if(mbEncoded)
2072+ {
2073+ // in/out buffers can be the same
2074+ mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);
2075+
2076+ if(mnBinaryLen == -1)
2077+ {
2078+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot decode binary", DONT_DELETE_MSG);
2079+ }
2080+
2081+ mbEncoded = false;
2082+ }
2083+
2084+ return mpBuf;
2085+}
2086+
2087+int CppSQLite3Binary::getBinaryLength()
2088+{
2089+ getBinary();
2090+ return mnBinaryLen;
2091+}
2092+
2093+unsigned char* CppSQLite3Binary::allocBuffer(int nLen)
2094+{
2095+ clear();
2096+
2097+ // Allow extra space for encoded binary as per comments in
2098+ // SQLite encode.c See bottom of this file for implementation
2099+ // of SQLite functions use 3 instead of 2 just to be sure ;-)
2100+ mnBinaryLen = nLen;
2101+ mnBufferLen = 3 + (257 * nLen) / 254;
2102+
2103+ mpBuf = (unsigned char*)malloc(mnBufferLen);
2104+
2105+ if(!mpBuf)
2106+ {
2107+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Cannot allocate memory", DONT_DELETE_MSG);
2108+ }
2109+
2110+ mbEncoded = false;
2111+
2112+ return mpBuf;
2113+}
2114+
2115+void CppSQLite3Binary::clear()
2116+{
2117+ if(mpBuf)
2118+ {
2119+ mnBinaryLen = 0;
2120+ mnBufferLen = 0;
2121+ free(mpBuf);
2122+ mpBuf = 0;
2123+ }
2124+}
2125+
2126+////////////////////////////////////////////////////////////////////////////////
2127+
2128+CppSQLite3Query::CppSQLite3Query()
2129+{
2130+ mpVM = 0;
2131+ mbEof = true;
2132+ mnCols = 0;
2133+ mbOwnVM = false;
2134+}
2135+
2136+CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)
2137+{
2138+ mpVM = rQuery.mpVM;
2139+ // Only one object can own the VM
2140+ const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
2141+ mbEof = rQuery.mbEof;
2142+ mnCols = rQuery.mnCols;
2143+ mbOwnVM = rQuery.mbOwnVM;
2144+}
2145+
2146+CppSQLite3Query::CppSQLite3Query(sqlite3* pDB, sqlite3_stmt* pVM, bool bEof, bool bOwnVM/*=true*/)
2147+{
2148+ mpDB = pDB;
2149+ mpVM = pVM;
2150+ mbEof = bEof;
2151+ mnCols = sqlite3_column_count(mpVM);
2152+ mbOwnVM = bOwnVM;
2153+}
2154+
2155+CppSQLite3Query::~CppSQLite3Query()
2156+{
2157+ try
2158+ {
2159+ finalize();
2160+ }
2161+ catch(...)
2162+ {
2163+ }
2164+}
2165+
2166+CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)
2167+{
2168+ try
2169+ {
2170+ finalize();
2171+ }
2172+ catch(...)
2173+ {
2174+ }
2175+ mpVM = rQuery.mpVM;
2176+ // Only one object can own the VM
2177+ const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;
2178+ mbEof = rQuery.mbEof;
2179+ mnCols = rQuery.mnCols;
2180+ mbOwnVM = rQuery.mbOwnVM;
2181+ return *this;
2182+}
2183+
2184+int CppSQLite3Query::numFields()
2185+{
2186+ checkVM();
2187+ return mnCols;
2188+}
2189+
2190+const char* CppSQLite3Query::fieldValue(int nField)
2191+{
2192+ checkVM();
2193+
2194+ if(nField < 0 || nField > mnCols - 1)
2195+ {
2196+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2197+ }
2198+
2199+ return (const char*)sqlite3_column_text(mpVM, nField);
2200+}
2201+
2202+const char* CppSQLite3Query::fieldValue(const char* szField)
2203+{
2204+ int nField = fieldIndex(szField);
2205+ return (const char*)sqlite3_column_text(mpVM, nField);
2206+}
2207+
2208+int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)
2209+{
2210+ if(fieldDataType(nField) == SQLITE_NULL)
2211+ {
2212+ return nNullValue;
2213+ }
2214+ else
2215+ {
2216+ return sqlite3_column_int(mpVM, nField);
2217+ }
2218+}
2219+
2220+int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)
2221+{
2222+ int nField = fieldIndex(szField);
2223+ return getIntField(nField, nNullValue);
2224+}
2225+
2226+double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)
2227+{
2228+ if(fieldDataType(nField) == SQLITE_NULL)
2229+ {
2230+ return fNullValue;
2231+ }
2232+ else
2233+ {
2234+ return sqlite3_column_double(mpVM, nField);
2235+ }
2236+}
2237+
2238+double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)
2239+{
2240+ int nField = fieldIndex(szField);
2241+ return getFloatField(nField, fNullValue);
2242+}
2243+
2244+const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)
2245+{
2246+ if(fieldDataType(nField) == SQLITE_NULL)
2247+ {
2248+ return szNullValue;
2249+ }
2250+ else
2251+ {
2252+ return (const char*)sqlite3_column_text(mpVM, nField);
2253+ }
2254+}
2255+
2256+const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)
2257+{
2258+ int nField = fieldIndex(szField);
2259+ return getStringField(nField, szNullValue);
2260+}
2261+
2262+const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)
2263+{
2264+ checkVM();
2265+
2266+ if(nField < 0 || nField > mnCols - 1)
2267+ {
2268+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2269+ }
2270+
2271+ nLen = sqlite3_column_bytes(mpVM, nField);
2272+ return (const unsigned char*)sqlite3_column_blob(mpVM, nField);
2273+}
2274+
2275+const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)
2276+{
2277+ int nField = fieldIndex(szField);
2278+ return getBlobField(nField, nLen);
2279+}
2280+
2281+bool CppSQLite3Query::fieldIsNull(int nField)
2282+{
2283+ return (fieldDataType(nField) == SQLITE_NULL);
2284+}
2285+
2286+bool CppSQLite3Query::fieldIsNull(const char* szField)
2287+{
2288+ int nField = fieldIndex(szField);
2289+ return (fieldDataType(nField) == SQLITE_NULL);
2290+}
2291+
2292+int CppSQLite3Query::fieldIndex(const char* szField)
2293+{
2294+ checkVM();
2295+
2296+ if(szField)
2297+ {
2298+ for(int nField = 0;nField < mnCols;nField++)
2299+ {
2300+ const char* szTemp = sqlite3_column_name(mpVM, nField);
2301+
2302+ if(strcmp(szField, szTemp) == 0)
2303+ {
2304+ return nField;
2305+ }
2306+ }
2307+ }
2308+
2309+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG);
2310+}
2311+
2312+const char* CppSQLite3Query::fieldName(int nCol)
2313+{
2314+ checkVM();
2315+
2316+ if(nCol < 0 || nCol > mnCols - 1)
2317+ {
2318+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2319+ }
2320+
2321+ return sqlite3_column_name(mpVM, nCol);
2322+}
2323+
2324+const char* CppSQLite3Query::fieldDeclType(int nCol)
2325+{
2326+ checkVM();
2327+
2328+ if(nCol < 0 || nCol > mnCols - 1)
2329+ {
2330+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2331+ }
2332+
2333+ return sqlite3_column_decltype(mpVM, nCol);
2334+}
2335+
2336+int CppSQLite3Query::fieldDataType(int nCol)
2337+{
2338+ checkVM();
2339+
2340+ if(nCol < 0 || nCol > mnCols - 1)
2341+ {
2342+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2343+ }
2344+
2345+ return sqlite3_column_type(mpVM, nCol);
2346+}
2347+
2348+bool CppSQLite3Query::eof()
2349+{
2350+ checkVM();
2351+ return mbEof;
2352+}
2353+
2354+void CppSQLite3Query::nextRow()
2355+{
2356+ checkVM();
2357+
2358+ int nRet = sqlite3_step(mpVM);
2359+
2360+ if(nRet == SQLITE_DONE)
2361+ {
2362+ // no rows
2363+ mbEof = true;
2364+ }
2365+ else if(nRet == SQLITE_ROW)
2366+ {
2367+ // more rows, nothing to do
2368+ }
2369+ else
2370+ {
2371+ nRet = sqlite3_finalize(mpVM);
2372+ mpVM = 0;
2373+ const char* szError = sqlite3_errmsg(mpDB);
2374+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2375+ }
2376+}
2377+
2378+void CppSQLite3Query::finalize()
2379+{
2380+ if(mpVM && mbOwnVM)
2381+ {
2382+ int nRet = sqlite3_finalize(mpVM);
2383+ mpVM = 0;
2384+ if(nRet != SQLITE_OK)
2385+ {
2386+ const char* szError = sqlite3_errmsg(mpDB);
2387+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2388+ }
2389+ }
2390+}
2391+
2392+void CppSQLite3Query::checkVM()
2393+{
2394+ if(mpVM == 0)
2395+ {
2396+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Virtual Machine pointer", DONT_DELETE_MSG);
2397+ }
2398+}
2399+
2400+////////////////////////////////////////////////////////////////////////////////
2401+
2402+CppSQLite3Table::CppSQLite3Table()
2403+{
2404+ mpaszResults = 0;
2405+ mnRows = 0;
2406+ mnCols = 0;
2407+ mnCurrentRow = 0;
2408+}
2409+
2410+CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)
2411+{
2412+ mpaszResults = rTable.mpaszResults;
2413+ // Only one object can own the results
2414+ const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
2415+ mnRows = rTable.mnRows;
2416+ mnCols = rTable.mnCols;
2417+ mnCurrentRow = rTable.mnCurrentRow;
2418+}
2419+
2420+CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)
2421+{
2422+ mpaszResults = paszResults;
2423+ mnRows = nRows;
2424+ mnCols = nCols;
2425+ mnCurrentRow = 0;
2426+}
2427+
2428+CppSQLite3Table::~CppSQLite3Table()
2429+{
2430+ try
2431+ {
2432+ finalize();
2433+ }
2434+ catch(...)
2435+ {
2436+ }
2437+}
2438+
2439+CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)
2440+{
2441+ try
2442+ {
2443+ finalize();
2444+ }
2445+ catch(...)
2446+ {
2447+ }
2448+ mpaszResults = rTable.mpaszResults;
2449+ // Only one object can own the results
2450+ const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;
2451+ mnRows = rTable.mnRows;
2452+ mnCols = rTable.mnCols;
2453+ mnCurrentRow = rTable.mnCurrentRow;
2454+ return *this;
2455+}
2456+
2457+void CppSQLite3Table::finalize()
2458+{
2459+ if(mpaszResults)
2460+ {
2461+ sqlite3_free_table(mpaszResults);
2462+ mpaszResults = 0;
2463+ }
2464+}
2465+
2466+int CppSQLite3Table::numFields()
2467+{
2468+ checkResults();
2469+ return mnCols;
2470+}
2471+
2472+int CppSQLite3Table::numRows()
2473+{
2474+ checkResults();
2475+ return mnRows;
2476+}
2477+
2478+const char* CppSQLite3Table::fieldValue(int nField)
2479+{
2480+ checkResults();
2481+
2482+ if(nField < 0 || nField > mnCols - 1)
2483+ {
2484+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2485+ }
2486+
2487+ int nIndex = (mnCurrentRow* mnCols) + mnCols + nField;
2488+ return mpaszResults[nIndex];
2489+}
2490+
2491+const char* CppSQLite3Table::fieldValue(const char* szField)
2492+{
2493+ checkResults();
2494+
2495+ if(szField)
2496+ {
2497+ for(int nField = 0;nField < mnCols;nField++)
2498+ {
2499+ if(strcmp(szField, mpaszResults[nField]) == 0)
2500+ {
2501+ int nIndex = (mnCurrentRow* mnCols) + mnCols + nField;
2502+ return mpaszResults[nIndex];
2503+ }
2504+ }
2505+ }
2506+
2507+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field name requested", DONT_DELETE_MSG);
2508+}
2509+
2510+int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)
2511+{
2512+ if(fieldIsNull(nField))
2513+ {
2514+ return nNullValue;
2515+ }
2516+ else
2517+ {
2518+ return atoi(fieldValue(nField));
2519+ }
2520+}
2521+
2522+int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)
2523+{
2524+ if(fieldIsNull(szField))
2525+ {
2526+ return nNullValue;
2527+ }
2528+ else
2529+ {
2530+ return atoi(fieldValue(szField));
2531+ }
2532+}
2533+
2534+double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)
2535+{
2536+ if(fieldIsNull(nField))
2537+ {
2538+ return fNullValue;
2539+ }
2540+ else
2541+ {
2542+ return atof(fieldValue(nField));
2543+ }
2544+}
2545+
2546+double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)
2547+{
2548+ if(fieldIsNull(szField))
2549+ {
2550+ return fNullValue;
2551+ }
2552+ else
2553+ {
2554+ return atof(fieldValue(szField));
2555+ }
2556+}
2557+
2558+const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)
2559+{
2560+ if(fieldIsNull(nField))
2561+ {
2562+ return szNullValue;
2563+ }
2564+ else
2565+ {
2566+ return fieldValue(nField);
2567+ }
2568+}
2569+
2570+const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)
2571+{
2572+ if(fieldIsNull(szField))
2573+ {
2574+ return szNullValue;
2575+ }
2576+ else
2577+ {
2578+ return fieldValue(szField);
2579+ }
2580+}
2581+
2582+bool CppSQLite3Table::fieldIsNull(int nField)
2583+{
2584+ checkResults();
2585+ return (fieldValue(nField) == 0);
2586+}
2587+
2588+bool CppSQLite3Table::fieldIsNull(const char* szField)
2589+{
2590+ checkResults();
2591+ return (fieldValue(szField) == 0);
2592+}
2593+
2594+const char* CppSQLite3Table::fieldName(int nCol)
2595+{
2596+ checkResults();
2597+
2598+ if(nCol < 0 || nCol > mnCols - 1)
2599+ {
2600+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid field index requested", DONT_DELETE_MSG);
2601+ }
2602+
2603+ return mpaszResults[nCol];
2604+}
2605+
2606+void CppSQLite3Table::setRow(int nRow)
2607+{
2608+ checkResults();
2609+
2610+ if(nRow < 0 || nRow > mnRows - 1)
2611+ {
2612+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid row index requested", DONT_DELETE_MSG);
2613+ }
2614+
2615+ mnCurrentRow = nRow;
2616+}
2617+
2618+void CppSQLite3Table::checkResults()
2619+{
2620+ if(mpaszResults == 0)
2621+ {
2622+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Results pointer", DONT_DELETE_MSG);
2623+ }
2624+}
2625+
2626+////////////////////////////////////////////////////////////////////////////////
2627+
2628+CppSQLite3Statement::CppSQLite3Statement()
2629+{
2630+ mpDB = 0;
2631+ mpVM = 0;
2632+}
2633+
2634+CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)
2635+{
2636+ mpDB = rStatement.mpDB;
2637+ mpVM = rStatement.mpVM;
2638+ // Only one object can own VM
2639+ const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
2640+}
2641+
2642+CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)
2643+{
2644+ mpDB = pDB;
2645+ mpVM = pVM;
2646+}
2647+
2648+CppSQLite3Statement::~CppSQLite3Statement()
2649+{
2650+ try
2651+ {
2652+ finalize();
2653+ }
2654+ catch(...)
2655+ {
2656+ }
2657+}
2658+
2659+CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)
2660+{
2661+ mpDB = rStatement.mpDB;
2662+ mpVM = rStatement.mpVM;
2663+ // Only one object can own VM
2664+ const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;
2665+ return *this;
2666+}
2667+
2668+int CppSQLite3Statement::execDML()
2669+{
2670+ checkDB();
2671+ checkVM();
2672+
2673+ const char* szError = 0;
2674+
2675+ int nRet = sqlite3_step(mpVM);
2676+
2677+ if(nRet == SQLITE_DONE)
2678+ {
2679+ int nRowsChanged = sqlite3_changes(mpDB);
2680+
2681+ nRet = sqlite3_reset(mpVM);
2682+
2683+ if(nRet != SQLITE_OK)
2684+ {
2685+ szError = sqlite3_errmsg(mpDB);
2686+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2687+ }
2688+
2689+ return nRowsChanged;
2690+ }
2691+ else
2692+ {
2693+ nRet = sqlite3_reset(mpVM);
2694+ szError = sqlite3_errmsg(mpDB);
2695+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2696+ }
2697+}
2698+
2699+CppSQLite3Query CppSQLite3Statement::execQuery()
2700+{
2701+ checkDB();
2702+ checkVM();
2703+
2704+ int nRet = sqlite3_step(mpVM);
2705+
2706+ if(nRet == SQLITE_DONE)
2707+ {
2708+ // no rows
2709+ return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);
2710+ }
2711+ else if(nRet == SQLITE_ROW)
2712+ {
2713+ // at least 1 row
2714+ return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);
2715+ }
2716+ else
2717+ {
2718+ nRet = sqlite3_reset(mpVM);
2719+ const char* szError = sqlite3_errmsg(mpDB);
2720+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2721+ }
2722+}
2723+
2724+void CppSQLite3Statement::bind(int nParam, const char* szValue)
2725+{
2726+ checkVM();
2727+ int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);
2728+
2729+ if(nRes != SQLITE_OK)
2730+ {
2731+ throw CppSQLite3Exception(nRes, "Error binding string param", DONT_DELETE_MSG);
2732+ }
2733+}
2734+
2735+void CppSQLite3Statement::bind(int nParam, const int nValue)
2736+{
2737+ checkVM();
2738+ int nRes = sqlite3_bind_int(mpVM, nParam, nValue);
2739+
2740+ if(nRes != SQLITE_OK)
2741+ {
2742+ throw CppSQLite3Exception(nRes, "Error binding int param", DONT_DELETE_MSG);
2743+ }
2744+}
2745+
2746+void CppSQLite3Statement::bind(int nParam, const double dValue)
2747+{
2748+ checkVM();
2749+ int nRes = sqlite3_bind_double(mpVM, nParam, dValue);
2750+
2751+ if(nRes != SQLITE_OK)
2752+ {
2753+ throw CppSQLite3Exception(nRes, "Error binding double param", DONT_DELETE_MSG);
2754+ }
2755+}
2756+
2757+void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)
2758+{
2759+ checkVM();
2760+ int nRes = sqlite3_bind_blob(mpVM, nParam, (const void*)blobValue, nLen, SQLITE_TRANSIENT);
2761+
2762+ if(nRes != SQLITE_OK)
2763+ {
2764+ throw CppSQLite3Exception(nRes, "Error binding blob param", DONT_DELETE_MSG);
2765+ }
2766+}
2767+
2768+void CppSQLite3Statement::bindNull(int nParam)
2769+{
2770+ checkVM();
2771+ int nRes = sqlite3_bind_null(mpVM, nParam);
2772+
2773+ if(nRes != SQLITE_OK)
2774+ {
2775+ throw CppSQLite3Exception(nRes, "Error binding NULL param", DONT_DELETE_MSG);
2776+ }
2777+}
2778+
2779+void CppSQLite3Statement::reset()
2780+{
2781+ if(mpVM)
2782+ {
2783+ int nRet = sqlite3_reset(mpVM);
2784+
2785+ if(nRet != SQLITE_OK)
2786+ {
2787+ const char* szError = sqlite3_errmsg(mpDB);
2788+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2789+ }
2790+ }
2791+}
2792+
2793+void CppSQLite3Statement::finalize()
2794+{
2795+ if(mpVM)
2796+ {
2797+ int nRet = sqlite3_finalize(mpVM);
2798+ mpVM = 0;
2799+
2800+ if(nRet != SQLITE_OK)
2801+ {
2802+ const char* szError = sqlite3_errmsg(mpDB);
2803+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2804+ }
2805+ }
2806+}
2807+
2808+void CppSQLite3Statement::checkDB()
2809+{
2810+ if(mpDB == 0)
2811+ {
2812+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Database not open", DONT_DELETE_MSG);
2813+ }
2814+}
2815+
2816+void CppSQLite3Statement::checkVM()
2817+{
2818+ if(mpVM == 0)
2819+ {
2820+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Null Virtual Machine pointer", DONT_DELETE_MSG);
2821+ }
2822+}
2823+
2824+////////////////////////////////////////////////////////////////////////////////
2825+
2826+CppSQLite3DB::CppSQLite3DB()
2827+{
2828+ mpDB = 0;
2829+ mnBusyTimeoutMs = 60000; // 60 seconds
2830+}
2831+
2832+CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)
2833+{
2834+ mpDB = db.mpDB;
2835+ mnBusyTimeoutMs = 60000; // 60 seconds
2836+}
2837+
2838+CppSQLite3DB::~CppSQLite3DB()
2839+{
2840+ Close();
2841+}
2842+
2843+CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)
2844+{
2845+ mpDB = db.mpDB;
2846+ mnBusyTimeoutMs = 60000; // 60 seconds
2847+ return *this;
2848+}
2849+
2850+void CppSQLite3DB::Open(const char* szFile)
2851+{
2852+ int nRet = sqlite3_open(szFile, &mpDB);
2853+
2854+ if(nRet != SQLITE_OK)
2855+ {
2856+ const char* szError = sqlite3_errmsg(mpDB);
2857+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2858+ }
2859+
2860+ setBusyTimeout(mnBusyTimeoutMs);
2861+}
2862+
2863+void CppSQLite3DB::Close()
2864+{
2865+ if(mpDB)
2866+ {
2867+ sqlite3_close(mpDB);
2868+ mpDB = 0;
2869+ }
2870+}
2871+
2872+CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)
2873+{
2874+ checkDB();
2875+
2876+ sqlite3_stmt* pVM = compile(szSQL);
2877+ return CppSQLite3Statement(mpDB, pVM);
2878+}
2879+
2880+bool CppSQLite3DB::tableExists(const char* szTable)
2881+{
2882+ char szSQL[128];
2883+ sprintf(szSQL, "select count(*) from sqlite_master where type='table' and name='%s'", szTable);
2884+ int nRet = execScalar(szSQL);
2885+ return (nRet > 0);
2886+}
2887+
2888+int CppSQLite3DB::execDML(const char* szSQL)
2889+{
2890+ checkDB();
2891+
2892+ char* szError = 0;
2893+
2894+ int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);
2895+
2896+ if(nRet == SQLITE_OK)
2897+ {
2898+ return sqlite3_changes(mpDB);
2899+ }
2900+ else
2901+ {
2902+ throw CppSQLite3Exception(nRet, szError);
2903+ }
2904+}
2905+
2906+CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)
2907+{
2908+ checkDB();
2909+
2910+ sqlite3_stmt* pVM = compile(szSQL);
2911+
2912+ int nRet = sqlite3_step(pVM);
2913+
2914+ if(nRet == SQLITE_DONE)
2915+ {
2916+ // no rows
2917+ return CppSQLite3Query(mpDB, pVM, true/*eof*/);
2918+ }
2919+ else if(nRet == SQLITE_ROW)
2920+ {
2921+ // at least 1 row
2922+ return CppSQLite3Query(mpDB, pVM, false/*eof*/);
2923+ }
2924+ else
2925+ {
2926+ nRet = sqlite3_finalize(pVM);
2927+ const char* szError = sqlite3_errmsg(mpDB);
2928+ throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);
2929+ }
2930+}
2931+
2932+int CppSQLite3DB::execScalar(const char* szSQL)
2933+{
2934+ CppSQLite3Query q = execQuery(szSQL);
2935+
2936+ if(q.eof() || q.numFields() < 1)
2937+ {
2938+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Invalid scalar query", DONT_DELETE_MSG);
2939+ }
2940+
2941+ return atoi(q.fieldValue(0));
2942+}
2943+
2944+CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)
2945+{
2946+ checkDB();
2947+
2948+ char* szError = 0;
2949+ char** paszResults = 0;
2950+ int nRet;
2951+ int nRows(0);
2952+ int nCols(0);
2953+
2954+ nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);
2955+
2956+ if(nRet == SQLITE_OK)
2957+ {
2958+ return CppSQLite3Table(paszResults, nRows, nCols);
2959+ }
2960+ else
2961+ {
2962+ throw CppSQLite3Exception(nRet, szError);
2963+ }
2964+}
2965+
2966+sqlite_int64 CppSQLite3DB::lastRowId()
2967+{
2968+ return sqlite3_last_insert_rowid(mpDB);
2969+}
2970+
2971+void CppSQLite3DB::setBusyTimeout(int nMillisecs)
2972+{
2973+ mnBusyTimeoutMs = nMillisecs;
2974+ sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);
2975+}
2976+
2977+void CppSQLite3DB::checkDB()
2978+{
2979+ if(!mpDB)
2980+ {
2981+ throw CppSQLite3Exception(CPPSQLITE_ERROR, "Database not open", DONT_DELETE_MSG);
2982+ }
2983+}
2984+
2985+sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)
2986+{
2987+ checkDB();
2988+
2989+ char* szError = 0;
2990+ const char* szTail = 0;
2991+ sqlite3_stmt* pVM;
2992+
2993+ int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);
2994+
2995+ if(nRet != SQLITE_OK)
2996+ {
2997+ throw CppSQLite3Exception(nRet, szError);
2998+ }
2999+
3000+ return pVM;
3001+}
3002+
3003+////////////////////////////////////////////////////////////////////////////////
3004+// SQLite encode.c reproduced here, containing implementation notes and source
3005+// for sqlite3_encode_binary() and sqlite3_decode_binary()
3006+////////////////////////////////////////////////////////////////////////////////
3007+
3008+/*
3009+** 2002 April 25
3010+**
3011+** The author disclaims copyright to this source code. In place of
3012+** a legal notice, here is a blessing:
3013+**
3014+** May you do good and not evil.
3015+** May you find forgiveness for yourself and forgive others.
3016+** May you share freely, never taking more than you give.
3017+**
3018+*************************************************************************
3019+** This file contains helper routines used to translate binary data into
3020+** a null-terminated string (suitable for use in SQLite) and back again.
3021+** These are convenience routines for use by people who want to store binary
3022+** data in an SQLite database. The code in this file is not used by any other
3023+** part of the SQLite library.
3024+**
3025+** $Id: encode.c,v 1.10 2004/01/14 21:59:23 drh Exp $
3026+*/
3027+
3028+/*
3029+** How This Encoder Works
3030+**
3031+** The output is allowed to contain any character except 0x27 (') and
3032+** 0x00. This is accomplished by using an escape character to encode
3033+** 0x27 and 0x00 as a two-byte sequence. The escape character is always
3034+** 0x01. An 0x00 is encoded as the two byte sequence 0x01 0x01. The
3035+** 0x27 character is encoded as the two byte sequence 0x01 0x03. Finally,
3036+** the escape character itself is encoded as the two-character sequence
3037+** 0x01 0x02.
3038+**
3039+** To summarize, the encoder works by using an escape sequences as follows:
3040+**
3041+** 0x00 -> 0x01 0x01
3042+** 0x01 -> 0x01 0x02
3043+** 0x27 -> 0x01 0x03
3044+**
3045+** If that were all the encoder did, it would work, but in certain cases
3046+** it could double the size of the encoded string. For example, to
3047+** encode a string of 100 0x27 characters would require 100 instances of
3048+** the 0x01 0x03 escape sequence resulting in a 200-character output.
3049+** We would prefer to keep the size of the encoded string smaller than
3050+** this.
3051+**
3052+** To minimize the encoding size, we first add a fixed offset value to each
3053+** byte in the sequence. The addition is modulo 256. (That is to say, if
3054+** the sum of the original character value and the offset exceeds 256, then
3055+** the higher order bits are truncated.) The offset is chosen to minimize
3056+** the number of characters in the string that need to be escaped. For
3057+** example, in the case above where the string was composed of 100 0x27
3058+** characters, the offset might be 0x01. Each of the 0x27 characters would
3059+** then be converted into an 0x28 character which would not need to be
3060+** escaped at all and so the 100 character input string would be converted
3061+** into just 100 characters of output. Actually 101 characters of output -
3062+** we have to record the offset used as the first byte in the sequence so
3063+** that the string can be decoded. Since the offset value is stored as
3064+** part of the output string and the output string is not allowed to contain
3065+** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.
3066+**
3067+** Here, then, are the encoding steps:
3068+**
3069+** (1) Choose an offset value and make it the first character of
3070+** output.
3071+**
3072+** (2) Copy each input character into the output buffer, one by
3073+** one, adding the offset value as you copy.
3074+**
3075+** (3) If the value of an input character plus offset is 0x00, replace
3076+** that one character by the two-character sequence 0x01 0x01.
3077+** If the sum is 0x01, replace it with 0x01 0x02. If the sum
3078+** is 0x27, replace it with 0x01 0x03.
3079+**
3080+** (4) Put a 0x00 terminator at the end of the output.
3081+**
3082+** Decoding is obvious:
3083+**
3084+** (5) Copy encoded characters except the first into the decode
3085+** buffer. Set the first encoded character aside for use as
3086+** the offset in step 7 below.
3087+**
3088+** (6) Convert each 0x01 0x01 sequence into a single character 0x00.
3089+** Convert 0x01 0x02 into 0x01. Convert 0x01 0x03 into 0x27.
3090+**
3091+** (7) Subtract the offset value that was the first character of
3092+** the encoded buffer from all characters in the output buffer.
3093+**
3094+** The only tricky part is step (1) - how to compute an offset value to
3095+** minimize the size of the output buffer. This is accomplished by testing
3096+** all offset values and picking the one that results in the fewest number
3097+** of escapes. To do that, we first scan the entire input and count the
3098+** number of occurances of each character value in the input. Suppose
3099+** the number of 0x00 characters is N(0), the number of occurances of 0x01
3100+** is N(1), and so forth up to the number of occurances of 0xff is N(255).
3101+** An offset of 0 is not allowed so we don't have to test it. The number
3102+** of escapes required for an offset of 1 is N(1)+N(2)+N(40). The number
3103+** of escapes required for an offset of 2 is N(2)+N(3)+N(41). And so forth.
3104+** In this way we find the offset that gives the minimum number of escapes,
3105+** and thus minimizes the length of the output string.
3106+*/
3107+
3108+/*
3109+** Encode a binary buffer "in" of size n bytes so that it contains
3110+** no instances of characters '\'' or '\000'. The output is
3111+** null-terminated and can be used as a string value in an INSERT
3112+** or UPDATE statement. Use sqlite3_decode_binary() to convert the
3113+** string back into its original binary.
3114+**
3115+** The result is written into a preallocated output buffer "out".
3116+** "out" must be able to hold at least 2 +(257*n)/254 bytes.
3117+** In other words, the output will be expanded by as much as 3
3118+** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
3119+** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
3120+**
3121+** The return value is the number of characters in the encoded
3122+** string, excluding the "\000" terminator.
3123+*/
3124+int sqlite3_encode_binary(const unsigned char* in, int n, unsigned char* out)
3125+{
3126+ int i = 0;
3127+ int j = 0;
3128+ int e = 0;
3129+ int m = 0;
3130+
3131+ int cnt[256];
3132+
3133+ if(n <= 0)
3134+ {
3135+ out[0] = 'x';
3136+ out[1] = 0;
3137+ return 1;
3138+ }
3139+ memset(cnt, 0, sizeof(cnt));
3140+ for(i = n - 1;i >= 0;i--)
3141+ {
3142+ cnt[in[i]]++;
3143+ }
3144+ m = n;
3145+ for(i = 1;i < 256;i++)
3146+ {
3147+ int sum;
3148+ if(i == '\'')
3149+ continue;
3150+ sum = cnt[i] + cnt[(i + 1) & 0xff] + cnt[(i + '\'') & 0xff];
3151+ if(sum < m)
3152+ {
3153+ m = sum;
3154+ e = i;
3155+ if(m == 0)
3156+ break;
3157+ }
3158+ }
3159+ out[0] = e;
3160+ j = 1;
3161+ for(i = 0;i < n;i++)
3162+ {
3163+ int c = (in[i] - e) & 0xff;
3164+ if(c == 0)
3165+ {
3166+ out[j++] = 1;
3167+ out[j++] = 1;
3168+ }
3169+ else if(c == 1)
3170+ {
3171+ out[j++] = 1;
3172+ out[j++] = 2;
3173+ }
3174+ else if(c == '\'')
3175+ {
3176+ out[j++] = 1;
3177+ out[j++] = 3;
3178+ }
3179+ else
3180+ {
3181+ out[j++] = c;
3182+ }
3183+ }
3184+ out[j] = 0;
3185+ return j;
3186+}
3187+
3188+/*
3189+** Decode the string "in" into binary data and write it into "out".
3190+** This routine reverses the encoding created by sqlite3_encode_binary().
3191+** The output will always be a few bytes less than the input. The number
3192+** of bytes of output is returned. If the input is not a well-formed
3193+** encoding, -1 is returned.
3194+**
3195+** The "in" and "out" parameters may point to the same buffer in order
3196+** to decode a string in place.
3197+*/
3198+int sqlite3_decode_binary(const unsigned char* in, unsigned char* out)
3199+{
3200+ int i = 0;
3201+ int c = 0;
3202+ int e = 0;
3203+
3204+ e = *(in++);
3205+ i = 0;
3206+ while((c = *(in++)) != 0)
3207+ {
3208+ if(c == 1)
3209+ {
3210+ c = *(in++);
3211+ if(c == 1)
3212+ {
3213+ c = 0;
3214+ }
3215+ else if(c == 2)
3216+ {
3217+ c = 1;
3218+ }
3219+ else if(c == 3)
3220+ {
3221+ c = '\'';
3222+ }
3223+ else
3224+ {
3225+ return -1;
3226+ }
3227+ }
3228+ out[i++] = (c + e) & 0xff;
3229+ }
3230+ return i;
3231+}
3232
3233=== added file 'common/CppSQLite3.h'
3234--- common/CppSQLite3.h 1970-01-01 00:00:00 +0000
3235+++ common/CppSQLite3.h 2011-11-23 01:01:25 +0000
3236@@ -0,0 +1,270 @@
3237+#pragma once
3238+
3239+#include "sqlite3.h"
3240+#include <cstdio>
3241+#include <cstring>
3242+
3243+#define CPPSQLITE_ERROR 1000
3244+
3245+class CppSQLite3Exception
3246+{
3247+public:
3248+
3249+ CppSQLite3Exception(const int nErrCode,
3250+ char* szErrMess,
3251+ bool bDeleteMsg=true);
3252+
3253+ CppSQLite3Exception(const CppSQLite3Exception& e);
3254+
3255+ virtual ~CppSQLite3Exception();
3256+
3257+ const int errorCode() { return mnErrCode; }
3258+
3259+ const char* errorMessage() { return mpszErrMess; }
3260+
3261+ static const char* errorCodeAsString(int nErrCode);
3262+
3263+private:
3264+
3265+ int mnErrCode;
3266+ char* mpszErrMess;
3267+};
3268+
3269+class CppSQLite3Buffer
3270+{
3271+public:
3272+
3273+ CppSQLite3Buffer();
3274+
3275+ ~CppSQLite3Buffer();
3276+
3277+ const char* format(const char* szFormat, ...);
3278+
3279+ operator const char*() { return mpBuf; }
3280+
3281+ void clear();
3282+
3283+private:
3284+
3285+ char* mpBuf;
3286+};
3287+
3288+class CppSQLite3Binary
3289+{
3290+public:
3291+
3292+ CppSQLite3Binary();
3293+
3294+ ~CppSQLite3Binary();
3295+
3296+ void setBinary(const unsigned char* pBuf, int nLen);
3297+ void setEncoded(const unsigned char* pBuf);
3298+
3299+ const unsigned char* getEncoded();
3300+ const unsigned char* getBinary();
3301+
3302+ int getBinaryLength();
3303+
3304+ unsigned char* allocBuffer(int nLen);
3305+
3306+ void clear();
3307+
3308+private:
3309+
3310+ unsigned char* mpBuf;
3311+ int mnBinaryLen;
3312+ int mnBufferLen;
3313+ int mnEncodedLen;
3314+ bool mbEncoded;
3315+};
3316+
3317+class CppSQLite3Query
3318+{
3319+public:
3320+
3321+ CppSQLite3Query();
3322+
3323+ CppSQLite3Query(const CppSQLite3Query& rQuery);
3324+
3325+ CppSQLite3Query(sqlite3* pDB,
3326+ sqlite3_stmt* pVM,
3327+ bool bEof,
3328+ bool bOwnVM=true);
3329+
3330+ CppSQLite3Query& operator=(const CppSQLite3Query& rQuery);
3331+
3332+ virtual ~CppSQLite3Query();
3333+
3334+ int numFields();
3335+
3336+ int fieldIndex(const char* szField);
3337+ const char* fieldName(int nCol);
3338+
3339+ const char* fieldDeclType(int nCol);
3340+ int fieldDataType(int nCol);
3341+
3342+ const char* fieldValue(int nField);
3343+ const char* fieldValue(const char* szField);
3344+
3345+ int getIntField(int nField, int nNullValue=0);
3346+ int getIntField(const char* szField, int nNullValue=0);
3347+
3348+ double getFloatField(int nField, double fNullValue=0.0);
3349+ double getFloatField(const char* szField, double fNullValue=0.0);
3350+
3351+ const char* getStringField(int nField, const char* szNullValue="");
3352+ const char* getStringField(const char* szField, const char* szNullValue="");
3353+
3354+ const unsigned char* getBlobField(int nField, int& nLen);
3355+ const unsigned char* getBlobField(const char* szField, int& nLen);
3356+
3357+ bool fieldIsNull(int nField);
3358+ bool fieldIsNull(const char* szField);
3359+
3360+ bool eof();
3361+
3362+ void nextRow();
3363+
3364+ void finalize();
3365+
3366+private:
3367+
3368+ void checkVM();
3369+
3370+ sqlite3* mpDB;
3371+ sqlite3_stmt* mpVM;
3372+ bool mbEof;
3373+ int mnCols;
3374+ bool mbOwnVM;
3375+};
3376+
3377+class CppSQLite3Table
3378+{
3379+public:
3380+
3381+ CppSQLite3Table();
3382+
3383+ CppSQLite3Table(const CppSQLite3Table& rTable);
3384+
3385+ CppSQLite3Table(char** paszResults, int nRows, int nCols);
3386+
3387+ virtual ~CppSQLite3Table();
3388+
3389+ CppSQLite3Table& operator=(const CppSQLite3Table& rTable);
3390+
3391+ int numFields();
3392+
3393+ int numRows();
3394+
3395+ const char* fieldName(int nCol);
3396+
3397+ const char* fieldValue(int nField);
3398+ const char* fieldValue(const char* szField);
3399+
3400+ int getIntField(int nField, int nNullValue=0);
3401+ int getIntField(const char* szField, int nNullValue=0);
3402+
3403+ double getFloatField(int nField, double fNullValue=0.0);
3404+ double getFloatField(const char* szField, double fNullValue=0.0);
3405+
3406+ const char* getStringField(int nField, const char* szNullValue="");
3407+ const char* getStringField(const char* szField, const char* szNullValue="");
3408+
3409+ bool fieldIsNull(int nField);
3410+ bool fieldIsNull(const char* szField);
3411+
3412+ void setRow(int nRow);
3413+
3414+ void finalize();
3415+
3416+private:
3417+
3418+ void checkResults();
3419+
3420+ int mnCols;
3421+ int mnRows;
3422+ int mnCurrentRow;
3423+ char** mpaszResults;
3424+};
3425+
3426+class CppSQLite3Statement
3427+{
3428+public:
3429+
3430+ CppSQLite3Statement();
3431+
3432+ CppSQLite3Statement(const CppSQLite3Statement& rStatement);
3433+
3434+ CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM);
3435+
3436+ virtual ~CppSQLite3Statement();
3437+
3438+ CppSQLite3Statement& operator=(const CppSQLite3Statement& rStatement);
3439+
3440+ int execDML();
3441+
3442+ CppSQLite3Query execQuery();
3443+
3444+ void bind(int nParam, const char* szValue);
3445+ void bind(int nParam, const int nValue);
3446+ void bind(int nParam, const double dwValue);
3447+ void bind(int nParam, const unsigned char* blobValue, int nLen);
3448+ void bindNull(int nParam);
3449+
3450+ void reset();
3451+
3452+ void finalize();
3453+
3454+private:
3455+
3456+ void checkDB();
3457+ void checkVM();
3458+
3459+ sqlite3* mpDB;
3460+ sqlite3_stmt* mpVM;
3461+};
3462+
3463+class CppSQLite3DB
3464+{
3465+public:
3466+
3467+ CppSQLite3DB();
3468+
3469+ virtual ~CppSQLite3DB();
3470+
3471+ void Open(const char* szFile);
3472+
3473+ void Close();
3474+
3475+ bool tableExists(const char* szTable);
3476+
3477+ int execDML(const char* szSQL);
3478+
3479+ CppSQLite3Query execQuery(const char* szSQL);
3480+
3481+ int execScalar(const char* szSQL);
3482+
3483+ CppSQLite3Table getTable(const char* szSQL);
3484+
3485+ CppSQLite3Statement compileStatement(const char* szSQL);
3486+
3487+ sqlite_int64 lastRowId();
3488+
3489+ void interrupt() { sqlite3_interrupt(mpDB); }
3490+
3491+ void setBusyTimeout(int nMillisecs);
3492+
3493+ static const char* SQLiteVersion() { return SQLITE_VERSION; }
3494+
3495+private:
3496+
3497+ CppSQLite3DB(const CppSQLite3DB& db);
3498+ CppSQLite3DB& operator=(const CppSQLite3DB& db);
3499+
3500+ sqlite3_stmt* compile(const char* szSQL);
3501+
3502+ void checkDB();
3503+
3504+ sqlite3* mpDB;
3505+ int mnBusyTimeoutMs;
3506+};
3507
3508=== added file 'common/SHA1.cpp'
3509--- common/SHA1.cpp 1970-01-01 00:00:00 +0000
3510+++ common/SHA1.cpp 2011-11-23 01:01:25 +0000
3511@@ -0,0 +1,282 @@
3512+/*
3513+ 100% free public domain implementation of the SHA-1 algorithm
3514+ by Dominik Reichl <dominik.reichl@t-online.de>
3515+ Web: http://www.dominik-reichl.de/
3516+
3517+ Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
3518+ - You can set the endianness in your files, no need to modify the
3519+ header file of the CSHA1 class any more
3520+ - Aligned data support
3521+ - Made support/compilation of the utility functions (ReportHash
3522+ and HashFile) optional (useful, if bytes count, for example in
3523+ embedded environments)
3524+
3525+ Version 1.5 - 2005-01-01
3526+ - 64-bit compiler compatibility added
3527+ - Made variable wiping optional (define SHA1_WIPE_VARIABLES)
3528+ - Removed unnecessary variable initializations
3529+ - ROL32 improvement for the Microsoft compiler (using _rotl)
3530+
3531+ ======== Test Vectors (from FIPS PUB 180-1) ========
3532+
3533+ SHA1("abc") =
3534+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
3535+
3536+ SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
3537+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
3538+
3539+ SHA1(A million repetitions of "a") =
3540+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
3541+*/
3542+
3543+#include "SHA1.h"
3544+
3545+#ifdef SHA1_UTILITY_FUNCTIONS
3546+#define SHA1_MAX_FILE_BUFFER 8000
3547+#endif
3548+
3549+// Rotate x bits to the left
3550+#ifndef ROL32
3551+#ifdef _MSC_VER
3552+#define ROL32(_val32, _nBits) _rotl(_val32, _nBits)
3553+#else
3554+#define ROL32(_val32, _nBits) (((_val32)<<(_nBits))|((_val32)>>(32-(_nBits))))
3555+#endif
3556+#endif
3557+
3558+#ifdef SHA1_LITTLE_ENDIAN
3559+#define SHABLK0(i) (m_block->l[i] = \
3560+ (ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
3561+#else
3562+#define SHABLK0(i) (m_block->l[i])
3563+#endif
3564+
3565+#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ m_block->l[(i+8)&15] \
3566+ ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
3567+
3568+// SHA-1 rounds
3569+#define _R0(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
3570+#define _R1(v,w,x,y,z,i) { z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5); w=ROL32(w,30); }
3571+#define _R2(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5); w=ROL32(w,30); }
3572+#define _R3(v,w,x,y,z,i) { z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5); w=ROL32(w,30); }
3573+#define _R4(v,w,x,y,z,i) { z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5); w=ROL32(w,30); }
3574+
3575+CSHA1::CSHA1()
3576+{
3577+ m_block = (SHA1_WORKSPACE_BLOCK *)m_workspace;
3578+
3579+ Reset();
3580+}
3581+
3582+CSHA1::~CSHA1()
3583+{
3584+ Reset();
3585+}
3586+
3587+void CSHA1::Reset()
3588+{
3589+ // SHA1 initialization constants
3590+ m_state[0] = 0x67452301;
3591+ m_state[1] = 0xEFCDAB89;
3592+ m_state[2] = 0x98BADCFE;
3593+ m_state[3] = 0x10325476;
3594+ m_state[4] = 0xC3D2E1F0;
3595+
3596+ m_count[0] = 0;
3597+ m_count[1] = 0;
3598+}
3599+
3600+void CSHA1::Transform(UINT_32* state, UINT_8* buffer)
3601+{
3602+ // Copy state[] to working vars
3603+ UINT_32 a = state[0], b = state[1], c = state[2], d = state[3], e = state[4];
3604+
3605+ memcpy(m_block, buffer, 64);
3606+
3607+ // 4 rounds of 20 operations each. Loop unrolled.
3608+ _R0(a, b, c, d, e, 0); _R0(e, a, b, c, d, 1); _R0(d, e, a, b, c, 2); _R0(c, d, e, a, b, 3);
3609+ _R0(b, c, d, e, a, 4); _R0(a, b, c, d, e, 5); _R0(e, a, b, c, d, 6); _R0(d, e, a, b, c, 7);
3610+ _R0(c, d, e, a, b, 8); _R0(b, c, d, e, a, 9); _R0(a, b, c, d, e, 10); _R0(e, a, b, c, d, 11);
3611+ _R0(d, e, a, b, c, 12); _R0(c, d, e, a, b, 13); _R0(b, c, d, e, a, 14); _R0(a, b, c, d, e, 15);
3612+ _R1(e, a, b, c, d, 16); _R1(d, e, a, b, c, 17); _R1(c, d, e, a, b, 18); _R1(b, c, d, e, a, 19);
3613+ _R2(a, b, c, d, e, 20); _R2(e, a, b, c, d, 21); _R2(d, e, a, b, c, 22); _R2(c, d, e, a, b, 23);
3614+ _R2(b, c, d, e, a, 24); _R2(a, b, c, d, e, 25); _R2(e, a, b, c, d, 26); _R2(d, e, a, b, c, 27);
3615+ _R2(c, d, e, a, b, 28); _R2(b, c, d, e, a, 29); _R2(a, b, c, d, e, 30); _R2(e, a, b, c, d, 31);
3616+ _R2(d, e, a, b, c, 32); _R2(c, d, e, a, b, 33); _R2(b, c, d, e, a, 34); _R2(a, b, c, d, e, 35);
3617+ _R2(e, a, b, c, d, 36); _R2(d, e, a, b, c, 37); _R2(c, d, e, a, b, 38); _R2(b, c, d, e, a, 39);
3618+ _R3(a, b, c, d, e, 40); _R3(e, a, b, c, d, 41); _R3(d, e, a, b, c, 42); _R3(c, d, e, a, b, 43);
3619+ _R3(b, c, d, e, a, 44); _R3(a, b, c, d, e, 45); _R3(e, a, b, c, d, 46); _R3(d, e, a, b, c, 47);
3620+ _R3(c, d, e, a, b, 48); _R3(b, c, d, e, a, 49); _R3(a, b, c, d, e, 50); _R3(e, a, b, c, d, 51);
3621+ _R3(d, e, a, b, c, 52); _R3(c, d, e, a, b, 53); _R3(b, c, d, e, a, 54); _R3(a, b, c, d, e, 55);
3622+ _R3(e, a, b, c, d, 56); _R3(d, e, a, b, c, 57); _R3(c, d, e, a, b, 58); _R3(b, c, d, e, a, 59);
3623+ _R4(a, b, c, d, e, 60); _R4(e, a, b, c, d, 61); _R4(d, e, a, b, c, 62); _R4(c, d, e, a, b, 63);
3624+ _R4(b, c, d, e, a, 64); _R4(a, b, c, d, e, 65); _R4(e, a, b, c, d, 66); _R4(d, e, a, b, c, 67);
3625+ _R4(c, d, e, a, b, 68); _R4(b, c, d, e, a, 69); _R4(a, b, c, d, e, 70); _R4(e, a, b, c, d, 71);
3626+ _R4(d, e, a, b, c, 72); _R4(c, d, e, a, b, 73); _R4(b, c, d, e, a, 74); _R4(a, b, c, d, e, 75);
3627+ _R4(e, a, b, c, d, 76); _R4(d, e, a, b, c, 77); _R4(c, d, e, a, b, 78); _R4(b, c, d, e, a, 79);
3628+
3629+ // Add the working vars back into state
3630+ state[0] += a;
3631+ state[1] += b;
3632+ state[2] += c;
3633+ state[3] += d;
3634+ state[4] += e;
3635+
3636+ // Wipe variables
3637+#ifdef SHA1_WIPE_VARIABLES
3638+ a = b = c = d = e = 0;
3639+#endif
3640+}
3641+
3642+// Use this function to hash in binary data and strings
3643+void CSHA1::Update(UINT_8* data, UINT_32 len)
3644+{
3645+ UINT_32 i, j;
3646+
3647+ j = (m_count[0] >> 3) & 63;
3648+
3649+ if((m_count[0] += len << 3) < (len << 3))
3650+ m_count[1]++;
3651+
3652+ m_count[1] += (len >> 29);
3653+
3654+ if((j + len) > 63)
3655+ {
3656+ i = 64 - j;
3657+ memcpy(&m_buffer[j], data, i);
3658+ Transform(m_state, m_buffer);
3659+
3660+ for(;i + 63 < len;i += 64)
3661+ Transform(m_state, &data[i]);
3662+
3663+ j = 0;
3664+ }
3665+ else
3666+ i = 0;
3667+
3668+ memcpy(&m_buffer[j], &data[i], len - i);
3669+}
3670+
3671+#ifdef SHA1_UTILITY_FUNCTIONS
3672+// Hash in file contents
3673+bool CSHA1::HashFile(char* szFileName)
3674+{
3675+ unsigned long ulFileSize, ulRest, ulBlocks;
3676+ unsigned long i;
3677+ UINT_8 uData[SHA1_MAX_FILE_BUFFER];
3678+ FILE* fIn;
3679+
3680+ if(szFileName == NULL)
3681+ return false;
3682+
3683+ fIn = fopen(szFileName, "rb");
3684+ if(fIn == NULL)
3685+ return false;
3686+
3687+ fseek(fIn, 0, SEEK_END);
3688+ ulFileSize = (unsigned long)ftell(fIn);
3689+ fseek(fIn, 0, SEEK_SET);
3690+
3691+ if(ulFileSize != 0)
3692+ {
3693+ ulBlocks = ulFileSize / SHA1_MAX_FILE_BUFFER;
3694+ ulRest = ulFileSize % SHA1_MAX_FILE_BUFFER;
3695+ }
3696+ else
3697+ {
3698+ ulBlocks = 0;
3699+ ulRest = 0;
3700+ }
3701+
3702+ for(i = 0;i < ulBlocks;i++)
3703+ {
3704+ fread(uData, 1, SHA1_MAX_FILE_BUFFER, fIn);
3705+ Update((UINT_8 *)uData, SHA1_MAX_FILE_BUFFER);
3706+ }
3707+
3708+ if(ulRest != 0)
3709+ {
3710+ fread(uData, 1, ulRest, fIn);
3711+ Update((UINT_8 *)uData, ulRest);
3712+ }
3713+
3714+ fclose(fIn); fIn = NULL;
3715+ return true;
3716+}
3717+
3718+#endif
3719+
3720+void CSHA1::Final()
3721+{
3722+ UINT_32 i;
3723+ UINT_8 finalcount[8];
3724+
3725+ for(i = 0;i < 8;i++)
3726+ finalcount[i] = (UINT_8)((m_count[((i >= 4) ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent
3727+
3728+ Update((UINT_8 *)"\200", 1);
3729+
3730+ while((m_count[0] & 504) != 448)
3731+ Update((UINT_8 *)"\0", 1);
3732+
3733+ Update(finalcount, 8); // Cause a SHA1Transform()
3734+
3735+ for(i = 0;i < 20;i++)
3736+ {
3737+ m_digest[i] = (UINT_8)((m_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255);
3738+ }
3739+
3740+ // Wipe variables for security reasons
3741+#ifdef SHA1_WIPE_VARIABLES
3742+ i = 0;
3743+ memset(m_buffer, 0, 64);
3744+ memset(m_state, 0, 20);
3745+ memset(m_count, 0, 8);
3746+ memset(finalcount, 0, 8);
3747+ Transform(m_state, m_buffer);
3748+#endif
3749+}
3750+
3751+#ifdef SHA1_UTILITY_FUNCTIONS
3752+// Get the final hash as a pre-formatted string
3753+void CSHA1::ReportHash(char* szReport, unsigned char uReportType)
3754+{
3755+ unsigned char i;
3756+ char szTemp[16];
3757+
3758+ if(szReport == NULL)
3759+ return;
3760+
3761+ if(uReportType == REPORT_HEX)
3762+ {
3763+ sprintf(szTemp, "%02X", m_digest[0]);
3764+ strcat(szReport, szTemp);
3765+
3766+ for(i = 1;i < 20;i++)
3767+ {
3768+ sprintf(szTemp, " %02X", m_digest[i]);
3769+ strcat(szReport, szTemp);
3770+ }
3771+ }
3772+ else if(uReportType == REPORT_DIGIT)
3773+ {
3774+ sprintf(szTemp, "%u", m_digest[0]);
3775+ strcat(szReport, szTemp);
3776+
3777+ for(i = 1;i < 20;i++)
3778+ {
3779+ sprintf(szTemp, " %u", m_digest[i]);
3780+ strcat(szReport, szTemp);
3781+ }
3782+ }
3783+ else
3784+ strcpy(szReport, "Error: Unknown report type!");
3785+}
3786+
3787+#endif
3788+
3789+// Get the raw message digest
3790+void CSHA1::GetHash(UINT_8* puDest)
3791+{
3792+ memcpy(puDest, m_digest, 20);
3793+}
3794
3795=== added file 'common/SHA1.h'
3796--- common/SHA1.h 1970-01-01 00:00:00 +0000
3797+++ common/SHA1.h 2011-11-23 01:01:25 +0000
3798@@ -0,0 +1,150 @@
3799+/*
3800+ 100% free public domain implementation of the SHA-1 algorithm
3801+ by Dominik Reichl <dominik.reichl@t-online.de>
3802+ Web: http://www.dominik-reichl.de/
3803+
3804+ Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
3805+ - You can set the endianness in your files, no need to modify the
3806+ header file of the CSHA1 class any more
3807+ - Aligned data support
3808+ - Made support/compilation of the utility functions (ReportHash
3809+ and HashFile) optional (useful, if bytes count, for example in
3810+ embedded environments)
3811+
3812+ Version 1.5 - 2005-01-01
3813+ - 64-bit compiler compatibility added
3814+ - Made variable wiping optional (define SHA1_WIPE_VARIABLES)
3815+ - Removed unnecessary variable initializations
3816+ - ROL32 improvement for the Microsoft compiler (using _rotl)
3817+
3818+ ======== Test Vectors (from FIPS PUB 180-1) ========
3819+
3820+ SHA1("abc") =
3821+ A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
3822+
3823+ SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq") =
3824+ 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
3825+
3826+ SHA1(A million repetitions of "a") =
3827+ 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
3828+*/
3829+
3830+#ifndef ___SHA1_HDR___
3831+#define ___SHA1_HDR___
3832+
3833+#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
3834+#define SHA1_UTILITY_FUNCTIONS
3835+#endif
3836+
3837+#include <memory.h> // Needed for memset and memcpy
3838+
3839+#ifdef SHA1_UTILITY_FUNCTIONS
3840+#include <stdio.h> // Needed for file access and sprintf
3841+#include <string.h> // Needed for strcat and strcpy
3842+#endif
3843+
3844+#ifdef _MSC_VER
3845+#include <stdlib.h>
3846+#endif
3847+
3848+// You can define the endian mode in your files, without modifying the SHA1
3849+// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
3850+// in your files, before including the SHA1.h header file. If you don't
3851+// define anything, the class defaults to little endian.
3852+
3853+#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
3854+#define SHA1_LITTLE_ENDIAN
3855+#endif
3856+
3857+// Same here. If you want variable wiping, #define SHA1_WIPE_VARIABLES, if
3858+// not, #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
3859+// defaults to wiping.
3860+
3861+#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
3862+#define SHA1_WIPE_VARIABLES
3863+#endif
3864+
3865+/////////////////////////////////////////////////////////////////////////////
3866+// Define 8- and 32-bit variables
3867+
3868+#ifndef UINT_32
3869+
3870+#ifdef _MSC_VER
3871+
3872+#define UINT_8 unsigned __int8
3873+#define UINT_32 unsigned __int32
3874+
3875+#else
3876+
3877+#define UINT_8 unsigned char
3878+/*AFF
3879+#if (ULONG_MAX == 0xFFFFFFFF)
3880+#define UINT_32 unsigned long
3881+#else
3882+#define UINT_32 unsigned int
3883+#endif
3884+*/
3885+#define UINT_32 unsigned int
3886+
3887+#endif
3888+#endif
3889+
3890+/////////////////////////////////////////////////////////////////////////////
3891+// Declare SHA1 workspace
3892+
3893+typedef union
3894+{
3895+ UINT_8 c[64];
3896+ UINT_32 l[16];
3897+} SHA1_WORKSPACE_BLOCK;
3898+
3899+class CSHA1
3900+{
3901+public:
3902+#ifdef SHA1_UTILITY_FUNCTIONS
3903+ // Two different formats for ReportHash(...)
3904+ enum
3905+ {
3906+ REPORT_HEX = 0,
3907+ REPORT_DIGIT = 1
3908+ };
3909+#endif
3910+
3911+ // Constructor and Destructor
3912+ CSHA1();
3913+ ~CSHA1();
3914+
3915+ UINT_32 m_state[5];
3916+ UINT_32 m_count[2];
3917+ UINT_32 __reserved1[1];
3918+ UINT_8 m_buffer[64];
3919+ UINT_8 m_digest[20];
3920+ UINT_32 __reserved2[3];
3921+
3922+ void Reset();
3923+
3924+ // Update the hash value
3925+ void Update(UINT_8* data, UINT_32 len);
3926+#ifdef SHA1_UTILITY_FUNCTIONS
3927+ bool HashFile(char* szFileName);
3928+#endif
3929+
3930+ // Finalize hash and report
3931+ void Final();
3932+
3933+ // Report functions: as pre-formatted and raw data
3934+#ifdef SHA1_UTILITY_FUNCTIONS
3935+ void ReportHash(char* szReport, unsigned char uReportType = REPORT_HEX);
3936+#endif
3937+ void GetHash(UINT_8* puDest);
3938+
3939+private:
3940+ // Private SHA-1 transformation
3941+ void Transform(UINT_32* state, UINT_8* buffer);
3942+
3943+ // Member variables
3944+ UINT_8 m_workspace[64];
3945+ SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above
3946+};
3947+
3948+#endif
3949
3950=== added file 'common/SetupInfo.cpp'
3951--- common/SetupInfo.cpp 1970-01-01 00:00:00 +0000
3952+++ common/SetupInfo.cpp 2011-11-23 01:01:25 +0000
3953@@ -0,0 +1,512 @@
3954+////////////////////////////////////////////////////////////////////////////////
3955+// Copyright (c) CitizenLab, 2006. All Rights Reserved.
3956+// The latest version of this code is available at http://psiphon.civisec.org/
3957+//
3958+// This software is open source; you can redistribute it and/or modify it
3959+// under the terms of the GNU General Public License as published by the
3960+// Free Software Foundation; either version 2 of the License, or (at your
3961+// option) any later version.
3962+//
3963+// This program is distributed WITHOUT ANY WARRANTY; without even the
3964+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
3965+// See the GNU General Public License for more details at:
3966+// http://psiphon.civisec.org/
3967+//
3968+// This General Public License does NOT permit incorporating this software
3969+// into proprietary programs.
3970+////////////////////////////////////////////////////////////////////////////////
3971+
3972+#include "SetupInfo.h"
3973+#include <stdio.h>
3974+#include <string.h>
3975+#include <stdlib.h>
3976+#include "strfunc.h"
3977+#include <sys/stat.h>
3978+
3979+#define SETUP_FUNC "psiphon.cnf"
3980+
3981+#define _T(X) X
3982+
3983+CSetupInfo g_info;
3984+
3985+CSetupInfo::CSetupInfo()
3986+{
3987+ Init();
3988+}
3989+
3990+CSetupInfo::CSetupInfo(const char* sIn)
3991+{
3992+ Init();
3993+ Parse(sIn);
3994+}
3995+
3996+CSetupInfo::~CSetupInfo()
3997+{
3998+ delete m_sIP;
3999+ delete m_sName;
4000+ delete m_Common;
4001+ delete m_Country;
4002+ delete m_State;
4003+ delete m_Email;
4004+ delete m_Unit;
4005+ delete m_Organization;
4006+ delete m_sIPServer;
4007+ delete m_sFinger;
4008+}
4009+
4010+void CSetupInfo::Init()
4011+{
4012+ m_sIP = strdup(_T("127.0.0.1"));
4013+ m_nPort = 443;
4014+ m_nShowImages = 1;
4015+ m_nAutoUpdateIP = 1;
4016+ m_nTestPort = 1;
4017+ m_nStartOnStartUp = 0;
4018+ m_sName = NULL;
4019+ m_nCheckForUpdatesOnStartUp = 1;
4020+ m_Common = strdup(_T("somename.somewhere.com"));
4021+ m_Country = strdup(_T("US"));
4022+ m_State = strdup(_T("Some State"));
4023+ m_Email = strdup(_T("root@somename.somewhere.com"));
4024+ m_Unit = strdup(_T("My Subunit of Large Organization"));
4025+ m_Organization = strdup(_T("My Large Organization Name"));
4026+ m_nRegenrateOnStartUp = 0;
4027+ m_nLogLevel = 0;
4028+ m_sIPServer = strdup(_T("http://psiphon.civisec.org/ip.php"));
4029+ m_sFinger = NULL;
4030+}
4031+
4032+void CSetupInfo::Out(char*& sOut)
4033+{
4034+ char FORMAT[] = _T("%s\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%d\t%d\t%s");
4035+
4036+ int nSize = GetStrLength(FORMAT)
4037+ + GetStrLength(m_sIP)
4038+ + GetStrLength(m_nPort)
4039+ + GetStrLength(m_nShowImages)
4040+ + GetStrLength(m_nAutoUpdateIP)
4041+ + GetStrLength(m_nTestPort)
4042+ + GetStrLength(m_nStartOnStartUp)
4043+ + GetStrLength(m_sName)
4044+ + GetStrLength(m_nCheckForUpdatesOnStartUp)
4045+ + GetStrLength(m_Common)
4046+ + GetStrLength(m_Country)
4047+ + GetStrLength(m_State)
4048+ + GetStrLength(m_Email)
4049+ + GetStrLength(m_Organization)
4050+ + GetStrLength(m_Unit)
4051+ + GetStrLength(m_nRegenrateOnStartUp)
4052+ + GetStrLength(m_nLogLevel)
4053+ + GetStrLength(m_sIPServer);
4054+
4055+ sOut = new char[nSize];
4056+
4057+ int nLen = _snprintf(sOut, nSize, FORMAT
4058+ , m_sIP
4059+ , m_nPort
4060+ , m_nShowImages
4061+ , m_nAutoUpdateIP
4062+ , m_nTestPort
4063+ , m_nStartOnStartUp
4064+ , m_sName
4065+ , m_nCheckForUpdatesOnStartUp
4066+ , m_Common
4067+ , m_Country
4068+ , m_State
4069+ , m_Email
4070+ , m_Organization
4071+ , m_Unit
4072+ , m_nRegenrateOnStartUp
4073+ , m_nLogLevel
4074+ , m_sIPServer);
4075+
4076+ if(nLen <= 0 || nLen >= nSize)
4077+ {
4078+ delete sOut;
4079+ sOut = NULL;
4080+ }
4081+}
4082+
4083+void CSetupInfo::Parse(const char* sIn)
4084+{
4085+ if(!sIn || !*sIn)
4086+ return;
4087+
4088+ char* _sIn = strdup(sIn);
4089+
4090+ char seps[] = _T("\t");
4091+ char* token = strtok(_sIn, seps);
4092+
4093+ if(!token)
4094+ return;
4095+
4096+ if(strcmp(token, _T("NULL")) != 0)
4097+ SetIP(token);
4098+
4099+ token = strtok(NULL, seps);
4100+ if(!token)
4101+ {
4102+ delete _sIn;
4103+ return;
4104+ }
4105+ SetPort(atoi(token));
4106+
4107+ token = strtok(NULL, seps);
4108+ if(!token)
4109+ {
4110+ delete _sIn;
4111+ return;
4112+ }
4113+ SetShowImages(atoi(token));
4114+
4115+ token = strtok(NULL, seps);
4116+ if(!token)
4117+ {
4118+ delete _sIn;
4119+ return;
4120+ }
4121+ SetAutoUpdateIP(atoi(token));
4122+
4123+ token = strtok(NULL, seps);
4124+ if(!token)
4125+ {
4126+ delete _sIn;
4127+ return;
4128+ }
4129+ SetTestPort(atoi(token));
4130+
4131+ token = strtok(NULL, seps);
4132+ if(!token)
4133+ {
4134+ delete _sIn;
4135+ return;
4136+ }
4137+ SetStartOnStartUp(atoi(token));
4138+
4139+ token = strtok(NULL, seps);
4140+ if(!token)
4141+ {
4142+ delete _sIn;
4143+ return;
4144+ }
4145+ SetName(token);
4146+
4147+ token = strtok(NULL, seps);
4148+ if(!token)
4149+ {
4150+ delete _sIn;
4151+ return;
4152+ }
4153+ SetCheckForUpdatesOnStartUp(atoi(token));
4154+
4155+ token = strtok(NULL, seps);
4156+ if(!token)
4157+ {
4158+ delete _sIn;
4159+ return;
4160+ }
4161+ SetCommon(token);
4162+
4163+ token = strtok(NULL, seps);
4164+ if(!token)
4165+ {
4166+ delete _sIn;
4167+ return;
4168+ }
4169+ SetCountry(token);
4170+
4171+ token = strtok(NULL, seps);
4172+ if(!token)
4173+ {
4174+ delete _sIn;
4175+ return;
4176+ }
4177+ SetState(token);
4178+
4179+ token = strtok(NULL, seps);
4180+ if(!token)
4181+ {
4182+ delete _sIn;
4183+ return;
4184+ }
4185+ SetEmail(token);
4186+
4187+ token = strtok(NULL, seps);
4188+ if(!token)
4189+ {
4190+ delete _sIn;
4191+ return;
4192+ }
4193+ SetOrganization(token);
4194+
4195+ token = strtok(NULL, seps);
4196+ if(!token)
4197+ {
4198+ delete _sIn;
4199+ return;
4200+ }
4201+ SetUnit(token);
4202+
4203+ token = strtok(NULL, seps);
4204+ if(!token)
4205+ {
4206+ delete _sIn;
4207+ return;
4208+ }
4209+ SetRegenrateOnStartUp(atoi(token));
4210+
4211+ token = strtok(NULL, seps);
4212+ if(!token)
4213+ {
4214+ delete _sIn;
4215+ return;
4216+ }
4217+ SetLogLevel(atoi(token));
4218+
4219+ token = strtok(NULL, seps);
4220+ if(!token)
4221+ {
4222+ delete _sIn;
4223+ return;
4224+ }
4225+ SetIPServer(token);
4226+
4227+ delete _sIn;
4228+}
4229+
4230+bool CSetupInfo::Store()
4231+{
4232+ FILE* pFile = fopen(SETUP_FUNC, _T("w"));
4233+ if(pFile == NULL)
4234+ return false;
4235+
4236+ char* pOut = NULL;
4237+ Out(pOut);
4238+ if(pOut == NULL)
4239+ return false;
4240+
4241+ fwrite(pOut, sizeof(char), strlen(pOut), pFile);
4242+
4243+ delete pOut;
4244+
4245+ fclose(pFile);
4246+
4247+ return true;
4248+}
4249+
4250+void CSetupInfo::Load()
4251+{
4252+ struct stat results;
4253+ if(stat(SETUP_FUNC, &results) != 0)
4254+ return;
4255+
4256+ FILE* pFile = fopen(SETUP_FUNC, _T("r"));
4257+ if(pFile == NULL)
4258+ return;
4259+
4260+ int nSize = results.st_size/sizeof(char) + 1;
4261+
4262+ char* pIn = new char[nSize];
4263+ memset(pIn, 0, nSize * sizeof(char));
4264+
4265+ fread(pIn, sizeof(char), nSize, pFile);
4266+
4267+ pIn[nSize - 1] = 0;
4268+
4269+ Parse(pIn);
4270+
4271+ delete pIn;
4272+
4273+ fclose(pFile);
4274+}
4275+
4276+char* CSetupInfo::GetIP()
4277+{
4278+ return m_sIP;
4279+}
4280+
4281+void CSetupInfo::SetIP(const char* _sIP)
4282+{
4283+ delete m_sIP;
4284+ m_sIP = strdup(_sIP);
4285+}
4286+
4287+int CSetupInfo::GetPort()
4288+{
4289+ return m_nPort;
4290+}
4291+
4292+void CSetupInfo::SetPort(int _nPort)
4293+{
4294+ m_nPort = _nPort;
4295+}
4296+
4297+int CSetupInfo::GetShowImages()
4298+{
4299+ return m_nShowImages;
4300+}
4301+
4302+void CSetupInfo::SetShowImages(int _nShowImages)
4303+{
4304+ m_nShowImages = _nShowImages;
4305+}
4306+
4307+int CSetupInfo::GetAutoUpdateIP()
4308+{
4309+ return m_nAutoUpdateIP;
4310+}
4311+
4312+void CSetupInfo::SetAutoUpdateIP(int _nAutoUpdateIP)
4313+{
4314+ m_nAutoUpdateIP = _nAutoUpdateIP;
4315+}
4316+
4317+int CSetupInfo::GetTestPort()
4318+{
4319+ return m_nTestPort;
4320+}
4321+
4322+void CSetupInfo::SetTestPort(int _nTestPort)
4323+{
4324+ m_nTestPort = _nTestPort;
4325+}
4326+
4327+int CSetupInfo::GetStartOnStartUp()
4328+{
4329+ return m_nStartOnStartUp;
4330+}
4331+
4332+void CSetupInfo::SetStartOnStartUp(int _nStartOnStartUp)
4333+{
4334+ m_nStartOnStartUp = _nStartOnStartUp;
4335+}
4336+
4337+char* CSetupInfo::GetName()
4338+{
4339+ return m_sName;
4340+}
4341+
4342+void CSetupInfo::SetName(const char* _sName)
4343+{
4344+ delete m_sName;
4345+ m_sName = strdup(_sName);
4346+}
4347+
4348+int CSetupInfo::GetCheckForUpdatesOnStartUp()
4349+{
4350+ return m_nCheckForUpdatesOnStartUp;
4351+}
4352+
4353+void CSetupInfo::SetCheckForUpdatesOnStartUp(int _nCheckForUpdatesOnStartUp)
4354+{
4355+ m_nCheckForUpdatesOnStartUp = _nCheckForUpdatesOnStartUp;
4356+}
4357+
4358+void CSetupInfo::SetCommon(const char* _Common)
4359+{
4360+ delete m_Common;
4361+ m_Common = strdup(_Common);
4362+}
4363+
4364+void CSetupInfo::SetUnit(const char* _Unit)
4365+{
4366+ delete m_Unit;
4367+ m_Unit = strdup(_Unit);
4368+}
4369+
4370+void CSetupInfo::SetOrganization(const char* _Organization)
4371+{
4372+ delete m_Organization;
4373+ m_Organization = strdup(_Organization);
4374+}
4375+
4376+void CSetupInfo::SetEmail(const char* _Email)
4377+{
4378+ delete m_Email;
4379+ m_Email = strdup(_Email);
4380+}
4381+
4382+void CSetupInfo::SetCountry(const char* _Country)
4383+{
4384+ delete m_Country;
4385+ m_Country = strdup(_Country);
4386+}
4387+
4388+void CSetupInfo::SetState(const char* _State)
4389+{
4390+ delete m_State;
4391+ m_State = strdup(_State);
4392+}
4393+
4394+void CSetupInfo::SetRegenrateOnStartUp(int _nRegenrateOnStartUp)
4395+{
4396+ m_nRegenrateOnStartUp = _nRegenrateOnStartUp;
4397+}
4398+
4399+char* CSetupInfo::GetCommon()
4400+{
4401+ return m_Common;
4402+}
4403+
4404+char* CSetupInfo::GetUnit()
4405+{
4406+ return m_Unit;
4407+}
4408+
4409+char* CSetupInfo::GetOrganization()
4410+{
4411+ return m_Organization;
4412+}
4413+
4414+char* CSetupInfo::GetEmail()
4415+{
4416+ return m_Email;
4417+}
4418+
4419+char* CSetupInfo::GetCountry()
4420+{
4421+ return m_Country;
4422+}
4423+
4424+char* CSetupInfo::GetState()
4425+{
4426+ return m_State;
4427+}
4428+
4429+int CSetupInfo::GetRegenrateOnStartUp()
4430+{
4431+ return m_nRegenrateOnStartUp;
4432+}
4433+
4434+int CSetupInfo::GetLogLevel()
4435+{
4436+ return m_nLogLevel;
4437+}
4438+
4439+void CSetupInfo::SetLogLevel(int _nLogLevel)
4440+{
4441+ m_nLogLevel = _nLogLevel;
4442+}
4443+
4444+char* CSetupInfo::GetIPServer()
4445+{
4446+ return m_sIPServer;
4447+}
4448+
4449+void CSetupInfo::SetIPServer(const char* _sIPServer)
4450+{
4451+ delete m_sIPServer;
4452+ m_sIPServer = strdup(_sIPServer);
4453+}
4454+
4455+char* CSetupInfo::GetFinger()
4456+{
4457+ return m_sFinger;
4458+}
4459+
4460+void CSetupInfo::SetFinger(const char* _sFinger)
4461+{
4462+ delete m_sFinger;
4463+ m_sFinger = strdup(_sFinger);
4464+}
4465+
4466
4467=== added file 'common/SetupInfo.h'
4468--- common/SetupInfo.h 1970-01-01 00:00:00 +0000
4469+++ common/SetupInfo.h 2011-11-23 01:01:25 +0000
4470@@ -0,0 +1,110 @@
4471+////////////////////////////////////////////////////////////////////////////////
4472+// Copyright (c) CitizenLab, 2006. All Rights Reserved.
4473+// The latest version of this code is available at http://psiphon.civisec.org/
4474+//
4475+// This software is open source; you can redistribute it and/or modify it
4476+// under the terms of the GNU General Public License as published by the
4477+// Free Software Foundation; either version 2 of the License, or (at your
4478+// option) any later version.
4479+//
4480+// This program is distributed WITHOUT ANY WARRANTY; without even the
4481+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
4482+// See the GNU General Public License for more details at:
4483+// http://psiphon.civisec.org/
4484+//
4485+// This General Public License does NOT permit incorporating this software
4486+// into proprietary programs.
4487+////////////////////////////////////////////////////////////////////////////////
4488+
4489+#pragma once
4490+
4491+class CSetupInfo
4492+{
4493+ char* m_sIP;
4494+ int m_nPort;
4495+ int m_nShowImages;
4496+ int m_nAutoUpdateIP;
4497+ int m_nTestPort;
4498+ int m_nStartOnStartUp;
4499+ char* m_sName;
4500+ int m_nCheckForUpdatesOnStartUp;
4501+
4502+ char* m_Common;
4503+ char* m_Unit;
4504+ char* m_Organization;
4505+ char* m_Email;
4506+ char* m_Country;
4507+ char* m_State;
4508+ int m_nRegenrateOnStartUp;
4509+ int m_nLogLevel;
4510+ char* m_sIPServer;
4511+ char* m_sFinger;
4512+
4513+public:
4514+ CSetupInfo();
4515+
4516+ CSetupInfo(const char* sIn);
4517+ ~CSetupInfo();
4518+
4519+public:
4520+ char* GetIP();
4521+ void SetIP(const char* _sIP);
4522+
4523+ int GetShowImages();
4524+ void SetShowImages(int _nShowImages);
4525+
4526+ int GetPort();
4527+ void SetPort(int _nPort);
4528+
4529+ int GetAutoUpdateIP();
4530+ void SetAutoUpdateIP(int _nAutoUpdateIP);
4531+
4532+ int GetTestPort();
4533+ void SetTestPort(int _nTestPort);
4534+
4535+ int GetStartOnStartUp();
4536+ void SetStartOnStartUp(int _nStartOnStartUp);
4537+
4538+ char* GetName();
4539+ void SetName(const char* _sName);
4540+
4541+ int GetCheckForUpdatesOnStartUp();
4542+ void SetCheckForUpdatesOnStartUp(int _nCheckForUpdatesOnStartUp);
4543+
4544+ bool Store();
4545+ void Load();
4546+
4547+ void SetCommon(const char* _Common);
4548+ void SetUnit(const char* _Unit);
4549+ void SetOrganization(const char* _Organization);
4550+ void SetEmail(const char* _Email);
4551+ void SetCountry(const char* _Country);
4552+ void SetState(const char* _State);
4553+ void SetRegenrateOnStartUp(int _nRegenrateOnStartUp);
4554+
4555+ char* GetCommon();
4556+ char* GetUnit();
4557+ char* GetOrganization();
4558+ char* GetEmail();
4559+ char* GetCountry();
4560+ char* GetState();
4561+ int GetRegenrateOnStartUp();
4562+
4563+ int GetLogLevel();
4564+ void SetLogLevel(int _nLogLevel);
4565+
4566+ char* GetIPServer();
4567+ void SetIPServer(const char* pIPServer);
4568+
4569+ char* GetFinger();
4570+ void SetFinger(const char* pFinger);
4571+
4572+protected:
4573+ void Init();
4574+ void Out(char*& sOut);
4575+
4576+ void Parse(const char* sIn);
4577+};
4578+
4579+extern CSetupInfo g_info;
4580+
4581
4582=== added file 'common/User.cpp'
4583--- common/User.cpp 1970-01-01 00:00:00 +0000
4584+++ common/User.cpp 2011-11-23 01:01:25 +0000
4585@@ -0,0 +1,598 @@
4586+////////////////////////////////////////////////////////////////////////////////
4587+// Copyright (c) CitizenLab, 2006. All Rights Reserved.
4588+// The latest version of this code is available at http://psiphon.civisec.org/
4589+//
4590+// This software is open source; you can redistribute it and/or modify it
4591+// under the terms of the GNU General Public License as published by the
4592+// Free Software Foundation; either version 2 of the License, or (at your
4593+// option) any later version.
4594+//
4595+// This program is distributed WITHOUT ANY WARRANTY; without even the
4596+// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
4597+// See the GNU General Public License for more details at:
4598+// http://psiphon.civisec.org/
4599+//
4600+// This General Public License does NOT permit incorporating this software
4601+// into proprietary programs.
4602+////////////////////////////////////////////////////////////////////////////////
4603+
4604+#include "convert.h"
4605+#include "CppSQLite3.h"
4606+#include "User.h"
4607+#include "SHA1.h"
4608+#include "strfunc.h"
4609+
4610+#define _T(X) X
4611+
4612+void escape(char* pDest, int nSize, const char* pSrc);
4613+
4614+char* CDBUser::m_sDB = _T("users.db");
4615+
4616+LOG_ROUTINE CDBUser::m_pLogFunc = NULL;
4617+
4618+CDBUser::CDBUser()
4619+{
4620+ Init();
4621+}
4622+
4623+CDBUser::~CDBUser()
4624+{
4625+ Cleanup();
4626+}
4627+
4628+void CDBUser::Init()
4629+{
4630+ m_sUserName = NULL;
4631+ m_sPassword = NULL;
4632+ m_sEmail = NULL;
4633+ m_sFullName = NULL;
4634+
4635+ m_nID = 0;
4636+ m_nDeleted = false;
4637+
4638+ m_nLastAccess = 0;
4639+ m_nWritten = 0;
4640+ m_nRead = 0;
4641+ m_nWriteTime = 0;
4642+ m_nReadTime = 0;
4643+}
4644+
4645+void CDBUser::Cleanup()
4646+{
4647+ delete m_sUserName;
4648+ delete m_sPassword;
4649+ delete m_sEmail;
4650+ delete m_sFullName;
4651+
4652+ Init();
4653+}
4654+
4655+int CDBUser::Get(int nUserID)
4656+{
4657+ if(nUserID <= 0)
4658+ return -1;
4659+
4660+ try
4661+ {
4662+ CppSQLite3DB db;
4663+ db.Open(m_sDB);
4664+
4665+ if(!db.tableExists(_T("users")))
4666+ return false;
4667+
4668+ CppSQLite3Statement stmt = db.compileStatement(_T("select nIndex, sUsername, sPassword, sEmail, sFullname from users where nIndex = ?;"));
4669+
4670+ stmt.bind(1, nUserID);
4671+
4672+ CppSQLite3Query q = stmt.execQuery();
4673+
4674+ if(!q.eof())
4675+ {
4676+ SetID(q.getIntField(0));
4677+
4678+ CConverter wUsername(q.fieldValue(1));
4679+ SetUsername(wUsername);
4680+
4681+ CConverter wPassword(q.fieldValue(2));
4682+ SetPassword(wPassword);
4683+
4684+ CConverter wEmail(q.fieldValue(3));
4685+ SetEmail(wEmail);
4686+
4687+ CConverter wFullName(q.fieldValue(4));
4688+ SetFullName(wFullName);
4689+
4690+ q.nextRow();
4691+
4692+ return 0;
4693+ }
4694+ }
4695+ catch(CppSQLite3Exception& e)
4696+ {
4697+ CConverter wMsg(e.errorMessage());
4698+ CDBUser::Log(wMsg);
4699+ }
4700+
4701+ return -1;
4702+}
4703+
4704+int CDBUser::FindUser(const char* pUserName, const char* pPassword)
4705+{
4706+ if(!pUserName || strlen(pUserName) > 100)
4707+ return -1;
4708+
4709+ if(!pPassword || strlen(pPassword) > 64)
4710+ return -1;
4711+
4712+ try
4713+ {
4714+ CppSQLite3DB db;
4715+ db.Open(m_sDB);
4716+
4717+ if(!db.tableExists(_T("users")))
4718+ return -1;
4719+
4720+ CppSQLite3Statement stmt = db.compileStatement(_T("select nIndex from users where sUsername=? and sPassword=? and nDeleted != 1;"));
4721+
4722+ stmt.bind(1, pUserName);
4723+ stmt.bind(2, pPassword);
4724+
4725+ CppSQLite3Query q = stmt.execQuery();
4726+
4727+ if(!q.eof())
4728+ {
4729+ return (q.getIntField(0));
4730+ }
4731+ }
4732+ catch(CppSQLite3Exception& e)
4733+ {
4734+ CConverter wMsg(e.errorMessage());
4735+ CDBUser::Log(wMsg);
4736+ }
4737+
4738+ return -1;
4739+}
4740+
4741+int CDBUser::FindUsername(const char* pUserName)
4742+{
4743+ if(!pUserName || strlen(pUserName) > 100)
4744+ return -1;
4745+
4746+ try
4747+ {
4748+ CppSQLite3DB db;
4749+ db.Open(m_sDB);
4750+
4751+ if(!db.tableExists(_T("users")))
4752+ return -1;
4753+
4754+
4755+ CppSQLite3Statement stmt = db.compileStatement(_T("select nIndex from users where sUsername=?;"));
4756+
4757+ stmt.bind(1, pUserName);
4758+
4759+ CppSQLite3Query q = stmt.execQuery();
4760+
4761+ if(!q.eof())
4762+ {
4763+ return (q.getIntField(0));
4764+ }
4765+ }
4766+ catch(CppSQLite3Exception& e)
4767+ {
4768+ CConverter wMsg(e.errorMessage());
4769+ CDBUser::Log(wMsg);
4770+ }
4771+
4772+ return -1;
4773+}
4774+
4775+int CDBUser::Insert()
4776+{
4777+ if(!m_sUserName || strlen(m_sUserName) > 100)
4778+ return -1;
4779+
4780+ if(!m_sPassword || strlen(m_sPassword) > 64)
4781+ return -1;
4782+
4783+ if(!m_sEmail || strlen(m_sEmail) > 100)
4784+ return -1;
4785+
4786+ if(!m_sFullName || strlen(m_sFullName) > 100)
4787+ return -1;
4788+ try
4789+ {
4790+ CppSQLite3DB db;
4791+ db.Open(m_sDB);
4792+
4793+ if(!db.tableExists(_T("users")))
4794+ {
4795+ db.execDML(_T("create table users(nIndex integer primary key, sUsername char(100), sPassword char(64), sEmail char(100), sFullname char(100), nDeleted int);"));
4796+ }
4797+
4798+ CppSQLite3Statement stmt = db.compileStatement(_T("insert into users (sUsername, sPassword, sEmail, sFullname, nDeleted)"
4799+ " values (?, ?, ?, ?, ?);"));
4800+
4801+ stmt.bind(1, m_sUserName);
4802+ stmt.bind(2, m_sPassword);
4803+ stmt.bind(3, m_sEmail);
4804+ stmt.bind(4, m_sFullName);
4805+ stmt.bind(5, m_nDeleted);
4806+
4807+
4808+ int nRows = stmt.execDML();
4809+
4810+ m_nID = (int)db.lastRowId();
4811+
4812+ return nRows;
4813+ }
4814+ catch(CppSQLite3Exception& e)
4815+ {
4816+ CConverter wMsg(e.errorMessage());
4817+ CDBUser::Log(wMsg);
4818+ }
4819+
4820+ return -1;
4821+}
4822+
4823+int CDBUser::Update()
4824+{
4825+ if(m_nID <= 0)
4826+ return -1;
4827+
4828+ if(!m_sPassword || strlen(m_sPassword) > 64)
4829+ return -1;
4830+
4831+ if(!m_sEmail || strlen(m_sEmail) > 100)
4832+ return -1;
4833+
4834+ if(!m_sFullName || strlen(m_sFullName) > 100)
4835+ return -1;
4836+
4837+ try
4838+ {
4839+ CppSQLite3DB db;
4840+ db.Open(m_sDB);
4841+
4842+ if(!db.tableExists("users"))
4843+ return -1;
4844+
4845+ CppSQLite3Statement stmt;
4846+
4847+ if(strlen(m_sPassword) > 0)
4848+ {
4849+ stmt = db.compileStatement(_T("update users set sPassword=?, sEmail=?, sFullname=? where nIndex=?;"));
4850+ stmt.bind(1, m_sPassword);
4851+ stmt.bind(2, m_sEmail);
4852+ stmt.bind(3, m_sFullName);
4853+ stmt.bind(4, m_nID);
4854+ }
4855+ else
4856+ {
4857+ stmt = db.compileStatement(_T("update users set sEmail=?, sFullname=? where nIndex=?;"));
4858+ stmt.bind(1, m_sEmail);
4859+ stmt.bind(2, m_sFullName);
4860+ stmt.bind(3, m_nID);
4861+ }
4862+
4863+ int nRows = stmt.execDML();
4864+ return nRows;
4865+ }
4866+ catch(CppSQLite3Exception& e)
4867+ {
4868+ CConverter wMsg(e.errorMessage());
4869+ CDBUser::Log(wMsg);
4870+ }
4871+
4872+ return -1;
4873+}
4874+
4875+void CDBUser::EncryptPassword(char* pKey, int nKeySize, const char* _pUsername, const char* _pPassword)
4876+{
4877+ if(!pKey)
4878+ return;
4879+
4880+ if(nKeySize == 0)
4881+ return;
4882+
4883+ if(!_pUsername || strlen(_pUsername) > 100)
4884+ return;
4885+ if(!_pPassword || strlen(_pPassword) > 64)
4886+ return;
4887+
4888+ CSHA1 sha1;
4889+
4890+ CConverter aUsername(_pUsername);
4891+ CConverter aPassword(_pPassword);
4892+
4893+ sha1.Update((UINT_8*)(char*)(const char*)aUsername, strlen(aUsername));
4894+ sha1.Update((UINT_8*)(char*)(const char*)aPassword, strlen(aPassword));
4895+ sha1.Final();
4896+
4897+ char* aKey = new char[nKeySize];
4898+ memset(aKey, 0, nKeySize * sizeof(char));
4899+ sha1.ReportHash(aKey, CSHA1::REPORT_HEX);
4900+
4901+ CConverter _pKey(aKey);
4902+ strncpy(pKey, _pKey, nKeySize);
4903+
4904+ delete aKey;
4905+}
4906+
4907+int CDBUser::Delete(int nUserID)
4908+{
4909+ if(nUserID <= 0)
4910+ return -1;
4911+
4912+ try
4913+ {
4914+ CppSQLite3DB db;
4915+ db.Open(m_sDB);
4916+
4917+ if(!db.tableExists(_T("users")))
4918+ return false;
4919+
4920+ CppSQLite3Statement stmt = db.compileStatement(_T("update users set nDeleted=1 where nIndex=?;"));
4921+ stmt.bind(1, nUserID);
4922+ stmt.execDML();
4923+
4924+ return 0;
4925+ }
4926+ catch(CppSQLite3Exception& e)
4927+ {
4928+ CConverter wMsg(e.errorMessage());
4929+ CDBUser::Log(wMsg);
4930+ }
4931+
4932+ return -1;
4933+}
4934+
4935+int CDBUser::GetUserCount()
4936+{
4937+ try
4938+ {
4939+ CppSQLite3DB db;
4940+ db.Open(m_sDB);
4941+
4942+ if(!db.tableExists(_T("users")))
4943+ return 0;
4944+
4945+ int nRet = db.execScalar(_T("select count(*) from users where nDeleted = 0"));
4946+
4947+ return nRet;
4948+ }
4949+ catch(CppSQLite3Exception& e)
4950+ {
4951+ CConverter wMsg(e.errorMessage());
4952+ CDBUser::Log(wMsg);
4953+ }
4954+
4955+ return -1;
4956+}
4957+
4958+int CDBUser::LoadUsers(CDBUser**& pUsers)
4959+{
4960+ int nUserCount = GetUserCount();
4961+ if(nUserCount <= 0)
4962+ return 0;
4963+
4964+ pUsers = new CDBUser * [nUserCount];
4965+
4966+ try
4967+ {
4968+ CppSQLite3DB db;
4969+ db.Open(m_sDB);
4970+
4971+ if(!db.tableExists(_T("users")))
4972+ return 0;
4973+
4974+ CppSQLite3Query q = db.execQuery(_T("select * from users where nDeleted = 0;"));
4975+
4976+ int i = 0;
4977+
4978+ while(!q.eof())
4979+ {
4980+ CDBUser* pUser = new CDBUser;
4981+
4982+ pUser->SetID(q.getIntField(0));
4983+
4984+ CConverter wUsername(q.fieldValue(1));
4985+ pUser->SetUsername(wUsername);
4986+
4987+ CConverter wPassword(q.fieldValue(2));
4988+ pUser->SetPassword(wPassword);
4989+
4990+ CConverter wEmail(q.fieldValue(3));
4991+ pUser->SetEmail(wEmail);
4992+
4993+ CConverter wFullName(q.fieldValue(4));
4994+ pUser->SetFullName(wFullName);
4995+
4996+ pUsers[i++] = pUser;
4997+
4998+ q.nextRow();
4999+ }
5000+
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches