diff --git a/src/main.c b/src/main.c index 9cb99c7..febd32a 100644 --- a/src/main.c +++ b/src/main.c @@ -625,114 +625,162 @@ int search_in_string(const char* raw_string, const char* search_string) { // Filterfunktion für den User-Agent. Nimmt den Datensatz entgegen und prüft gegen die gesetzten Filter, gibt dann 0 oder 1 zurück int user_agent_matches(char* user_agent) { if (filters.user_agent_count == 0) return 1; - - int has_include_filters = 0; - int include_match = 0; + // Ausschluss-Filter geht vor + for (int i = 0; i < filters.user_agent_count; i++) { + if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) { + int pattern_found = search_in_string(user_agent, filters.user_agent_filters[i].pattern); + if (pattern_found) { + return 0; // früheres Verlassen der Schleife, sobald Ausschlussfilter zutrifft + } + } + } + // Prüfung im entsprechenden Modus + int include_count = 0; + int include_matches = 0; for (int i = 0; i < filters.user_agent_count; i++) { - int pattern_found = search_in_string(user_agent, filters.user_agent_filters[i].pattern); - if (filters.user_agent_filters[i].mode == FILTER_INCLUDE) { - has_include_filters = 1; + include_count++; + int pattern_found = search_in_string(user_agent, filters.user_agent_filters[i].pattern); if (pattern_found) { - include_match = 1; - } - } else { // ausschließen-Filter - if (pattern_found) { - return 0; + include_matches++; + if (filters.combination_mode == 1) { // OR-Modus + return 1; // Früheres Verlassen der Schleife bei erstem zutreffendem Einschlussfilter im OR-Modus + } } } } - if (has_include_filters) { - return include_match; + // Diese Prüfung wird ausgeführt, wenn Einschlussfilter vorhanden sind + if (include_count > 0) { + if (filters.combination_mode == 0) { // AND-Modus + return include_matches == include_count; // Alle Einschlussfilter müssen zutreffen, die Treffer müssen Anzahl der Filter entsprechen + } else { // OR-Modus + return include_matches > 0; // Ausschlussfilter im ODER-Modus - wenn ein beliebiger Eintrag zum Ausschlussfilter passt, wird 0=negativ zurückgegeben + } } - return 1; + return 1; // Keine Einschlussfilter, keine zutreffenden Ausschlussfilter, positiver Rückgabewert =1 } int status_code_matches(int status_code) { if (filters.status_count == 0) return 1; - - int has_include_filters = 0; - int include_match = 0; - + // Ausschluss-Filter prüfen: immer übergeordnet gültig for (int i = 0; i < filters.status_count; i++) { - if (filters.status_filters[i].mode == FILTER_INCLUDE) { - has_include_filters = 1; + if (filters.status_filters[i].mode == FILTER_EXCLUDE) { if (filters.status_filters[i].code == status_code) { - include_match = 1; - } - } else { - if (filters.status_filters[i].code == status_code) { - return 0; + return 0; } } } - if (has_include_filters) { - return include_match; + // Filter prüfen in entsprechendem Modus + int include_count = 0; + int include_matches = 0; + + for (int i = 0; i < filters.status_count; i++) { + if (filters.status_filters[i].mode == FILTER_INCLUDE) { + include_count++; + if (filters.status_filters[i].code == status_code) { + include_matches++; + if (filters.combination_mode == 1) { // OR-Modus + return 1; // positiver Rückgabewert, Schleife wird verlassen sobald erster Treffer im OR-Modus + } + } + } } - return 1; + // Diese Prüfung wird ausgeführt, wenn Einschlussfilter vorhanden sind + if (include_count > 0) { + if (filters.combination_mode == 0) { // UND-Modus + return include_matches == include_count; // Filter-Treffer müssen der Anzahl der Statuscode-Filter entsprechen + } else { // OR-Modus + return include_matches > 0; // Ausschlussfilter im ODER-Modus - wenn ein beliebiger Eintrag zum Ausschlussfilter passt, wird 0=negativ zurückgegeben + } + } + return 1; // Keine Einschlussfilter, keine Treffer in den Ausschlussfiltern, positiver Rückgabewert = 1 } int ip_address_matches(char* ip_address) { if (filters.ip_count == 0) return 1; - int has_include_filters = 0; - int include_match = 0; - + // Prüfen der Ausschlussfilter, sind dem Rest vorgelagert for (int i = 0; i < filters.ip_count; i++) { - if (filters.ip_filters[i].mode == FILTER_INCLUDE) { - has_include_filters = 1; + if (filters.ip_filters[i].mode == FILTER_EXCLUDE) { if (strcmp(filters.ip_filters[i].ip_address, ip_address) == 0) { - include_match = 1; - } - } else { - if (strcmp(filters.ip_filters[i].ip_address, ip_address) == 0) { - return 0; + return 0; // zutreffender Ausschlussfilter führt zu negativem Rückgabewert } } } - if (has_include_filters) { - return include_match; + // Prüfung im AND oder im OR-Modus + int include_count = 0; + int include_matches = 0; + + for (int i = 0; i < filters.ip_count; i++) { + if (filters.ip_filters[i].mode == FILTER_INCLUDE) { + include_count++; + if (strcmp(filters.ip_filters[i].ip_address, ip_address) == 0) { + include_matches++; + if (filters.combination_mode == 1) { // OR-Modus + return 1; // Früheres Verlassen der Schleife, sofern erster Filter im OR-Modus zutrifft + } + } + } } - return 1; + // Diese Prüfung wird ausgeführt, wenn Einschlussfilter vorhanden sind + if (include_count > 0) { + if (filters.combination_mode == 0) { // UND-Modus + return include_matches == include_count; // Filter-Treffer müssen der Anzahl der IP-Adressen-Filter entsprechen + } else { // OR-Modus + return include_matches > 0; // zutreffender Ausschlussfilter führt zu negativem Rückgabewert + } + } + return 1; // Keine Einschlussfilter, keine Treffer in den Ausschlussfiltern, positiver Rückgabewert = 1 } // Vergleicht einen übergebenen Prüfwert für einen Zeitstempel mit dem aktuell gesetzten Filter. Wenn der Prüfwert im Filterbereich ist,wird 1 zurückgegeben. int time_matches(struct simple_time entry_time) { - // gibt 1 zurück, wenn kein Filter gesetzt wird -> der komplette Log-Datensatz wird ausgegeben if (filters.time_count == 0) return 1; - int has_include_filters = 0; - int include_match = 0; - - // es können mehrere Filter gleichzeitig gesetzt sein, diese werden alle nacheinander in einer Schleife geprüft + // Übergeordneter Ausschlussfilter for (int i = 0; i < filters.time_count; i++) { - int in_range = (compare_times(entry_time, filters.time_filters[i].start_time) >= 0 && - compare_times(entry_time, filters.time_filters[i].end_time) <= 0); // gibt 0=false zurück, wenn der Prüfwert nicht im Filterbereich ist - if (filters.time_filters[i].mode == FILTER_INCLUDE) { - has_include_filters = 1; // Flag für inlusive Filter + if (filters.time_filters[i].mode == FILTER_EXCLUDE) { + int in_range = (compare_times(entry_time, filters.time_filters[i].start_time) >= 0 && + compare_times(entry_time, filters.time_filters[i].end_time) <= 0); if (in_range) { - include_match = 1; // gibt 1=true aus, wenn der Prüfwert in den geprüften inklusiven Filter passt - } - // ausschließen-Filter - } else { - if (in_range) { - return 0; // gibt 0=false aus, wenn der geprüfte Filter exklusiv ist, und der Prüfwert in den Filterbereich passt + return 0; // zutreffender Ausschlussfilter führt zu negativem Rückgabewert, ist den Einschlussfiltern übergeordnet } } } - if (has_include_filters) { - return include_match; // gibt 0=false aus, wenn es inklusive Filter gibt (has_include_filters =1), aber kein Zeitstempel in den Filterbereich passt + // Prüfung im entsprechenden Modus + int include_count = 0; + int include_matches = 0; + for (int i = 0; i < filters.time_count; i++) { + if (filters.time_filters[i].mode == FILTER_INCLUDE) { + include_count++; + int in_range = (compare_times(entry_time, filters.time_filters[i].start_time) >= 0 && + compare_times(entry_time, filters.time_filters[i].end_time) <= 0); + if (in_range) { + include_matches++; + if (filters.combination_mode == 1) { // OR-Modus + return 1; // Sobald der erste Zeitraum im OR-Modus zutrifft, wird die Schleife verlassen + } + } + } } - return 1; + // Diese Prüfung wird ausgeführt, wenn Einschlussfilter vorhanden sind + if (include_count > 0) { + if (filters.combination_mode == 0) { // AND-Modus + return include_matches == include_count; // Filter-Treffer müssen der Anzahl der Zeitraum-Filter entsprechen + } else { // OR-Modus + return include_matches > 0; // zutreffender Ausschlussfilter führt zu negativem Rückgabewert + } + } + return 1; // keine Einschlussfilter und keine zutreffenden Ausschlussfilter - positiver Rückgabewert } // Prüfen aller Filter im AND-Modus oder OR-Modus (combination_mode) pro Log-Eintrag @@ -772,64 +820,142 @@ void show_status() { printf("❌ Keine Log-Daten geladen\n"); } - printf("\n🔍 Aktive Filter:\n"); - int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count; // UPDATE THIS LINE + printf("\n🔍 Aktive Filter-Logik:\n"); + int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count; if (total_filters == 0) { - printf(" Keine Filter gesetzt\n"); - printf(" Filter-Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); + printf(" Keine Filter gesetzt → alle Einträge werden angezeigt\n"); } else { - printf(" Filter-Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); + printf(" Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); + printf(" Regel: Ausschlussfilter (!) haben Vorrang, dann Einschlussfilter\n"); + printf("\n Filter-Ausdruck:\n"); if (filters.status_count > 0) { - printf(" Status-Codes (%d): ", filters.status_count); + printf(" Status: "); + + int excludes = 0, includes = 0; for (int i = 0; i < filters.status_count; i++) { - char mode_char = (filters.status_filters[i].mode == FILTER_EXCLUDE) ? '!' : ' '; - printf("%c%d", mode_char, filters.status_filters[i].code); - if (i < filters.status_count - 1) printf(", "); + if (filters.status_filters[i].mode == FILTER_EXCLUDE) excludes++; + else includes++; + } + + // Ausschlussfilter (immer im ODER-Modus) + if (excludes > 0) { + printf("!("); + int first = 1; + for (int i = 0; i < filters.status_count; i++) { + if (filters.status_filters[i].mode == FILTER_EXCLUDE) { + if (!first) printf(" OR "); + printf("%d", filters.status_filters[i].code); + first = 0; + } + } + printf(")"); + if (includes > 0) printf(" AND "); + } + + // Einschlussfilter (folgen dem gesetzten Modus) + if (includes > 0) { + if (includes > 1) printf("("); + int first = 1; + for (int i = 0; i < filters.status_count; i++) { + if (filters.status_filters[i].mode == FILTER_INCLUDE) { + if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); + printf("%d", filters.status_filters[i].code); + first = 0; + } + } + if (includes > 1) printf(")"); } printf("\n"); } if (filters.ip_count > 0) { - printf(" IP-Adressen (%d): ", filters.ip_count); + printf(" IP: "); + + int excludes = 0, includes = 0; for (int i = 0; i < filters.ip_count; i++) { - char mode_char = (filters.ip_filters[i].mode == FILTER_EXCLUDE) ? '!' : ' '; - printf("%c%s", mode_char, filters.ip_filters[i].ip_address); - if (i < filters.ip_count - 1) printf(", "); + if (filters.ip_filters[i].mode == FILTER_EXCLUDE) excludes++; + else includes++; + } + + if (excludes > 0) { + printf("!("); + int first = 1; + for (int i = 0; i < filters.ip_count; i++) { + if (filters.ip_filters[i].mode == FILTER_EXCLUDE) { + if (!first) printf(" OR "); + printf("%s", filters.ip_filters[i].ip_address); + first = 0; + } + } + printf(")"); + if (includes > 0) printf(" AND "); + } + + if (includes > 0) { + if (includes > 1) printf("("); + int first = 1; + for (int i = 0; i < filters.ip_count; i++) { + if (filters.ip_filters[i].mode == FILTER_INCLUDE) { + if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); + printf("%s", filters.ip_filters[i].ip_address); + first = 0; + } + } + if (includes > 1) printf(")"); } printf("\n"); } if (filters.user_agent_count > 0) { - printf(" User-Agent Pattern (%d): ", filters.user_agent_count); + printf(" UserAgent: "); + + int excludes = 0, includes = 0; for (int i = 0; i < filters.user_agent_count; i++) { - char mode_char = (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) ? '!' : ' '; - printf("%c\"%s\"", mode_char, filters.user_agent_filters[i].pattern); - if (i < filters.user_agent_count - 1) printf(", "); + if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) excludes++; + else includes++; + } + + if (excludes > 0) { + printf("!("); + int first = 1; + for (int i = 0; i < filters.user_agent_count; i++) { + if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) { + if (!first) printf(" OR "); + printf("\"%s\"", filters.user_agent_filters[i].pattern); + first = 0; + } + } + printf(")"); + if (includes > 0) printf(" AND "); + } + + if (includes > 0) { + if (includes > 1) printf("("); + int first = 1; + for (int i = 0; i < filters.user_agent_count; i++) { + if (filters.user_agent_filters[i].mode == FILTER_INCLUDE) { + if (!first) printf(" %s ", filters.combination_mode == 0 ? "AND" : "OR"); + printf("\"%s\"", filters.user_agent_filters[i].pattern); + first = 0; + } + } + if (includes > 1) printf(")"); } printf("\n"); } if (filters.time_count > 0) { - printf(" Zeiträume (%d):\n", filters.time_count); - for (int i = 0; i < filters.time_count; i++) { - char mode_char = (filters.time_filters[i].mode == FILTER_EXCLUDE) ? '!' : ' '; - printf(" %c%02d.%02d.%d %02d:%02d:%02d - %02d.%02d.%d %02d:%02d:%02d\n", - mode_char, - filters.time_filters[i].start_time.day, - filters.time_filters[i].start_time.month, - filters.time_filters[i].start_time.year, - filters.time_filters[i].start_time.hour, - filters.time_filters[i].start_time.minute, - filters.time_filters[i].start_time.second, - filters.time_filters[i].end_time.day, - filters.time_filters[i].end_time.month, - filters.time_filters[i].end_time.year, - filters.time_filters[i].end_time.hour, - filters.time_filters[i].end_time.minute, - filters.time_filters[i].end_time.second); - } + printf(" Time: %d Filter(s) gesetzt\n", filters.time_count); + } + + // Zeigt aktuellen Modus + int active_types = (filters.status_count > 0) + (filters.ip_count > 0) + + (filters.user_agent_count > 0) + (filters.time_count > 0); + if (active_types > 1) { + printf("\n %s-Verknüpfung - Ausschlussfilter vorrangig\n", + filters.combination_mode == 0 ? "UND" : "ODER"); } } @@ -1054,7 +1180,7 @@ void show_filtered_entries() { for (int i = 0; i < total_entries; i++) { if (passes_filter(i)) { - printf("%-16s | %-7s | %-22s | %-6d | %-5d | %02d.%02d.%d %02d:%02d:%02d\n", + printf("%-16s | %-7s | %-22s | %-6d | %-5d | %-36s | %02d.%02d.%d %02d:%02d:%02d\n", all_entries[i].ip_address, all_entries[i].request_method, all_entries[i].url_path, @@ -1327,7 +1453,7 @@ void menu_set_filters() { } void menu_delete_filters() { - int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count; // UPDATE THIS LINE + int total_filters = filters.status_count + filters.ip_count + filters.time_count + filters.user_agent_count; if (total_filters == 0) { printf("Keine Filter gesetzt zum Löschen.\n"); @@ -1437,10 +1563,14 @@ void menu_delete_filters() { } void menu_filter_mode() { - printf("\n=== FILTER-MODUS ===\n"); - printf("Aktueller Modus: %s\n", filters.combination_mode == 0 ? "AND (alle müssen zutreffen)" : "OR (einer muss zutreffen)"); - printf("1. AND-Modus (alle Filter müssen zutreffen)\n"); - printf("2. OR-Modus (mindestens ein Filter muss zutreffen)\n"); + printf("=== FILTER-MODUS ===\n"); + printf("Aktueller Modus: %s\n", filters.combination_mode == 0 ? "AND" : "OR"); + printf("\nDieser Modus bestimmt:\n"); + printf("1. Wie mehrere Filter desselben Typs kombiniert werden\n"); + printf("2. Wie verschiedene Filter-Typen kombiniert werden\n"); + printf("\nBeispiele:\n"); + printf("AND: IP=1.2.3.4 UND User-Agent=mozilla (beide müssen zutreffen)\n"); + printf("OR: IP=1.2.3.4 ODER User-Agent=mozilla (einer muss zutreffen)\n"); printf("Auswahl: "); int choice = read_safe_integer(); @@ -1514,7 +1644,7 @@ void menu_show_entries() { if (choice == 1) { if (filtered_count > 1000) { - printf("WARNUNG: %d Einträge sind sehr viele für die Anzeige!\n", filtered_count); + printf("WARNUNG: Die Anzeige von %d Einträgen ist in der Kommandozeile nur schlecht darstellbar.\n", filtered_count); printf("Möchten Sie trotzdem fortfahren? (1=Ja, 0=Nein): "); int confirm = read_safe_integer(); if (confirm != 1) {