Ejemplo n.º 1
0
bool hplugins_addpacket(unsigned short cmd, unsigned short length, void (*receive) (int fd), unsigned int point, unsigned int pluginID)
{
	struct HPluginPacket *packet;
	int i;

	if (point >= hpPHP_MAX) {
		ShowError("HPM->addPacket:%s: unknown point '%u' specified for packet 0x%04x (len %d)\n",HPM->pid2name(pluginID),point,cmd,length);
		return false;
	}

	for (i = 0; i < VECTOR_LENGTH(HPM->packets[point]); i++) {
		if (VECTOR_INDEX(HPM->packets[point], i).cmd == cmd ) {
			ShowError("HPM->addPacket:%s: can't add packet 0x%04x, already in use by '%s'!",
					HPM->pid2name(pluginID), cmd, HPM->pid2name(VECTOR_INDEX(HPM->packets[point], i).pluginID));
			return false;
		}
	}

	VECTOR_ENSURE(HPM->packets[point], 1, 1);
	VECTOR_PUSHZEROED(HPM->packets[point]);
	packet = &VECTOR_LAST(HPM->packets[point]);

	packet->pluginID = pluginID;
	packet->cmd = cmd;
	packet->len = length;
	packet->receive = receive;

	return true;
}
Ejemplo n.º 2
0
/**
 * Saves changed achievements for a character.
 * @param[in]   char_id     character identifier.
 * @param[out]  cp          pointer to loaded achievements.
 * @param[in]   p           pointer to map-sent character achievements.
 * @return number of achievements saved.
 */
static int inter_achievement_tosql(int char_id, struct char_achievements *cp, const struct char_achievements *p)
{
	StringBuf buf;
	int i = 0, rows = 0;

	nullpo_ret(cp);
	nullpo_ret(p);
	Assert_ret(char_id > 0);

	StrBuf->Init(&buf);
	StrBuf->Printf(&buf, "REPLACE INTO `%s` (`char_id`, `ach_id`, `completed_at`, `rewarded_at`", char_achievement_db);
	for (i = 0; i < MAX_ACHIEVEMENT_OBJECTIVES; i++)
		StrBuf->Printf(&buf, ", `obj_%d`", i);
	StrBuf->AppendStr(&buf, ") VALUES ");

	for (i = 0; i < VECTOR_LENGTH(*p); i++) {
		int j = 0;
		bool save = false;
		struct achievement *pa = &VECTOR_INDEX(*p, i), *cpa = NULL;

		ARR_FIND(0, VECTOR_LENGTH(*cp), j, ((cpa = &VECTOR_INDEX(*cp, j)) && cpa->id == pa->id));

		if (j == VECTOR_LENGTH(*cp))
			save = true;
		else if (memcmp(cpa, pa, sizeof(struct achievement)) != 0)
			save = true;

		if (save) {
			StrBuf->Printf(&buf, "%s('%d', '%d', '%"PRId64"', '%"PRId64"'", rows ?", ":"", char_id, pa->id, (int64)pa->completed_at, (int64)pa->rewarded_at);
			for (j = 0; j < MAX_ACHIEVEMENT_OBJECTIVES; j++)
				StrBuf->Printf(&buf, ", '%d'", pa->objective[j]);
			StrBuf->AppendStr(&buf, ")");
			rows++;
		}
	}

	if (rows > 0 && SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) {
		Sql_ShowDebug(inter->sql_handle);
		StrBuf->Destroy(&buf); // Destroy the buffer.
		return 0;
	}
	// Destroy the buffer.
	StrBuf->Destroy(&buf);

	if (rows) {
		ShowInfo("achievements saved for char %d (total: %d, saved: %d)\n", char_id, VECTOR_LENGTH(*p), rows);

		/* Sync with inter-db acheivements. */
		VECTOR_CLEAR(*cp);
		VECTOR_ENSURE(*cp, VECTOR_LENGTH(*p), 1);
		VECTOR_PUSHARRAY(*cp, VECTOR_DATA(*p), VECTOR_LENGTH(*p));
	}

	return rows;
}
Ejemplo n.º 3
0
/**
 * Imports a shared symbol.
 *
 * @param name The symbol name.
 * @param pID  The requesting plugin ID.
 * @return The symbol value.
 * @retval NULL if the symbol wasn't found.
 */
void *hplugin_import_symbol(char *name, unsigned int pID)
{
	int i;
	ARR_FIND(0, VECTOR_LENGTH(HPM->symbols), i, strcmp(VECTOR_INDEX(HPM->symbols, i)->name, name) == 0);

	if (i != VECTOR_LENGTH(HPM->symbols))
		return VECTOR_INDEX(HPM->symbols, i)->ptr;

	ShowError("HPM:get_symbol:%s: '"CL_WHITE"%s"CL_RESET"' not found!\n",HPM->pid2name(pID),name);
	return NULL;
}
Ejemplo n.º 4
0
/**
 * Adds an entry to a plugin data store.
 *
 * @param type[in]         The store type.
 * @param pluginID[in]     The plugin identifier.
 * @param storeptr[in,out] A pointer to the store. The store will be initialized if necessary.
 * @param data[in]         The data entry to add.
 * @param classid[in]      The entry class identifier.
 * @param autofree[in]     Whether the entry should be automatically freed when removed.
 */
void hplugins_addToHPData(enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store **storeptr, void *data, uint32 classid, bool autofree)
{
	struct hplugin_data_store *store;
	struct hplugin_data_entry *entry;
	int i;
	nullpo_retv(storeptr);

	if (!HPM->data_store_validate(type, storeptr, true)) {
		/* woo it failed! */
		ShowError("HPM:addToHPData:%s: failed, type %u (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid);
		return;
	}
	store = *storeptr;

	/* duplicate check */
	ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid);
	if (i != VECTOR_LENGTH(store->entries)) {
		ShowError("HPM:addToHPData:%s: error! attempting to insert duplicate struct of id %u and classid %u\n", HPM->pid2name(pluginID), pluginID, classid);
		return;
	}

	/* hplugin_data_entry is always same size, probably better to use the ERS (with reasonable chunk size e.g. 10/25/50) */
	CREATE(entry, struct hplugin_data_entry, 1);

	/* input */
	entry->pluginID = pluginID;
	entry->classid = classid;
	entry->flag.free = autofree ? 1 : 0;
	entry->data = data;

	VECTOR_ENSURE(store->entries, 1, 1);
	VECTOR_PUSH(store->entries, entry);
}
Ejemplo n.º 5
0
void intercom_claim(intercom_ctx *ctx, struct client *client) {
  struct timespec now;
  clock_gettime(CLOCK_MONOTONIC, &now);

  intercom_packet_claim *packet = malloc(sizeof(intercom_packet_claim) + CLAIM_MAX * sizeof(intercom_packet_claim_entry));
  int i;

  uint32_t nonce = rand();

  packet->hdr = (intercom_packet_hdr) {
    .type = INTERCOM_CLAIM,
    .nonce = nonce,
    .ttl = 255,
  };

  memcpy(&packet->sender, ctx->ip.s6_addr, sizeof(uint8_t) * 16);
  memcpy(&packet->mac, client->mac, sizeof(uint8_t) * 6);
  packet->lastseen = now.tv_sec - client->lastseen.tv_sec;

  intercom_packet_claim_entry *entry = (intercom_packet_claim_entry*)((uint8_t*)(packet) + sizeof(intercom_packet_claim));

  for (i = 0; i < VECTOR_LEN(client->addresses) && i < CLAIM_MAX; i++) {
    struct client_ip *ip = &VECTOR_INDEX(client->addresses, i);
    entry->lastseen = now.tv_sec - ip->lastseen.tv_sec;
    memcpy(&entry->address, ip->address.s6_addr, sizeof(uint8_t) * 16);
    entry++;
  }

  packet->num_addresses = i;

  ssize_t packet_len = sizeof(intercom_packet_claim) + i * sizeof(intercom_packet_claim_entry);
  intercom_recently_seen_add(ctx, &packet->hdr);
  intercom_send_packet(ctx, (uint8_t*)packet, packet_len);
}
Ejemplo n.º 6
0
/**
 * Executes an event on all loaded plugins.
 *
 * @param type The event type to trigger.
 */
void hplugin_trigger_event(enum hp_event_types type)
{
	int i;
	for (i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) {
		struct hplugin *plugin = VECTOR_INDEX(HPM->plugins, i);
		if (plugin->hpi->event[type] != NULL)
			plugin->hpi->event[type]();
	}
}
Ejemplo n.º 7
0
/**
 * Retrieves an entry from a plugin data store.
 *
 * @param type[in]     The store type.
 * @param pluginID[in] The plugin identifier.
 * @param store[in]    The store.
 * @param classid[in]  The entry class identifier.
 *
 * @return The retrieved entry, or NULL.
 */
void *hplugins_getFromHPData(enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store *store, uint32 classid)
{
	int i;

	if (!HPM->data_store_validate(type, &store, false)) {
		/* woo it failed! */
		ShowError("HPM:getFromHPData:%s: failed, type %u (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid);
		return NULL;
	}
	if (!store)
		return NULL;

	ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid);
	if (i != VECTOR_LENGTH(store->entries))
		return VECTOR_INDEX(store->entries, i)->data;

	return NULL;
}
Ejemplo n.º 8
0
/**
 * Checks whether a plugin is currently loaded
 *
 * @param filename The plugin filename.
 * @retval true  if the plugin exists and is currently loaded.
 * @retval false otherwise.
 */
bool hplugin_exists(const char *filename)
{
	int i;
	for (i = 0; i < VECTOR_LENGTH(HPM->plugins); i++) {
		if (strcmpi(VECTOR_INDEX(HPM->plugins, i)->filename,filename) == 0)
			return true;
	}
	return false;
}
Ejemplo n.º 9
0
bool intercom_has_ifname(intercom_ctx *ctx, char *ifname) {
  for (int i = 0; i < VECTOR_LEN(ctx->interfaces); i++) {
    intercom_if *iface = &VECTOR_INDEX(ctx->interfaces, i);

    if (strcmp(ifname, iface->ifname) == 0)
      return true;
  }

  return false;
}
Ejemplo n.º 10
0
/**
 * Removes an entry from a plugin data store.
 *
 * @param type[in]     The store type.
 * @param pluginID[in] The plugin identifier.
 * @param store[in]    The store.
 * @param classid[in]  The entry class identifier.
 */
void hplugins_removeFromHPData(enum HPluginDataTypes type, uint32 pluginID, struct hplugin_data_store *store, uint32 classid)
{
	struct hplugin_data_entry *entry;
	int i;

	if (!HPM->data_store_validate(type, &store, false)) {
		/* woo it failed! */
		ShowError("HPM:removeFromHPData:%s: failed, type %u (%u|%u)\n", HPM->pid2name(pluginID), type, pluginID, classid);
		return;
	}
	if (!store)
		return;

	ARR_FIND(0, VECTOR_LENGTH(store->entries), i, VECTOR_INDEX(store->entries, i)->pluginID == pluginID && VECTOR_INDEX(store->entries, i)->classid == classid);
	if (i == VECTOR_LENGTH(store->entries))
		return;

	entry = VECTOR_INDEX(store->entries, i);
	VECTOR_ERASE(store->entries, i); // Erase and compact
	aFree(entry->data); // when it's removed we delete it regardless of autofree
	aFree(entry);
}
Ejemplo n.º 11
0
void intercom_update_interfaces(intercom_ctx *ctx) {
  for (int i = 0; i < VECTOR_LEN(ctx->interfaces); i++) {
    intercom_if *iface = &VECTOR_INDEX(ctx->interfaces, i);

    iface->ifindex = if_nametoindex(iface->ifname);

    if (!iface->ifindex)
      continue;

    if (join_mcast(ctx->fd, ctx->groupaddr.sin6_addr, iface))
      iface->ok = true;
  }
}
Ejemplo n.º 12
0
/**
 * Adds a configuration listener for a plugin.
 *
 * @param pluginID The plugin identifier.
 * @param type     The configuration type to listen for.
 * @param name     The configuration entry name.
 * @param func     The callback function.
 * @retval true if the listener was added successfully.
 * @retval false in case of error.
 */
bool hplugins_addconf(unsigned int pluginID, enum HPluginConfType type, char *name, void (*parse_func) (const char *key, const char *val), int (*return_func) (const char *key))
{
	struct HPConfListenStorage *conf;
	int i;

	if (parse_func == NULL) {
		ShowError("HPM->addConf:%s: missing setter function for config '%s'\n",HPM->pid2name(pluginID),name);
		return false;
	}

	if (type == HPCT_BATTLE && return_func == NULL) {
		ShowError("HPM->addConf:%s: missing getter function for config '%s'\n",HPM->pid2name(pluginID),name);
		return false;
	}

	if (type >= HPCT_MAX) {
		ShowError("HPM->addConf:%s: unknown point '%u' specified for config '%s'\n",HPM->pid2name(pluginID),type,name);
		return false;
	}

	ARR_FIND(0, VECTOR_LENGTH(HPM->config_listeners[type]), i, strcmpi(name, VECTOR_INDEX(HPM->config_listeners[type], i).key) == 0);
	if (i != VECTOR_LENGTH(HPM->config_listeners[type])) {
		ShowError("HPM->addConf:%s: duplicate '%s', already in use by '%s'!",
				HPM->pid2name(pluginID), name, HPM->pid2name(VECTOR_INDEX(HPM->config_listeners[type], i).pluginID));
		return false;
	}

	VECTOR_ENSURE(HPM->config_listeners[type], 1, 1);
	VECTOR_PUSHZEROED(HPM->config_listeners[type]);
	conf = &VECTOR_LAST(HPM->config_listeners[type]);

	conf->pluginID = pluginID;
	safestrncpy(conf->key, name, HPM_ADDCONF_LENGTH);
	conf->parse_func = parse_func;
	conf->return_func = return_func;

	return true;
}
Ejemplo n.º 13
0
/*==========================================
 * Inbox Request
 *------------------------------------------*/
void mapif_rodex_sendinbox(int fd, int char_id, int8 opentype, int8 flag, int count, int64 mail_id, struct rodex_maillist *mails)
{
	int per_packet = (UINT16_MAX - 24) / sizeof(struct rodex_message);
	int sent = 0;
	bool is_first = true;
	nullpo_retv(mails);
	Assert_retv(char_id > 0);
	Assert_retv(count >= 0);
	Assert_retv(mail_id >= 0);

	do {
		int i = 24, j, size, limit;
		int to_send = count - sent;
		bool is_last = true;

		if (to_send <= per_packet) {
			size = to_send * sizeof(struct rodex_message) + 24;
			limit = to_send;
			is_last = true;
		} else {
			limit = min(to_send, per_packet);
			if (limit != to_send) {
				is_last = false;
			}
			size = limit * sizeof(struct rodex_message) + 24;
		}

		WFIFOHEAD(fd, size);
		WFIFOW(fd, 0) = 0x3895;
		WFIFOW(fd, 2) = size;
		WFIFOL(fd, 4) = char_id;
		WFIFOB(fd, 8) = opentype;
		WFIFOB(fd, 9) = flag;
		WFIFOB(fd, 10) = is_last;
		WFIFOB(fd, 11) = is_first;
		WFIFOL(fd, 12) = limit;
		WFIFOQ(fd, 16) = mail_id;
		for (j = 0; j < limit; ++j, ++sent, i += sizeof(struct rodex_message)) {
			memcpy(WFIFOP(fd, i), &VECTOR_INDEX(*mails, sent), sizeof(struct rodex_message));
		}
		WFIFOSET(fd, size);

		is_first = false;
	} while (sent < count);
}
Ejemplo n.º 14
0
/**
 * Adds a plugin-defined command-line argument.
 *
 * @param pluginID  the current plugin's ID.
 * @param name      the command line argument's name, including the leading '--'.
 * @param has_param whether the command line argument expects to be followed by a value.
 * @param func      the triggered function.
 * @param help      the help string to be displayed by '--help', if any.
 * @return the success status.
 */
bool hpm_add_arg(unsigned int pluginID, char *name, bool has_param, CmdlineExecFunc func, const char *help)
{
	int i;

	if (!name || strlen(name) < 3 || name[0] != '-' || name[1] != '-') {
		ShowError("HPM:add_arg:%s invalid argument name: arguments must begin with '--' (from %s)\n", name, HPM->pid2name(pluginID));
		return false;
	}

	ARR_FIND(0, VECTOR_LENGTH(cmdline->args_data), i, strcmp(VECTOR_INDEX(cmdline->args_data, i).name, name) == 0);

	if (i != VECTOR_LENGTH(cmdline->args_data)) {
		ShowError("HPM:add_arg:%s duplicate! (from %s)\n",name,HPM->pid2name(pluginID));
		return false;
	}

	return cmdline->arg_add(pluginID, name, '\0', func, help, has_param ? CMDLINE_OPT_PARAM : CMDLINE_OPT_NORMAL);
}
Ejemplo n.º 15
0
/**
 * Creates a new console command entry.
 *
 * @param name The command name.
 * @param func The command callback.
 */
void console_parse_create(char *name, CParseFunc func)
{
	int i;
	char *tok;
	char sublist[CP_CMD_LENGTH * 5];
	struct CParseEntry *cmd;

	safestrncpy(sublist, name, CP_CMD_LENGTH * 5);
	tok = strtok(sublist,":");

	ARR_FIND(0, VECTOR_LENGTH(console->input->command_list), i, strcmpi(tok, VECTOR_INDEX(console->input->command_list, i)->cmd) == 0);

	if (i == VECTOR_LENGTH(console->input->command_list)) {
		CREATE(cmd, struct CParseEntry, 1);
		safestrncpy(cmd->cmd, tok, CP_CMD_LENGTH);
		cmd->type = CPET_UNKNOWN;
		VECTOR_ENSURE(console->input->commands, 1, 1);
		VECTOR_PUSH(console->input->commands, cmd);
		VECTOR_ENSURE(console->input->command_list, 1, 1);
		VECTOR_PUSH(console->input->command_list, cmd);
	}
Ejemplo n.º 16
0
	safestrncpy(sublist, name, CP_CMD_LENGTH * 5);
	tok = strtok(sublist,":");

	ARR_FIND(0, VECTOR_LENGTH(console->input->command_list), i, strcmpi(tok, VECTOR_INDEX(console->input->command_list, i)->cmd) == 0);

	if (i == VECTOR_LENGTH(console->input->command_list)) {
		CREATE(cmd, struct CParseEntry, 1);
		safestrncpy(cmd->cmd, tok, CP_CMD_LENGTH);
		cmd->type = CPET_UNKNOWN;
		VECTOR_ENSURE(console->input->commands, 1, 1);
		VECTOR_PUSH(console->input->commands, cmd);
		VECTOR_ENSURE(console->input->command_list, 1, 1);
		VECTOR_PUSH(console->input->command_list, cmd);
	}

	cmd = VECTOR_INDEX(console->input->command_list, i);
	while ((tok = strtok(NULL, ":")) != NULL) {
		if (cmd->type == CPET_UNKNOWN) {
			cmd->type = CPET_CATEGORY;
			VECTOR_INIT(cmd->u.children);
		}
		Assert_retv(cmd->type == CPET_CATEGORY);

		ARR_FIND(0, VECTOR_LENGTH(cmd->u.children), i, strcmpi(VECTOR_INDEX(cmd->u.children, i)->cmd,tok) == 0);
		if (i == VECTOR_LENGTH(cmd->u.children)) {
			struct CParseEntry *entry;
			CREATE(entry, struct CParseEntry, 1);
			safestrncpy(entry->cmd, tok, CP_CMD_LENGTH);
			entry->type = CPET_UNKNOWN;
			VECTOR_ENSURE(console->input->commands, 1, 1);
			VECTOR_PUSH(console->input->commands, entry);
Ejemplo n.º 17
0
void intercom_add_interface(intercom_ctx *ctx, char *ifname) {
  if (intercom_has_ifname(ctx, ifname))
    return;

  intercom_if iface = {
    .ok = false,
    .ifname = ifname
  };

  VECTOR_ADD(ctx->interfaces, iface);

  intercom_update_interfaces(ctx);
}

void intercom_init(intercom_ctx *ctx) {

  struct in6_addr mgroup_addr;
  inet_pton(AF_INET6, INTERCOM_GROUP, &mgroup_addr); // TODO Fehler abfangen

  ctx->groupaddr = (struct sockaddr_in6) {
    .sin6_family = AF_INET6,
    .sin6_addr = mgroup_addr,
    .sin6_port = htons(INTERCOM_PORT),
  };

  ctx->fd = socket(PF_INET6, SOCK_DGRAM | SOCK_NONBLOCK, 0);

  if (ctx->fd < 0)
    exit_error("creating socket");

  struct sockaddr_in6 server_addr = {};

  server_addr.sin6_family = AF_INET6;
  server_addr.sin6_addr = in6addr_any;
  server_addr.sin6_port = htons(INTERCOM_PORT);

  if (bind(ctx->fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
    perror("bind failed");
    exit(EXIT_FAILURE);
  }
}

void intercom_seek(intercom_ctx *ctx, const struct in6_addr *address) {
  intercom_packet_seek packet;

  uint32_t nonce = rand();

  packet.hdr = (intercom_packet_hdr) {
    .type = INTERCOM_SEEK,
    .nonce = nonce,
    .ttl = 255,
  };

  memcpy(&packet.address, address, 16);

  intercom_recently_seen_add(ctx, &packet.hdr);

  intercom_send_packet(ctx, (uint8_t*)&packet, sizeof(packet));
}

void intercom_send_packet(intercom_ctx *ctx, uint8_t *packet, ssize_t packet_len) {
  for (int i = 0; i < VECTOR_LEN(ctx->interfaces); i++) {
    intercom_if *iface = &VECTOR_INDEX(ctx->interfaces, i);

    if (!iface->ok)
      continue;

    struct sockaddr_in6 groupaddr = ctx->groupaddr;

    groupaddr.sin6_scope_id = iface->ifindex;

    printf("intercom send %i %zi\n", iface->ifindex, packet_len);
    ssize_t rc = sendto(ctx->fd, packet, packet_len, 0, &groupaddr, sizeof(groupaddr));

    if (rc < 0)
      iface->ok = false;
  }
}

bool intercom_recently_seen(intercom_ctx *ctx, intercom_packet_hdr *hdr) {
  for (int i = 0; i < VECTOR_LEN(ctx->recent_packets); i++) {
    intercom_packet_hdr *ref_hdr = &VECTOR_INDEX(ctx->recent_packets, i);

    if (ref_hdr->nonce == hdr->nonce && ref_hdr->type == hdr->type)
        return true;
  }
  return false;
}

void intercom_recently_seen_add(intercom_ctx *ctx, intercom_packet_hdr *hdr) {
  if (VECTOR_LEN(ctx->recent_packets) > INTERCOM_MAX_RECENT)
    VECTOR_DELETE(ctx->recent_packets, 0);

  VECTOR_ADD(ctx->recent_packets, *hdr);
}

void intercom_handle_seek(struct l3ctx *ctx, intercom_packet_seek *packet) {
  icmp6_send_solicitation(ctx, (const struct in6_addr *)packet->address);
}
Ejemplo n.º 18
0
/**
 * Loads console commands list
 **/
void console_load_defaults(void)
{
	/**
	 * Defines a main category.
	 *
	 * Categories can't be used as commands!
	 * E.G.
	 * - sql update skip
	 *   'sql' is the main category
	 * CP_DEF_C(category)
	 **/
#define CP_DEF_C(x) { #x , CPET_CATEGORY, NULL , NULL, NULL }
	/**
	 * Defines a sub-category.
	 *
	 * Sub-categories can't be used as commands!
	 * E.G.
	 * - sql update skip
	 *   'update' is a sub-category
	 * CP_DEF_C2(command, category)
	 **/
#define CP_DEF_C2(x,y) { #x , CPET_CATEGORY, NULL , #y, NULL }
	/**
	 * Defines a command that is inside a category or sub-category
	 * CP_DEF_S(command, category/sub-category)
	 **/
#define CP_DEF_S(x,y) { #x, CPET_FUNCTION, CPCMD_C_A(x,y), #y, NULL }
	/**
	 * Defines a command that is _not_ inside any category
	 * CP_DEF_S(command)
	 **/
#define CP_DEF(x) { #x , CPET_FUNCTION, CPCMD_A(x), NULL, NULL }

	struct {
		char *name;
		int type;
		CParseFunc func;
		char *connect;
		struct CParseEntry *self;
	} default_list[] = {
		CP_DEF(help),
		/**
		 * Server related commands
		 **/
		CP_DEF_C(server),
		CP_DEF_S(ers_report,server),
		CP_DEF_S(mem_report,server),
		CP_DEF_S(malloc_usage,server),
		CP_DEF_S(exit,server),
		/**
		 * Sql related commands
		 **/
		CP_DEF_C(sql),
		CP_DEF_C2(update,sql),
		CP_DEF_S(skip,update),
	};
	int len = ARRAYLENGTH(default_list);
	struct CParseEntry *cmd;
	int i;

	VECTOR_ENSURE(console->input->commands, len, 1);

	for(i = 0; i < len; i++) {
		CREATE(cmd, struct CParseEntry, 1);

		safestrncpy(cmd->cmd, default_list[i].name, CP_CMD_LENGTH);

		cmd->type = default_list[i].type;

		switch (cmd->type) {
			case CPET_FUNCTION:
				cmd->u.func = default_list[i].func;
				break;
			case CPET_CATEGORY:
				VECTOR_INIT(cmd->u.children);
				break;
			case CPET_UNKNOWN:
				break;
		}

		VECTOR_PUSH(console->input->commands, cmd);
		default_list[i].self = cmd;
		if (!default_list[i].connect) {
			VECTOR_ENSURE(console->input->command_list, 1, 1);
			VECTOR_PUSH(console->input->command_list, cmd);
		}
	}

	for (i = 0; i < len; i++) {
		int k;
		if (!default_list[i].connect)
			continue;
		ARR_FIND(0, VECTOR_LENGTH(console->input->commands), k, strcmpi(default_list[i].connect, VECTOR_INDEX(console->input->commands, k)->cmd) == 0);
		if (k != VECTOR_LENGTH(console->input->commands)) {
			struct CParseEntry *parent = VECTOR_INDEX(console->input->commands, k);
			Assert_retb(parent->type == CPET_CATEGORY);
			cmd = default_list[i].self;
			VECTOR_ENSURE(parent->u.children, 1, 1);
			VECTOR_PUSH(parent->u.children, cmd);
		}
	}
#undef CP_DEF_C
#undef CP_DEF_C2
#undef CP_DEF_S
#undef CP_DEF
}