diff --git a/src/ckdb.h b/src/ckdb.h index 91734fd7..dce130ea 100644 --- a/src/ckdb.h +++ b/src/ckdb.h @@ -52,7 +52,7 @@ #define DB_VLOCK "1" #define DB_VERSION "0.9.2" -#define CKDB_VERSION DB_VERSION"-0.502" +#define CKDB_VERSION DB_VERSION"-0.503" #define WHERE_FFL " - from %s %s() line %d" #define WHERE_FFL_HERE __FILE__, __func__, __LINE__ @@ -540,7 +540,8 @@ extern tv_t missing_secuser_max; typedef struct users { int64_t userid; char username[TXT_BIG+1]; - // Anything in 'status' disables the account + char usertrim[TXT_BIG+1]; // Non DB field + // TODO: Anything in 'status' disables the account char status[TXT_BIG+1]; char emailaddress[TXT_BIG+1]; tv_t joineddate; @@ -1174,6 +1175,7 @@ extern PGconn *dbconnect(); // *** extern char *safe_text(char *txt); +extern void username_trim(USERS *users); extern void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS); diff --git a/src/ckdb_data.c b/src/ckdb_data.c index 5c0ae560..9dcf4431 100644 --- a/src/ckdb_data.c +++ b/src/ckdb_data.c @@ -40,6 +40,33 @@ char *safe_text(char *txt) return ret; } +#define TRIM_IGNORE(ch) ((ch) == '_' || (ch) == '.' || (ch) == '-' || isspace(ch)) + +void username_trim(USERS *users) +{ + char *front, *trail; + + front = users->username; + while (*front && TRIM_IGNORE(*front)) + front++; + + STRNCPY(users->usertrim, front); + + front = users->usertrim; + trail = front + strlen(front) - 1; + while (trail >= front) { + if (TRIM_IGNORE(*trail)) + *(trail--) = '\0'; + else + break; + } + + while (trail >= front) { + *trail = tolower(*trail); + trail--; + } +} + void _txt_to_data(enum data_type typ, char *nam, char *fld, void *data, size_t siz, WHERE_FFL_ARGS) { char *tmp; diff --git a/src/ckdb_dbio.c b/src/ckdb_dbio.c index cf4b23f4..414c9b4e 100644 --- a/src/ckdb_dbio.c +++ b/src/ckdb_dbio.c @@ -450,13 +450,13 @@ K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, ExecStatusType rescode; bool conned = false; PGresult *res; - K_ITEM *item; - USERS *row; + K_ITEM *item, *u_item; + USERS *row, *users; char *ins; char tohash[64]; uint64_t hash; __maybe_unused uint64_t tmp; - bool ok = false; + bool dup, ok = false; char *params[8 + HISTORYDATECOUNT]; int n, par = 0; @@ -468,14 +468,30 @@ K_ITEM *users_add(PGconn *conn, char *username, char *emailaddress, DATA_USERS(row, item); + STRNCPY(row->username, username); + username_trim(row); + + dup = false; + K_RLOCK(users_free); + u_item = users_store->head; + while (u_item) { + DATA_USERS(users, u_item); + if (strcmp(row->usertrim, users->usertrim) == 0) { + dup = true; + break; + } + u_item = u_item->next; + } + K_RUNLOCK(users_free); + + if (dup) + goto unitem; + row->userid = nextid(conn, "userid", (int64_t)(666 + (random() % 334)), cd, by, code, inet); if (row->userid == 0) goto unitem; - // TODO: pre-check the username exists? (to save finding out via a DB error) - - STRNCPY(row->username, username); row->status[0] = '\0'; STRNCPY(row->emailaddress, emailaddress); @@ -644,6 +660,8 @@ bool users_fill(PGconn *conn) if (!ok) break; + username_trim(row); + users_root = add_to_ktree(users_root, item, cmp_users); userid_root = add_to_ktree(userid_root, item, cmp_userid); k_add_head(users_store, item);