progress
This commit is contained in:
		
							parent
							
								
									87eb2c34d9
								
							
						
					
					
						commit
						80504583a4
					
				
							
								
								
									
										338
									
								
								src/main.c
									
									
									
									
									
								
							
							
						
						
									
										338
									
								
								src/main.c
									
									
									
									
									
								
							@ -32,13 +32,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 | 
			
		||||
#define TOP_X 20 // definiert die Anzahl der Einträge, die in den Top-Listen angezeigt werden sollen
 | 
			
		||||
#define SUSPICIOUS_REQUEST_LEN_THRESHOLD 256
 | 
			
		||||
 | 
			
		||||
// definiert Variablen für den Filtermodus. FILTER_INCLUDE=0, FILTER_EXCLUDE=1. Verbessert die Lesbarkeit des Codes.
 | 
			
		||||
// TODO entfernen?
 | 
			
		||||
typedef enum {
 | 
			
		||||
    FILTER_INCLUDE,
 | 
			
		||||
    FILTER_EXCLUDE
 | 
			
		||||
} filter_mode_t;
 | 
			
		||||
 | 
			
		||||
// struct für die Darstellung von Timestamps. Die granulare Trennung in verschiedene int-Werte macht die spätere Verarbeitung modular anpassbar/erweiterbar und erleichtert die Verarbeitung.
 | 
			
		||||
struct simple_time {
 | 
			
		||||
    int day;
 | 
			
		||||
@ -68,47 +61,47 @@ struct log_entry {
 | 
			
		||||
// Struktur für einen Status-Filtereintrag mit Inhalt & Modus
 | 
			
		||||
struct status_filter {
 | 
			
		||||
    int code;
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct method_filter {
 | 
			
		||||
    char pattern[10];
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// für IP-Adressen
 | 
			
		||||
struct ip_filter {
 | 
			
		||||
    char ip_address[50];
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// für Zeit, Start- und Endzeit
 | 
			
		||||
struct time_filter {
 | 
			
		||||
    struct simple_time start_time;
 | 
			
		||||
    struct simple_time end_time;
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Filter für User-Agent
 | 
			
		||||
struct user_agent_filter {
 | 
			
		||||
    char pattern[256];  
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Filter für URL-Pfad/Request
 | 
			
		||||
struct url_filter {
 | 
			
		||||
    char pattern[MAX_REQUEST_LENGTH];
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct annotation_flag_filter {
 | 
			
		||||
    int annotation_flag_is_present;
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct annotation_filter {
 | 
			
		||||
    char pattern[64];
 | 
			
		||||
    filter_mode_t mode;
 | 
			
		||||
    int filter_exclude_flag;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Struktur zum erhalten aller Filtereinträge, kann im Dialogbetrieb bearbeitet werden. Mit Zähler.
 | 
			
		||||
@ -140,12 +133,20 @@ struct filter_system {
 | 
			
		||||
    int combination_mode; // 0=AND-Filter oder 1=OR-Filter
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Definition einer Datenstruktur für die IP-Adressen Topliste
 | 
			
		||||
struct ip_stat {
 | 
			
		||||
    char ip_address[50];
 | 
			
		||||
    int count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Initialisierung eines Arrays für die Logeinträge und weiterer Startvariablen
 | 
			
		||||
struct log_entry *all_entries = NULL;
 | 
			
		||||
int max_entries = 0;
 | 
			
		||||
int total_entries = 0;
 | 
			
		||||
int suspicious_patterns_count = 0;
 | 
			
		||||
struct filter_system filters = {0};
 | 
			
		||||
// für -v option
 | 
			
		||||
int flag_verbose = 0;
 | 
			
		||||
 | 
			
		||||
// Hilfsfunktion für die Erkennung von Leerzeichen
 | 
			
		||||
int is_space(char c) {
 | 
			
		||||
@ -246,7 +247,7 @@ void cleanup_memory(){
 | 
			
		||||
 | 
			
		||||
// sauberes Schließen und bereinigen bei Fehlerstatus, sofern Speicher nicht alloziert werden kann
 | 
			
		||||
void cleanup_and_exit(){
 | 
			
		||||
    printf("Programmende. Speicher wird freigegeben und mit NULL überschrieben.\n");
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Programmende. Speicher wird freigegeben und mit NULL überschrieben.\n");
 | 
			
		||||
    cleanup_memory();
 | 
			
		||||
    exit(1);
 | 
			
		||||
}
 | 
			
		||||
@ -258,7 +259,7 @@ void mem_expand_dynamically(){
 | 
			
		||||
        int old_max = max_entries;
 | 
			
		||||
        max_entries = max_entries * GROWTH_FACTOR;
 | 
			
		||||
        
 | 
			
		||||
        printf("DEBUG: Dynamische Speichererweiterung von %d auf %d Einträge um Faktor %f\n", old_max, max_entries, GROWTH_FACTOR);
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Dynamische Speichererweiterung von %d auf %d Einträge um Faktor %f\n", old_max, max_entries, GROWTH_FACTOR);
 | 
			
		||||
        
 | 
			
		||||
        struct log_entry *new_ptr = realloc(all_entries, max_entries * sizeof(struct log_entry));
 | 
			
		||||
        
 | 
			
		||||
@ -269,7 +270,7 @@ void mem_expand_dynamically(){
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        all_entries = new_ptr;
 | 
			
		||||
        printf("DEBUG: Speicher erfolgreich erweitert auf %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry)));
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Speicher erfolgreich erweitert auf %lu Bytes\n", (unsigned long)(max_entries * sizeof(struct log_entry)));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -283,7 +284,7 @@ void allocate_initial_memory(){
 | 
			
		||||
        exit(1); // cleanup_and_exit() nicht nötig, da der Speicherbereich nicht beschrieben wurde - use-after-free unproblematisch
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: Speicher erfolgreich alloziert für %d Log-Einträge (%lu Bytes)\n", max_entries, (unsigned long)(max_entries * sizeof(struct log_entry)));
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Speicher erfolgreich alloziert für %d Log-Einträge (%lu Bytes)\n", max_entries, (unsigned long)(max_entries * sizeof(struct log_entry)));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void get_current_timestamp(char* buffer, int buffer_size) {
 | 
			
		||||
@ -311,24 +312,30 @@ int is_directory(char* path) {
 | 
			
		||||
 | 
			
		||||
// Hilfsfunktion zum prüfen, ob es sich um eine plausible nginx-Logdatei handelt (Metrik: Dateiname - BESSER: Regex oder Magic Bytes?)
 | 
			
		||||
int is_log_file(char* filename) {   
 | 
			
		||||
    char* log_pos = strstr(filename, ".log"); // Sucht und findet den Pointer auf die Startposition des Suchstrings
 | 
			
		||||
    if (log_pos == NULL) return 0;
 | 
			
		||||
    
 | 
			
		||||
    char* after_log = log_pos + 4;
 | 
			
		||||
    
 | 
			
		||||
    if (*after_log == '\0') return 1; // true, wenn die Datei mit .log endet
 | 
			
		||||
    
 | 
			
		||||
    if (*after_log == '.') {
 | 
			
		||||
        after_log++;
 | 
			
		||||
        if (*after_log == '\0') return 0; // false, wenn die Datei mit einem Punkt nach .log endet
 | 
			
		||||
        
 | 
			
		||||
        while (*after_log != '\0') {
 | 
			
		||||
            if (*after_log < '0' || *after_log > '9') return 0; // wenn was anderes als Zahlen nach dem . kommen, gib False zurück
 | 
			
		||||
            after_log++;
 | 
			
		||||
        }
 | 
			
		||||
        return 1; // true, wenn nach .log. noch Zahlen vorhanden sind, wie typisch bei NGINX-Logrotation
 | 
			
		||||
    // versteckte Dateien sowie . oder .. überspringen
 | 
			
		||||
    if (filename[0] == '.') {
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    return 0; // false, wenn nichts zutrifft
 | 
			
		||||
    
 | 
			
		||||
    // Mögliche Bestandteile von NGINX-Logfile-Dateinamen
 | 
			
		||||
    char* log_patterns[] = {
 | 
			
		||||
        ".log",
 | 
			
		||||
        "access",
 | 
			
		||||
        "error",
 | 
			
		||||
        "combined",
 | 
			
		||||
        "redirect",
 | 
			
		||||
        NULL
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    // Vergleich der vorhandenen Dateinamen mit den Suchmustern
 | 
			
		||||
    for (int i = 0; log_patterns[i] != NULL; i++) {
 | 
			
		||||
        if (strstr(filename, log_patterns[i]) != NULL) {
 | 
			
		||||
            if ((strstr(filename, "error")!= NULL)||(strstr(filename, ".gz")!= NULL)) continue;
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Funktion zum suchen eines Suchbegriffs innerhalb eines Strings (lowercase)
 | 
			
		||||
@ -374,12 +381,25 @@ int search_in_string(char* raw_string, char* search_string) {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// Fügt eine Annotation zu einem bestimmten Eintrag hinzu
 | 
			
		||||
// https://stackoverflow.com/questions/5901181/c-string-append
 | 
			
		||||
void annotate_entry(int index, char* annotation_string) {
 | 
			
		||||
    if (index >= 0 && index < total_entries) {
 | 
			
		||||
        strncpy(all_entries[index].annotation, annotation_string, sizeof(all_entries[index].annotation) - 1);
 | 
			
		||||
        all_entries[index].annotation[sizeof(all_entries[index].annotation) - 1] = '\0';
 | 
			
		||||
        all_entries[index].annotated_flag = 1;
 | 
			
		||||
        //printf("DEBUG: Annotation zu Eintrag %d: %s\n", index, annotation_string);
 | 
			
		||||
        if (all_entries[index].annotation== NULL){
 | 
			
		||||
            strncpy(all_entries[index].annotation, annotation_string, sizeof(all_entries[index].annotation) - 1);
 | 
			
		||||
            all_entries[index].annotation[sizeof(all_entries[index].annotation) - 1] = '\0';
 | 
			
		||||
            all_entries[index].annotated_flag = 1;
 | 
			
		||||
        } else {
 | 
			
		||||
            char * new_str ;
 | 
			
		||||
            if((new_str = malloc(strlen(all_entries[index].annotation)+strlen(",")+strlen(annotation_string)+1)) != NULL){
 | 
			
		||||
                new_str[0] = '\0';   // ensures the memory is an empty string
 | 
			
		||||
                strcat(new_str,",");
 | 
			
		||||
                strcat(new_str,annotation_string);
 | 
			
		||||
                strncpy(all_entries[index].annotation, new_str, sizeof(all_entries[index].annotation) - 1);
 | 
			
		||||
                all_entries[index].annotation[sizeof(all_entries[index].annotation) - 1] = '\0';
 | 
			
		||||
                free(new_str);
 | 
			
		||||
                new_str=NULL;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -387,7 +407,7 @@ void annotate_entry(int index, char* annotation_string) {
 | 
			
		||||
 | 
			
		||||
// TRANSPARENZ: Diese Funktion ist KI-generiert
 | 
			
		||||
void annotate_suspicious_entries(struct log_entry* dataset) {
 | 
			
		||||
    printf("DEBUG: Prüfe %d Einträge auf verdächtige Muster...\n", total_entries);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Prüfe %d Einträge auf verdächtige Muster...\n", total_entries);
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < total_entries; i++) {
 | 
			
		||||
        // Initialisierung der Annotation falls noch nicht gesetzt
 | 
			
		||||
@ -616,7 +636,7 @@ void annotate_suspicious_entries(struct log_entry* dataset) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: Analyse abgeschlossen. %d verdächtige Muster erkannt.\n", suspicious_patterns_count);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Analyse abgeschlossen. %d verdächtige Muster erkannt.\n", suspicious_patterns_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
@ -921,8 +941,8 @@ void load_log_file(char* path) {
 | 
			
		||||
    char full_path[512];
 | 
			
		||||
 | 
			
		||||
    if (is_directory(path)) {
 | 
			
		||||
        printf("DEBUG: Verzeichnis erkannt: %s\n", path);
 | 
			
		||||
        printf("DEBUG: Suche nach .log Dateien...\n");
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Verzeichnis erkannt: %s\n", path);
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Suche nach .log Dateien...\n");
 | 
			
		||||
 | 
			
		||||
        DIR* dir = opendir(path);
 | 
			
		||||
        if (dir == NULL) {
 | 
			
		||||
@ -962,7 +982,7 @@ void load_log_file(char* path) {
 | 
			
		||||
            printf("INFO: Insgesamt %d .log Dateien verarbeitet.\n", files_found);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        printf("DEBUG: Einzelne Datei erkannt: %s\n", path);
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Einzelne Datei erkannt: %s\n", path);
 | 
			
		||||
        if (strstr(path, ".gz") != NULL) {
 | 
			
		||||
            load_gz_file(path);
 | 
			
		||||
        } else {
 | 
			
		||||
@ -972,9 +992,8 @@ void load_log_file(char* path) {
 | 
			
		||||
 | 
			
		||||
    printf("INFO: Erfolgreich %d Einträge insgesamt geladen.\n", total_entries);
 | 
			
		||||
    // die aufgerufene Funktion ist KI-generiert und annotiert verdächtige Requests automatisch.
 | 
			
		||||
    // TODO
 | 
			
		||||
    annotate_suspicious_entries(all_entries);
 | 
			
		||||
    printf("DEBUG: Aktueller Speicherverbrauch: %lu Bytes für %d Einträge\n",
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Aktueller Speicherverbrauch: %lu Bytes für %d Einträge\n",
 | 
			
		||||
           (unsigned long)(max_entries * sizeof(struct log_entry)), max_entries);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -983,7 +1002,7 @@ int user_agent_matches(char* user_agent) {
 | 
			
		||||
    if (filters.user_agent_count == 0) return 1;
 | 
			
		||||
    // Ausschluss-Filter geht vor    
 | 
			
		||||
    for (int i = 0; i < filters.user_agent_count; i++) {
 | 
			
		||||
        if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.user_agent_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            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
 | 
			
		||||
@ -995,7 +1014,7 @@ int user_agent_matches(char* user_agent) {
 | 
			
		||||
    int include_matches = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.user_agent_count; i++) {
 | 
			
		||||
        if (filters.user_agent_filters[i].mode == FILTER_INCLUDE) {
 | 
			
		||||
        if (filters.user_agent_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            include_count++;
 | 
			
		||||
            int pattern_found = search_in_string(user_agent, filters.user_agent_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
@ -1024,7 +1043,7 @@ int url_matches(char* url_path) {
 | 
			
		||||
    if (filters.url_count == 0) return 1;
 | 
			
		||||
    // Ausschluss-Filter geht vor    
 | 
			
		||||
    for (int i = 0; i < filters.url_count; i++) {
 | 
			
		||||
        if (filters.url_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.url_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            int pattern_found = search_in_string(url_path, filters.url_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
                return 0; // früheres Verlassen der Schleife, sobald Ausschlussfilter zutrifft
 | 
			
		||||
@ -1036,7 +1055,7 @@ int url_matches(char* url_path) {
 | 
			
		||||
    int include_matches = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.url_count; i++) {
 | 
			
		||||
        if (filters.url_filters[i].mode == FILTER_INCLUDE) {
 | 
			
		||||
        if (filters.url_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            include_count++;
 | 
			
		||||
            int pattern_found = search_in_string(url_path, filters.url_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
@ -1065,7 +1084,7 @@ int method_matches(char* request_method) {
 | 
			
		||||
    if (filters.method_count == 0) return 1;
 | 
			
		||||
    // Ausschluss-Filter geht vor    
 | 
			
		||||
    for (int i = 0; i < filters.method_count; i++) {
 | 
			
		||||
        if (filters.method_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.method_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            int pattern_found = search_in_string(request_method, filters.method_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
                return 0; // früheres Verlassen der Schleife, sobald Ausschlussfilter zutrifft
 | 
			
		||||
@ -1077,7 +1096,7 @@ int method_matches(char* request_method) {
 | 
			
		||||
    int include_matches = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.method_count; i++) {
 | 
			
		||||
        if (filters.method_filters[i].mode == FILTER_INCLUDE) {
 | 
			
		||||
        if (filters.method_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            include_count++;
 | 
			
		||||
            int pattern_found = search_in_string(request_method, filters.method_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
@ -1105,7 +1124,7 @@ int status_code_matches(int status_code) {
 | 
			
		||||
    if (filters.status_count == 0) return 1;
 | 
			
		||||
    // Ausschluss-Filter prüfen: immer übergeordnet gültig
 | 
			
		||||
    for (int i = 0; i < filters.status_count; i++) {
 | 
			
		||||
        if (filters.status_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.status_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            if (filters.status_filters[i].code == status_code) {
 | 
			
		||||
                return 0; 
 | 
			
		||||
            }
 | 
			
		||||
@ -1117,7 +1136,7 @@ int status_code_matches(int status_code) {
 | 
			
		||||
    int include_matches = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.status_count; i++) {
 | 
			
		||||
        if (filters.status_filters[i].mode == FILTER_INCLUDE) {
 | 
			
		||||
        if (filters.status_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            include_count++;
 | 
			
		||||
            if (filters.status_filters[i].code == status_code) {
 | 
			
		||||
                include_matches++;
 | 
			
		||||
@ -1144,7 +1163,7 @@ int ip_address_matches(char* ip_address) {
 | 
			
		||||
    
 | 
			
		||||
    // Prüfen der Ausschlussfilter, sind dem Rest vorgelagert
 | 
			
		||||
    for (int i = 0; i < filters.ip_count; i++) {
 | 
			
		||||
        if (filters.ip_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.ip_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            if (strcmp(filters.ip_filters[i].ip_address, ip_address) == 0) {
 | 
			
		||||
                return 0; // zutreffender Ausschlussfilter führt zu negativem Rückgabewert
 | 
			
		||||
            }
 | 
			
		||||
@ -1156,7 +1175,7 @@ int ip_address_matches(char* ip_address) {
 | 
			
		||||
    int include_matches = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.ip_count; i++) {
 | 
			
		||||
        if (filters.ip_filters[i].mode == FILTER_INCLUDE) {
 | 
			
		||||
        if (filters.ip_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            include_count++;
 | 
			
		||||
            if (strcmp(filters.ip_filters[i].ip_address, ip_address) == 0) {
 | 
			
		||||
                include_matches++;
 | 
			
		||||
@ -1179,14 +1198,14 @@ int ip_address_matches(char* ip_address) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int is_annotated(int annotated_flag){
 | 
			
		||||
    if (filters.annotation_flag_filter.mode == FILTER_EXCLUDE && filters.annotation_flag_filter_enabled == 1 && annotated_flag == 1) {
 | 
			
		||||
    if (filters.annotation_flag_filter.filter_exclude_flag == 1 && filters.annotation_flag_filter_enabled == 1 && annotated_flag == 1) {
 | 
			
		||||
        return 0; // zutreffender Ausschlussfilter führt zu negativem Rückgabewert
 | 
			
		||||
    }
 | 
			
		||||
    else if (filters.annotation_flag_filter.mode == FILTER_INCLUDE && filters.annotation_flag_filter_enabled == 1 && annotated_flag == 1) {
 | 
			
		||||
    else if (filters.annotation_flag_filter.filter_exclude_flag == 0 && filters.annotation_flag_filter_enabled == 1 && annotated_flag == 1) {
 | 
			
		||||
        return 1; // zutreffender Einschlussfilter führt zu positivem Rückgabewert
 | 
			
		||||
    }
 | 
			
		||||
    // nichtannotiert, aber inklusiver Filter aktiv -> Eintrag nicht anzeigen
 | 
			
		||||
    else if (annotated_flag == 0 && filters.annotation_flag_filter.mode == FILTER_INCLUDE && filters.annotation_flag_filter_enabled == 1){
 | 
			
		||||
    else if (annotated_flag == 0 && filters.annotation_flag_filter.filter_exclude_flag == 0 && filters.annotation_flag_filter_enabled == 1){
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    // Filter nicht aktiv, positiver Rückgabewert
 | 
			
		||||
@ -1198,7 +1217,7 @@ int annotation_matches(char* annotation) {
 | 
			
		||||
    if (filters.annotation_count == 0) return 1;
 | 
			
		||||
    // Ausschluss-Filter geht vor    
 | 
			
		||||
    for (int i = 0; i < filters.annotation_count; i++) {
 | 
			
		||||
        if (filters.annotation_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.annotation_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            int pattern_found = search_in_string(annotation, filters.annotation_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
                return 0; // früheres Verlassen der Schleife, sobald Ausschlussfilter zutrifft
 | 
			
		||||
@ -1210,7 +1229,7 @@ int annotation_matches(char* annotation) {
 | 
			
		||||
    int include_matches = 0;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.annotation_count; i++) {
 | 
			
		||||
        if (filters.annotation_filters[i].mode == FILTER_INCLUDE) {
 | 
			
		||||
        if (filters.annotation_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            include_count++;
 | 
			
		||||
            int pattern_found = search_in_string(annotation, filters.annotation_filters[i].pattern);
 | 
			
		||||
            if (pattern_found) {
 | 
			
		||||
@ -1240,7 +1259,7 @@ int time_matches(struct simple_time entry_time) {
 | 
			
		||||
    
 | 
			
		||||
    // Übergeordneter Ausschlussfilter
 | 
			
		||||
    for (int i = 0; i < filters.time_count; i++) {
 | 
			
		||||
        if (filters.time_filters[i].mode == FILTER_EXCLUDE) {
 | 
			
		||||
        if (filters.time_filters[i].filter_exclude_flag == 1) {
 | 
			
		||||
            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) {
 | 
			
		||||
@ -1253,7 +1272,7 @@ int time_matches(struct simple_time entry_time) {
 | 
			
		||||
    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) {
 | 
			
		||||
        if (filters.time_filters[i].filter_exclude_flag == 0) {
 | 
			
		||||
            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);
 | 
			
		||||
@ -1387,7 +1406,7 @@ void export_filtered_entries(char *filepath) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // CSV-Kopfzeile für Timesketch-Kompatibilität
 | 
			
		||||
    fprintf(file, "datetime,timestamp_desc,ip_address,method,url_path,status_code,bytes_sent,user_agent,source_file,parsing_timestamp,annotation\n");
 | 
			
		||||
    fprintf(file, "datetime,message,timestamp_desc,ip_address,method,url_path,status_code,bytes_sent,user_agent,parsing_timestamp,tag\n");
 | 
			
		||||
    
 | 
			
		||||
    int exported_count = 0;
 | 
			
		||||
    char iso_datetime[32];
 | 
			
		||||
@ -1396,20 +1415,44 @@ void export_filtered_entries(char *filepath) {
 | 
			
		||||
        if (passes_filter(i)) {
 | 
			
		||||
            format_iso8601_time(all_entries[i].time, iso_datetime, sizeof(iso_datetime));
 | 
			
		||||
            
 | 
			
		||||
            // https://stackoverflow.com/questions/5901181/c-string-append
 | 
			
		||||
            // https://www.quora.com/How-can-we-count-the-number-of-special-characters-in-a-string-in-the-C-language-using-fgets
 | 
			
		||||
            char* tag_str;
 | 
			
		||||
            int num_delimiters = 0;
 | 
			
		||||
            int c=0;
 | 
			
		||||
            while(all_entries[i].annotation[c]!='\0'){
 | 
			
		||||
                num_delimiters++;
 | 
			
		||||
            }
 | 
			
		||||
            if (tag_str=malloc(sizeof(all_entries[i].annotation)+sizeof("[  ]")+(sizeof(','))*num_delimiters)+1)!=NULL){
 | 
			
		||||
                tag_str[0] = '\0';
 | 
			
		||||
                
 | 
			
		||||
            fprintf(file, "\"%s\",\"HTTP Access Log\",\"%s\",\"%s\",\"%s\",%d,%d,\"%s\",\"%s\",\"%s\"\n",
 | 
			
		||||
                iso_datetime,
 | 
			
		||||
 | 
			
		||||
                char* token = strtok(all_entries[i].annotation, ",");
 | 
			
		||||
                if (!token) return;
 | 
			
		||||
                strcat(tag_str, "[ ");
 | 
			
		||||
                for (i=0;i<num_delimiters;i++){
 | 
			
		||||
                    strcat(tag_str, "\"");
 | 
			
		||||
                    strcat(tag_str, strtok(NULL, ","));
 | 
			
		||||
                    strcat(tag_str, '"');
 | 
			
		||||
                }
 | 
			
		||||
                strcat(tag_str, " ]");
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            fprintf(file, "\"%s\",\"%s\",\"HTTP Access Log\",\"%s\",\"%s\",\"%s\",%d,%d,\"%s\",\"%s\",\"%s\"\n",
 | 
			
		||||
                iso_datetime, // datetime
 | 
			
		||||
                all_entries[i].source_file, // message
 | 
			
		||||
                all_entries[i].ip_address,
 | 
			
		||||
                all_entries[i].request_method,
 | 
			
		||||
                all_entries[i].url_path,
 | 
			
		||||
                all_entries[i].status_code,
 | 
			
		||||
                all_entries[i].bytes_sent,
 | 
			
		||||
                all_entries[i].user_agent,
 | 
			
		||||
                all_entries[i].source_file,
 | 
			
		||||
                all_entries[i].parsing_timestamp,
 | 
			
		||||
                all_entries[i].annotation
 | 
			
		||||
                tag_str
 | 
			
		||||
                //all_entries[i].annotation // tag
 | 
			
		||||
            );
 | 
			
		||||
            
 | 
			
		||||
            free(tag_str);
 | 
			
		||||
            tag_str=NULL;
 | 
			
		||||
            exported_count++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -1418,10 +1461,6 @@ void export_filtered_entries(char *filepath) {
 | 
			
		||||
    printf("INFO: %d Logeinträge erfolgreich als Timesketch-kompatible CSV-Datei nach '%s' exportiert.\n", exported_count, filename);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ip_stat {
 | 
			
		||||
    char ip_address[50];
 | 
			
		||||
    int count;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// zeigt alle annotierten Einträge detailliert an
 | 
			
		||||
void show_annotated_entries() {
 | 
			
		||||
@ -1461,27 +1500,36 @@ void show_annotated_entries() {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO doku
 | 
			
		||||
// top-IP-Adressen sortieren nach Aufkommen und anzeigen
 | 
			
		||||
void show_top_x_ips(){
 | 
			
		||||
    // initialisieren von 1000 Datenstrukturen mit einem char ip_address[50] und int count (oben definiert)
 | 
			
		||||
    struct ip_stat ip_stats[1000];
 | 
			
		||||
    // lokaler Zähler
 | 
			
		||||
    int unique_ips = 0;
 | 
			
		||||
    
 | 
			
		||||
    // iterieren über alle IP-Adressen, die im Filterset sind
 | 
			
		||||
    for (int i = 0; i < total_entries; i++) {
 | 
			
		||||
        if (!passes_filter(i)) continue;
 | 
			
		||||
        
 | 
			
		||||
        // IP lokal speichern
 | 
			
		||||
        char* current_ip = all_entries[i].ip_address;
 | 
			
		||||
        
 | 
			
		||||
        // initialisieren des Index - -1 heißt bisher nie aufgetreten
 | 
			
		||||
        int found_index = -1;
 | 
			
		||||
        for (int j = 0; j < unique_ips; j++) {
 | 
			
		||||
            // Wenn die IP-Adresse im Vergeichsdatensatz gefunden wird, wird der index entsprechend gesetzt/erstellt
 | 
			
		||||
            if (strcmp(ip_stats[j].ip_address, current_ip) == 0) {
 | 
			
		||||
                found_index = j;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        // wenn ein neuer index erstellt wurde (IP-Adresse war noch nicht in der Datenstruktur) oder gefunden wurde...
 | 
			
		||||
        if (found_index >= 0) {
 | 
			
		||||
            // inkrementieren des counters für Anzahl wie oft gefunden
 | 
			
		||||
            ip_stats[found_index].count++;
 | 
			
		||||
        } else {
 | 
			
		||||
            // wenn nicht gefunden (found_index == -1) wird die IP mit count = 1 neu angelegt
 | 
			
		||||
            if (unique_ips < 1000) {
 | 
			
		||||
                strcpy(ip_stats[unique_ips].ip_address, current_ip);
 | 
			
		||||
                ip_stats[unique_ips].count = 1;
 | 
			
		||||
@ -1490,6 +1538,8 @@ void show_top_x_ips(){
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // iterieren über alle unique ips
 | 
			
		||||
    // Bubble sort: https://www.proggen.org/doku.php?id=training:sorting:bubblesort:solution
 | 
			
		||||
    for (int i = 0; i < unique_ips - 1; i++) {
 | 
			
		||||
        for (int j = 0; j < unique_ips - i - 1; j++) {
 | 
			
		||||
            if (ip_stats[j].count < ip_stats[j + 1].count) {
 | 
			
		||||
@ -1500,6 +1550,7 @@ void show_top_x_ips(){
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // visuelle Darstellung
 | 
			
		||||
    printf("\nTOP %d IP-ADRESSEN\n", TOP_X);
 | 
			
		||||
    printf("Rang | IP-Adresse       | Anzahl Anfragen\n");
 | 
			
		||||
    printf("-----|------------------|----------------\n");
 | 
			
		||||
@ -1516,7 +1567,7 @@ void show_top_x_ips(){
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO doku
 | 
			
		||||
// gleiche Mechanik wie in show_top_x_ips - könnte wahrscheinlich vereinheitlicht werden
 | 
			
		||||
void show_top_user_agents(){
 | 
			
		||||
    struct user_agent_stat {
 | 
			
		||||
        char user_agent[256];
 | 
			
		||||
@ -1633,7 +1684,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--status=");
 | 
			
		||||
        for (int i = 0; i < filters.status_count; i++) {
 | 
			
		||||
            if (i > 0) {printf(",");};
 | 
			
		||||
            if (filters.status_filters[i].mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
            if (filters.status_filters[i].filter_exclude_flag == 1) printf("!");
 | 
			
		||||
            printf("%d", filters.status_filters[i].code);
 | 
			
		||||
        }
 | 
			
		||||
        printf(" ");
 | 
			
		||||
@ -1643,7 +1694,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--method=");
 | 
			
		||||
        for (int i = 0; i < filters.method_count; i++) {
 | 
			
		||||
            if (i > 0) {printf(",");}
 | 
			
		||||
            if (filters.method_filters[i].mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
            if (filters.method_filters[i].filter_exclude_flag == 1) printf("!");
 | 
			
		||||
            printf("%s", filters.method_filters[i].pattern);
 | 
			
		||||
        }
 | 
			
		||||
        printf(" ");
 | 
			
		||||
@ -1653,7 +1704,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--ip=");
 | 
			
		||||
        for (int i = 0; i < filters.ip_count; i++) {
 | 
			
		||||
            if (i > 0) {printf(",");};
 | 
			
		||||
            if (filters.ip_filters[i].mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
            if (filters.ip_filters[i].filter_exclude_flag == 1) printf("!");
 | 
			
		||||
            printf("%s", filters.ip_filters[i].ip_address);
 | 
			
		||||
        }
 | 
			
		||||
        printf(" ");
 | 
			
		||||
@ -1663,7 +1714,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--useragent=");
 | 
			
		||||
        for (int i = 0; i < filters.user_agent_count; i++) {
 | 
			
		||||
            if (i > 0) {printf(",");};
 | 
			
		||||
            if (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
            if (filters.user_agent_filters[i].filter_exclude_flag == 1) printf("!");
 | 
			
		||||
            printf("%s", filters.user_agent_filters[i].pattern);
 | 
			
		||||
        }
 | 
			
		||||
        printf(" ");
 | 
			
		||||
@ -1673,7 +1724,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--url=");
 | 
			
		||||
        for (int i = 0; i < filters.url_count; i++) {
 | 
			
		||||
            if (i > 0) {printf(",");};
 | 
			
		||||
            if (filters.url_filters[i].mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
            if (filters.url_filters[i].filter_exclude_flag == 1) printf("!");
 | 
			
		||||
            printf("%s", filters.url_filters[i].pattern);
 | 
			
		||||
        }
 | 
			
		||||
        printf(" ");
 | 
			
		||||
@ -1683,7 +1734,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--timerange=");
 | 
			
		||||
        for(int i =0; i < filters.time_count;i++){
 | 
			
		||||
            if(i > 0) {printf(",");};
 | 
			
		||||
            if (filters.time_filters[i].mode == FILTER_EXCLUDE) {printf("!");};
 | 
			
		||||
            if (filters.time_filters[i].filter_exclude_flag == 1) {printf("!");};
 | 
			
		||||
            // die führenden 0 sind hier wichtig
 | 
			
		||||
            printf("%04d-%02d-%02d-%02d-%02d-%02d:%04d-%02d-%02d-%02d-%02d-%02d ",
 | 
			
		||||
                filters.time_filters[i].start_time.year,
 | 
			
		||||
@ -1704,7 +1755,7 @@ void print_filter_args(){
 | 
			
		||||
    // macht nicht viel Sinn, diese hier zu integrieren, so lang der User nicht weiß, wie die Annotationen lauten
 | 
			
		||||
    if (filters.annotation_flag_filter_enabled) {
 | 
			
		||||
        printf("--annotated=");
 | 
			
		||||
        if (filters.annotation_flag_filter.mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
        if (filters.annotation_flag_filter.filter_exclude_flag == 1) printf("!");
 | 
			
		||||
        printf("true ");
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@ -1712,7 +1763,7 @@ void print_filter_args(){
 | 
			
		||||
        printf("--annotation=");
 | 
			
		||||
        for (int i = 0; i < filters.annotation_count; i++) {
 | 
			
		||||
            if (i > 0) printf(",");
 | 
			
		||||
            if (filters.annotation_filters[i].mode == FILTER_EXCLUDE) printf("!");
 | 
			
		||||
            if (filters.annotation_filters[i].filter_exclude_flag == 1) printf("!");
 | 
			
		||||
            printf("%s", filters.annotation_filters[i].pattern);
 | 
			
		||||
        }
 | 
			
		||||
        printf(" ");
 | 
			
		||||
@ -1982,7 +2033,7 @@ int menu_set_filters(){
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            
 | 
			
		||||
            filters.status_filters[filters.status_count].code = status;
 | 
			
		||||
            filters.status_filters[filters.status_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.status_filters[filters.status_count].filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.status_count++;
 | 
			
		||||
            printf("Status-Code Filter hinzugefügt. Gesamt: %d\n", filters.status_count);
 | 
			
		||||
            
 | 
			
		||||
@ -2004,7 +2055,7 @@ int menu_set_filters(){
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            
 | 
			
		||||
            strcpy(filters.ip_filters[filters.ip_count].ip_address, ip);
 | 
			
		||||
            filters.ip_filters[filters.ip_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.ip_filters[filters.ip_count].filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.ip_count++;
 | 
			
		||||
            printf("IP-Filter hinzugefügt. Gesamt: %d\n", filters.ip_count);
 | 
			
		||||
            
 | 
			
		||||
@ -2076,7 +2127,7 @@ int menu_set_filters(){
 | 
			
		||||
            new_time_filter.end_time.minute = end_minute;
 | 
			
		||||
            new_time_filter.end_time.second = end_second;
 | 
			
		||||
            
 | 
			
		||||
            new_time_filter.mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            new_time_filter.filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            
 | 
			
		||||
            filters.time_filters[filters.time_count] = new_time_filter;
 | 
			
		||||
            filters.time_count++;
 | 
			
		||||
@ -2101,7 +2152,7 @@ int menu_set_filters(){
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            
 | 
			
		||||
            strcpy(filters.user_agent_filters[filters.user_agent_count].pattern, pattern);
 | 
			
		||||
            filters.user_agent_filters[filters.user_agent_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.user_agent_filters[filters.user_agent_count].filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.user_agent_count++;
 | 
			
		||||
            printf("User-Agent Filter hinzugefügt. Gesamt: %d\n", filters.user_agent_count);
 | 
			
		||||
            
 | 
			
		||||
@ -2123,7 +2174,7 @@ int menu_set_filters(){
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            
 | 
			
		||||
            strcpy(filters.method_filters[filters.method_count].pattern, pattern);
 | 
			
		||||
            filters.method_filters[filters.method_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.method_filters[filters.method_count].filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.method_count++;
 | 
			
		||||
            printf("Method-Filter hinzugefügt. Gesamt: %d\n", filters.method_count);
 | 
			
		||||
            
 | 
			
		||||
@ -2145,7 +2196,7 @@ int menu_set_filters(){
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            
 | 
			
		||||
            strcpy(filters.url_filters[filters.url_count].pattern, pattern);
 | 
			
		||||
            filters.url_filters[filters.url_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.url_filters[filters.url_count].filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.url_count++;
 | 
			
		||||
            printf("URL-Filter hinzugefügt. Gesamt: %d\n", filters.url_count);
 | 
			
		||||
        } else if (choice == 7) {
 | 
			
		||||
@ -2155,7 +2206,7 @@ int menu_set_filters(){
 | 
			
		||||
            
 | 
			
		||||
            int filter_type = safe_read_integer("Auswahl: ", 1, 2);
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            filters.annotation_flag_filter.mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.annotation_flag_filter.filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.annotation_flag_filter_enabled = 1;
 | 
			
		||||
        } else if (choice == 8) {
 | 
			
		||||
            if (filters.annotation_count >= MAX_FILTERS) {
 | 
			
		||||
@ -2175,7 +2226,7 @@ int menu_set_filters(){
 | 
			
		||||
            if (filter_type < 0) continue;
 | 
			
		||||
            
 | 
			
		||||
            strcpy(filters.annotation_filters[filters.annotation_count].pattern, pattern);
 | 
			
		||||
            filters.annotation_filters[filters.annotation_count].mode = (filter_type == 2) ? FILTER_EXCLUDE : FILTER_INCLUDE;
 | 
			
		||||
            filters.annotation_filters[filters.annotation_count].filter_exclude_flag = (filter_type == 2) ? 1 : 0;
 | 
			
		||||
            filters.annotation_count++;
 | 
			
		||||
            printf("Annotations-Filter hinzugefügt. Gesamt: %d\n", filters.annotation_count);
 | 
			
		||||
        } else if (choice == -2) {
 | 
			
		||||
@ -2203,32 +2254,32 @@ void menu_delete_filters(){
 | 
			
		||||
    int filter_index = 1;
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.status_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.status_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.status_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. Status-Code: %d (%s)\n", filter_index++, filters.status_filters[i].code, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < filters.method_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.method_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.method_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. HTTP-Methode: \"%s\" (%s)\n", filter_index++, filters.method_filters[i].pattern, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.ip_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.ip_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.ip_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. IP-Adresse: %s (%s)\n", filter_index++, filters.ip_filters[i].ip_address, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.user_agent_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.user_agent_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.user_agent_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. User-Agent: \"%s\" (%s)\n", filter_index++, filters.user_agent_filters[i].pattern, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < filters.url_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.url_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.url_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. URL-Pfad: \"%s\" (%s)\n", filter_index++, filters.url_filters[i].pattern, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    for (int i = 0; i < filters.time_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.time_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.time_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. Zeitraum: %02d.%02d.%d %02d:%02d:%02d - %02d.%02d.%d %02d:%02d:%02d (%s)\n", 
 | 
			
		||||
               filter_index++,
 | 
			
		||||
               filters.time_filters[i].start_time.day,
 | 
			
		||||
@ -2247,12 +2298,12 @@ void menu_delete_filters(){
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (filters.annotation_flag_filter_enabled){
 | 
			
		||||
        char* mode_str = (filters.annotation_flag_filter.mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.annotation_flag_filter.filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. Annotierte Einträge %s", filter_index++, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < filters.annotation_count; i++) {
 | 
			
		||||
        char* mode_str = (filters.annotation_filters[i].mode == FILTER_EXCLUDE) ? "ausschließen" : "einschließen";
 | 
			
		||||
        char* mode_str = (filters.annotation_filters[i].filter_exclude_flag == 1) ? "ausschließen" : "einschließen";
 | 
			
		||||
        printf("%2d. Annotations-Filter: \"%s\" (%s)\n", filter_index++, filters.annotation_filters[i].pattern, mode_str);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@ -2531,7 +2582,7 @@ void menu_show_entries(){
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Funktionen zum setzen der Filter (existierende Datenstrukturen)
 | 
			
		||||
void add_parsed_status_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_status_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.status_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2539,7 +2590,7 @@ void add_parsed_status_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    // Kovertierung des Statuscodes zu long mit Error handling
 | 
			
		||||
    char* endptr;
 | 
			
		||||
    int status_code = strtol(value, &endptr, 10);
 | 
			
		||||
    if (*endptr != '\n'){
 | 
			
		||||
    if (*endptr != '\0'){
 | 
			
		||||
        printf("ERROR: Ungültiger Wert im Statuscode-Filter: %s", value);
 | 
			
		||||
    }
 | 
			
		||||
    if (status_code < 100 || status_code > 599) {
 | 
			
		||||
@ -2549,13 +2600,13 @@ void add_parsed_status_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    
 | 
			
		||||
    // setzen des Filters
 | 
			
		||||
    filters.status_filters[filters.status_count].code = status_code;
 | 
			
		||||
    filters.status_filters[filters.status_count].mode = mode;
 | 
			
		||||
    filters.status_filters[filters.status_count].filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    filters.status_count++;
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: Filter hinzugefügt: %s%d\n", mode == FILTER_EXCLUDE ? "!" : "", status_code);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Filter hinzugefügt: %s%d\n", filter_exclude_flag == 1 ? "!" : "", status_code);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_parsed_ip_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_ip_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.ip_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2569,14 +2620,14 @@ void add_parsed_ip_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    
 | 
			
		||||
    // setzen des Filters
 | 
			
		||||
    strcpy(filters.ip_filters[filters.ip_count].ip_address, value);
 | 
			
		||||
    filters.ip_filters[filters.ip_count].mode = mode;
 | 
			
		||||
    filters.ip_filters[filters.ip_count].filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    filters.ip_count++;
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: IP-Adressfilter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: IP-Adressfilter hinzugefügt: %s%s\n", filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gleiche Mechanik wie bei IP-Adresse
 | 
			
		||||
void add_parsed_method_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_method_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.method_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2588,14 +2639,14 @@ void add_parsed_method_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    strcpy(filters.method_filters[filters.method_count].pattern, value);
 | 
			
		||||
    filters.method_filters[filters.method_count].mode = mode;
 | 
			
		||||
    filters.method_filters[filters.method_count].filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    filters.method_count++;
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: Methoden-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Methoden-Filter hinzugefügt: %s%s\n", filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gleiche Mechanik wie bei IP-Adresse
 | 
			
		||||
void add_parsed_useragent_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_useragent_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.user_agent_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2607,14 +2658,14 @@ void add_parsed_useragent_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    strcpy(filters.user_agent_filters[filters.user_agent_count].pattern, value);
 | 
			
		||||
    filters.user_agent_filters[filters.user_agent_count].mode = mode;
 | 
			
		||||
    filters.user_agent_filters[filters.user_agent_count].filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    filters.user_agent_count++;
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: User Agent Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: User Agent Filter hinzugefügt: %s%s\n", filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gleiche Mechanik wie bei IP-Adresse
 | 
			
		||||
void add_parsed_url_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_url_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.url_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2626,14 +2677,14 @@ void add_parsed_url_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    strcpy(filters.url_filters[filters.url_count].pattern, value);
 | 
			
		||||
    filters.url_filters[filters.url_count].mode = mode;
 | 
			
		||||
    filters.url_filters[filters.url_count].filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    filters.url_count++;
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: URL/Payload-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: URL/Payload-Filter hinzugefügt: %s%s\n", filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Parsen des Timestamp-Filters ist etwas komplexer, da er in die Datenstruktur geschrieben werden muss.
 | 
			
		||||
void add_parsed_timerange_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_timerange_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.time_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2760,14 +2811,14 @@ void add_parsed_timerange_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    new_time_filter.end_time.minute = end_minute;
 | 
			
		||||
    new_time_filter.end_time.second = end_second;
 | 
			
		||||
    
 | 
			
		||||
    new_time_filter.mode = mode;
 | 
			
		||||
    new_time_filter.filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    
 | 
			
		||||
    // Logik hier: der neue Filter wird stets an einen neuen Index geschrieben. Dieser ergibt sich aus der aktuellen ANZAHL der existierenden Zeitfilter. Das funktioniert, weil der index bei 0 beginnt
 | 
			
		||||
    filters.time_filters[filters.time_count] = new_time_filter;
 | 
			
		||||
    filters.time_count++;
 | 
			
		||||
 | 
			
		||||
    printf("DEBUG: Zeitraum-Filter hinzugefügt (%s): %04d-%02d-%02d %02d:%02d:%02d bis %04d-%02d-%02d %02d:%02d:%02d\n",
 | 
			
		||||
        mode == FILTER_EXCLUDE ? "ausschließen" : "einschließen",
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Zeitraum-Filter hinzugefügt (%s): %04d-%02d-%02d %02d:%02d:%02d bis %04d-%02d-%02d %02d:%02d:%02d\n",
 | 
			
		||||
        filter_exclude_flag == 1 ? "ausschließen" : "einschließen",
 | 
			
		||||
        new_time_filter.start_time.year, new_time_filter.start_time.month, new_time_filter.start_time.day,
 | 
			
		||||
        new_time_filter.start_time.hour, new_time_filter.start_time.minute, new_time_filter.start_time.second,
 | 
			
		||||
        new_time_filter.end_time.year, new_time_filter.end_time.month, new_time_filter.end_time.day,
 | 
			
		||||
@ -2775,25 +2826,25 @@ void add_parsed_timerange_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// recht einfache Mechanik für den Bool´schen Filter für annotierte Einträge
 | 
			
		||||
void add_parsed_annotated_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_annotated_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (strcmp(value, "true") == 0) {
 | 
			
		||||
        filters.annotation_flag_filter.annotation_flag_is_present = 1;
 | 
			
		||||
        filters.annotation_flag_filter.mode = mode;
 | 
			
		||||
        filters.annotation_flag_filter.filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
        filters.annotation_flag_filter_enabled = 1;
 | 
			
		||||
        printf("DEBUG: Annotations-Flag-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Annotations-Flag-Filter hinzugefügt: %s%s\n", filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
        // falls doch mal jemand false eingibt
 | 
			
		||||
    } else if (strcmp(value, "false") == 0) {
 | 
			
		||||
        filters.annotation_flag_filter.annotation_flag_is_present = 0;
 | 
			
		||||
        filters.annotation_flag_filter.mode = mode;
 | 
			
		||||
        filters.annotation_flag_filter.filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
        filters.annotation_flag_filter_enabled = 1;
 | 
			
		||||
        printf("DEBUG: Annotations-Flag-Filter hinzugefügt: %s%s\n", mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
        if (flag_verbose) printf("DEBUG: Annotations-Flag-Filter hinzugefügt: %s%s\n", filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
    } else {
 | 
			
		||||
        printf("WARNING: Ungültiger Wert für --annotated Filter: %s (nur 'true' unterstützt)\n", value);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Wieder gleiche Mechanik wie beim User Agent etc
 | 
			
		||||
void add_parsed_annotation_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
void add_parsed_annotation_filter(char* value, int filter_exclude_flag) {
 | 
			
		||||
    if (filters.annotation_count >= MAX_FILTERS) {
 | 
			
		||||
        printf("WARNING: MAX_FILTERS überschritten, ignoriere: %s\n", value);
 | 
			
		||||
        return;
 | 
			
		||||
@ -2805,11 +2856,11 @@ void add_parsed_annotation_filter(char* value, filter_mode_t mode) {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    strcpy(filters.annotation_filters[filters.annotation_count].pattern, value);
 | 
			
		||||
    filters.annotation_filters[filters.annotation_count].mode = mode;
 | 
			
		||||
    filters.annotation_filters[filters.annotation_count].filter_exclude_flag = filter_exclude_flag;
 | 
			
		||||
    filters.annotation_count++;
 | 
			
		||||
    
 | 
			
		||||
    printf("DEBUG: Annotations-Filter hinzugefügt: %s%s\n", 
 | 
			
		||||
           mode == FILTER_EXCLUDE ? "!" : "", value);
 | 
			
		||||
    if (flag_verbose) printf("DEBUG: Annotations-Filter hinzugefügt: %s%s\n", 
 | 
			
		||||
           filter_exclude_flag == 1 ? "!" : "", value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Funktion zum Parsen der Filter-Werte, die mit --<Filtertyp>=<Werte,Komma-getrennt> übergeben werden. 
 | 
			
		||||
@ -2828,31 +2879,31 @@ void parse_filter_values(char* values_str, char* filter_type) {
 | 
			
		||||
        // Sollte der Nutzer Leerzeichen verwendet haben, müssen diese übersprungen werden
 | 
			
		||||
        while (*token == ' ') token++;
 | 
			
		||||
        // setzen des Modus, Standard inklusiv
 | 
			
		||||
        filter_mode_t mode = FILTER_INCLUDE;
 | 
			
		||||
        int filter_exclude_flag = 0;
 | 
			
		||||
        // ..mit !-Präfix exklusiv.
 | 
			
		||||
        if (*token == '!') {
 | 
			
		||||
            mode = FILTER_EXCLUDE;
 | 
			
		||||
            filter_exclude_flag = 1;
 | 
			
		||||
            token++; // den Pointer vom ! weiteriterieren, dieser ist nicht Teil des Filters
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (strlen(token) > 0) {
 | 
			
		||||
            // wenn das token Werte hat, werden die entsprechenden Funktionen aufgerufen, die die Filter setzen
 | 
			
		||||
            if (strcmp(filter_type, "status") == 0) {
 | 
			
		||||
                add_parsed_status_filter(token, mode);
 | 
			
		||||
                add_parsed_status_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "ip") == 0) {
 | 
			
		||||
                add_parsed_ip_filter(token, mode);
 | 
			
		||||
                add_parsed_ip_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "method") == 0) {
 | 
			
		||||
                add_parsed_method_filter(token, mode);
 | 
			
		||||
                add_parsed_method_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "useragent") == 0) {
 | 
			
		||||
                add_parsed_useragent_filter(token, mode);
 | 
			
		||||
                add_parsed_useragent_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "url") == 0) {
 | 
			
		||||
                add_parsed_url_filter(token, mode);
 | 
			
		||||
                add_parsed_url_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "timerange") == 0) {
 | 
			
		||||
                add_parsed_timerange_filter(token, mode);
 | 
			
		||||
                add_parsed_timerange_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "annotated") == 0) {
 | 
			
		||||
                add_parsed_annotated_filter(token, mode);
 | 
			
		||||
                add_parsed_annotated_filter(token, filter_exclude_flag);
 | 
			
		||||
            } else if (strcmp(filter_type, "annotation") == 0) {
 | 
			
		||||
                add_parsed_annotation_filter(token, mode);
 | 
			
		||||
                add_parsed_annotation_filter(token, filter_exclude_flag);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // nächste Iteration - nächstes token einlesen, damit die while-Schleife weiteriteriert
 | 
			
		||||
@ -2903,10 +2954,10 @@ int parse_filter_argument(char* arg) {
 | 
			
		||||
    } else if (strstr(filter_type, "mode") != NULL) {
 | 
			
		||||
        if (strstr(values, "and") != NULL || strstr(values, "AND") != NULL) {
 | 
			
		||||
            filters.combination_mode = 0;
 | 
			
		||||
            printf("DEBUG: AND-Modus gesetzt\n");
 | 
			
		||||
            if (flag_verbose) printf("DEBUG: AND-Modus gesetzt\n");
 | 
			
		||||
        } else if (strstr(values, "or") != NULL || strstr(values, "OR") != NULL) {
 | 
			
		||||
            filters.combination_mode = 1;
 | 
			
		||||
            printf("DEBUG: OR-Modus gesetzt\n");
 | 
			
		||||
            if (flag_verbose) printf("DEBUG: OR-Modus gesetzt\n");
 | 
			
		||||
        } else {
 | 
			
		||||
            printf("WARNING: ungültiger Modus-Wert: %s ('and' oder 'oder' möglich)\n", values);
 | 
			
		||||
        }
 | 
			
		||||
@ -3010,6 +3061,7 @@ int main(int argc, char* argv[]) {
 | 
			
		||||
    int flag_interactive = 0;
 | 
			
		||||
    int flag_export = 0;
 | 
			
		||||
    int flag_help = 0;
 | 
			
		||||
    // int flag_verbose = 0; - global definiert
 | 
			
		||||
 | 
			
		||||
    char export_filename[90];
 | 
			
		||||
    int flag_has_filename = 0;
 | 
			
		||||
@ -3039,6 +3091,8 @@ int main(int argc, char* argv[]) {
 | 
			
		||||
 | 
			
		||||
            } else if (strcmp(argv[i], "-h")==0) {
 | 
			
		||||
                flag_help = 1;
 | 
			
		||||
            } else if (strcmp(argv[i], "-v")==0) {
 | 
			
		||||
                flag_verbose = 1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -3074,7 +3128,7 @@ int main(int argc, char* argv[]) {
 | 
			
		||||
            } else if (choice == 3) {
 | 
			
		||||
                export_filtered_entries(0);
 | 
			
		||||
            } else if (choice == 4) {
 | 
			
		||||
                printf("Programmende\n");
 | 
			
		||||
                if (flag_verbose) printf("DEBUG: Programmende\n");
 | 
			
		||||
                break;
 | 
			
		||||
            } else if (choice == -4) {
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user