Index: src/airodump-ng.c
===================================================================
--- src/airodump-ng.c	(revisione 2005)
+++ src/airodump-ng.c	(copia locale)
@@ -69,6 +69,9 @@
 #include "osdep/common.h"
 #include "common.h"
 
+extern char * getStringTimeFromSec(double seconds);
+
+
 void dump_sort( void );
 void dump_print( int ws_row, int ws_col, int if_num );
 
@@ -2648,49 +2651,7 @@
 	return get_battery_state();
 }
 
-char * getStringTimeFromSec(double seconds)
-{
-    int hour[3];
-    char * ret;
-    char * HourTime;
-    char * MinTime;
 
-    if (seconds <0)
-        return NULL;
-
-    ret = (char *) calloc(1,256);
-
-    HourTime = (char *) calloc (1,128);
-    MinTime  = (char *) calloc (1,128);
-
-    hour[0]  = (int) (seconds);
-    hour[1]  = hour[0] / 60;
-    hour[2]  = hour[1] / 60;
-    hour[0] %= 60 ;
-    hour[1] %= 60 ;
-
-    if (hour[2] != 0 )
-        snprintf(HourTime, 128, "%d %s", hour[2], ( hour[2] == 1 ) ? "hour" : "hours");
-    if (hour[1] != 0 )
-        snprintf(MinTime, 128, "%d %s", hour[1], ( hour[1] == 1 ) ? "min" : "mins");
-
-    if ( hour[2] != 0 && hour[1] != 0 )
-        snprintf(ret, 256, "%s %s", HourTime, MinTime);
-    else
-    {
-        if (hour[2] == 0 && hour[1] == 0)
-            snprintf(ret, 256, "%d s", hour[0] );
-        else
-            snprintf(ret, 256, "%s", (hour[2] == 0) ? MinTime : HourTime );
-    }
-
-    free(MinTime);
-    free(HourTime);
-
-    return ret;
-
-}
-
 char * getBatteryString(void)
 {
     int batt_time;
Index: src/airolib-ng.c
===================================================================
--- src/airolib-ng.c	(revisione 2005)
+++ src/airolib-ng.c	(copia locale)
@@ -43,6 +43,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <getopt.h>
+#include <pthread.h>
 
 
 #include "aircrack-ng.h"
@@ -57,7 +58,27 @@
 #define IMPORT_COWPATTY "cowpatty"
 
 extern char * getVersion(char * progname, int maj, int min, int submin, int svnrev, int beta, int rc);
+extern int get_nb_cpus();
+extern char * getStringTimeFromSec(double seconds);
 
+struct BatchParam
+{
+    sqlite3* db;
+    int threadID;
+} BatchParam;
+
+struct BatchThreadStats
+{
+    int known;
+    int pmkPerSec;
+};
+
+int firstBTSPrint = 1;
+int cpu_count = 1;
+struct BatchThreadStats bts[MAX_THREADS] = {{0,0}};
+pthread_mutex_t mx_batch_print = PTHREAD_MUTEX_INITIALIZER;
+pthread_mutex_t mx_database = PTHREAD_MUTEX_INITIALIZER;
+
 void print_help(const char * msg) {
 	printf("\n"
 		"  %s - (C) 2007, 2008, 2009 ebfe\n"
@@ -110,7 +131,7 @@
 	while (1) {
 		rc = sqlite3_exec(db,sql,callback,cb_arg,&zErrMsg);
 		if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
-			fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c    \r",++waited, looper[looperc++ % sizeof(looper)]);
+			fprintf(stdout,"\r\033[KDatabase is %s. Waiting %is ... %1c    ",(rc == SQLITE_LOCKED ? "locked" : "busy"), ++waited, looper[looperc++ % sizeof(looper)]);
 			fflush(stdout);
 			sleep(1);
 		} else {
@@ -118,7 +139,6 @@
 				fprintf(stderr, "SQL error. %s\n", zErrMsg);
 				sqlite3_free(zErrMsg);
 			}
-			if (waited != 0) printf("\n\n");
 			return rc;
 		}
 	}
@@ -139,17 +159,16 @@
 		rc = sqlite3_step(stmt);
 		if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
 			if (wait != 0) {
-				fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c    \r",++waited, looper[looperc]);
+				fprintf(stdout,"\r\033[KDatabase is locked or busy. Waiting %is ... %1c",++waited, looper[looperc]);
 				fflush(stdout);
 				wait--;
 				looperc = looperc+1 % sizeof(looper);
 				sleep(1);
 			} else {
-				fprintf(stderr,"Database was locked or busy while getting results. I've given up.\n");
+				fprintf(stderr,"\r\033[KDatabase was locked or busy while getting results. I've given up.\n");
 				return rc;
 			}
 		} else {
-			if (waited != 0) printf("\n\n");
 			return rc;
 		}
 	}
@@ -170,17 +189,16 @@
 		rc = sqlite3_prepare_v2(db,sql,-1,ppStmt,NULL);
 		if (rc == SQLITE_LOCKED || rc == SQLITE_BUSY) {
 			if (wait != 0) {
-				fprintf(stdout,"Database is locked or busy. Waiting %is ... %1c    \r", ++waited, looper[looperc]);
+				fprintf(stdout,"\r\033[KDatabase is locked or busy. Waiting %is ... %1c", ++waited, looper[looperc]);
 				fflush(stdout);
 				wait--;
 				looperc = looperc+1 % sizeof(looper);
 				sleep(1);
 			} else {
-				fprintf(stderr,"Database was locked or busy while creating statement. I've given up.\n");
+				fprintf(stderr,"\r\033[KDatabase was locked or busy while creating statement. I've given up.\n");
 				return rc;
 			}
 		} else {
-			if (waited != 0) printf("\n\n");
 			return rc;
 		}
 	}
@@ -217,6 +235,38 @@
 	return rc;
 }
 
+// Verify an ESSID. Returns 1 if ESSID is invalid.
+//TODO More things to verify? Invalid chars?
+int verify_essid(char* essid) {
+	return essid == NULL || strlen(essid) < 1 || strlen(essid) > 32;
+}
+
+// sql function which checks a given ESSID
+void sql_verify_essid(sqlite3_context* context, int argc, sqlite3_value** values) {
+	char* essid = (char*)sqlite3_value_text(values[0]);
+	if (argc != 1 || essid == 0) {
+		fprintf(stderr,"SQL function VERIFY_ESSID called with invalid arguments");
+		return;
+	}
+	sqlite3_result_int(context,verify_essid(essid));
+}
+
+int verify_passwd(char* passwd) {
+	return passwd == NULL || strlen(passwd) < 8 || strlen(passwd) > 63;
+}
+
+void sql_verify_passwd(sqlite3_context* context, int argc, sqlite3_value** values) {
+	char* passwd = (char*)sqlite3_value_text(values[0]);
+	if (argc != 1 || passwd == 0) {
+		fprintf(stderr,"SQL function VERIFY_PASSWD called with invalid arguments");
+		return;
+	}
+	sqlite3_result_int(context,verify_passwd(passwd));
+}
+
+
+
+
 // generic function to dump the output of a sql statement to stdout.
 // will return sqlite error codes but also handle (read: ignore) them itself
 int sql_stdout(sqlite3* db, const char* sql, int* rowcount) {
@@ -297,12 +347,236 @@
 
 }
 
+// sql function. takes ESSID and PASSWD, gives PMK
+void sql_calcpmk(sqlite3_context* context, int argc, sqlite3_value** values) {
+	unsigned char pmk[40];
+	char* passwd = (char*)sqlite3_value_blob(values[1]);
+	char* essid = (char*)sqlite3_value_blob(values[0]);
+	if (argc < 2 || passwd == 0 || essid == 0) {
+		sqlite3_result_error(context, "SQL function PMK() called with invalid arguments.\n", -1);
+		return;
+	}
+	calc_pmk(passwd,essid,pmk);
+	sqlite3_result_blob(context,pmk,32,SQLITE_TRANSIENT);
+}
+
+#ifdef HAVE_REGEXP
+void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
+	int ret;
+	regex_t regex;
+	char* reg = (char*)sqlite3_value_text(values[0]);
+	char* text = (char*)sqlite3_value_text(values[1]);
+
+	if ( argc != 2 || reg == 0 || text == 0) {
+		sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
+		return;
+	}
+
+	ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
+	if ( ret != 0 ) {
+		sqlite3_result_error(context, "error compiling regular expression", -1);
+		return;
+	}
+
+	ret = regexec(&regex, text , 0, NULL, 0);
+	regfree(&regex);
+
+	sqlite3_result_int(context, (ret != REG_NOMATCH));
+}
+#endif
+
+int initDataBase(const char * filename, sqlite3 ** db)
+{
+	//int rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
+	int rc = sqlite3_open(filename, &(*db));
+
+	if (rc != SQLITE_OK) {
+		sql_error(*db);
+		sqlite3_close(*db);
+
+		// May be usefull later
+		return rc;
+	}
+
+	sql_exec(*db, "create table essid (essid_id integer primary key autoincrement, essid text, prio integer default 64);");
+	sql_exec(*db, "create table passwd (passwd_id integer primary key autoincrement, passwd text);");
+	sql_exec(*db, "create table pmk (pmk_id integer primary key autoincrement, passwd_id int, essid_id int, pmk blob);");
+	sql_exec(*db, "create table workbench (wb_id integer primary key autoincrement, essid_id integer, passwd_id integer, lockid integer default 0);");
+	sql_exec(*db, "create index lock_lockid on workbench (lockid);");
+	sql_exec(*db, "create index pmk_pw on pmk (passwd_id);");
+	sql_exec(*db, "create unique index essid_u on essid (essid);");
+	sql_exec(*db, "create unique index passwd_u on passwd (passwd);");
+	sql_exec(*db, "create unique index ep_u on pmk (essid_id,passwd_id);");
+	sql_exec(*db, "create unique index wb_u on workbench (essid_id,passwd_id);");
+	sql_exec(*db, "CREATE TRIGGER delete_essid DELETE ON essid BEGIN DELETE FROM pmk WHERE pmk.essid_id = OLD.essid_id; DELETE FROM workbench WHERE workbench.essid_id = OLD.essid_id; END;");
+	sql_exec(*db, "CREATE TRIGGER delete_passwd DELETE ON passwd BEGIN DELETE FROM pmk WHERE pmk.passwd_id = OLD.passwd_id; DELETE FROM workbench WHERE workbench.passwd_id = OLD.passwd_id; END;");
+
+
+#ifdef SQL_DEBUG
+	sql_exec(*db, "begin;");
+	sql_exec(*db, "insert into essid (essid,prio) values ('e',random())");
+	sql_exec(*db, "insert into passwd (passwd) values ('p')");
+	sql_exec(*db, "insert into essid (essid,prio) select essid||'a',random() from essid;");
+	sql_exec(*db, "insert into essid (essid,prio) select essid||'b',random() from essid;");
+	sql_exec(*db, "insert into essid (essid,prio) select essid||'c',random() from essid;");
+	sql_exec(*db, "insert into essid (essid,prio) select essid||'d',random() from essid;");
+	sql_exec(*db, "insert into passwd (passwd) select passwd||'a' from passwd;");
+	sql_exec(*db, "insert into passwd (passwd) select passwd||'b' from passwd;");
+	sql_exec(*db, "insert into passwd (passwd) select passwd||'c' from passwd;");
+	sql_exec(*db, "insert into passwd (passwd) select passwd||'d' from passwd;");
+	sql_exec(*db, "insert into passwd (passwd) select passwd||'e' from passwd;");
+	sql_exec(*db, "insert into pmk (essid_id,passwd_id) select essid_id,passwd_id from essid,passwd limit 1000000;");
+	sql_exec(*db,"commit;");
+#endif
+
+	sqlite3_close(*db);
+	printf("Database <%s> successfully created\n", filename);
+	return 0;
+}
+
+int check_for_db(sqlite3 ** db, const char * filename, int can_create, int readonly)
+{
+	struct stat dbfile;
+	int rc;
+	int accessflags = R_OK | W_OK;
+	if (readonly)
+		accessflags = R_OK;
+
+	// Check if DB exist. If it does not, initialize it
+	if (access(filename, accessflags)) {
+		printf("Database <%s> does not already exist, ", filename);
+		if (can_create)
+		{
+			printf("creating it...\n");
+
+			rc = initDataBase(filename, db);
+
+			if (rc)
+			{
+				printf("Error initializing database (return code: %d), exiting...\n", rc);
+				return 1;
+			}
+		}
+		else
+		{
+			printf("exiting ...\n");
+			return 1;
+		}
+	}
+	else
+	{
+		if (stat(filename, &dbfile))
+		{
+			perror("stat()");
+			return 1;
+		}
+		if ((S_ISREG(dbfile.st_mode) && !S_ISDIR(dbfile.st_mode)) == 0)
+		{
+			printf("\"%s\" does not appear to be a file.\n", filename);
+			return 1;
+		}
+	}
+
+	rc = sqlite3_open(filename, &(*db));
+	if(rc) {
+		sql_error(*db);
+		sqlite3_close(*db);
+		return 1;
+	}
+
+	// TODO: Sanity check: Table definitions, index
+
+	// register new functions to be used in SQL statements
+	if (sqlite3_create_function(*db, "PMK", 2, SQLITE_ANY, 0, &sql_calcpmk,0,0) != SQLITE_OK) {
+		printf("Failed creating PMK function.\n");
+		sql_error(*db);
+		sqlite3_close(*db);
+		return 1;
+	}
+	if (sqlite3_create_function(*db, "VERIFY_ESSID", 1, SQLITE_ANY, 0, &sql_verify_essid,0,0) != SQLITE_OK) {
+		printf("Failed creating VERIFY_ESSID function.\n");
+		sql_error(*db);
+		sqlite3_close(*db);
+		return 1;
+	}
+	if (sqlite3_create_function(*db, "VERIFY_PASSWD", 1, SQLITE_ANY, 0, &sql_verify_passwd,0,0) != SQLITE_OK) {
+		printf("Failed creating VERIFY_PASSWD function.\n");
+		sql_error(*db);
+		sqlite3_close(*db);
+		return 1;
+	}
+#ifdef HAVE_REGEXP
+	if (sqlite3_create_function(*db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0) != SQLITE_OK) {
+		printf("Failed creating regexp() handler.\n");
+		sql_error(*db);
+		sqlite3_close(*db);
+		return 1;
+	}
+#endif
+
+	return 0;
+}
+
+void printBatchStats(sqlite3* db)
+{
+    pthread_mutex_lock(&mx_batch_print);
+
+    if (firstBTSPrint == 0)
+    {
+        fprintf(stdout, "\033[%iA", cpu_count + 1);         // Move up cpu_count + 1 lines
+    } else {
+        firstBTSPrint = 0;
+    }
+
+	int essids = query_int(db, "SELECT COUNT(*) FROM essid;");
+	int passwds = query_int(db,"SELECT COUNT(*) FROM passwd;");
+
+    int id;
+    int totalPMKPerSec = 0;
+    int oneFound = 0;
+    for (id = 0; id < cpu_count; id++)
+    {
+        if (bts[id].known == 1)
+        {
+            fprintf(stdout,"\r\033[KThread %i computed %i PMK/s.\n", id, bts[id].pmkPerSec);
+
+            totalPMKPerSec+= bts[id].pmkPerSec;
+            oneFound = 1;
+        }
+        else
+            fprintf(stdout,"\r\033[KThread %i has not reported statistics yet.\n", id);
+    }
+
+    if (oneFound == 1)
+    {
+        int total = essids*passwds;
+		int totalLeft = total - query_int(db, "SELECT COUNT(*) FROM pmk;");
+		char* etaString = getStringTimeFromSec(totalLeft / (double) totalPMKPerSec);
+        fprintf(stdout, "\r\033[KTotal of %i PMK/s, %i left to go of %i. ETA: %s \n", totalPMKPerSec, totalLeft, total, etaString);
+		free(etaString);
+    } else {
+        fprintf(stdout, "\r\033[KNo threads have reported statistics yet.\n");
+    }
+
+
+    fflush(stdout);
+    pthread_mutex_unlock(&mx_batch_print);
+}
+
+void reportBatchStats(int threadID, int pmkPerSec)
+{
+    bts[threadID].known = 1;
+    bts[threadID].pmkPerSec = pmkPerSec;
+}
+
 /*
 batch-process all combinations of ESSIDs and PASSWDs. this function may be called
 only once per db at the same time, yet multiple processes can batch-process a single db.
 don't modify this function's layout or it's queries without carefully considering speed, efficiency and concurrency.
 */
-void batch_process(sqlite3* db) {
+void batch_process(sqlite3* db, int threadID) {
+	pthread_mutex_lock(&mx_database);
+
 	int rc;
 	int cur_essid = 0;
 	struct timeval starttime;
@@ -311,8 +585,10 @@
 	int rowcount = 0;
 	char *sql;
 
-	if (sql_exec(db, "CREATE TEMPORARY TABLE temp.buffer (wb_id integer, essid_id integer, passwd_id integer, essid text, passwd text, pmk blob);") != SQLITE_OK) {
-		fprintf(stderr,"Failed to create buffer for batch processing.\n");
+    int retVal = sql_exec(db, "CREATE TEMPORARY TABLE IF NOT EXISTS temp.buffer (wb_id integer, essid_id integer, passwd_id integer, essid text, passwd text, pmk blob);");
+	if (retVal != SQLITE_OK) {
+		fprintf(stderr,"Failed to create buffer for batch processing. %i\n", retVal);
+		pthread_mutex_unlock(&mx_database);
 		return;
 	}
 
@@ -327,10 +603,11 @@
 			do {
 				//loop over workbench
 				sql_exec(db,"DELETE FROM temp.buffer;");
+
 				// select some work from the workbench into our own buffer
 				// move lockid ahead so other clients won't get those rows any time soon
 				sql_exec(db,"BEGIN EXCLUSIVE;");
-				sql_exec(db,"INSERT INTO temp.buffer (wb_id,essid_id,passwd_id,essid,passwd) SELECT wb_id, essid.essid_id,passwd.passwd_id,essid,passwd FROM workbench CROSS JOIN essid ON essid.essid_id = workbench.essid_id CROSS JOIN passwd ON passwd.passwd_id = workbench.passwd_id ORDER BY lockid LIMIT 25000;");
+				sql_exec(db,"INSERT INTO temp.buffer (wb_id,essid_id,passwd_id,essid,passwd) SELECT wb_id, essid.essid_id,passwd.passwd_id,essid,passwd FROM workbench CROSS JOIN essid ON essid.essid_id = workbench.essid_id CROSS JOIN passwd ON passwd.passwd_id = workbench.passwd_id ORDER BY lockid LIMIT 2500;");
 				sql_exec(db,"UPDATE workbench SET lockid=lockid+1 WHERE wb_id IN (SELECT wb_id FROM buffer);");
 				sql_exec(db,"COMMIT;");
 
@@ -338,9 +615,11 @@
 				if (rc > 0) {
 					// now calculate all the PMKs with a single statement.
 					// remember the update won't lock the db
+					pthread_mutex_unlock(&mx_database);
 					sql_exec(db,"UPDATE temp.buffer SET pmk = PMK(essid,passwd);");
+					pthread_mutex_lock(&mx_database);
 
-					// commit work and delete package from workbench
+                    // commit work and delete package from workbench
 					sql_exec(db,"BEGIN EXCLUSIVE;");
 					sql_exec(db,"INSERT OR IGNORE INTO pmk (essid_id,passwd_id,pmk) SELECT essid_id,passwd_id,pmk FROM temp.buffer");
 					sql_exec(db,"DELETE FROM workbench WHERE wb_id IN (SELECT wb_id FROM buffer);");
@@ -349,16 +628,19 @@
 					rowcount += rc;
 					gettimeofday(&curtime,NULL);
 					int timediff = curtime.tv_sec - starttime.tv_sec;
-					fprintf(stdout,"\rComputed %i PMK in %i seconds (%i PMK/s, %i in buffer). ",rowcount,timediff, timediff > 0 ? rowcount / timediff : rowcount, query_int(db,"SELECT COUNT(*) FROM workbench;"));
-					fflush(stdout);
+					reportBatchStats(threadID, timediff > 0 ? rowcount / timediff : rowcount);
+                    printBatchStats(db);
 				}
 			} while (rc > 0);
+
 			sql = sqlite3_mprintf("INSERT OR IGNORE INTO workbench (essid_id,passwd_id) SELECT essid.essid_id,passwd.passwd_id FROM passwd CROSS JOIN essid LEFT JOIN pmk ON pmk.essid_id = essid.essid_id AND pmk.passwd_id = passwd.passwd_id WHERE essid.essid_id = %i AND pmk.essid_id IS NULL LIMIT 250000;",cur_essid);
 			sql_exec(db,sql);
 			sqlite3_free(sql);
 		} while (query_int(db,"SELECT COUNT(*) FROM workbench INNER JOIN essid ON essid.essid_id = workbench.essid_id INNER JOIN passwd ON passwd.passwd_id = workbench.passwd_id;") > 0);
 
 		cur_essid = query_int(db,"SELECT essid.essid_id FROM essid LEFT JOIN pmk USING (essid_id) WHERE VERIFY_ESSID(essid.essid) == 0 GROUP BY essid.essid_id HAVING COUNT(pmk.essid_id) < (SELECT COUNT(*) FROM passwd) ORDER BY essid.prio,COUNT(pmk.essid_id),RANDOM() LIMIT 1;");
+		pthread_mutex_unlock(&mx_database);
+
 		if (cur_essid == 0) {
 			printf("All ESSID processed.\n\n");
 			sqlite3_close(db);
@@ -380,36 +662,13 @@
 	sql_exec(db,"DROP TABLE temp.buffer;");
 }
 
-// Verify an ESSID. Returns 1 if ESSID is invalid.
-//TODO More things to verify? Invalid chars?
-int verify_essid(char* essid) {
-	return essid == NULL || strlen(essid) < 1 || strlen(essid) > 32;
+void* batch_process_thread(void* voidBatchParams)
+{
+    struct BatchParam * bp = (struct BatchParam *) voidBatchParams;
+    batch_process(bp->db, bp->threadID);
+    pthread_exit(0);
 }
 
-// sql function which checks a given ESSID
-void sql_verify_essid(sqlite3_context* context, int argc, sqlite3_value** values) {
-	char* essid = (char*)sqlite3_value_text(values[0]);
-	if (argc != 1 || essid == 0) {
-		fprintf(stderr,"SQL function VERIFY_ESSID called with invalid arguments");
-		return;
-	}
-	sqlite3_result_int(context,verify_essid(essid));
-}
-
-int verify_passwd(char* passwd) {
-	return passwd == NULL || strlen(passwd) < 8 || strlen(passwd) > 63;
-}
-
-void sql_verify_passwd(sqlite3_context* context, int argc, sqlite3_value** values) {
-	char* passwd = (char*)sqlite3_value_text(values[0]);
-	if (argc != 1 || passwd == 0) {
-		fprintf(stderr,"SQL function VERIFY_PASSWD called with invalid arguments");
-		return;
-	}
-	sqlite3_result_int(context,verify_passwd(passwd));
-}
-
-
 // clean the db, analyze, maybe vacuum and check
 void vacuum(sqlite3* db, int deep) {
 	printf("Deleting invalid ESSIDs and passwords...\n");
@@ -681,21 +940,21 @@
 			ignored++;
 		}
 		if (imported % 1000 == 0) {
-			fprintf(stdout,"%i lines read, %i invalid lines ignored.\r",imported,ignored);
+			fprintf(stdout,"\r\033[K%i lines read, %i invalid lines ignored.",imported,ignored);
 			fflush(stdout);
 		}
 	}
 	sqlite3_finalize(stmt);
 
 	if (!feof(f)) {
-		printf("Error while reading file.\n");
+		printf("\nError while reading file.");
 		sql_exec(db,"ROLLBACK;");
 		fclose(f);
 		return 1;
 	}
 	fclose(f);
 
-	printf("Writing...\n");
+	printf("\nWriting...\n");
 	sql_exec(db,"COMMIT;");
 
 	printf("Done.\n");
@@ -703,176 +962,6 @@
 
 }
 
-// sql function. takes ESSID and PASSWD, gives PMK
-void sql_calcpmk(sqlite3_context* context, int argc, sqlite3_value** values) {
-	unsigned char pmk[40];
-	char* passwd = (char*)sqlite3_value_blob(values[1]);
-	char* essid = (char*)sqlite3_value_blob(values[0]);
-	if (argc < 2 || passwd == 0 || essid == 0) {
-		sqlite3_result_error(context, "SQL function PMK() called with invalid arguments.\n", -1);
-		return;
-	}
-	calc_pmk(passwd,essid,pmk);
-	sqlite3_result_blob(context,pmk,32,SQLITE_TRANSIENT);
-}
-
-#ifdef HAVE_REGEXP
-void sqlite_regexp(sqlite3_context* context, int argc, sqlite3_value** values) {
-	int ret;
-	regex_t regex;
-	char* reg = (char*)sqlite3_value_text(values[0]);
-	char* text = (char*)sqlite3_value_text(values[1]);
-
-	if ( argc != 2 || reg == 0 || text == 0) {
-		sqlite3_result_error(context, "SQL function regexp() called with invalid arguments.\n", -1);
-		return;
-	}
-
-	ret = regcomp(&regex, reg, REG_EXTENDED | REG_NOSUB);
-	if ( ret != 0 ) {
-		sqlite3_result_error(context, "error compiling regular expression", -1);
-		return;
-	}
-
-	ret = regexec(&regex, text , 0, NULL, 0);
-	regfree(&regex);
-
-	sqlite3_result_int(context, (ret != REG_NOMATCH));
-}
-#endif
-
-int initDataBase(const char * filename, sqlite3 ** db)
-{
-	//int rc = sqlite3_open_v2(filename, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
-	int rc = sqlite3_open(filename, &(*db));
-
-	if (rc != SQLITE_OK) {
-		sql_error(*db);
-		sqlite3_close(*db);
-
-		// May be usefull later
-		return rc;
-	}
-
-	sql_exec(*db, "create table essid (essid_id integer primary key autoincrement, essid text, prio integer default 64);");
-	sql_exec(*db, "create table passwd (passwd_id integer primary key autoincrement, passwd text);");
-	sql_exec(*db, "create table pmk (pmk_id integer primary key autoincrement, passwd_id int, essid_id int, pmk blob);");
-	sql_exec(*db, "create table workbench (wb_id integer primary key autoincrement, essid_id integer, passwd_id integer, lockid integer default 0);");
-	sql_exec(*db, "create index lock_lockid on workbench (lockid);");
-	sql_exec(*db, "create index pmk_pw on pmk (passwd_id);");
-	sql_exec(*db, "create unique index essid_u on essid (essid);");
-	sql_exec(*db, "create unique index passwd_u on passwd (passwd);");
-	sql_exec(*db, "create unique index ep_u on pmk (essid_id,passwd_id);");
-	sql_exec(*db, "create unique index wb_u on workbench (essid_id,passwd_id);");
-	sql_exec(*db, "CREATE TRIGGER delete_essid DELETE ON essid BEGIN DELETE FROM pmk WHERE pmk.essid_id = OLD.essid_id; DELETE FROM workbench WHERE workbench.essid_id = OLD.essid_id; END;");
-	sql_exec(*db, "CREATE TRIGGER delete_passwd DELETE ON passwd BEGIN DELETE FROM pmk WHERE pmk.passwd_id = OLD.passwd_id; DELETE FROM workbench WHERE workbench.passwd_id = OLD.passwd_id; END;");
-
-
-#ifdef SQL_DEBUG
-	sql_exec(*db, "begin;");
-	sql_exec(*db, "insert into essid (essid,prio) values ('e',random())");
-	sql_exec(*db, "insert into passwd (passwd) values ('p')");
-	sql_exec(*db, "insert into essid (essid,prio) select essid||'a',random() from essid;");
-	sql_exec(*db, "insert into essid (essid,prio) select essid||'b',random() from essid;");
-	sql_exec(*db, "insert into essid (essid,prio) select essid||'c',random() from essid;");
-	sql_exec(*db, "insert into essid (essid,prio) select essid||'d',random() from essid;");
-	sql_exec(*db, "insert into passwd (passwd) select passwd||'a' from passwd;");
-	sql_exec(*db, "insert into passwd (passwd) select passwd||'b' from passwd;");
-	sql_exec(*db, "insert into passwd (passwd) select passwd||'c' from passwd;");
-	sql_exec(*db, "insert into passwd (passwd) select passwd||'d' from passwd;");
-	sql_exec(*db, "insert into passwd (passwd) select passwd||'e' from passwd;");
-	sql_exec(*db, "insert into pmk (essid_id,passwd_id) select essid_id,passwd_id from essid,passwd limit 1000000;");
-	sql_exec(*db,"commit;");
-#endif
-
-	sqlite3_close(*db);
-	printf("Database <%s> successfully created\n", filename);
-	return 0;
-}
-
-int check_for_db(sqlite3 ** db, const char * filename, int can_create, int readonly)
-{
-	struct stat dbfile;
-	int rc;
-	int accessflags = R_OK | W_OK;
-	if (readonly)
-		accessflags = R_OK;
-
-	// Check if DB exist. If it does not, initialize it
-	if (access(filename, accessflags)) {
-		printf("Database <%s> does not already exist, ", filename);
-		if (can_create)
-		{
-			printf("creating it...\n");
-
-			rc = initDataBase(filename, db);
-
-			if (rc)
-			{
-				printf("Error initializing database (return code: %d), exiting...\n", rc);
-				return 1;
-			}
-		}
-		else
-		{
-			printf("exiting ...\n");
-			return 1;
-		}
-	}
-	else
-	{
-		if (stat(filename, &dbfile))
-		{
-			perror("stat()");
-			return 1;
-		}
-		if ((S_ISREG(dbfile.st_mode) && !S_ISDIR(dbfile.st_mode)) == 0)
-		{
-			printf("\"%s\" does not appear to be a file.\n", filename);
-			return 1;
-		}
-	}
-
-	rc = sqlite3_open(filename, &(*db));
-	if(rc) {
-		sql_error(*db);
-		sqlite3_close(*db);
-		return 1;
-	}
-
-	// TODO: Sanity check: Table definitions, index
-
-	// register new functions to be used in SQL statements
-	if (sqlite3_create_function(*db, "PMK", 2, SQLITE_ANY, 0, &sql_calcpmk,0,0) != SQLITE_OK) {
-		printf("Failed creating PMK function.\n");
-		sql_error(*db);
-		sqlite3_close(*db);
-		return 1;
-	}
-	if (sqlite3_create_function(*db, "VERIFY_ESSID", 1, SQLITE_ANY, 0, &sql_verify_essid,0,0) != SQLITE_OK) {
-		printf("Failed creating VERIFY_ESSID function.\n");
-		sql_error(*db);
-		sqlite3_close(*db);
-		return 1;
-	}
-	if (sqlite3_create_function(*db, "VERIFY_PASSWD", 1, SQLITE_ANY, 0, &sql_verify_passwd,0,0) != SQLITE_OK) {
-		printf("Failed creating VERIFY_PASSWD function.\n");
-		sql_error(*db);
-		sqlite3_close(*db);
-		return 1;
-	}
-#ifdef HAVE_REGEXP
-	if (sqlite3_create_function(*db, "regexp", 2, SQLITE_ANY,0, &sqlite_regexp,0,0) != SQLITE_OK) {
-		printf("Failed creating regexp() handler.\n");
-		sql_error(*db);
-		sqlite3_close(*db);
-		return 1;
-	}
-#endif
-
-	return 0;
-}
-
 int main(int argc, char **argv) {
 	sqlite3 *db;
 	int option_index, option;
@@ -882,6 +971,11 @@
 		return 1;
 	}
 
+	cpu_count = get_nb_cpus();
+	if (cpu_count <= 0)
+		cpu_count = 1;
+
+
 	db = NULL;
 
 	option_index = 0;
@@ -911,14 +1005,41 @@
 		switch (option)
 		{
 			case 'b':
+			{
 				// Batch
-				if ( check_for_db(&db, argv[1], 0, 1) ) {
-					return 1;
-				}
-				batch_process(db);
+                pthread_t tid[cpu_count];
+                int threadID = 0;
+                for (threadID = 0; threadID < cpu_count; threadID++)
+                {
+                    sqlite3* db = 0;
+                    pthread_mutex_lock(&mx_database);
+                    if ( check_for_db(&db, argv[1], 0, 1) )
+                        return 1;
+                    
+                    pthread_mutex_unlock(&mx_database);
 
+                    struct BatchParam bp;
+                    bp.db = db;
+                    bp.threadID = threadID;
+
+                    if ( pthread_create(&(tid[threadID]), NULL, (void *) batch_process_thread, (void *) &bp ) != 0)
+                        fprintf(stdout, "pthread_create Error");
+                }
+
+                sqlite3* db = 0;
+
+                pthread_mutex_lock(&mx_database);
+                if ( check_for_db(&db, argv[1], 0, 1) )
+                    return 1;
+                pthread_mutex_unlock(&mx_database);
+
+                printBatchStats(db);
+
+                for (threadID = 0; threadID < cpu_count; threadID++)
+                    pthread_join( tid[threadID], NULL );
+
 				break;
-
+            }
 			case 'c':
 				// Clean
 				if ( check_for_db(&db, argv[1], 0, 0) ) {
Index: src/common.c
===================================================================
--- src/common.c	(revisione 2005)
+++ src/common.c	(copia locale)
@@ -389,3 +389,47 @@
 
 	return value;
 }
+
+char * getStringTimeFromSec(double seconds)
+{
+    int hour[3];
+    char * ret;
+    char * HourTime;
+    char * MinTime;
+
+    if (seconds <0)
+        return NULL;
+
+    ret = (char *) calloc(1,256);
+
+    HourTime = (char *) calloc (1,128);
+    MinTime  = (char *) calloc (1,128);
+
+    hour[0]  = (int) (seconds);
+    hour[1]  = hour[0] / 60;
+    hour[2]  = hour[1] / 60;
+    hour[0] %= 60 ;
+    hour[1] %= 60 ;
+
+    if (hour[2] != 0 )
+        snprintf(HourTime, 128, "%d %s", hour[2], ( hour[2] == 1 ) ? "hour" : "hours");
+    if (hour[1] != 0 )
+        snprintf(MinTime, 128, "%d %s", hour[1], ( hour[1] == 1 ) ? "min" : "mins");
+
+    if ( hour[2] != 0 && hour[1] != 0 )
+        snprintf(ret, 256, "%s %s", HourTime, MinTime);
+    else
+    {
+        if (hour[2] == 0 && hour[1] == 0)
+            snprintf(ret, 256, "%d s", hour[0] );
+        else
+            snprintf(ret, 256, "%s", (hour[2] == 0) ? MinTime : HourTime );
+    }
+
+    free(MinTime);
+    free(HourTime);
+
+    return ret;
+
+}
+
