static unsigned long charset_filter_plaintexts(struct db_main *db,
    struct list_main **lists)
{
	int length, old_length;
	unsigned long count;
	struct list_entry *current, *next;
	char *ptr, key[PLAINTEXT_BUFFER_SIZE];

	for (length = 0; length <= CHARSET_LENGTH; length++)
		list_init(&lists[length]);

	count = 0;

	if ((current = db->plaintexts->head))
		do {
			next = current->next;

			if (!current->data[0])
				continue;

			old_length = 0;
			ptr = current->data;
			if (f_filter) {
				old_length = strlen(current->data);
/*
 * The current->data string might happen to end near page boundary and the next
 * page might not be mapped, whereas ext_filter_body() may pre-read a few chars
 * beyond NUL for greater speed in uses during cracking.  Also, the external
 * filter() may make the string longer.  Finally, ext_filter_body() assumes
 * that the string passed to it fits in PLAINTEXT_BUFFER_SIZE.  Hence, we copy
 * the string here.
 */
				if (old_length < sizeof(key)) {
					memcpy(key, current->data,
					    old_length + 1);
				} else {
					memcpy(key, current->data,
					    sizeof(key) - 1);
					key[sizeof(key) - 1] = 0;
				}
				if (!ext_filter_body(key, key))
					continue;
				ptr = key;
			}

			length = 0;
			while (*ptr) {
				int c = *(unsigned char *)ptr;

				if (c < CHARSET_MIN || c > CHARSET_MAX)
					break;
				length++;
				ptr++;
			}

			if (!*ptr) {
				struct list_main *list;

/*
 * lists[CHARSET_LENGTH] is a catch-all for excessive length strings that
 * nevertheless consist exclusively of characters in the CHARSET_MIN to
 * CHARSET_MAX range (including in their portion beyond CHARSET_LENGTH).
 */
				if (length > CHARSET_LENGTH)
					list = lists[CHARSET_LENGTH];
				else
					list = lists[length - 1];
				if (old_length) {
					if (length > old_length) {
						list_add(list, key);
					} else {
						memcpy(current->data, key,
						    length + 1);
						list_add_link(list, current);
					}
				} else {
/*
 * Truncate very long strings at PLAINTEXT_BUFFER_SIZE for consistency with
 * what would happen if we applied a dummy filter(), as well as for easy
 * testing against older revisions of this code.
 */
					if (length >= PLAINTEXT_BUFFER_SIZE)
						current->data
						    [PLAINTEXT_BUFFER_SIZE -
						    1] = 0;
					list_add_link(list, current);
				}
				count++;
			}
		} while ((current = next));

	return count;
}
static int inc_key_loop(int length, int fixed, int count,
	char *char1, char2_table char2, chars_table *chars)
{
	char key_i[PLAINTEXT_BUFFER_SIZE];
	char key_e[PLAINTEXT_BUFFER_SIZE];
	char *key;
	char *chars_cache;
	int numbers_cache;
	int pos;

	key_i[length + 1] = 0;
	numbers[fixed] = count;

	chars_cache = NULL;

#ifdef WEBAPI
	// DistributedCracking.net: Code block added
	// Restore previous state below the label update_ending
	if(packet_id > 0 && !inc_rec_state.initialized) {
		inc_rec_state.initialized++;

		memcpy(key_i, inc_rec_state.key_i, strlen(inc_rec_state.key_i) + 1);
	
		pos = inc_rec_state.pos;
		numbers_cache = inc_rec_state.numbers_cache;
		if(inc_rec_state.cc_0 != -1) {
			chars_cache = (*chars[inc_rec_state.cc_0])
				[ARCH_INDEX(inc_rec_state.cc_1)]
				[ARCH_INDEX(inc_rec_state.cc_2)];


			goto restore;
		}
	}
#endif
update_all:
	pos = 0;
update_ending:
	if (pos < 2) {
		if (pos == 0)
			key_i[0] = char1[numbers[0]];
		if (length) key_i[1] = (*char2)
			[ARCH_INDEX(key_i[0]) - CHARSET_MIN][numbers[1]];
		pos = 2;
	}
	while (pos < length) {
		key_i[pos] = (*chars[pos - 2])
			[ARCH_INDEX(key_i[pos - 2]) - CHARSET_MIN]
			[ARCH_INDEX(key_i[pos - 1]) - CHARSET_MIN]
			[numbers[pos]];
		pos++;
	}
	numbers_cache = numbers[length];
	if (pos == length) {
		chars_cache = (*chars[pos - 2])
			[ARCH_INDEX(key_i[pos - 2]) - CHARSET_MIN]
			[ARCH_INDEX(key_i[pos - 1]) - CHARSET_MIN];

#ifdef WEBAPI
		// DistributedCracking.net: Allow for restoration
		inc_rec_state.cc_0 = pos - 2;
		inc_rec_state.cc_1 = key_i[pos - 2] - CHARSET_MIN;
		inc_rec_state.cc_2 = key_i[pos - 1] - CHARSET_MIN;
#endif

update_last:
		key_i[length] = chars_cache[numbers_cache];
	}

	key = key_i;

	if (!ext_mode || !f_filter || ext_filter_body(key_i, key = key_e))
	if (crk_process_key(key)) return 1;

#ifdef WEBAPI
	// DistributedCracking.net: Block added
	if(packet_id > 0 &&
		++inc_rec_state.words_generated == inc_rec_state.words_requested) {
		return 1;
	}

	// DistributedCracking.net: label added
restore:
#endif
	
	if (rec_compat) goto compat;

	pos = length;
	if (fixed < length) {
		if (++numbers_cache <= count) {
			if (length >= 2) goto update_last;
			numbers[length] = numbers_cache;
			goto update_ending;
		}
		numbers[pos--] = 0;
		while (pos > fixed) {
			if (++numbers[pos] <= count) goto update_ending;
			numbers[pos--] = 0;
		}
	}
	while (pos-- > 0) {
		if (++numbers[pos] < count) goto update_ending;
		numbers[pos] = 0;
	}

	return 0;

compat:
	pos = 0;
	if (fixed) {
		if (++numbers[0] < count) goto update_all;
		if (!length && numbers[0] <= count) goto update_all;
		numbers[0] = 0;
		pos = 1;
		while (pos < fixed) {
			if (++numbers[pos] < count) goto update_all;
			numbers[pos++] = 0;
		}
	}
	while (++pos <= length) {
		if (++numbers[pos] <= count) goto update_all;
		numbers[pos] = 0;
	}

	return 0;
}