Ejemplo n.º 1
0
Archivo: hub.c Proyecto: q3k/uhub
static void hub_event_dispatcher(void* callback_data, struct event_data* message)
{
	struct hub_info* hub = (struct hub_info*) callback_data;
	struct hub_user* user = (struct hub_user*) message->ptr;
	assert(hub != NULL);

	switch (message->id)
	{
		case UHUB_EVENT_USER_JOIN:
		{
			if (user_is_disconnecting(user))
				break;

			if (message->flags)
			{
				hub_send_password_challenge(hub, user);
			}
			else
			{
				on_login_success(hub, user);
			}
			break;
		}

		case UHUB_EVENT_USER_QUIT:
		{
			uman_remove(hub, user);
			uman_send_quit_message(hub, user);
			on_logout_user(hub, user);
			hub_schedule_destroy_user(hub, user);
			break;
		}

		case UHUB_EVENT_USER_DESTROY:
		{
			user_destroy(user);
			break;
		}

		case UHUB_EVENT_HUB_SHUTDOWN:
		{
			struct hub_user* u = (struct hub_user*) list_get_first(hub->users->list);
			while (u)
			{
				uman_remove(hub, u);
				user_destroy(u);
				u = (struct hub_user*) list_get_first(hub->users->list);
			}
			break;
		}


		default:
			/* FIXME: ignored */
			break;
	}
}
Ejemplo n.º 2
0
void plugin_shutdown(struct uhub_plugins* handle)
{
	struct plugin_handle* plugin = (struct plugin_handle*) list_get_first(handle->loaded);
	while (plugin)
	{
		list_remove(handle->loaded, plugin);
		plugin_unload(plugin);
		plugin = (struct plugin_handle*) list_get_first(handle->loaded);
	}

	list_destroy(handle->loaded);
}
Ejemplo n.º 3
0
main()

{
	DynamicList* l = list_inicialize();

	/*Aluno* Al1 = (Aluno*)malloc(sizeof(Aluno));
	Aluno* Al2 = (Aluno*)malloc(sizeof(Aluno));

	Al1->RA = 1516;
	Al1->nome = "JOAO";

	Al2->RA = 2324;
	Al2->nome = "SIBA";
	*/

	printf("\nInseriu? %s", list_add_last(l, 'a')?"sim":"não");
	printf("\nInseriu? %s", list_add_last(l, 'b')?"sim":"não");

	printf("\nFirst %c\n", list_get_first(l));
	printf("\nLast %c\n", list_get_last(l));

	printf("\nInseriu? %s", list_add_last(l, 'c')?"sim":"não");
	printf("\nInseriu? %s", list_add_last(l, 'd')?"sim":"não");
	printf("\nInseriu? %s", list_add_first(l, 'e')?"sim":"não");
	printf("\nInseriu? %s", list_add_first(l, 'f')?"sim":"não");
	printf("\nInseriu? %s", list_add_first(l, 'g')?"sim":"não");

	printf("\nFirst %c\n", list_get_first(l));
	printf("\nLast %c\n", list_get_last(l));

	list_print(l);

	printf("\nSize %d\n", list_size(l));

	list_clear(l);

	printf("\nSize %d\n", list_size(l));

	printf("\nInseriu? %s", list_add_last(l, 'c')?"sim":"não");
	printf("\nInseriu? %s", list_add_last(l, 'd')?"sim":"não");
	printf("\nInseriu? %s", list_add_first(l, 'e')?"sim":"não");
	printf("\nInseriu? %s", list_add_first(l, 'f')?"sim":"não");
	printf("\nInseriu? %s", list_add_first(l, 'g')?"sim":"não");

	list_print(l);

	list_remove_first(l);	
	list_remove_first(l);	
	list_remove_first(l);	
	
	list_print(l);
}
Ejemplo n.º 4
0
Archivo: route.c Proyecto: junaidk/uhub
int route_to_subscribers(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
	int do_send;
	char* tmp;
	
	struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
	while (user)
	{
		if (user->feature_cast)
		{
			do_send = 1;
			
			tmp = list_get_first(command->feature_cast_include);
			while (tmp)
			{
				if (!user_have_feature_cast_support(user, tmp))
				{
					do_send = 0;
					break;
				}
				tmp = list_get_next(command->feature_cast_include);;
			}
			
			if (!do_send) {
				user = (struct hub_user*) list_get_next(hub->users->list);
				continue;
			}
			
			tmp = list_get_first(command->feature_cast_exclude);
			while (tmp)
			{
				if (user_have_feature_cast_support(user, tmp))
				{
					do_send = 0;
					break;
				}
				tmp = list_get_next(command->feature_cast_exclude);
			}
			
			if (do_send)
			{
				route_to_user(hub, user, command);
			}
		}
		user = (struct hub_user*) list_get_next(hub->users->list);
	}
	
	return 0;
}
Ejemplo n.º 5
0
list_t * list_delete(list_t *li, void *data)
{
	if(!li)
		return NULL;

	list_t *i = li;
	if(data) {
		i = list_get_first(li);
		while(i) {
			if(data == list_get_data(i))
				break;
			i = i->next;
		}
		if(!i)
			return li;
	}

	list_t *r = NULL;
	if(i->next) {
		i->next->prev = i->prev;
		r = i->next;
	}
	if(i->prev) {
		i->prev->next = i->next;
		r = i->prev;
	}
	free(i);
	return r;
}
Ejemplo n.º 6
0
void jabber_mam_process(JabberStream *js, const char* after)
{
	if (!js->mam)
		return;
	
	if (js->mam->current && js->mam->current->completed) {
		free(js->mam->current->start);
		free(js->mam->current->end);
		free(js->mam->current->with);

		memset(js->mam->last_timestamp, 0, 32);
		
		free(js->mam->current);
		js->mam->current = NULL;
	}

	if (!js->mam->current) {
		list_t *queue_item = list_get_first(js->mam->queue);
		if (queue_item) {
			js->mam->queue = list_delete(js->mam->queue, queue_item);

			js->mam->current = list_get_data(queue_item);

			js->mam->queue = list_get_next(js->mam->queue);
		}
	}
	
	if (js->mam->current)
		jabber_mam_request(js, after);
}
Ejemplo n.º 7
0
static int Update_Analog_Input_Read_Property(BACNET_READ_PROPERTY_DATA *rpdata) 
{
	static int index;
	word_object *object;
	int instance_no = bacnet_Analog_Input_Instance_To_Index(rpdata -> object_instance);

	if(rpdata->object_property != bacnet_PROP_PRESENT_VALUE) 
	{
    		goto not_pv;
	}

	pthread_mutex_lock(&list_lock);
	if(list_heads[instance_no] == NULL)
	{
		pthread_mutex_unlock(&list_lock);
		goto not_pv;
	}
	
	object = list_get_first(&list_heads[instance_no]);
	pthread_mutex_unlock(&list_lock);

	printf("AI_Present_Value request for instance %i\n", instance_no);

	//bacnet_Analog_Input_Present_Value_Set(0, 20); // For testing and debugging purposes only
	printf("-------------- %i:%04X\n", instance_no, object->value);
	
	bacnet_Analog_Input_Present_Value_Set(instance_no, object->value);
	free(object);
	
not_pv:
	return bacnet_Analog_Input_Read_Property(rpdata);
}
Ejemplo n.º 8
0
/** get item from specific position
 */
void* list_get (linked_list* _this, int position) {
    // list is empty
    if (_this->size == 0) {
        //NODE_DBG("LinkedList#get: The list is empty.");
       return NULL;
    } else if (position >= _this->size) {
        // out of bound
        //NODE_DBG("LinkedList#get: Index out of bound");
        return NULL;
    }
    // get head item
    if (position == 0) {
        return list_get_first(_this);
    } else if (position+1 == _this->size) {
        // get tail item
        return list_get_last(_this);
    } else {
       node* node = _this->head;
        int i = 0;
        // loop until position
        while (i < position) {
            node = node->next;
            i++;
        }
        return node->item;
    }
}
Ejemplo n.º 9
0
static void *print_func(void *arg) {
	word_object *current_object;
	fprintf(stderr, "Print thread starting\n");

	while(1) {
	pthread_mutex_lock(&list_lock);
	while (list_head == NULL) {
		pthread_cond_wait(&list_data_ready, &list_lock);
	}

	current_object = list_get_first();

	pthread_mutex_unlock(&list_lock);

	/* make sure that list_lock is released first-
	printf() and free() can block*/
	printf ("Print thread: %s\n", current_object->word);
	free(current_object->word);
	free(current_object);

	/* Let list flush() know that we've done work */
	pthread_cond_signal(&list_data_flush);
}

    /* Silence compiler warning */
return arg;
}
Ejemplo n.º 10
0
static int command_patternadd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct patterns_data* pdata = (struct patterns_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* arg1 = (struct plugin_command_arg_data*) list_get_first(cmd->args);
	struct plugin_command_arg_data* arg2 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
	struct plugin_command_arg_data* arg3 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
	struct plugin_command_arg_data* arg4 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
  
	char* t = arg1->data.string;
	enum pattern_types type;
	
	if (!pattern_string_to_type(t, &type))
	{
		cbuf_append_format(buf, "*** %s: Wrong pattern type \"%s\". Available types are: MC, PM, NI, UA.", cmd->prefix, t);
	}
	else
	{
		enum auth_credentials mincred = arg2->data.credentials;
		enum auth_credentials maxcred = arg3->data.credentials;
		char* str = arg4->data.string;
	  
		int rc = sql_execute(pdata, null_callback, NULL, "INSERT INTO patterns VALUES(NULL, '%s', %d, '%s', '%s');", sql_escape_string(str), type, auth_cred_to_string(mincred), auth_cred_to_string(maxcred));
	  
		if (rc > 0)
			cbuf_append_format(buf, "*** %s: Added pattern \"%s\" to %s group.", cmd->prefix, str, pattern_type_to_string(type));
		else
			cbuf_append_format(buf, "*** %s: Unable to add pattern \"%s\".", cmd->prefix, str);
	}
	
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);

	return 0;
}
Ejemplo n.º 11
0
static int command_patternexadd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct patterns_data* pdata = (struct patterns_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* arg1 = (struct plugin_command_arg_data*) list_get_first(cmd->args);
	struct plugin_command_arg_data* arg2 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
	struct plugin_command_arg_data* arg3 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
	struct plugin_command_arg_data* arg4 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
  
	int pattern_id = arg1->data.integer;
	enum auth_credentials mincred = arg2->data.credentials;
	enum auth_credentials maxcred = arg3->data.credentials;
	char* str = arg4->data.string;
  
	int rc = sql_execute(pdata, null_callback, NULL, "PRAGMA foreign_keys=ON; INSERT INTO pattern_exceptions VALUES(NULL, '%s', %d, '%s', '%s');", sql_escape_string(str), pattern_id, auth_cred_to_string(mincred), auth_cred_to_string(maxcred));
  
	if (rc > 0)
		cbuf_append_format(buf, "*** %s: Added pattern exception \"%s\" to pattern ID %d.", cmd->prefix, str, pattern_id);
	else
		cbuf_append_format(buf, "*** %s: Unable to add pattern exception \"%s\" to pattern ID %d.", cmd->prefix, str, pattern_id);
  
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);

	return 0;
}
Ejemplo n.º 12
0
/**
 * Obtain 'num' messages from the chat history and append them to outbuf.
 *
 * @return the number of messages added to the buffer.
 */
static size_t get_messages(struct chat_history_data* data, size_t num, struct cbuffer* outbuf)
{
	struct linked_list* messages = data->chat_history;
	char* message;
	int skiplines = 0;
	size_t lines = 0;
	size_t total = list_size(messages);

	if (total == 0)
		return 0;

	if (num <= 0 || num > total)
		num = total;

	if (num != total)
		skiplines = total - num;

	cbuf_append(outbuf, "\n");
	message = (char*) list_get_first(messages);
	while (message)
	{
		if (--skiplines < 0)
		{
			cbuf_append(outbuf, message);
			lines++;
		}
		message = (char*) list_get_next(messages);
	}
	cbuf_append(outbuf, "\n");
	return lines;
}
Ejemplo n.º 13
0
int uman_send_user_list(struct hub_info* hub, struct hub_user* target)
{
	int ret = 1;
	struct hub_user* user;
	user_flag_set(target, flag_user_list);
	user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on INF or PAS msg */
	while (user)
	{
		if (user_is_logged_in(user))
		{
			ret = route_to_user(hub, target, user->info);
			if (!ret)
				break;
		}
		user = (struct hub_user*) list_get_next(hub->users->list);
	}

#if 0
	FIXME: FIXME FIXME handle send queue excess
	if (!target->send_queue_size)
	{
	    user_flag_unset(target, flag_user_list);
	}
#endif
	return ret;
}
Ejemplo n.º 14
0
Archivo: route.c Proyecto: junaidk/uhub
int route_info_message(struct hub_info* hub, struct hub_user* u)
{
	if (!user_is_nat_override(u))
	{
		return route_to_all(hub, u->info);
	}
	else
	{
		struct adc_message* cmd = adc_msg_copy(u->info);
		const char* address = user_get_address(u);
		struct hub_user* user = 0;
		
		adc_msg_remove_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR);
		adc_msg_add_named_argument(cmd, ADC_INF_FLAG_IPV4_ADDR, address);
	
		user = (struct hub_user*) list_get_first(hub->users->list);
		while (user)
		{
			if (user_is_nat_override(user))
				route_to_user(hub, user, cmd);
			else
				route_to_user(hub, user, u->info);
			
			user = (struct hub_user*) list_get_next(hub->users->list);
		}
		adc_msg_free(cmd);
	}
	return 0;
}
Ejemplo n.º 15
0
Archivo: route.c Proyecto: junaidk/uhub
int route_to_all(struct hub_info* hub, struct adc_message* command) /* iterate users */
{
	struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list);
	while (user)
	{
		route_to_user(hub, user, command);
		user = (struct hub_user*) list_get_next(hub->users->list);
	}

	return 0;
}
Ejemplo n.º 16
0
struct hub_user* uman_get_user_by_nick(struct hub_info* hub, const char* nick)
{
	struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
	while (user)
	{
		if (strcmp(user->id.nick, nick) == 0)
			return user;
		user = (struct hub_user*) list_get_next(hub->users->list);
	}
	return NULL;
}
Ejemplo n.º 17
0
int event_queue_process(struct event_queue* queue)
{
	struct event_data* data;
	if (queue->locked)
		return 0;
	
	/* lock primary queue, and handle the primary queue messages. */
	queue->locked = 1;
	
	data = (struct event_data*) list_get_first(queue->q1);
	while (data)
	{
#ifdef EQ_DEBUG
		eq_debug("EXEC", data);
#endif
		queue->callback(queue->callback_data, data);
		data = (struct event_data*) list_get_next(queue->q1);
	}
	
	list_clear(queue->q1, event_queue_cleanup_callback);
	uhub_assert(list_size(queue->q1) == 0);
		
	/* unlock queue */
	queue->locked = 0;
	
	/* transfer from secondary queue to the primary queue. */
	data = (struct event_data*) list_get_first(queue->q2);
	while (data)
	{
		list_remove(queue->q2, data);
		list_append(queue->q1, data);
		data = (struct event_data*) list_get_first(queue->q2);
	}
	
	/* if more events exist, schedule it */
	if (list_size(queue->q1))
	{
		return 1;
	}
	return 0;
}
Ejemplo n.º 18
0
/** get item from tail
 */
void* list_get_last (linked_list* _this) {
    // list is empty
    if (_this->size == 0) {
        //NODE_DBG("LinkedList#getLast: The list is empty.");
        return NULL;
    }
    // only head node
    if (_this->size == 1) {
        return list_get_first(_this);
    }
    return _this->tail->item;
}
Ejemplo n.º 19
0
Archivo: user.c Proyecto: junaidk/uhub
int user_have_feature_cast_support(struct hub_user* user, char feature[4])
{
	char* tmp = list_get_first(user->feature_cast);
	while (tmp)
	{
		if (strncmp(tmp, feature, 4) == 0)
			return 1;
	
		tmp = list_get_next(user->feature_cast);
	}
	
	return 0;
}
Ejemplo n.º 20
0
int main(void)
{
    int i;
    int ret;
    t_list * list = list_init();

    if (list == NULL)
        return 1;

    for (i = 0; i < NUM; i++) {
        tab_item_ptr[i] = &tab_item[i];
    }

    for (i = 0; i < NUM; i++) {
        ret = list_insert_last(list, tab_item_ptr[i]);
        if (ret != LIST_OP_OK)
            fprintf(stderr, "CHYBA\n");
    }

    printf("LIST\n");
    
    for (i = 0; i < NUM; i++) {
        printf("%d: %x\n", i, list_get_first(list));
        list_free_first(list);
    }

    for (i = 0; i < NUM; i++) {
        printf("%d: %x\n", i, list_get_first(list));
        list_free_first(list);
    }

    list_free(list);

    printf("%x\n", list);

    return 0;
}
Ejemplo n.º 21
0
size_t uman_get_user_by_addr(struct hub_info* hub, struct linked_list* users, struct ip_range* range)
{
	size_t num = 0;
	struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users - only on incoming INF msg */
	while (user)
	{
		if (ip_in_range(&user->id.addr, range))
		{
			list_append(users, user);
			num++;
		}
		user = (struct hub_user*) list_get_next(hub->users->list);
	}
	return num;
}
Ejemplo n.º 22
0
Archivo: auth.c Proyecto: Nyogtha/uhub
int acl_is_ip_nat_override(struct acl_handle* handle, const char* ip_address)
{
	struct ip_addr_encap raw;
	struct ip_range* info = (struct ip_range*) list_get_first(handle->nat_override);
	ip_convert_to_binary(ip_address, &raw);
	
	while (info)
	{
		if (ip_in_range(&raw, info))
		{
			return 1;
		}
		info = (struct ip_range*) list_get_next(handle->nat_override);
	}
	return 0;
}
Ejemplo n.º 23
0
Archivo: hub.c Proyecto: q3k/uhub
void hub_chat_history_add(struct hub_info* hub, struct hub_user* user, struct adc_message* cmd)
{
	char* msg_esc   = adc_msg_get_argument(cmd, 0);
	char* message = adc_msg_unescape(msg_esc);
	char* log = hub_malloc(strlen(message) + strlen(user->id.nick) + 14);
	sprintf(log, "%s <%s> %s\n", get_timestamp(time(NULL)), user->id.nick, message);
	list_append(hub->chat_history, log);
	while (list_size(hub->chat_history) > (size_t) hub->config->max_chat_history)
	{
		char* msg = list_get_first(hub->chat_history);
		list_remove(hub->chat_history, msg);
		hub_free(msg);
	}
	hub_free(message);
	hub_free(msg_esc);
}
Ejemplo n.º 24
0
/**
 * Add a chat message to history.
 */
static void history_add(struct plugin_handle* plugin, struct plugin_user* from, const char* message, int flags)
{
	size_t loglen = strlen(message) + strlen(from->nick) + 13;
	struct chat_history_data* data = (struct chat_history_data*) plugin->ptr;
	char* log = hub_malloc(loglen + 1);

	snprintf(log, loglen, "%s <%s> %s\n", get_timestamp(time(NULL)), from->nick, message);
	log[loglen] = '\0';
	list_append(data->chat_history, log);
	while (list_size(data->chat_history) > data->history_max)
	{
		char* msg = list_get_first(data->chat_history);
		list_remove(data->chat_history, msg);
		hub_free(msg);
	}
}
Ejemplo n.º 25
0
static plugin_st get_user(struct plugin_handle* plugin, const char* nickname, struct auth_info* data)
{
	struct acl_data* acl = (struct acl_data*) plugin->ptr;
	struct auth_info* info = (struct auth_info*) list_get_first(acl->users);
	while (info)
	{
		if (strcasecmp((char*)info->nickname, nickname) == 0)
		{
			memcpy(data, info, sizeof(struct auth_info));
			return st_allow;
		}
		info = (struct auth_info*) list_get_next(acl->users);
	}
	if (acl->exclusive)
		return st_deny;
	return st_default;
}
Ejemplo n.º 26
0
void jabber_mam_clear(mam_t *mam)
{
	if (mam)
		return;
	
	list_t *queue_item = list_get_first(mam->queue);
	while (queue_item) {
		mam_item_t *mam_item = list_get_data(queue_item);
        
		free(mam_item->start);
		free(mam_item->end);
		free(mam_item->with);
		free(mam_item);
        
		queue_item = list_get_next(queue_item);
	}
}
Ejemplo n.º 27
0
Archivo: hub.c Proyecto: q3k/uhub
void hub_logout_log(struct hub_info* hub, struct hub_user* user)
{
	struct hub_logout_info* loginfo = hub_malloc_zero(sizeof(struct hub_logout_info));
	if (!loginfo) return;
	loginfo->time = time(NULL);
	strcpy(loginfo->cid, user->id.cid);
	strcpy(loginfo->nick, user->id.nick);
	memcpy(&loginfo->addr, &user->id.addr, sizeof(struct ip_addr_encap));
	loginfo->reason = user->quit_reason;

	list_append(hub->logout_info, loginfo);
	while (list_size(hub->logout_info) > (size_t) hub->config->max_logout_log)
	{
		struct hub_logout_info* entry = list_get_first(hub->logout_info);
		list_remove(hub->logout_info, entry);
		hub_free(entry);
	}
}
Ejemplo n.º 28
0
static int command_newsadd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct extras_data* extrasdata = (struct extras_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* arg1 = (struct plugin_command_arg_data*) list_get_first(cmd->args);
  
	const char* news_text = sql_escape_string(arg1->data.string);
  
	int rc = sql_execute(extrasdata, null_callback, NULL, "INSERT INTO news (id, text) VALUES(NULL, '%s');", news_text);
  
	if (rc > 0)
		cbuf_append_format(buf, "*** %s: News updated.", cmd->prefix);
	else
		cbuf_append_format(buf, "*** %s: Unable to update news.", cmd->prefix);
  
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);

	return 0;
}
Ejemplo n.º 29
0
static int command_patternexdel(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct patterns_data* pdata = (struct patterns_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* args = (struct plugin_command_arg_data*) list_get_first(cmd->args);
	
	int id = args->data.integer;

	int rc = sql_execute(pdata, null_callback, NULL, "DELETE FROM pattern_exceptions WHERE id=%d;", id);
  
	if (rc > 0)
		cbuf_append_format(buf, "*** %s: Deleted pattern exception with ID %d.", cmd->prefix, id);
	else
		cbuf_append_format(buf, "*** %s: Unable to delete pattern exception with id %d.", cmd->prefix, id);
  
	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);

	return 0;
}
Ejemplo n.º 30
0
static int command_patterntest(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd)
{
	struct patterns_data* pdata = (struct patterns_data*) plugin->ptr;
	struct cbuffer* buf = cbuf_create(128);
	struct plugin_command_arg_data* arg1 = (struct plugin_command_arg_data*) list_get_first(cmd->args);
	struct plugin_command_arg_data* arg2 = (struct plugin_command_arg_data*) list_get_next(cmd->args);
	
	int id = arg1->data.integer;
	char* str = arg2->data.string;
	
	sqlite3_stmt *res;
	int error = 0;
	const char *tail;
	char query[80];

	cbuf_append_format(buf, "*** %s: ", cmd->prefix);

	int n = sprintf(query, "SELECT regexp FROM patterns WHERE id=%d LIMIT 1;", id);

	error = sqlite3_prepare_v2(pdata->db, query, n, &res, &tail);

	if (sqlite3_step(res) == SQLITE_ROW)
	{
		if(pattern_match(str, (char*) sqlite3_column_text(res, 0)))
			cbuf_append_format(buf, "Tested string \"%s\" matches pattern \"%s\".", str, sqlite3_column_text(res, 0));
		else
			cbuf_append_format(buf, "Tested string \"%s\" does not match pattern \"%s\".", str, sqlite3_column_text(res, 0));
	}
	else
	{
		cbuf_append_format(buf, "Pattern ID \"%d\" not found.", id);
	}

	sqlite3_finalize(res);

	plugin->hub.send_message(plugin, user, cbuf_get(buf));
	cbuf_destroy(buf);

	return 0;
}