Пример #1
0
void molten_stats(connection_t *con) {

	size_t length;

	length = stats_get_count();

	for(size_t i = 0; i < length; i++) {

		if (con_print(con, "STAT %s %lu\r\n", stats_get_name(i), stats_get_value_by_num(i)) < 0) {
			enqueue(&molten_quit, con);
			return;
		}

	}

	length = stats_derived_count();

	for(size_t i = 0; i < length; i++) {

		if (con_print(con, "STAT %s %lu\r\n", stats_derived_name(i), stats_derived_value(i)) < 0) {
			enqueue(&molten_quit, con);
			return;
		}

	}

	con_write_bl(con, "END\r\n", 5) < 0 ? enqueue(&molten_quit, con) : enqueue(&molten_parse, con);

	return;
}
Пример #2
0
/**
 * @brief	Get the UIDL for a message or collection of messages, in response to a POP3 UIDL command.
 * @param	con		the POP3 client connection issuing the command.
 * @return	This function returns no value.
 */
void pop_uidl(connection_t *con) {

	uint64_t number;
	inx_cursor_t *cursor;
	meta_message_t *active;
	bool_t result;

	if (con->pop.session_state != 1) {
		pop_invalid(con);
		return;
	}

	// Get the argument, if any.
	result = pop_num_parse(con, &number, false);

	meta_user_rlock(con->pop.user);

	// Output all of the messages that aren't deleted or appended.
	if (!result) {
		number = 1;
		con_print(con, "+OK %llu messages total.\r\n", pop_total_messages(con->pop.user->messages));

		if (con->pop.user->messages && (cursor = inx_cursor_alloc(con->pop.user->messages))) {

			while ((active = inx_cursor_value_next(cursor))) {

				if ((active->status & (MAIL_STATUS_APPENDED | MAIL_STATUS_HIDDEN)) == 0) {
					con_print(con, "%llu %llu\r\n", number++, active->messagenum);
				} else if ((active->status & MAIL_STATUS_APPENDED) == 0) {
					number++;
				}

			}

			inx_cursor_free(cursor);
		}

		con_write_bl(con, ".\r\n", 3);
	}
	// Output a specific message.
	else {

		if (!(active = pop_get_message(con->pop.user->messages, number))) {
			con_write_bl(con, "-ERR Message not found.\r\n", 25);
		}
		else if ((active->status & MAIL_STATUS_HIDDEN) == MAIL_STATUS_HIDDEN) {
			con_write_bl(con, "-ERR Message marked for deletion.\r\n", 35);
		}
		else {
			con_print(con, "+OK %llu %llu\r\n", number, active->messagenum);
		}

	}

	meta_user_unlock(con->pop.user);

	return;
}
Пример #3
0
/**
 * @brief	Display the POP3 server capabilities, in response to a POP3 CAPA command.
 * @param	con		the POP3 client connection issuing the command.
 * @return	This function returns no value.
 */
void pop_capa(connection_t *con) {

	// If the user is in authorization mode via an insecure channel and there is an SSL context, output the STLS capability.
	if (con->pop.session_state == 0 && con_secure(con) == 0) {
		con_print(con, "+OK Capabilities follow.\r\nTOP\r\nUSER\r\nUIDL\r\nSTLS\r\nPIPELINING\r\nEXPIRE NEVER\r\nLOGIN-DELAY 0\r\n"
			"RESP-CODES\r\nAUTH-RESP-CODE\r\nIMPLEMENTATION magmad %s\r\n.\r\n", build_version());
	}
	// Otherwise don't advertise STLS.
	else {
		con_print(con, "+OK Capabilities follow.\r\nTOP\r\nUSER\r\nUIDL\r\nPIPELINING\r\nEXPIRE NEVER\r\nLOGIN-DELAY 0\r\n"
			"RESP-CODES\r\nAUTH-RESP-CODE\r\nIMPLEMENTATION magmad %s\r\n.\r\n", build_version());
	}

	return;
}
Пример #4
0
/**
 * @brief	Get the sequence number of the last read message, in response to a POP3 LAST command.
 * @see		pop_get_last()
 * @param	con		the POP3 client connection issuing the command.
 * @return	This function returns no value.
 */
void pop_last(connection_t *con) {

	uint64_t number = 0;

	if (con->pop.session_state != 1) {
		pop_invalid(con);
		return;
	}

	meta_user_rlock(con->pop.user);
	number = pop_get_last(con->pop.user->messages);
	meta_user_unlock(con->pop.user);

	// Print the information.
	con_print(con, "+OK %llu\r\n", number);

	return;
}
Пример #5
0
/**
 * @brief	Display a user's message statistics, in response to a POP3 STAT command.
 * @see		pop_total_messages(), pop_total_size()
 * @param	con		the POP3 client connection issuing the command.
 * @return	This function returns no value.
 */
void pop_stat(connection_t *con) {

	uint64_t count, size;

	if (con->pop.session_state != 1) {
		pop_invalid(con);
		return;
	}

	meta_user_rlock(con->pop.user);
	count = pop_total_messages(con->pop.user->messages);
	size = pop_total_size(con->pop.user->messages);
	meta_user_unlock(con->pop.user);

	// Print the information.
	con_print(con, "+OK %llu %llu\r\n", count, size);

	return;
}
Пример #6
0
void con_print_pos(int x, int y, const char *s)
{
    con_goto(x,y);
    con_print(s);
}
Пример #7
0
/**
 * @brief	Retrieve a user's message, in response to a POP3 RETR command.
 * @note	This function will fail if a deleted message was specified by the user.
 * @param	con		the POP3 client connection issuing the command.
 * @return	This function returns no value.
 */
void pop_retr(connection_t *con) {

	uint64_t number;
	meta_message_t *meta;
	mail_message_t *message;

	if (con->pop.session_state != 1) {
		pop_invalid(con);
		return;
	}

	// Which message are we getting.
	if (!pop_num_parse(con, &number, true)) {
		con_write_bl(con, "-ERR The retrieve command requires a numeric argument.\r\n", 56);
		return;
	}

	meta_user_rlock(con->pop.user);

	// Get the message.
	if (!(meta = pop_get_message(con->pop.user->messages, number))) {
		meta_user_unlock(con->pop.user);
		con_write_bl(con, "-ERR Message not found.\r\n", 25);
		return;
	}

	// Check for deletion.
	if ((meta->status & MAIL_STATUS_HIDDEN) == MAIL_STATUS_HIDDEN) {
		meta_user_unlock(con->pop.user);
		con_write_bl(con,  "-ERR This message has been marked for deletion.\r\n", 49);
		return;
	}

	// Load the message and spit back the right number of lines.
	if (!(message = mail_load_message(meta, con->pop.user, con->server, 1))) {
		meta_user_unlock(con->pop.user);
		con_write_bl(con, "-ERR The message you requested could not be loaded into memory. It has either been "
			"deleted by another connection or is corrupted.\r\n", 131);
		return;
	}

	meta_user_unlock(con->pop.user);

	// Dot stuff the message.
	st_replace(&(message->text), PLACER("\n.", 2), PLACER("\n..", 3));

	// Tell the client to prepare for a message. The size is strictly informational.
	con_print(con, "+OK %u characters follow.\r\n", st_length_get(message->text));

	// We use raw socket IO because it is much faster when writing large amounts of data.
	con_write_st(con, message->text);

	// If the message didn't end with a line break, spit two.
	if (*(st_char_get(message->text) + st_length_get(message->text) - 1) == '\n') {
		con_write_bl(con, ".\r\n", 3);
	}
	else {
		con_write_bl(con, "\r\n.\r\n", 5);
	}

	mail_destroy(message);

	return;
}
Пример #8
0
/**
 * @brief	Perform client command processing on an established imap session.
 * @note	This function will read the next line of user input, parse the command, and then attempt to execute it with the appropriate handler.
 * @param	con		a pointer to the connection object underlying the imap session.
 * @return	This function returns no value.
 */
void imap_process(connection_t *con) {

	int_t state;
	command_t *command, client = { .function = NULL };

	// If the connection indicates an error occurred, or the socket was closed by the client we send the connection to the logout function.
	if (((state = con_read_line(con, false)) < 0) || (state == -2)) {
		con->command = NULL;
		enqueue(&imap_logout, con);
		return;
	}
	else if (pl_empty(con->network.line) && ((con->protocol.spins++) + con->protocol.violations) > con->server->violations.cutoff) {
		con->command = NULL;
		enqueue(&imap_logout, con);
		return;
	}
	else if (pl_empty(con->network.line)) {
		con->command = NULL;
		enqueue(&imap_process, con);
		return;
	}

	// Parse the line into its tag and command elements.
	if ((state = imap_command_parser(con)) < 0) {

		// Try to be helpful about the parsing error.
		if (state == -1) {
			con_write_bl(con, "* BAD Unable to parse the command tag.\r\n", 40);
		}
		else if (state == -2) {
			con_print(con, "%.*s BAD Unable to parse the command.\r\n", st_length_int(con->imap.tag), st_char_get(con->imap.tag));
		}
		else {
			con_print(con, "%.*s BAD The command arguments were submitted using an invalid syntax.\r\n", st_length_int(con->imap.tag), st_char_get(con->imap.tag));
		}

		// If the client keeps breaking rules drop them.
		if (((con->protocol.spins++) + con->protocol.violations) > con->server->violations.cutoff) {
			con->command = NULL;
			enqueue(&imap_logout, con);
			return;
		}

		// Requeue and hope the next line of data is useful.
		con->command = NULL;
		enqueue(&imap_process, con);
		return;

	}

	client.string = st_char_get(con->imap.command);
	client.length = st_length_get(con->imap.command);

	if ((command = bsearch(&client, imap_commands, sizeof(imap_commands) / sizeof(imap_commands[0]), sizeof(command_t), imap_compare))) {

		con->command = command;
		con->protocol.spins = 0;

		if (command->function == &imap_logout) {
			enqueue(command->function, con);
		}
		else {
			requeue(command->function, &imap_requeue, con);
		}
	}
	else {
		con->command = NULL;
		requeue(&imap_invalid, &imap_requeue, con);
	}
	return;
}