| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -49,7 +49,7 @@
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					#define DB_VLOCK "1" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					#define DB_VERSION "0.9.2" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					#define CKDB_VERSION DB_VERSION"-0.302" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					#define CKDB_VERSION DB_VERSION"-0.303" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					#define WHERE_FFL " - from %s %s() line %d" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					#define WHERE_FFL_HERE __FILE__, __func__, __LINE__ | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -802,6 +802,7 @@ enum cmd_values {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_HOMEPAGE, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_GETATTS, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_SETATTS, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_EXPATTS, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_DSP, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_STATS, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						CMD_PPLNS, | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -3343,6 +3344,74 @@ unitem:
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							return NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					static bool useratts_item_expire(PGconn *conn, K_ITEM *ua_item, tv_t *cd) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						ExecStatusType rescode; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						bool conned = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_TREE_CTX ctx[1]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						PGresult *res; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_ITEM *item; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						USERATTS *useratts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *upd; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						bool ok = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *params[4 + HISTORYDATECOUNT]; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						int n, par = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						LOGDEBUG("%s(): add", __func__); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						DATA_USERATTS(useratts, ua_item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						/* This is pointless if ua_item is part of the tree, however,
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						 * it allows for if ua_item isn't already part of the tree */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_RLOCK(useratts_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						item = find_useratts(useratts->userid, useratts->attname); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_RUNLOCK(useratts_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (item) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							DATA_USERATTS(useratts, item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if (!conn) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								conn = dbconnect(); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								conned = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							upd = "update useratts set expirydate=$1 where userid=$2 and " | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								"attname=$3 and expirydate=$4"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							par = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							params[par++] = tv_to_buf(cd, NULL, 0); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							params[par++] = bigint_to_buf(useratts->userid, NULL, 0); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							params[par++] = str_to_buf(useratts->attname, NULL, 0); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							params[par++] = tv_to_buf((tv_t *)&default_expiry, NULL, 0); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							PARCHKVAL(par, 4, params); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							res = PQexecParams(conn, upd, par, NULL, (const char **)params, NULL, NULL, 0, CKPQ_WRITE); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							rescode = PQresultStatus(res); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if (!PGOK(rescode)) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								PGLOGERR("Update", rescode, conn); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								goto unparam; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						ok = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					unparam: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (par) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							PQclear(res); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if (conned) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								PQfinish(conn); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							for (n = 0; n < par; n++) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								free(params[n]); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_WLOCK(useratts_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (ok && item) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							useratts_root = remove_from_ktree(useratts_root, item, cmp_useratts, ctx); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							copy_tv(&(useratts->expirydate), cd); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							useratts_root = add_to_ktree(useratts_root, item, cmp_useratts); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_WUNLOCK(useratts_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return ok; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					static bool useratts_fill(PGconn *conn) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						ExecStatusType rescode; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -10261,6 +10330,15 @@ static char *cmd_homepage(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return buf; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					/* Return the list of useratts for the given username=value
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Format is attlist=attname.element,attname.element,... | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Replies will be attname.element=value | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * The 2 date fields, date and date2, have a secondary element name | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  dateexp and date2exp | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  This will return Y or N depending upon if the date has expired as: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *   attname.dateexp=N (or Y) and attname.date2exp=N (or Y) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  Expired means the date is <= now | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 tv_t *now, __maybe_unused char *by, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 __maybe_unused char *code, __maybe_unused char *inet, | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10274,7 +10352,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						USERS *users; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *reason = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *answer = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *ptr, *comma, *dot; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *attlist = NULL, *ptr, *comma, *dot; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						size_t len, off; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						bool first; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -10302,7 +10380,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							APPEND_REALLOC_INIT(answer, off, len); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							ptr = strdup(transfer_data(i_attlist)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							attlist = ptr = strdup(transfer_data(i_attlist)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							first = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							while (ptr && *ptr) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								comma = strchr(ptr, ','); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10310,7 +10388,6 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									*(comma++) = '\0'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								dot = strchr(ptr, '.'); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								if (!dot) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									free(answer); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									reason = "Missing element"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									goto nuts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -10346,7 +10423,7 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											   sizeof(num_buf)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										ans = ctv_buf; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "dateexp") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										// Y/N if date is before now (not expired)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										// Y/N if date is <= now (expired)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										if (tv_newer(&(useratts->attdate), now)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											ans = TRUE_STR; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										else | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10357,13 +10434,12 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											   sizeof(num_buf)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										ans = ctv_buf; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "date2exp") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										// Y/N if date2 is before now (not expired)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										// Y/N if date2 is <= now (expired)
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										if (tv_newer(&(useratts->attdate2), now)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											ans = TRUE_STR; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											ans = FALSE_STR; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										free(answer); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										reason = "Unknown element"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										goto nuts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10377,7 +10453,12 @@ static char *cmd_getatts(__maybe_unused PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					nuts: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (attlist) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							free(attlist); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (reason) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if (answer) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								free(answer); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							snprintf(reply, siz, "ERR.%s", reason); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							LOGERR("%s.%s.%s", cmd, id, reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							return strdup(reply); | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10403,6 +10484,21 @@ static void att_to_date(tv_t *date, char *data, tv_t *now)
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					/* Store useratts in the DB for the given username=value
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Format is 1 or more: ua_attname.element=value | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  i.e. each starts with the constant "ua_" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * attname cannot contain Tab . or = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * element is per the coded list below, which also cannot contain Tab . or = | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Any matching useratts attnames found currently in the DB are expired | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Transfer will sort them so that any of the same attname | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  will be next to each other | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  thus will combine multiple elements for the same attname | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  into one single useratts record (as is mandatory) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * The 2 date fields date and date2 require either epoch values sec,usec | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  (usec is optional and defaults to 0) or one of: now or now+NNN | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  now is the current epoch value and now+NNN is the epoch + NNN seconds | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  See att_to_date() above | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					static char *cmd_setatts(PGconn *conn, char *cmd, char *id, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 tv_t *now, char *by, char *code, char *inet, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 __maybe_unused tv_t *notcd, K_TREE *trf_root) | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10421,6 +10517,7 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *reason = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *dot, *data; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						bool begun = false; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						int set = 0, db = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						LOGDEBUG("%s(): cmd '%s'", __func__, cmd); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10439,12 +10536,6 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							goto bats; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							DATA_USERS(users, u_item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							/* format is: ua_attname.element=value
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							 *  i.e. eash starts with the constant "ua_" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							 * transfer will sort them so that any of the same attname | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							 *  will be next to each other | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							 *  thus can combine multiple elements for the same attname | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							 *  into one single useratts record (as is mandatory) */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							t_item = first_in_ktree(trf_root, ctx); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							while (t_item) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								DATA_TRANSFER(transfer, t_item); | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -10475,9 +10566,10 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											begun = true; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										if (useratts_item_add(conn, ua_item, now, begun)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										if (useratts_item_add(conn, ua_item, now, begun)) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											ua_item = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											db++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											res = PQexec(conn, "Rollback", CKPQ_WRITE); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											PQclear(res); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
											reason = "DBERR"; | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10495,18 +10587,25 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										HISTORYDATEINIT(useratts, now, by, code, inet); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										HISTORYDATETRANSFER(trf_root, useratts); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									// List of valid element names for storage
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									if (strcmp(dot, "str") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										STRNCPY(useratts->attstr, data); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										set++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "str2") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										STRNCPY(useratts->attstr2, data); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										set++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "num") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										TXT_TO_BIGINT("num", data, useratts->attnum); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										set++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "num2") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										TXT_TO_BIGINT("num2", data, useratts->attnum2); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										set++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "date") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										att_to_date(&(useratts->attdate), data, now); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										set++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else if (strcmp(dot, "date2") == 0) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										att_to_date(&(useratts->attdate2), data, now); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										set++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										reason = "Unknown element"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										goto bats; | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -10537,6 +10636,7 @@ static char *cmd_setatts(PGconn *conn, char *cmd, char *id,
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									reason = "DBERR"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									goto bats; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								db++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								res = PQexec(conn, "Commit", CKPQ_WRITE); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								PQclear(res); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				 | 
				
					@ -10554,11 +10654,94 @@ bats:
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							LOGERR("%s.%s.%s", cmd, id, reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							return strdup(reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						snprintf(reply, siz, "ok.set"); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						snprintf(reply, siz, "ok.set %d,%d", db, set); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						LOGDEBUG("%s.%s", id, reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return strdup(reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					/* Expire the list of useratts for the given username=value
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Format is attlist=attname,attname,... | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 * Each matching DB attname record will have it's expirydate set to now | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  thus an attempt to access it with getatts will not find it and | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 *  return nothing for that attname | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					 */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					static char *cmd_expatts(__maybe_unused PGconn *conn, char *cmd, char *id, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 tv_t *now, __maybe_unused char *by, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 __maybe_unused char *code, __maybe_unused char *inet, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								 __maybe_unused tv_t *notcd, K_TREE *trf_root) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					{ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_ITEM *i_username, *i_attlist, *u_item, *ua_item; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char reply[1024] = ""; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						size_t siz = sizeof(reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						USERATTS *useratts; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						USERS *users; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *reason = NULL; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						char *attlist, *ptr, *comma; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						int db = 0, mis = 0; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						LOGDEBUG("%s(): cmd '%s'", __func__, cmd); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						i_username = require_name(trf_root, "username", 3, (char *)userpatt, reply, siz); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (!i_username) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							reason = "Missing username"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							goto rats; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_RLOCK(users_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						u_item = find_users(transfer_data(i_username)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						K_RUNLOCK(users_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (!u_item) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							reason = "Unknown user"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							goto rats; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							DATA_USERS(users, u_item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							i_attlist = require_name(trf_root, "attlist", 1, NULL, reply, siz); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							if (!i_attlist) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								reason = "Missing attlist"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								goto rats; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							attlist = ptr = strdup(transfer_data(i_attlist)); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							while (ptr && *ptr) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								comma = strchr(ptr, ','); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								if (comma) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									*(comma++) = '\0'; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								K_RLOCK(useratts_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								ua_item = find_useratts(users->userid, ptr); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								K_RUNLOCK(useratts_free); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								if (!ua_item) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									mis++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									DATA_USERATTS(useratts, ua_item); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									HISTORYDATEINIT(useratts, now, by, code, inet); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									HISTORYDATETRANSFER(trf_root, useratts); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									/* Since we are expiring records, don't bother
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									 *  with combining them all into a single | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									 *  transaction and don't abort on error | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									 * Thus if an error is returned, retry would be | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									 *  necessary, but some may also have been | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									 *  expired successfully */ | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									if (!useratts_item_expire(conn, ua_item, now)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										reason = "DBERR"; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
									else | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										db++; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								ptr = comma; | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							free(attlist); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					rats: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						if (reason) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							snprintf(reply, siz, "ERR.%s", reason); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							LOGERR("%s.%s.%s", cmd, id, reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
							return strdup(reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						snprintf(reply, siz, "ok.exp %d,%d", db, mis); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						LOGDEBUG("%s.%s.%s", cmd, id, reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						return strdup(reply); | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					// order by userid asc
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					static cmp_t cmp_mu(K_ITEM *a, K_ITEM *b) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
					{ | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -11143,6 +11326,7 @@ static struct CMDS {
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_HOMEPAGE,	"homepage",	false,	false,	cmd_homepage,	ACCESS_WEB }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_GETATTS,	"getatts",	false,	false,	cmd_getatts,	ACCESS_WEB }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_SETATTS,	"setatts",	false,	false,	cmd_setatts,	ACCESS_WEB }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_EXPATTS,	"expatts",	false,	false,	cmd_expatts,	ACCESS_WEB }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_DSP,	"dsp",		false,	false,	cmd_dsp,	ACCESS_SYSTEM }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_STATS,	"stats",	true,	false,	cmd_stats,	ACCESS_SYSTEM }, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
						{ CMD_PPLNS,	"pplns",	false,	false,	cmd_pplns,	ACCESS_SYSTEM }, | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -11994,6 +12178,7 @@ static void *socketer(__maybe_unused void *arg)
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_USERSET: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_GETATTS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_SETATTS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_EXPATTS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_BLOCKLIST: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_NEWID: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
										case CMD_STATS: | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				 | 
				
					@ -12230,6 +12415,7 @@ static bool reload_line(PGconn *conn, char *filename, uint64_t count, char *buf)
					 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_HOMEPAGE: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_GETATTS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_SETATTS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_EXPATTS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_DSP: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_STATS: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				 | 
				
								case CMD_PPLNS: | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				 | 
				
					
 
					 |