1 /*
    2  * WARNING: automatically generated by kwebapp 0.6.14.
    3  * DO NOT EDIT!
    4  */
    5 #include <sys/queue.h>
    6 
    7 #include <assert.h>
    8 /*
    9  * Required for b64_ntop().
   10  */
   11 #include <netinet/in.h>
   12 #include <resolv.h>
   13 #include <ctype.h>
   14 #include <inttypes.h>
   15 #include <stdarg.h>
   16 #include <stdio.h>
   17 #include <stdint.h>
   18 #include <stdlib.h>
   19 #include <string.h>
   20 #include <time.h>
   21 #include <unistd.h>
   22 
   23 #include <ksql.h>
   24 #include <kcgi.h>
   25 #include <kcgijson.h>
   26 
   27 #include "db.h"
   28 
   29 /*
   30  * File imported from /usr/local/share/kwebapp/jsmn.c.
   31  */
   32 /* 
   33  * https://github.com/zserge/jsmn
   34  * Current as of 26-09-2018.
   35  */
   36 /**
   37  * Copyright (c) 2010 Serge A. Zaitsev
   38  *
   39  * Permission is hereby granted, free of charge, to any person obtaining a copy
   40  * of this software and associated documentation files (the "Software"), to deal
   41  * in the Software without restriction, including without limitation the rights
   42  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   43  * copies of the Software, and to permit persons to whom the Software is
   44  * furnished to do so, subject to the following conditions:
   45  * 
   46  * The above copyright notice and this permission notice shall be included in
   47  * all copies or substantial portions of the Software.
   48  * 
   49  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   50  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   51  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   52  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   53  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   54  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   55  * THE SOFTWARE.
   56  */
   57 
   58 /**
   59  * Allocates a fresh unused token from the token pull.
   60  */
   61 static jsmntok_t *
   62 jsmn_alloc_token(jsmn_parser *parser, 
   63 	jsmntok_t *tokens, size_t num_tokens) 
   64 {
   65 	jsmntok_t *tok;
   66 	if (parser->toknext >= num_tokens) {
   67 		return NULL;
   68 	}
   69 	tok = &tokens[parser->toknext++];
   70 	tok->start = tok->end = -1;
   71 	tok->size = 0;
   72 	return tok;
   73 }
   74 
   75 /**
   76  * Fills token type and boundaries.
   77  */
   78 static void 
   79 jsmn_fill_token(jsmntok_t *token, jsmntype_t type, int start, int end) 
   80 {
   81 	token->type = type;
   82 	token->start = start;
   83 	token->end = end;
   84 	token->size = 0;
   85 }
   86 
   87 /**
   88  * Fills next available token with JSON primitive.
   89  */
   90 static int 
   91 jsmn_parse_primitive(jsmn_parser *parser, const char *js,
   92 	size_t len, jsmntok_t *tokens, size_t num_tokens) 
   93 {
   94 	jsmntok_t *token;
   95 	int start;
   96 
   97 	start = parser->pos;
   98 
   99 	for (; parser->pos < len && js[parser->pos] != '\0'; 
  100 	     parser->pos++) {
  101 		switch (js[parser->pos]) {
  102 		/* In strict mode primitive must be followed by "," or
  103 		 * "}" or "]" */
  104 		case ':':
  105 		case '\t' : case '\r' : case '\n' : case ' ' :
  106 		case ','  : case ']'  : case '}' :
  107 			goto found;
  108 		}
  109 		if (js[parser->pos] < 32 || js[parser->pos] >= 127) {
  110 			parser->pos = start;
  111 			return JSMN_ERROR_INVAL;
  112 		}
  113 	}
  114 found:
  115 	if (tokens == NULL) {
  116 		parser->pos--;
  117 		return 0;
  118 	}
  119 	token = jsmn_alloc_token(parser, tokens, num_tokens);
  120 	if (token == NULL) {
  121 		parser->pos = start;
  122 		return JSMN_ERROR_NOMEM;
  123 	}
  124 	jsmn_fill_token(token, JSMN_PRIMITIVE, start, parser->pos);
  125 	parser->pos--;
  126 	return 0;
  127 }
  128 
  129 /**
  130  * Fills next token with JSON string.
  131  */
  132 static int 
  133 jsmn_parse_string(jsmn_parser *parser, const char *js,
  134 	size_t len, jsmntok_t *tokens, size_t num_tokens) 
  135 {
  136 	jsmntok_t *token;
  137 
  138 	int start = parser->pos;
  139 
  140 	parser->pos++;
  141 
  142 	/* Skip starting quote */
  143 	for (; parser->pos < len && js[parser->pos] != '\0'; 
  144 	     parser->pos++) {
  145 		char c = js[parser->pos];
  146 
  147 		/* Quote: end of string */
  148 		if (c == '\"') {
  149 			if (tokens == NULL) {
  150 				return 0;
  151 			}
  152 			token = jsmn_alloc_token
  153 				(parser, tokens, num_tokens);
  154 			if (token == NULL) {
  155 				parser->pos = start;
  156 				return JSMN_ERROR_NOMEM;
  157 			}
  158 			jsmn_fill_token
  159 				(token, JSMN_STRING, 
  160 				 start+1, parser->pos);
  161 			return 0;
  162 		}
  163 
  164 		/* Backslash: Quoted symbol expected */
  165 		if (c == '\\' && parser->pos + 1 < len) {
  166 			int i;
  167 			parser->pos++;
  168 			switch (js[parser->pos]) {
  169 			/* Allowed escaped symbols */
  170 			case '\"': case '/' : case '\\' : case 'b' :
  171 			case 'f' : case 'r' : case 'n'  : case 't' :
  172 				break;
  173 			/* Allows escaped symbol \uXXXX */
  174 			case 'u':
  175 				parser->pos++;
  176 				for(i = 0; 
  177 				    i < 4 && parser->pos < len && 
  178 				    js[parser->pos] != '\0'; i++) {
  179 					/* If it isn't a hex character we have an error */
  180 					if(!((js[parser->pos] >= 48 && 
  181 					      js[parser->pos] <= 57) || /* 0-9 */
  182 					   (js[parser->pos] >= 65 && 
  183 					    js[parser->pos] <= 70) || /* A-F */
  184 					   (js[parser->pos] >= 97 && 
  185 					    js[parser->pos] <= 102))) { /* a-f */
  186 						parser->pos = start;
  187 						return JSMN_ERROR_INVAL;
  188 					}
  189 					parser->pos++;
  190 				}
  191 				parser->pos--;
  192 				break;
  193 			/* Unexpected symbol */
  194 			default:
  195 				parser->pos = start;
  196 				return JSMN_ERROR_INVAL;
  197 			}
  198 		}
  199 	}
  200 	parser->pos = start;
  201 	return JSMN_ERROR_PART;
  202 }
  203 
  204 /**
  205  * Parse JSON string and fill tokens.
  206  */
  207 int 
  208 jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
  209 	jsmntok_t *tokens, unsigned int num_tokens) 
  210 {
  211 	int r;
  212 	int i;
  213 	jsmntok_t *token;
  214 	int count = parser->toknext;
  215 
  216 	for (; parser->pos < len && js[parser->pos] != '\0'; 
  217 	     parser->pos++) {
  218 		char c;
  219 		jsmntype_t type;
  220 
  221 		c = js[parser->pos];
  222 		switch (c) {
  223 		case '{': case '[':
  224 			count++;
  225 			if (tokens == NULL) {
  226 				break;
  227 			}
  228 			token = jsmn_alloc_token
  229 				(parser, tokens, num_tokens);
  230 			if (token == NULL)
  231 				return JSMN_ERROR_NOMEM;
  232 			if (parser->toksuper != -1) {
  233 				tokens[parser->toksuper].size++;
  234 			}
  235 			token->type = (c == '{' ? 
  236 				JSMN_OBJECT : JSMN_ARRAY);
  237 			token->start = parser->pos;
  238 			parser->toksuper = parser->toknext - 1;
  239 			break;
  240 		case '}': case ']':
  241 			if (tokens == NULL)
  242 				break;
  243 			type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
  244 			for (i = parser->toknext - 1; i >= 0; i--) {
  245 				token = &tokens[i];
  246 				if (token->start != -1 && 
  247 				    token->end == -1) {
  248 					if (token->type != type) {
  249 						return JSMN_ERROR_INVAL;
  250 					}
  251 					parser->toksuper = -1;
  252 					token->end = parser->pos + 1;
  253 					break;
  254 				}
  255 			}
  256 			/* Error if unmatched closing bracket */
  257 			if (i == -1) 
  258 				return JSMN_ERROR_INVAL;
  259 			for (; i >= 0; i--) {
  260 				token = &tokens[i];
  261 				if (token->start != -1 && 
  262 				    token->end == -1) {
  263 					parser->toksuper = i;
  264 					break;
  265 				}
  266 			}
  267 			break;
  268 		case '\"':
  269 			r = jsmn_parse_string
  270 				(parser, js, len, tokens, num_tokens);
  271 			if (r < 0) 
  272 				return r;
  273 			count++;
  274 			if (parser->toksuper != -1 && tokens != NULL)
  275 				tokens[parser->toksuper].size++;
  276 			break;
  277 		case '\t' : case '\r' : case '\n' : case ' ':
  278 			break;
  279 		case ':':
  280 			parser->toksuper = parser->toknext - 1;
  281 			break;
  282 		case ',':
  283 			if (tokens != NULL && parser->toksuper != -1 &&
  284 			    tokens[parser->toksuper].type != JSMN_ARRAY &&
  285 			    tokens[parser->toksuper].type != JSMN_OBJECT) {
  286 				for (i = parser->toknext - 1; i >= 0; i--) {
  287 					if (tokens[i].type == JSMN_ARRAY || 
  288 					    tokens[i].type == JSMN_OBJECT) {
  289 						if (tokens[i].start != -1 && 
  290 						    tokens[i].end == -1) {
  291 							parser->toksuper = i;
  292 							break;
  293 						}
  294 					}
  295 				}
  296 			}
  297 			break;
  298 		/* In non-strict mode every unquoted value is a primitive */
  299 		default:
  300 			r = jsmn_parse_primitive
  301 				(parser, js, len, tokens, num_tokens);
  302 			if (r < 0) return r;
  303 			count++;
  304 			if (parser->toksuper != -1 && tokens != NULL)
  305 				tokens[parser->toksuper].size++;
  306 			break;
  307 		}
  308 	}
  309 
  310 	if (tokens != NULL) {
  311 		for (i = parser->toknext - 1; i >= 0; i--) {
  312 			/* Unmatched opened object or array */
  313 			if (tokens[i].start != -1 && tokens[i].end == -1) {
  314 				return JSMN_ERROR_PART;
  315 			}
  316 		}
  317 	}
  318 
  319 	return count;
  320 }
  321 
  322 /**
  323  * Creates a new parser based over a given  buffer with an array of tokens
  324  * available.
  325  */
  326 void 
  327 jsmn_init(jsmn_parser *parser) 
  328 {
  329 	parser->pos = 0;
  330 	parser->toknext = 0;
  331 	parser->toksuper = -1;
  332 }
  333 
  334 /*
  335  * The remainder here are written for kwebapp.
  336  */
  337 
  338 int 
  339 jsmn_eq(const char *json, const jsmntok_t *tok, const char *s) 
  340 {
  341 	if (tok->type == JSMN_STRING && 
  342 	    (int)strlen(s) == tok->end - tok->start &&
  343 	    strncmp(json + tok->start, s, tok->end - tok->start) == 0) 
  344 		return 1;
  345 	return 0;
  346 }
  347 
  348 static int
  349 jsmn_parse_real(const char *buf, size_t sz, double *ret)
  350 {
  351 	char 	 tmp[128];
  352 	int	 rc;
  353 
  354 	if (sz > sizeof(tmp) - 1)
  355 		return 0;
  356 
  357 	memcpy(tmp, buf, sz);
  358 	tmp[sz] = '\0';
  359 
  360 	if ((rc = sscanf(tmp, "%lf", ret)) < 0)
  361 		return -1;
  362 
  363 	return 1 == rc;
  364 }
  365 
  366 static int
  367 jsmn_parse_int(const char *buf, size_t sz, int64_t *ret)
  368 {
  369 	char 	 tmp[32];
  370 	int	 rc;
  371 
  372 	if (sz > sizeof(tmp) - 1)
  373 		return 0;
  374 
  375 	memcpy(tmp, buf, sz);
  376 	tmp[sz] = '\0';
  377 
  378 	if ((rc = sscanf(tmp, "%" SCNd64, ret)) < 0)
  379 		return -1;
  380 
  381 	return 1 == rc;
  382 }
  383 /*
  384  * All SQL statements we'll later define in "stmts".
  385  */
  386 enum	stmt {
  387 	STMT_COMPANY_BY_UNIQUE_id,
  388 	STMT_COMPANY_BY_SEARCH_0,
  389 	STMT_COMPANY_INSERT,
  390 	STMT_USER_BY_UNIQUE_email,
  391 	STMT_USER_BY_UNIQUE_uid,
  392 	STMT_USER_BY_SEARCH_0,
  393 	STMT_USER_BY_SEARCH_1,
  394 	STMT_USER_BY_SEARCH_2,
  395 	STMT_USER_INSERT,
  396 	STMT_USER_UPDATE_0,
  397 	STMT_USER_UPDATE_1,
  398 	STMT_SESSION_BY_UNIQUE_id,
  399 	STMT_SESSION_BY_SEARCH_0,
  400 	STMT_SESSION_INSERT,
  401 	STMT_SESSION_DELETE_0,
  402 	STMT__MAX
  403 };
  404 
  405 /*
  406  * Our full set of SQL statements.
  407  * We define these beforehand because that's how ksql(3) handles 
  408  * statement generation.
  409  * Notice the "AS" part: this allows for multiple inner joins without 
  410  * ambiguity.
  411  */
  412 static	const char *const stmts[STMT__MAX] = {
  413 	/* STMT_COMPANY_BY_UNIQUE_id */
  414 	"SELECT " DB_SCHEMA_COMPANY(company) " FROM company WHERE company.id = ?",
  415 	/* STMT_COMPANY_BY_SEARCH_0 */
  416 	"SELECT " DB_SCHEMA_COMPANY(company) " FROM company "
  417 		"WHERE company.somenum ISNULL",
  418 	/* STMT_COMPANY_INSERT */
  419 	"INSERT INTO company (name,somenum) VALUES (?,?)",
  420 	/* STMT_USER_BY_UNIQUE_email */
  421 	"SELECT " DB_SCHEMA_USER(user) "," DB_SCHEMA_COMPANY(_a) " FROM user "
  422 		"INNER JOIN company AS _a ON _a.id=user.cid "
  423 		"WHERE user.email = ?",
  424 	/* STMT_USER_BY_UNIQUE_uid */
  425 	"SELECT " DB_SCHEMA_USER(user) "," DB_SCHEMA_COMPANY(_a) " FROM user "
  426 		"INNER JOIN company AS _a ON _a.id=user.cid "
  427 		"WHERE user.uid = ?",
  428 	/* STMT_USER_BY_SEARCH_0 */
  429 	"SELECT " DB_SCHEMA_USER(user) "," DB_SCHEMA_COMPANY(_a) " FROM user "
  430 		"INNER JOIN company AS _a ON _a.id=user.cid "
  431 		"WHERE user.name = ? LIMIT 5",
  432 	/* STMT_USER_BY_SEARCH_1 */
  433 	"SELECT " DB_SCHEMA_USER(user) "," DB_SCHEMA_COMPANY(_a) " FROM user "
  434 		"INNER JOIN company AS _a ON _a.id=user.cid "
  435 		"WHERE user.email = ?",
  436 	/* STMT_USER_BY_SEARCH_2 */
  437 	"SELECT " DB_SCHEMA_USER(user) "," DB_SCHEMA_COMPANY(_a) " FROM user "
  438 		"INNER JOIN company AS _a ON _a.id=user.cid "
  439 		"WHERE user.uid = ? ORDER BY _a.name ASC",
  440 	/* STMT_USER_INSERT */
  441 	"INSERT INTO user (cid,sex,hash,email,image,name) VALUES (?,?,?,?,?,?)",
  442 	/* STMT_USER_UPDATE_0 */
  443 	"UPDATE user SET hash = ? WHERE uid = ?",
  444 	/* STMT_USER_UPDATE_1 */
  445 	"UPDATE user SET email = ? WHERE uid = ?",
  446 	/* STMT_SESSION_BY_UNIQUE_id */
  447 	"SELECT " DB_SCHEMA_SESSION(session) "," DB_SCHEMA_USER(_b) "," DB_SCHEMA_COMPANY(_c) " FROM session "
  448 		"INNER JOIN user AS _b ON _b.uid=session.userid "
  449 		"INNER JOIN company AS _c ON _c.id=_b.cid "
  450 		"WHERE session.id = ?",
  451 	/* STMT_SESSION_BY_SEARCH_0 */
  452 	"SELECT " DB_SCHEMA_SESSION(session) "," DB_SCHEMA_USER(_b) "," DB_SCHEMA_COMPANY(_c) " FROM session "
  453 		"INNER JOIN user AS _b ON _b.uid=session.userid "
  454 		"INNER JOIN company AS _c ON _c.id=_b.cid "
  455 		"WHERE _c.name = ? AND session.mtime = ?",
  456 	/* STMT_SESSION_INSERT */
  457 	"INSERT INTO session (userid,token,mtime) VALUES (?,?,?)",
  458 	/* STMT_SESSION_DELETE_0 */
  459 	"DELETE FROM session WHERE id = ?",
  460 };
  461 
  462 const struct kvalid valid_keys[VALID__MAX] = {
  463 	{ valid_company_name, "company-name" },
  464 	{ valid_company_id, "company-id" },
  465 	{ valid_company_somenum, "company-somenum" },
  466 	{ valid_user_cid, "user-cid" },
  467 	{ valid_user_sex, "user-sex" },
  468 	{ valid_user_hash, "user-hash" },
  469 	{ valid_user_email, "user-email" },
  470 	{ valid_user_image, "user-image" },
  471 	{ valid_user_name, "user-name" },
  472 	{ valid_user_uid, "user-uid" },
  473 	{ valid_session_userid, "session-userid" },
  474 	{ valid_session_token, "session-token" },
  475 	{ valid_session_mtime, "session-mtime" },
  476 	{ valid_session_id, "session-id" },
  477 };
  478 
  479 /*
  480  * Finally, all of the functions we'll use.
  481  */
  482 
  483 void
  484 db_trans_open(struct ksql *p, size_t id, int mode)
  485 {
  486 	if (mode < 0)
  487 		ksql_trans_exclopen(p, id);
  488 	else if (mode > 0)
  489 		ksql_trans_singleopen(p, id);
  490 	else
  491 		ksql_trans_open(p, id);
  492 }
  493 
  494 void
  495 db_trans_rollback(struct ksql *p, size_t id)
  496 {
  497 	ksql_trans_rollback(p, id);
  498 }
  499 
  500 void
  501 db_trans_commit(struct ksql *p, size_t id)
  502 {
  503 	ksql_trans_commit(p, id);
  504 }
  505 
  506 struct ksql *
  507 db_open(const char *file)
  508 {
  509 	struct ksqlcfg cfg;
  510 	struct ksql *db;
  511 
  512 	ksql_cfg_defaults(&cfg);
  513 	cfg.flags |= KSQL_FOREIGN_KEYS;
  514 
  515 	db = ksql_alloc_child(&cfg, NULL, NULL);
  516 	if (NULL == db)
  517 		return(NULL);
  518 	ksql_open(db, file);
  519 	return(db);
  520 }
  521 
  522 void
  523 db_close(struct ksql *p)
  524 {
  525 	if (NULL == p)
  526 		return;
  527 	ksql_close(p);
  528 	ksql_free(p);
  529 }
  530 
  531 void
  532 db_company_fill(struct company *p, struct ksqlstmt *stmt, size_t *pos)
  533 {
  534 	size_t i = 0;
  535 	enum ksqlc c;
  536 	int hasval;
  537 
  538 	if (NULL == pos)
  539 		pos = &i;
  540 	memset(p, 0, sizeof(*p));
  541 	c = ksql_result_str_alloc(stmt, &p->name, (*pos)++);
  542 	if (KSQL_OK != c)
  543 		exit(EXIT_FAILURE);
  544 	c = ksql_result_int(stmt, &p->id, (*pos)++);
  545 	if (KSQL_OK != c)
  546 		exit(EXIT_FAILURE);
  547 	c = ksql_result_isnull(stmt, &hasval, *pos);
  548 	if (KSQL_OK != c)
  549 		exit(EXIT_FAILURE);
  550 	p->has_somenum = !hasval;
  551 	if (p->has_somenum) {
  552 		c = ksql_result_int(stmt, &p->somenum, (*pos)++);
  553 		if (KSQL_OK != c)
  554 			exit(EXIT_FAILURE);
  555 	} else
  556 		(*pos)++;
  557 }
  558 
  559 static void
  560 db_company_fill_r(struct company *p, struct ksqlstmt *stmt, size_t *pos)
  561 {
  562 	size_t i = 0;
  563 
  564 	if (NULL == pos)
  565 		pos = &i;
  566 	db_company_fill(p, stmt, pos);
  567 }
  568 
  569 void
  570 db_company_unfill(struct company *p)
  571 {
  572 	if (NULL == p)
  573 		return;
  574 	free(p->name);
  575 }
  576 
  577 static void
  578 db_company_unfill_r(struct company *p)
  579 {
  580 	if (NULL == p)
  581 		return;
  582 
  583 	db_company_unfill(p);
  584 }
  585 
  586 void
  587 db_company_free(struct company *p)
  588 {
  589 	db_company_unfill_r(p);
  590 	free(p);
  591 }
  592 
  593 void
  594 db_company_freeq(struct company_q *q)
  595 {
  596 	struct company *p;
  597 
  598 	if (NULL == q)
  599 		return;
  600 	while (NULL != (p = TAILQ_FIRST(q))) {
  601 		TAILQ_REMOVE(q, p, _entries);
  602 		db_company_free(p);
  603 	}
  604 
  605 	free(q);
  606 }
  607 
  608 int64_t
  609 db_company_insert(struct ksql *db, const char *v1, int64_t *v2)
  610 {
  611 	struct ksqlstmt *stmt;
  612 	int64_t id = -1;
  613 
  614 	ksql_stmt_alloc(db, &stmt,
  615 		stmts[STMT_COMPANY_INSERT],
  616 		STMT_COMPANY_INSERT);
  617 	ksql_bind_str(stmt, 0, v1);
  618 	if (NULL == v2)
  619 		ksql_bind_null(stmt, 1);
  620 	else
  621 		ksql_bind_int(stmt, 1, *v2);
  622 	if (KSQL_DONE == ksql_stmt_cstep(stmt))
  623 		ksql_lastid(db, &id);
  624 	ksql_stmt_free(stmt);
  625 	return(id);
  626 }
  627 
  628 void
  629 json_company_data(struct kjsonreq *r, const struct company *p)
  630 {
  631 	kjson_putstringp(r, "name", p->name);
  632 	kjson_putintp(r, "id", p->id);
  633 
  634 	if ( ! p->has_somenum)
  635 		kjson_putnullp(r, "somenum");
  636 	else
  637 		kjson_putintp(r, "somenum", p->somenum);
  638 
  639 }
  640 
  641 void
  642 json_company_obj(struct kjsonreq *r, const struct company *p)
  643 {
  644 	kjson_objp_open(r, "company");
  645 	json_company_data(r, p);
  646 	kjson_obj_close(r);
  647 }
  648 
  649 void
  650 json_company_array(struct kjsonreq *r, const struct company_q *q)
  651 {
  652 	struct company *p;
  653 
  654 	kjson_arrayp_open(r, "company_q");
  655 	TAILQ_FOREACH(p, q, _entries) {
  656 		kjson_obj_open(r);
  657 		json_company_data(r, p);
  658 		kjson_obj_close(r);
  659 	}
  660 	kjson_array_close(r);
  661 }
  662 
  663 int
  664 jsmn_company(struct company *p, const char *buf, const jsmntok_t *t, size_t toksz)
  665 {
  666 	int i;
  667 	size_t j;
  668 
  669 	if (toksz < 1 || t[0].type != JSMN_OBJECT)
  670 		return 0;
  671 
  672 	for (i = 0, j = 0; i < t[0].size; i++) {
  673 		if (jsmn_eq(buf, &t[j+1], "name")) {
  674 			j++;
  675 			if (t[j+1].type != JSMN_STRING)
  676 				return 0;
  677 			p->name = strndup
  678 				(buf + t[j+1].start,
  679 				 t[j+1].end - t[j+1].start);
  680 			if (NULL == p->name)
  681 				return -1;
  682 			j++;
  683 			continue;
  684 		}
  685 		if (jsmn_eq(buf, &t[j+1], "id")) {
  686 			j++;
  687 			if (t[j+1].type != JSMN_PRIMITIVE ||
  688 			    ('-' != buf[t[j+1].start] &&
  689 			    ! isdigit((unsigned int)buf[t[j+1].start])))
  690 				return 0;
  691 			if ( ! jsmn_parse_int(buf + t[j+1].start,
  692 			    t[j+1].end - t[j+1].start, &p->id))
  693 				return 0;
  694 			j++;
  695 			continue;
  696 		}
  697 		if (jsmn_eq(buf, &t[j+1], "somenum")) {
  698 			j++;
  699 			if (t[j+1].type == JSMN_PRIMITIVE &&
  700 			    'n' == buf[t[j+1].start]) {
  701 				p->has_somenum = 0;
  702 				j++;
  703 				continue;
  704 			} else
  705 				p->has_somenum = 1;
  706 			if (t[j+1].type != JSMN_PRIMITIVE ||
  707 			    ('-' != buf[t[j+1].start] &&
  708 			    ! isdigit((unsigned int)buf[t[j+1].start])))
  709 				return 0;
  710 			if ( ! jsmn_parse_int(buf + t[j+1].start,
  711 			    t[j+1].end - t[j+1].start, &p->somenum))
  712 				return 0;
  713 			j++;
  714 			continue;
  715 		}
  716 
  717 		/* Anything else is unexpected. */
  718 
  719 		return 0;
  720 	}
  721 	return j+1;
  722 }
  723 
  724 void
  725 jsmn_company_clear(struct company *p)
  726 
  727 {
  728 	if (NULL == p)
  729 		return;
  730 	free(p->name);
  731 }
  732 
  733 void
  734 jsmn_company_free_array(struct company *p, size_t sz)
  735 {
  736 	size_t i;
  737 	for (i = 0; i < sz; i++)
  738 		jsmn_company_clear(&p[i]);
  739 	free(p);
  740 }
  741 
  742 int
  743 jsmn_company_array(struct company **p, size_t *sz, const char *buf, const jsmntok_t *t, size_t toksz)
  744 {
  745 	size_t i, j;
  746 	int rc;
  747 
  748 	*sz = 0;
  749 	*p = NULL;
  750 
  751 	if (toksz < 1 || t[0].type != JSMN_ARRAY)
  752 		return 0;
  753 
  754 	*sz = t[0].size;
  755 	if (NULL == (*p = calloc(*sz, sizeof(struct company))))
  756 		return -1;
  757 
  758 	for (i = j = 0; i < *sz; i++) {
  759 		rc = jsmn_company(&(*p)[i], buf, &t[j+1], toksz - j);
  760 		if (rc <= 0)
  761 			return rc;
  762 		j += rc;
  763 	}
  764 	return j + 1;
  765 }
  766 
  767 int
  768 valid_company_name(struct kpair *p)
  769 {
  770 	if ( ! kvalid_string(p))
  771 		return 0;
  772 	if (p->valsz <= 0)
  773 		return 0;
  774 	return 1;
  775 }
  776 
  777 int
  778 valid_company_id(struct kpair *p)
  779 {
  780 	if ( ! kvalid_int(p))
  781 		return 0;
  782 	return 1;
  783 }
  784 
  785 int
  786 valid_company_somenum(struct kpair *p)
  787 {
  788 	if ( ! kvalid_int(p))
  789 		return 0;
  790 	return 1;
  791 }
  792 
  793 struct company_q *
  794 db_company_list_by_somenum_isnull(struct ksql *db)
  795 {
  796 	struct ksqlstmt *stmt;
  797 	struct company_q *q;
  798 	struct company *p;
  799 
  800 	q = malloc(sizeof(struct company_q));
  801 	if (NULL == q) {
  802 		perror(NULL);
  803 		exit(EXIT_FAILURE);
  804 	}
  805 	TAILQ_INIT(q);
  806 
  807 	ksql_stmt_alloc(db, &stmt,
  808 		stmts[STMT_COMPANY_BY_SEARCH_0],
  809 		STMT_COMPANY_BY_SEARCH_0);
  810 	while (KSQL_ROW == ksql_stmt_step(stmt)) {
  811 		p = malloc(sizeof(struct company));
  812 		if (NULL == p) {
  813 			perror(NULL);
  814 			exit(EXIT_FAILURE);
  815 		}
  816 		db_company_fill_r(p, stmt, NULL);
  817 		TAILQ_INSERT_TAIL(q, p, _entries);
  818 	}
  819 	ksql_stmt_free(stmt);
  820 	return(q);
  821 }
  822 
  823 void
  824 db_user_fill(struct user *p, struct ksqlstmt *stmt, size_t *pos)
  825 {
  826 	size_t i = 0;
  827 	enum ksqlc c;
  828 	int64_t tmpint;
  829 	int hasval;
  830 
  831 	if (NULL == pos)
  832 		pos = &i;
  833 	memset(p, 0, sizeof(*p));
  834 	c = ksql_result_int(stmt, &p->cid, (*pos)++);
  835 	if (KSQL_OK != c)
  836 		exit(EXIT_FAILURE);
  837 	c = ksql_result_int(stmt, &tmpint, (*pos)++);
  838 	if (KSQL_OK != c)
  839 		exit(EXIT_FAILURE);
  840 	p->sex = tmpint;
  841 	c = ksql_result_str_alloc(stmt, &p->hash, (*pos)++);
  842 	if (KSQL_OK != c)
  843 		exit(EXIT_FAILURE);
  844 	c = ksql_result_str_alloc(stmt, &p->email, (*pos)++);
  845 	if (KSQL_OK != c)
  846 		exit(EXIT_FAILURE);
  847 	c = ksql_result_isnull(stmt, &hasval, *pos);
  848 	if (KSQL_OK != c)
  849 		exit(EXIT_FAILURE);
  850 	p->has_image = !hasval;
  851 	if (p->has_image) {
  852 		c = ksql_result_blob_alloc(stmt, &p->image, &p->image_sz, (*pos)++);
  853 		if (KSQL_OK != c)
  854 			exit(EXIT_FAILURE);
  855 	} else
  856 		(*pos)++;
  857 	c = ksql_result_str_alloc(stmt, &p->name, (*pos)++);
  858 	if (KSQL_OK != c)
  859 		exit(EXIT_FAILURE);
  860 	c = ksql_result_int(stmt, &p->uid, (*pos)++);
  861 	if (KSQL_OK != c)
  862 		exit(EXIT_FAILURE);
  863 }
  864 
  865 static void
  866 db_user_fill_r(struct user *p, struct ksqlstmt *stmt, size_t *pos)
  867 {
  868 	size_t i = 0;
  869 
  870 	if (NULL == pos)
  871 		pos = &i;
  872 	db_user_fill(p, stmt, pos);
  873 	db_company_fill_r(&p->company, stmt, pos);
  874 }
  875 
  876 void
  877 db_user_unfill(struct user *p)
  878 {
  879 	if (NULL == p)
  880 		return;
  881 	free(p->hash);
  882 	free(p->email);
  883 	free(p->image);
  884 	free(p->name);
  885 }
  886 
  887 static void
  888 db_user_unfill_r(struct user *p)
  889 {
  890 	if (NULL == p)
  891 		return;
  892 
  893 	db_user_unfill(p);
  894 	db_company_unfill_r(&p->company);
  895 }
  896 
  897 void
  898 db_user_free(struct user *p)
  899 {
  900 	db_user_unfill_r(p);
  901 	free(p);
  902 }
  903 
  904 int64_t
  905 db_user_insert(struct ksql *db, int64_t v1, enum sex v2, const char *v3,
  906 	const char *v4, size_t v5_sz, const void **v5, const char *v6)
  907 {
  908 	struct ksqlstmt *stmt;
  909 	int64_t id = -1;
  910 	char hash1[64];
  911 
  912 	crypt_newhash(v3, "blowfish,a", hash1, sizeof(hash1));
  913 
  914 	ksql_stmt_alloc(db, &stmt,
  915 		stmts[STMT_USER_INSERT],
  916 		STMT_USER_INSERT);
  917 	ksql_bind_int(stmt, 0, v1);
  918 	ksql_bind_int(stmt, 1, v2);
  919 	ksql_bind_str(stmt, 2, hash1);
  920 	ksql_bind_str(stmt, 3, v4);
  921 	if (NULL == v5)
  922 		ksql_bind_null(stmt, 4);
  923 	else
  924 		ksql_bind_blob(stmt, 4, *v5, v5_sz);
  925 	ksql_bind_str(stmt, 5, v6);
  926 	if (KSQL_DONE == ksql_stmt_cstep(stmt))
  927 		ksql_lastid(db, &id);
  928 	ksql_stmt_free(stmt);
  929 	return(id);
  930 }
  931 
  932 void
  933 json_user_data(struct kjsonreq *r, const struct user *p)
  934 {
  935 	char *buf1;
  936 	size_t sz;
  937 
  938 	/*
  939 	 * We need to base64 encode the binary buffers prior to 
  940 	 * serialisation.
  941 	 * Allocate space for these buffers and do so now.
  942 	 * We'll free the buffers at the epilogue of the function.
  943 	 */
  944 
  945 	sz = (p->image_sz + 2) / 3 * 4 + 1;
  946 	buf1 = malloc(sz);
  947 	if (NULL == buf1) {
  948 		perror(NULL);
  949 		exit(EXIT_FAILURE);
  950 	}
  951 	if (p->has_image)
  952 		b64_ntop(p->image, p->image_sz, buf1, sz);
  953 
  954 	kjson_objp_open(r, "company");
  955 	json_company_data(r, &p->company);
  956 	kjson_obj_close(r);
  957 	kjson_putintp(r, "cid", p->cid);
  958 	kjson_putintp(r, "sex", p->sex);
  959 
  960 	/* Omitting hash: is a password hash. */
  961 
  962 	kjson_putstringp(r, "email", p->email);
  963 
  964 	if ( ! p->has_image)
  965 		kjson_putnullp(r, "image");
  966 	else
  967 		kjson_putstringp(r, "image", buf1);
  968 
  969 	kjson_putstringp(r, "name", p->name);
  970 	kjson_putintp(r, "uid", p->uid);
  971 
  972 	free(buf1);
  973 }
  974 
  975 void
  976 json_user_obj(struct kjsonreq *r, const struct user *p)
  977 {
  978 	kjson_objp_open(r, "user");
  979 	json_user_data(r, p);
  980 	kjson_obj_close(r);
  981 }
  982 
  983 void
  984 json_user_iterate(const struct user *p, void *arg)
  985 {
  986 	struct kjsonreq *r = arg;
  987 
  988 	kjson_obj_open(r);
  989 	json_user_data(r, p);
  990 	kjson_obj_close(r);
  991 }
  992 
  993 int
  994 jsmn_user(struct user *p, const char *buf, const jsmntok_t *t, size_t toksz)
  995 {
  996 	int i;
  997 	size_t j;
  998 	int64_t tmpint;
  999 	int rc;
 1000 	char *tmpbuf;
 1001 
 1002 	if (toksz < 1 || t[0].type != JSMN_OBJECT)
 1003 		return 0;
 1004 
 1005 	for (i = 0, j = 0; i < t[0].size; i++) {
 1006 		if (jsmn_eq(buf, &t[j+1], "company")) {
 1007 			j++;
 1008 			if (t[j+1].type != JSMN_OBJECT)
 1009 				return 0;
 1010 			rc = jsmn_company
 1011 				(&p->company, buf,
 1012 				 &t[j+1], toksz - j);
 1013 			if (rc <= 0)
 1014 				return rc;
 1015 			j += rc;
 1016 			continue;
 1017 		}
 1018 		if (jsmn_eq(buf, &t[j+1], "cid")) {
 1019 			j++;
 1020 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1021 			    ('-' != buf[t[j+1].start] &&
 1022 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1023 				return 0;
 1024 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1025 			    t[j+1].end - t[j+1].start, &p->cid))
 1026 				return 0;
 1027 			j++;
 1028 			continue;
 1029 		}
 1030 		if (jsmn_eq(buf, &t[j+1], "sex")) {
 1031 			j++;
 1032 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1033 			    ('-' != buf[t[j+1].start] &&
 1034 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1035 				return 0;
 1036 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1037 			    t[j+1].end - t[j+1].start, &tmpint))
 1038 				return 0;
 1039 			p->sex = tmpint;
 1040 			j++;
 1041 			continue;
 1042 		}
 1043 		if (jsmn_eq(buf, &t[j+1], "hash")) {
 1044 			j++;
 1045 			if (t[j+1].type != JSMN_STRING)
 1046 				return 0;
 1047 			p->hash = strndup
 1048 				(buf + t[j+1].start,
 1049 				 t[j+1].end - t[j+1].start);
 1050 			if (NULL == p->hash)
 1051 				return -1;
 1052 			j++;
 1053 			continue;
 1054 		}
 1055 		if (jsmn_eq(buf, &t[j+1], "email")) {
 1056 			j++;
 1057 			if (t[j+1].type != JSMN_STRING)
 1058 				return 0;
 1059 			p->email = strndup
 1060 				(buf + t[j+1].start,
 1061 				 t[j+1].end - t[j+1].start);
 1062 			if (NULL == p->email)
 1063 				return -1;
 1064 			j++;
 1065 			continue;
 1066 		}
 1067 		if (jsmn_eq(buf, &t[j+1], "image")) {
 1068 			j++;
 1069 			if (t[j+1].type == JSMN_PRIMITIVE &&
 1070 			    'n' == buf[t[j+1].start]) {
 1071 				p->has_image = 0;
 1072 				j++;
 1073 				continue;
 1074 			} else
 1075 				p->has_image = 1;
 1076 			if (t[j+1].type != JSMN_STRING)
 1077 				return 0;
 1078 			tmpbuf = strndup
 1079 				(buf + t[j+1].start,
 1080 				 t[j+1].end - t[j+1].start);
 1081 			if (NULL == tmpbuf)
 1082 				return -1;
 1083 			p->image = malloc((t[j+1].end - t[j+1].start) + 1);
 1084 			if (NULL == p->image) {
 1085 				free(tmpbuf);
 1086 				return -1;
 1087 			}
 1088 			rc = b64_pton(tmpbuf, p->image,
 1089 				(t[j+1].end - t[j+1].start) + 1);
 1090 			free(tmpbuf);
 1091 			if (rc < 0)
 1092 				return -1;
 1093 			p->image_sz = rc;
 1094 			j++;
 1095 			continue;
 1096 		}
 1097 		if (jsmn_eq(buf, &t[j+1], "name")) {
 1098 			j++;
 1099 			if (t[j+1].type != JSMN_STRING)
 1100 				return 0;
 1101 			p->name = strndup
 1102 				(buf + t[j+1].start,
 1103 				 t[j+1].end - t[j+1].start);
 1104 			if (NULL == p->name)
 1105 				return -1;
 1106 			j++;
 1107 			continue;
 1108 		}
 1109 		if (jsmn_eq(buf, &t[j+1], "uid")) {
 1110 			j++;
 1111 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1112 			    ('-' != buf[t[j+1].start] &&
 1113 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1114 				return 0;
 1115 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1116 			    t[j+1].end - t[j+1].start, &p->uid))
 1117 				return 0;
 1118 			j++;
 1119 			continue;
 1120 		}
 1121 
 1122 		/* Anything else is unexpected. */
 1123 
 1124 		return 0;
 1125 	}
 1126 	return j+1;
 1127 }
 1128 
 1129 void
 1130 jsmn_user_clear(struct user *p)
 1131 
 1132 {
 1133 	if (NULL == p)
 1134 		return;
 1135 	jsmn_company_clear(&p->company);
 1136 	free(p->hash);
 1137 	free(p->email);
 1138 	free(p->image);
 1139 	free(p->name);
 1140 }
 1141 
 1142 void
 1143 jsmn_user_free_array(struct user *p, size_t sz)
 1144 {
 1145 	size_t i;
 1146 	for (i = 0; i < sz; i++)
 1147 		jsmn_user_clear(&p[i]);
 1148 	free(p);
 1149 }
 1150 
 1151 int
 1152 jsmn_user_array(struct user **p, size_t *sz, const char *buf, const jsmntok_t *t, size_t toksz)
 1153 {
 1154 	size_t i, j;
 1155 	int rc;
 1156 
 1157 	*sz = 0;
 1158 	*p = NULL;
 1159 
 1160 	if (toksz < 1 || t[0].type != JSMN_ARRAY)
 1161 		return 0;
 1162 
 1163 	*sz = t[0].size;
 1164 	if (NULL == (*p = calloc(*sz, sizeof(struct user))))
 1165 		return -1;
 1166 
 1167 	for (i = j = 0; i < *sz; i++) {
 1168 		rc = jsmn_user(&(*p)[i], buf, &t[j+1], toksz - j);
 1169 		if (rc <= 0)
 1170 			return rc;
 1171 		j += rc;
 1172 	}
 1173 	return j + 1;
 1174 }
 1175 
 1176 int
 1177 valid_user_cid(struct kpair *p)
 1178 {
 1179 	if ( ! kvalid_int(p))
 1180 		return 0;
 1181 	return 1;
 1182 }
 1183 
 1184 int
 1185 valid_user_sex(struct kpair *p)
 1186 {
 1187 	if ( ! kvalid_int(p))
 1188 		return 0;
 1189 	switch(p->parsed.i) {
 1190 	case 0:
 1191 	case 1:
 1192 	case 2:
 1193 		break;
 1194 	default:
 1195 		return 0;
 1196 	}
 1197 	return 1;
 1198 }
 1199 
 1200 int
 1201 valid_user_hash(struct kpair *p)
 1202 {
 1203 	if ( ! kvalid_string(p))
 1204 		return 0;
 1205 	if (p->valsz <= 0)
 1206 		return 0;
 1207 	return 1;
 1208 }
 1209 
 1210 int
 1211 valid_user_email(struct kpair *p)
 1212 {
 1213 	if ( ! kvalid_email(p))
 1214 		return 0;
 1215 	return 1;
 1216 }
 1217 
 1218 int
 1219 valid_user_image(struct kpair *p)
 1220 {
 1221 	return 1;
 1222 }
 1223 
 1224 int
 1225 valid_user_name(struct kpair *p)
 1226 {
 1227 	if ( ! kvalid_string(p))
 1228 		return 0;
 1229 	return 1;
 1230 }
 1231 
 1232 int
 1233 valid_user_uid(struct kpair *p)
 1234 {
 1235 	if ( ! kvalid_int(p))
 1236 		return 0;
 1237 	return 1;
 1238 }
 1239 
 1240 void
 1241 db_user_iterate_by_name_eq(struct ksql *db, user_cb cb, void *arg, const char *v1)
 1242 {
 1243 	struct ksqlstmt *stmt;
 1244 	struct user p;
 1245 
 1246 	ksql_stmt_alloc(db, &stmt,
 1247 		stmts[STMT_USER_BY_SEARCH_0],
 1248 		STMT_USER_BY_SEARCH_0);
 1249 	ksql_bind_str(stmt, 0, v1);
 1250 	while (KSQL_ROW == ksql_stmt_step(stmt)) {
 1251 		db_user_fill_r(&p, stmt, NULL);
 1252 		(*cb)(&p, arg);
 1253 		db_user_unfill_r(&p);
 1254 	}
 1255 	ksql_stmt_free(stmt);
 1256 }
 1257 
 1258 struct user *
 1259 db_user_get_creds(struct ksql *db, const char *v1, const char *v2)
 1260 {
 1261 	struct ksqlstmt *stmt;
 1262 	struct user *p = NULL;
 1263 
 1264 	ksql_stmt_alloc(db, &stmt,
 1265 		stmts[STMT_USER_BY_SEARCH_1],
 1266 		STMT_USER_BY_SEARCH_1);
 1267 	ksql_bind_str(stmt, 0, v1);
 1268 	if (KSQL_ROW == ksql_stmt_step(stmt)) {
 1269 		p = malloc(sizeof(struct user));
 1270 		if (NULL == p) {
 1271 			perror(NULL);
 1272 			exit(EXIT_FAILURE);
 1273 		}
 1274 		db_user_fill_r(p, stmt, NULL);
 1275 		if (NULL != p && (crypt_checkpass(v2, p->hash) < 0)) {
 1276 			db_user_free(p);
 1277 			p = NULL;
 1278 		}
 1279 	}
 1280 	ksql_stmt_free(stmt);
 1281 	return p;
 1282 }
 1283 
 1284 struct user *
 1285 db_user_get_by_uid_eq(struct ksql *db, int64_t v1)
 1286 {
 1287 	struct ksqlstmt *stmt;
 1288 	struct user *p = NULL;
 1289 
 1290 	ksql_stmt_alloc(db, &stmt,
 1291 		stmts[STMT_USER_BY_SEARCH_2],
 1292 		STMT_USER_BY_SEARCH_2);
 1293 	ksql_bind_int(stmt, 0, v1);
 1294 	if (KSQL_ROW == ksql_stmt_step(stmt)) {
 1295 		p = malloc(sizeof(struct user));
 1296 		if (NULL == p) {
 1297 			perror(NULL);
 1298 			exit(EXIT_FAILURE);
 1299 		}
 1300 		db_user_fill_r(p, stmt, NULL);
 1301 	}
 1302 	ksql_stmt_free(stmt);
 1303 	return p;
 1304 }
 1305 
 1306 int
 1307 db_user_update_hash_by_uid_eq(struct ksql *db, const char *v1, int64_t v2)
 1308 {
 1309 	struct ksqlstmt *stmt;
 1310 	enum ksqlc c;
 1311 	char hash1[64];
 1312 
 1313 	crypt_newhash(v1, "blowfish,a", hash1, sizeof(hash1));
 1314 
 1315 	ksql_stmt_alloc(db, &stmt,
 1316 		stmts[STMT_USER_UPDATE_0],
 1317 		STMT_USER_UPDATE_0);
 1318 	ksql_bind_str(stmt, 0, hash1);
 1319 	ksql_bind_int(stmt, 1, v2);
 1320 	c = ksql_stmt_cstep(stmt);
 1321 	ksql_stmt_free(stmt);
 1322 	return(KSQL_CONSTRAINT != c);
 1323 }
 1324 
 1325 int
 1326 db_user_update_email_by_uid_eq(struct ksql *db, const char *v1, int64_t v2)
 1327 {
 1328 	struct ksqlstmt *stmt;
 1329 	enum ksqlc c;
 1330 
 1331 	ksql_stmt_alloc(db, &stmt,
 1332 		stmts[STMT_USER_UPDATE_1],
 1333 		STMT_USER_UPDATE_1);
 1334 	ksql_bind_str(stmt, 0, v1);
 1335 	ksql_bind_int(stmt, 1, v2);
 1336 	c = ksql_stmt_cstep(stmt);
 1337 	ksql_stmt_free(stmt);
 1338 	return(KSQL_CONSTRAINT != c);
 1339 }
 1340 
 1341 void
 1342 db_session_fill(struct session *p, struct ksqlstmt *stmt, size_t *pos)
 1343 {
 1344 	size_t i = 0;
 1345 	enum ksqlc c;
 1346 
 1347 	if (NULL == pos)
 1348 		pos = &i;
 1349 	memset(p, 0, sizeof(*p));
 1350 	c = ksql_result_int(stmt, &p->userid, (*pos)++);
 1351 	if (KSQL_OK != c)
 1352 		exit(EXIT_FAILURE);
 1353 	c = ksql_result_int(stmt, &p->token, (*pos)++);
 1354 	if (KSQL_OK != c)
 1355 		exit(EXIT_FAILURE);
 1356 	c = ksql_result_int(stmt, &p->mtime, (*pos)++);
 1357 	if (KSQL_OK != c)
 1358 		exit(EXIT_FAILURE);
 1359 	c = ksql_result_int(stmt, &p->id, (*pos)++);
 1360 	if (KSQL_OK != c)
 1361 		exit(EXIT_FAILURE);
 1362 }
 1363 
 1364 static void
 1365 db_session_fill_r(struct session *p, struct ksqlstmt *stmt, size_t *pos)
 1366 {
 1367 	size_t i = 0;
 1368 
 1369 	if (NULL == pos)
 1370 		pos = &i;
 1371 	db_session_fill(p, stmt, pos);
 1372 	db_user_fill_r(&p->user, stmt, pos);
 1373 }
 1374 
 1375 void
 1376 db_session_unfill(struct session *p)
 1377 {
 1378 	if (NULL == p)
 1379 		return;
 1380 }
 1381 
 1382 static void
 1383 db_session_unfill_r(struct session *p)
 1384 {
 1385 	if (NULL == p)
 1386 		return;
 1387 
 1388 	db_session_unfill(p);
 1389 	db_user_unfill_r(&p->user);
 1390 }
 1391 
 1392 void
 1393 db_session_free(struct session *p)
 1394 {
 1395 	db_session_unfill_r(p);
 1396 	free(p);
 1397 }
 1398 
 1399 int64_t
 1400 db_session_insert(struct ksql *db, int64_t v1, int64_t v2, time_t v3)
 1401 {
 1402 	struct ksqlstmt *stmt;
 1403 	int64_t id = -1;
 1404 
 1405 	ksql_stmt_alloc(db, &stmt,
 1406 		stmts[STMT_SESSION_INSERT],
 1407 		STMT_SESSION_INSERT);
 1408 	ksql_bind_int(stmt, 0, v1);
 1409 	ksql_bind_int(stmt, 1, v2);
 1410 	ksql_bind_int(stmt, 2, v3);
 1411 	if (KSQL_DONE == ksql_stmt_cstep(stmt))
 1412 		ksql_lastid(db, &id);
 1413 	ksql_stmt_free(stmt);
 1414 	return(id);
 1415 }
 1416 
 1417 void
 1418 json_session_data(struct kjsonreq *r, const struct session *p)
 1419 {
 1420 	kjson_objp_open(r, "user");
 1421 	json_user_data(r, &p->user);
 1422 	kjson_obj_close(r);
 1423 	kjson_putintp(r, "userid", p->userid);
 1424 	kjson_putintp(r, "token", p->token);
 1425 	kjson_putintp(r, "mtime", p->mtime);
 1426 	kjson_putintp(r, "id", p->id);
 1427 }
 1428 
 1429 void
 1430 json_session_obj(struct kjsonreq *r, const struct session *p)
 1431 {
 1432 	kjson_objp_open(r, "session");
 1433 	json_session_data(r, p);
 1434 	kjson_obj_close(r);
 1435 }
 1436 
 1437 void
 1438 json_session_iterate(const struct session *p, void *arg)
 1439 {
 1440 	struct kjsonreq *r = arg;
 1441 
 1442 	kjson_obj_open(r);
 1443 	json_session_data(r, p);
 1444 	kjson_obj_close(r);
 1445 }
 1446 
 1447 int
 1448 jsmn_session(struct session *p, const char *buf, const jsmntok_t *t, size_t toksz)
 1449 {
 1450 	int i;
 1451 	size_t j;
 1452 	int rc;
 1453 
 1454 	if (toksz < 1 || t[0].type != JSMN_OBJECT)
 1455 		return 0;
 1456 
 1457 	for (i = 0, j = 0; i < t[0].size; i++) {
 1458 		if (jsmn_eq(buf, &t[j+1], "user")) {
 1459 			j++;
 1460 			if (t[j+1].type != JSMN_OBJECT)
 1461 				return 0;
 1462 			rc = jsmn_user
 1463 				(&p->user, buf,
 1464 				 &t[j+1], toksz - j);
 1465 			if (rc <= 0)
 1466 				return rc;
 1467 			j += rc;
 1468 			continue;
 1469 		}
 1470 		if (jsmn_eq(buf, &t[j+1], "userid")) {
 1471 			j++;
 1472 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1473 			    ('-' != buf[t[j+1].start] &&
 1474 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1475 				return 0;
 1476 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1477 			    t[j+1].end - t[j+1].start, &p->userid))
 1478 				return 0;
 1479 			j++;
 1480 			continue;
 1481 		}
 1482 		if (jsmn_eq(buf, &t[j+1], "token")) {
 1483 			j++;
 1484 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1485 			    ('-' != buf[t[j+1].start] &&
 1486 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1487 				return 0;
 1488 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1489 			    t[j+1].end - t[j+1].start, &p->token))
 1490 				return 0;
 1491 			j++;
 1492 			continue;
 1493 		}
 1494 		if (jsmn_eq(buf, &t[j+1], "mtime")) {
 1495 			j++;
 1496 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1497 			    ('-' != buf[t[j+1].start] &&
 1498 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1499 				return 0;
 1500 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1501 			    t[j+1].end - t[j+1].start, &p->mtime))
 1502 				return 0;
 1503 			j++;
 1504 			continue;
 1505 		}
 1506 		if (jsmn_eq(buf, &t[j+1], "id")) {
 1507 			j++;
 1508 			if (t[j+1].type != JSMN_PRIMITIVE ||
 1509 			    ('-' != buf[t[j+1].start] &&
 1510 			    ! isdigit((unsigned int)buf[t[j+1].start])))
 1511 				return 0;
 1512 			if ( ! jsmn_parse_int(buf + t[j+1].start,
 1513 			    t[j+1].end - t[j+1].start, &p->id))
 1514 				return 0;
 1515 			j++;
 1516 			continue;
 1517 		}
 1518 
 1519 		/* Anything else is unexpected. */
 1520 
 1521 		return 0;
 1522 	}
 1523 	return j+1;
 1524 }
 1525 
 1526 void
 1527 jsmn_session_clear(struct session *p)
 1528 
 1529 {
 1530 	if (NULL == p)
 1531 		return;
 1532 	jsmn_user_clear(&p->user);
 1533 }
 1534 
 1535 void
 1536 jsmn_session_free_array(struct session *p, size_t sz)
 1537 {
 1538 	size_t i;
 1539 	for (i = 0; i < sz; i++)
 1540 		jsmn_session_clear(&p[i]);
 1541 	free(p);
 1542 }
 1543 
 1544 int
 1545 jsmn_session_array(struct session **p, size_t *sz, const char *buf, const jsmntok_t *t, size_t toksz)
 1546 {
 1547 	size_t i, j;
 1548 	int rc;
 1549 
 1550 	*sz = 0;
 1551 	*p = NULL;
 1552 
 1553 	if (toksz < 1 || t[0].type != JSMN_ARRAY)
 1554 		return 0;
 1555 
 1556 	*sz = t[0].size;
 1557 	if (NULL == (*p = calloc(*sz, sizeof(struct session))))
 1558 		return -1;
 1559 
 1560 	for (i = j = 0; i < *sz; i++) {
 1561 		rc = jsmn_session(&(*p)[i], buf, &t[j+1], toksz - j);
 1562 		if (rc <= 0)
 1563 			return rc;
 1564 		j += rc;
 1565 	}
 1566 	return j + 1;
 1567 }
 1568 
 1569 int
 1570 valid_session_userid(struct kpair *p)
 1571 {
 1572 	if ( ! kvalid_int(p))
 1573 		return 0;
 1574 	return 1;
 1575 }
 1576 
 1577 int
 1578 valid_session_token(struct kpair *p)
 1579 {
 1580 	if ( ! kvalid_int(p))
 1581 		return 0;
 1582 	return 1;
 1583 }
 1584 
 1585 int
 1586 valid_session_mtime(struct kpair *p)
 1587 {
 1588 	if ( ! kvalid_int(p))
 1589 		return 0;
 1590 	return 1;
 1591 }
 1592 
 1593 int
 1594 valid_session_id(struct kpair *p)
 1595 {
 1596 	if ( ! kvalid_int(p))
 1597 		return 0;
 1598 	return 1;
 1599 }
 1600 
 1601 void
 1602 db_session_iterate_foo(struct ksql *db, session_cb cb, void *arg, const char *v1,
 1603 	time_t v2)
 1604 {
 1605 	struct ksqlstmt *stmt;
 1606 	struct session p;
 1607 
 1608 	ksql_stmt_alloc(db, &stmt,
 1609 		stmts[STMT_SESSION_BY_SEARCH_0],
 1610 		STMT_SESSION_BY_SEARCH_0);
 1611 	ksql_bind_str(stmt, 0, v1);
 1612 	ksql_bind_int(stmt, 1, v2);
 1613 	while (KSQL_ROW == ksql_stmt_step(stmt)) {
 1614 		db_session_fill_r(&p, stmt, NULL);
 1615 		(*cb)(&p, arg);
 1616 		db_session_unfill_r(&p);
 1617 	}
 1618 	ksql_stmt_free(stmt);
 1619 }
 1620 
 1621 int
 1622 db_session_delete_by_id_eq(struct ksql *db, int64_t v1)
 1623 {
 1624 	struct ksqlstmt *stmt;
 1625 	enum ksqlc c;
 1626 
 1627 	ksql_stmt_alloc(db, &stmt,
 1628 		stmts[STMT_SESSION_DELETE_0],
 1629 		STMT_SESSION_DELETE_0);
 1630 	ksql_bind_int(stmt, 0, v1);
 1631 	c = ksql_stmt_cstep(stmt);
 1632 	ksql_stmt_free(stmt);
 1633 	return(KSQL_CONSTRAINT != c);
 1634 }
 1635