From 3cab08dbf3a5d20f7cad1fb7feea862ac686f321 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sat, 2 Sep 2023 13:24:12 +0200 Subject: [PATCH 01/16] new branch for option to insert an event --- .gitignore | 1 + src/Makefile | 31 ++++++++++++++++++++----- src/cli_arg_parsing.c | 53 ++++++++++++++++++++++--------------------- src/insert_event.c | 33 +++++++++++++++++++++++++++ src/insert_event.h | 3 +++ src/main.c | 4 ++-- 6 files changed, 91 insertions(+), 34 deletions(-) create mode 100644 src/insert_event.c create mode 100644 src/insert_event.h diff --git a/.gitignore b/.gitignore index 3ff478d..af39d48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ a.out .gitconfig +*.o diff --git a/src/Makefile b/src/Makefile index 5df0b27..d8b836f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,3 +1,22 @@ +CC = gcc +CFLAGS = -Wall + +# List of all source files (assuming they're all in the same directory) +SRC_FILES = $(wildcard *.c) + +# Generate a list of object files by replacing the .c extension with .o +OBJ_FILES = $(SRC_FILES:.c=.o) + +ics_analyzer: $(OBJ_FILES) + gcc -Wall $(OBJ_FILES) -o ics_analyzer + +main.o: main.c + $(CC) $(CFLAGS) -c $< + +# use implicit rule to compile C source files to object files +%.o: %.c %.h + $(CC) $(CFLAGS) -c $< + .PHONY:all all: gcc -Wall *.c @@ -10,15 +29,15 @@ debug: .PHONY:run run: gcc -Wall *.c - ./a.out + ./ics_analyzer .PHONY:install install: a.out - cp a.out /usr/local/bin/ics_analyzer + cp ics_analyzer /usr/local/bin/ics_analyzer .PHONY:clean clean: - -rm a.out + -rm ics_analyzer *.o .PHONY:uninstall uninstall: @@ -26,8 +45,8 @@ uninstall: .PHONY:test test: - ./a.out + ./ics_analyzer @echo - ./a.out -h + ./ics_analyzer -h @echo - ./a.out -f ../tests/calendar.ics + ./ics_analyzer -f ../tests/calendar.ics diff --git a/src/cli_arg_parsing.c b/src/cli_arg_parsing.c index 167ca6e..db0c35e 100644 --- a/src/cli_arg_parsing.c +++ b/src/cli_arg_parsing.c @@ -1,3 +1,4 @@ +#include "insert_event.h" #include "cli_arg_parsing.h" #include #include @@ -5,37 +6,37 @@ #include void usage() { - printf ("-h\tprint this help\n"); - printf ("-f\tspecify ics file path\n"); - exit(0); + printf ("-h\tprint this help\n"); + printf ("-f\tspecify ics file path\n"); + exit(0); } void get_cli_args(int argc, char **argv, char **file_name) { - int opt = 0; + int opt = 0; - memset(file_name, '\0', strlen(*file_name)); + memset(file_name, '\0', strlen(*file_name)); - if (argc < 2) { - char *home = getenv("HOME"); - *file_name = home; + char *home = getenv("HOME"); + *file_name = home; - if (home != NULL) { - strcat(*file_name, "/.local/share/evolution/calendar/system/calendar.ics"); - } else { - printf ("Environment variable HOME is not set.\n"); - exit(1); - } - return; - } + if (home != NULL) { + strcat(*file_name, "/.local/share/evolution/calendar/system/calendar.ics"); + } else { + printf ("Environment variable HOME is not set.\n"); + exit(1); + } - while ((opt = getopt(argc, argv, "f:h")) != -1) { - switch(opt) { - case 'f': - *file_name = optarg; - break; - case 'h': - usage(); - } - } + while ((opt = getopt(argc, argv, "f:hi")) != -1) { + switch(opt) { + case 'f': + *file_name = optarg; + break; + case 'h': + usage(); + break; + case 'i': + insert_event(*file_name); + break; + } + } } - diff --git a/src/insert_event.c b/src/insert_event.c new file mode 100644 index 0000000..75bbace --- /dev/null +++ b/src/insert_event.c @@ -0,0 +1,33 @@ +#include "insert_event.h" +#include +#include +#include +#include +#include + +void insert_event(char *file_name) { + int myfd = open(file_name, O_APPEND | O_WRONLY); + + char summary_buf[256] = "SUMMARY:"; + + char *input_buffer = &summary_buf[8]; + + printf("Insert a new event\n"); + printf("SUMMARY: "); + fgets (input_buffer, (sizeof(summary_buf)-strlen(summary_buf)), stdin); + + if (strchr(input_buffer, '\n') == NULL) + printf ("The input has been truncated to:\n%s\n", input_buffer); + + // modify the string to have \r\n line ending + summary_buf[strlen(summary_buf)+1] = '\0'; + summary_buf[strlen(summary_buf)-1] = '\r'; + summary_buf[strlen(summary_buf)] = '\n'; + + write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); + write(myfd, summary_buf, strlen(summary_buf)); + + close(myfd); + + exit(0); +} diff --git a/src/insert_event.h b/src/insert_event.h new file mode 100644 index 0000000..563dec0 --- /dev/null +++ b/src/insert_event.h @@ -0,0 +1,3 @@ +#pragma once + +void insert_event(char *file_name); diff --git a/src/main.c b/src/main.c index 74902f8..07fe3a7 100644 --- a/src/main.c +++ b/src/main.c @@ -14,8 +14,8 @@ #include int main(int argc, char **argv) { - char *ics_path = ""; - get_cli_args(argc, argv, &ics_path); + char *ics_path = ""; + get_cli_args(argc, argv, &ics_path); char my_line[4096] = ""; -- 2.45.2 From 72dbf969f5369d05528d502231ef2f6103949011 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sat, 2 Sep 2023 15:18:13 +0200 Subject: [PATCH 02/16] dont append to the end but seek END:VCALENDAR --- src/Makefile | 5 ----- src/insert_event.c | 26 +++++++++++++++++++++++++- src/insert_event.h | 1 + 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/Makefile b/src/Makefile index d8b836f..be7b47e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -21,11 +21,6 @@ main.o: main.c all: gcc -Wall *.c -.PHONY:debug -debug: - gcc -Wall -g *.c - gdb a.out - .PHONY:run run: gcc -Wall *.c diff --git a/src/insert_event.c b/src/insert_event.c index 75bbace..03ce9ea 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -6,7 +6,7 @@ #include void insert_event(char *file_name) { - int myfd = open(file_name, O_APPEND | O_WRONLY); + int myfd = open(file_name, O_RDWR); char summary_buf[256] = "SUMMARY:"; @@ -24,10 +24,34 @@ void insert_event(char *file_name) { summary_buf[strlen(summary_buf)-1] = '\r'; summary_buf[strlen(summary_buf)] = '\n'; + seek_cal_end(myfd); write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); write(myfd, summary_buf, strlen(summary_buf)); + write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); close(myfd); exit(0); } + +void seek_cal_end(int fd) { + char search_string[] = "END:VCALENDAR"; + int j = 0; + char char_reader = '\0'; + + lseek(fd, -1, SEEK_END); + + while(read(fd, &char_reader, 1)) { + // no need to compare to the null terminator of the search_string + if (char_reader == search_string[strlen(search_string)-j-1]) { + j++; + } else { + j = 0; + } + if (j == (strlen(search_string))) { + lseek(fd, -1, SEEK_CUR); + break; + } + lseek(fd, -2, SEEK_CUR); + } +} diff --git a/src/insert_event.h b/src/insert_event.h index 563dec0..4719351 100644 --- a/src/insert_event.h +++ b/src/insert_event.h @@ -1,3 +1,4 @@ #pragma once void insert_event(char *file_name); +void seek_cal_end(int fd); -- 2.45.2 From cd60b79511d54c5b19c28aeb24b08403bee847eb Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sat, 2 Sep 2023 19:25:58 +0200 Subject: [PATCH 03/16] make user choose if all day event and get uuid --- src/Makefile | 4 +++- src/insert_event.c | 43 +++++++++++++++++++++++++++++++++++++++++-- src/insert_event.h | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/Makefile b/src/Makefile index be7b47e..844c555 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,6 @@ CC = gcc CFLAGS = -Wall +LDFLAGS = -luuid # List of all source files (assuming they're all in the same directory) SRC_FILES = $(wildcard *.c) @@ -7,8 +8,9 @@ SRC_FILES = $(wildcard *.c) # Generate a list of object files by replacing the .c extension with .o OBJ_FILES = $(SRC_FILES:.c=.o) +# linking ics_analyzer: $(OBJ_FILES) - gcc -Wall $(OBJ_FILES) -o ics_analyzer + gcc -Wall $(OBJ_FILES) -o ics_analyzer $(LDFLAGS) main.o: main.c $(CC) $(CFLAGS) -c $< diff --git a/src/insert_event.c b/src/insert_event.c index 03ce9ea..bf62390 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -4,15 +4,27 @@ #include #include #include +#include void insert_event(char *file_name) { int myfd = open(file_name, O_RDWR); - + int all_day_event = 0; char summary_buf[256] = "SUMMARY:"; - char *input_buffer = &summary_buf[8]; + uuid_t uuid; + char uuid_str[37] = ""; printf("Insert a new event\n"); + + printf("Is this an all day event? [y/n] "); + all_day_event = binary_user_choice(); + + if (all_day_event) { + printf("this will be an all day event\n"); + } else { + printf("this will not be an all day event\n"); + } + printf("SUMMARY: "); fgets (input_buffer, (sizeof(summary_buf)-strlen(summary_buf)), stdin); @@ -24,8 +36,15 @@ void insert_event(char *file_name) { summary_buf[strlen(summary_buf)-1] = '\r'; summary_buf[strlen(summary_buf)] = '\n'; + uuid_generate(uuid); + // parse uuid to a string + uuid_unparse(uuid, uuid_str); + seek_cal_end(myfd); write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); + write(myfd, "UID:", strlen("UID:")); + write(myfd, uuid_str, strlen(uuid_str)); + write(myfd, "\r\n", strlen("\r\n")); write(myfd, summary_buf, strlen(summary_buf)); write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); @@ -55,3 +74,23 @@ void seek_cal_end(int fd) { lseek(fd, -2, SEEK_CUR); } } + + +int binary_user_choice() { + char input_buffer[64] = ""; + if (fgets (input_buffer, sizeof(input_buffer), stdin) == NULL) { + printf ("an fgets error occured\n"); + } + if (! strchr(input_buffer, '\n')) { + printf ("Input buffer overflow!\n"); + exit(1); + } + if (input_buffer[0] == 'n' || input_buffer[0] == 'N') { + return 0; + } else if (input_buffer[0] == 'y' || input_buffer[0] == 'Y') { + return 1; + } else { + printf ("Please enter a N/n or Y/y character!\n"); + exit(1); + } +} diff --git a/src/insert_event.h b/src/insert_event.h index 4719351..d9ce902 100644 --- a/src/insert_event.h +++ b/src/insert_event.h @@ -2,3 +2,4 @@ void insert_event(char *file_name); void seek_cal_end(int fd); +int binary_user_choice(); -- 2.45.2 From 27a69bee93d9e64dceb4150489c10cd30e1d002d Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sun, 3 Sep 2023 08:07:13 +0200 Subject: [PATCH 04/16] extended get_date func for DTSTAMP --- src/date_time_handling.c | 8 +++++++- src/insert_event.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/date_time_handling.c b/src/date_time_handling.c index e7e6a17..b2010dd 100644 --- a/src/date_time_handling.c +++ b/src/date_time_handling.c @@ -4,12 +4,18 @@ #include #include +// buffer needs to contain this string: "xxxxxxxxTxxxxxx" +// or "YYYYmmddTHHMMSSZ" void get_date(char buffer[]) { // add 1 because strlen does not include the null character size_t buffer_size = strlen(buffer) + 1; time_t my_unix_ts = time(NULL); struct tm* my_tm_local = localtime(&my_unix_ts); - strftime(buffer, buffer_size, "%Y%m%dT%H%M%S", my_tm_local); + if (strlen(buffer) == 15) { + strftime(buffer, buffer_size, "%Y%m%dT%H%M%S", my_tm_local); + } else if (strlen(buffer) == 16) { + strftime(buffer, buffer_size, "%Y%m%dT%H%M%SZ", my_tm_local); + } } // 20230823T194138 -> 2023-08-23 19:41:38 diff --git a/src/insert_event.c b/src/insert_event.c index bf62390..049d555 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -1,4 +1,5 @@ #include "insert_event.h" +#include "date_time_handling.h" #include #include #include @@ -13,6 +14,7 @@ void insert_event(char *file_name) { char *input_buffer = &summary_buf[8]; uuid_t uuid; char uuid_str[37] = ""; + char dtstamp[] = "YYYYmmddTHHMMSSZ"; printf("Insert a new event\n"); @@ -40,11 +42,16 @@ void insert_event(char *file_name) { // parse uuid to a string uuid_unparse(uuid, uuid_str); + get_date(dtstamp); + seek_cal_end(myfd); write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); write(myfd, "UID:", strlen("UID:")); write(myfd, uuid_str, strlen(uuid_str)); write(myfd, "\r\n", strlen("\r\n")); + write(myfd, "DTSTAMP:", strlen("DTSTAMP:")); + write(myfd, dtstamp, strlen(dtstamp)); + write(myfd, "\r\n", strlen("\r\n")); write(myfd, summary_buf, strlen(summary_buf)); write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); @@ -75,7 +82,6 @@ void seek_cal_end(int fd) { } } - int binary_user_choice() { char input_buffer[64] = ""; if (fgets (input_buffer, sizeof(input_buffer), stdin) == NULL) { -- 2.45.2 From ac270de18dcc1672c3af899ecb11142885793ecb Mon Sep 17 00:00:00 2001 From: bjoernf Date: Thu, 7 Sep 2023 03:09:12 +0200 Subject: [PATCH 05/16] updated gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index af39d48..9a61f13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ a.out +ics_analyzer .gitconfig *.o -- 2.45.2 From 2264fc06eff0c5afb96cbcd99c183c826849dcb6 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Thu, 7 Sep 2023 03:14:45 +0200 Subject: [PATCH 06/16] clearified comment for function --- src/date_time_handling.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/date_time_handling.c b/src/date_time_handling.c index b2010dd..648c1cc 100644 --- a/src/date_time_handling.c +++ b/src/date_time_handling.c @@ -4,8 +4,8 @@ #include #include -// buffer needs to contain this string: "xxxxxxxxTxxxxxx" -// or "YYYYmmddTHHMMSSZ" +// buffer needs to contain a string with a strlen of 15 (format: "xxxxxxxxTxxxxxx") +// or a strlen of 16 (format: "YYYYmmddTHHMMSSZ") void get_date(char buffer[]) { // add 1 because strlen does not include the null character size_t buffer_size = strlen(buffer) + 1; -- 2.45.2 From 0bf170921383f7782fbb136508dce8d79e1a21b8 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Thu, 7 Sep 2023 03:37:56 +0200 Subject: [PATCH 07/16] created docs dir with ics format info --- docs/ics_format.txt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 docs/ics_format.txt diff --git a/docs/ics_format.txt b/docs/ics_format.txt new file mode 100644 index 0000000..1b73b48 --- /dev/null +++ b/docs/ics_format.txt @@ -0,0 +1,16 @@ +ICS files from Microsoft Outlook differ from those that were created by Gnome Evolution. +(semicolons are used instead of colons at some position) + +Evolution +--------- +all day event: +DTSTART;VALUE=DATE:20230908 +DTEND;VALUE=DATE:20230909 + +appointment: +DTSTART;TZID=/freeassociation.sourceforge.net/Continent/City: + 20230909T090000 +DTEND;TZID=/freeassociation.sourceforge.net/Continent/City: + 20230909T093000 + +This includes the continent and city of the used time zone. -- 2.45.2 From c19f1b8e6ea85a93240e15bbf40f849503de963f Mon Sep 17 00:00:00 2001 From: bjoernf Date: Thu, 7 Sep 2023 06:18:05 +0200 Subject: [PATCH 08/16] updated docs --- docs/ics_format.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/ics_format.txt b/docs/ics_format.txt index 1b73b48..c29bc2c 100644 --- a/docs/ics_format.txt +++ b/docs/ics_format.txt @@ -14,3 +14,5 @@ DTEND;TZID=/freeassociation.sourceforge.net/Continent/City: 20230909T093000 This includes the continent and city of the used time zone. + +"DESCRIPTION:" is an optional field. -- 2.45.2 From af4658f47222333ae6afe898d44153df04cf3626 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Thu, 7 Sep 2023 14:29:47 +0200 Subject: [PATCH 09/16] reorganizations and got time zone --- src/cut_string.c | 41 ---------------- src/cut_string.h | 5 -- src/date_time_handling.c | 19 +++++++- src/date_time_handling.h | 1 + src/insert_event.c | 6 +++ src/main.c | 3 +- src/remove_whitespace.c | 45 ----------------- src/remove_whitespace.h | 8 --- src/string_handling.c | 103 +++++++++++++++++++++++++++++++++++++++ src/string_handling.h | 8 +++ 10 files changed, 136 insertions(+), 103 deletions(-) delete mode 100644 src/cut_string.c delete mode 100644 src/cut_string.h delete mode 100644 src/remove_whitespace.c delete mode 100644 src/remove_whitespace.h create mode 100644 src/string_handling.c create mode 100644 src/string_handling.h diff --git a/src/cut_string.c b/src/cut_string.c deleted file mode 100644 index 7d546cc..0000000 --- a/src/cut_string.c +++ /dev/null @@ -1,41 +0,0 @@ -// cut a string into two parts by the first occurence of delimiter -// and choose the first part (side 0) or the second part (side 1) -// the chosen part will overwrite the original string - -// cut a string into two parts by delimiter -// and choose the first part (side 0) or the second part (side 1) -// the chosen part will overwrite the original string - -#include - -void cut_string(char my_string[], char delimiter, int side) { - char part1[256] = ""; - char part2[256] = ""; - - int split = 0; - - int j = 0; - for (int i = 0; i < strlen(my_string); i++) { - if (my_string[i] == delimiter) { - if (split == 0) { - split = 1; - continue; - } - } - - if (split == 0) { - part1[i] = my_string[i]; - } else { - part2[j] = my_string[i]; - j++; - } - } - - memset(my_string, '\0', strlen(my_string)); - if (side == 0) { - strcpy(my_string, part1); - } else { - strcpy(my_string, part2); - } -} - diff --git a/src/cut_string.h b/src/cut_string.h deleted file mode 100644 index 9b8803d..0000000 --- a/src/cut_string.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -// cut string into two parts and choose one part -// side is 0 or 1 -void cut_string(char my_string[], char delimiter, int side); diff --git a/src/date_time_handling.c b/src/date_time_handling.c index 648c1cc..b4178f2 100644 --- a/src/date_time_handling.c +++ b/src/date_time_handling.c @@ -1,8 +1,9 @@ #include "date_time_handling.h" #include #include -#include #include +#include +#include // buffer needs to contain a string with a strlen of 15 (format: "xxxxxxxxTxxxxxx") // or a strlen of 16 (format: "YYYYmmddTHHMMSSZ") @@ -49,4 +50,18 @@ void print_end_date(char end_date[]) { printf ("%c%c:", time[2], time[3]); printf ("%c%c", time[4], time[5]); } - + +char *get_tz() { + char *timezone_path = malloc(256); + ssize_t bytes_read = readlink("/etc/localtime", timezone_path, 255); + + if (bytes_read != -1) { + // Null-terminate the string + timezone_path[bytes_read] = '\0'; + } else { + perror("readlink"); + exit(1); + } + + return timezone_path; +} diff --git a/src/date_time_handling.h b/src/date_time_handling.h index 9a9415b..cb92e19 100644 --- a/src/date_time_handling.h +++ b/src/date_time_handling.h @@ -2,5 +2,6 @@ #include void get_date(char buffer[]); +char *get_tz(); void pretty_print_date_time(char date_time[]); void print_end_date(char end_date[]); diff --git a/src/insert_event.c b/src/insert_event.c index 049d555..e1e24f9 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -1,4 +1,5 @@ #include "insert_event.h" +#include "string_handling.h" #include "date_time_handling.h" #include #include @@ -15,6 +16,10 @@ void insert_event(char *file_name) { uuid_t uuid; char uuid_str[37] = ""; char dtstamp[] = "YYYYmmddTHHMMSSZ"; + char *time_zone = get_tz(); + remove_until_delim(time_zone, '/', 4); + + printf ("tz is: %s\n", time_zone); printf("Insert a new event\n"); @@ -56,6 +61,7 @@ void insert_event(char *file_name) { write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); close(myfd); + free(time_zone); exit(0); } diff --git a/src/main.c b/src/main.c index 07fe3a7..f3d5d8f 100644 --- a/src/main.c +++ b/src/main.c @@ -1,12 +1,11 @@ #include "cli_arg_parsing.h" #include "date_time_handling.h" #include "list_handling.h" -#include "cut_string.h" +#include "string_handling.h" #include "move_lines.h" #include "read_until_nl.h" #include "read_until_string.h" #include "seek_string_a.h" -#include "remove_whitespace.h" #include #include #include diff --git a/src/remove_whitespace.c b/src/remove_whitespace.c deleted file mode 100644 index 646e2aa..0000000 --- a/src/remove_whitespace.c +++ /dev/null @@ -1,45 +0,0 @@ -// this function removes all new lines and carriage returns from a string -// you might want to write a new function that replaces '\r' and '\n' -// with a delimiter of user's choice - -#include - -void remove_nl_and_cr(char raw_string[]) { - char processed_string[strlen(raw_string)]; - - // counter for num of elements of processed_string - int j = 0; - for (int i = 0; i +#include + +void cut_string(char my_string[], char delimiter, int side) { + char part1[256] = ""; + char part2[256] = ""; + + int split = 0; + + int j = 0; + for (int i = 0; i < strlen(my_string); i++) { + if (my_string[i] == delimiter) { + if (split == 0) { + split = 1; + continue; + } + } + + if (split == 0) { + part1[i] = my_string[i]; + } else { + part2[j] = my_string[i]; + j++; + } + } + + memset(my_string, '\0', strlen(my_string)); + if (side == 0) { + strcpy(my_string, part1); + } else { + strcpy(my_string, part2); + } +} + +// this function removes all new lines and carriage returns from a string +// you might want to write a new function that replaces '\r' and '\n' +// with a delimiter of user's choice +void remove_nl_and_cr(char raw_string[]) { + char processed_string[strlen(raw_string)]; + + // counter for num of elements of processed_string + int j = 0; + for (int i = 0; i= occurence) { + tmp_string[j] = raw_string[i]; + j++; + } + } + strcpy(raw_string, tmp_string); + free(tmp_string); +} diff --git a/src/string_handling.h b/src/string_handling.h new file mode 100644 index 0000000..114e836 --- /dev/null +++ b/src/string_handling.h @@ -0,0 +1,8 @@ +#pragma once + +// cut string into two parts and choose one part +// side is 0 or 1 +void cut_string(char my_string[], char delimiter, int side); +void remove_nl_and_cr(char raw_string[]); +void remove_whitespace(char raw_string[]); +void remove_until_delim(char raw_string[], char delimiter, int occurence); -- 2.45.2 From 717edb95209b93715eecb8040d8c90f793132128 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Fri, 8 Sep 2023 13:01:21 +0200 Subject: [PATCH 10/16] DTSTART field was implemented --- src/date_time_handling.c | 21 +++++++++++++++++ src/date_time_handling.h | 1 + src/insert_event.c | 50 ++++++++++++++++++++++++++++++++++++++++ src/insert_event.h | 2 ++ 4 files changed, 74 insertions(+) diff --git a/src/date_time_handling.c b/src/date_time_handling.c index b4178f2..e122540 100644 --- a/src/date_time_handling.c +++ b/src/date_time_handling.c @@ -1,4 +1,5 @@ #include "date_time_handling.h" +#include "string_handling.h" #include #include #include @@ -38,6 +39,26 @@ void pretty_print_date_time(char date_time[]) { } } +void marshall_date_time(char date_time[]) { + char transformed_string[strlen(date_time)]; + int j = 0; + remove_nl_and_cr(date_time); + for (int i = 0; i<=strlen(date_time); i++) { + if (date_time[i] != ':' && date_time[i] != '-') { + if (date_time[i] == ' ') { + transformed_string[j] = 'T'; + } else { + transformed_string[j] = date_time[i]; + } + + j++; + } + + } + memset(date_time, '\0', strlen(date_time)); + strcpy(date_time, transformed_string); +} + void print_end_date(char end_date[]) { // end_date is all day event if (strlen(end_date) == 8) diff --git a/src/date_time_handling.h b/src/date_time_handling.h index cb92e19..d76cda1 100644 --- a/src/date_time_handling.h +++ b/src/date_time_handling.h @@ -4,4 +4,5 @@ void get_date(char buffer[]); char *get_tz(); void pretty_print_date_time(char date_time[]); +void marshall_date_time(char date_time[]); void print_end_date(char end_date[]); diff --git a/src/insert_event.c b/src/insert_event.c index e1e24f9..f7d2965 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -17,6 +17,8 @@ void insert_event(char *file_name) { char uuid_str[37] = ""; char dtstamp[] = "YYYYmmddTHHMMSSZ"; char *time_zone = get_tz(); + char *dtstart_buffer = malloc(128); + remove_until_delim(time_zone, '/', 4); printf ("tz is: %s\n", time_zone); @@ -49,6 +51,10 @@ void insert_event(char *file_name) { get_date(dtstamp); + get_dtstart(dtstart_buffer, all_day_event); + marshall_date_time(dtstart_buffer); + form_dtstart_string(dtstart_buffer, time_zone); + seek_cal_end(myfd); write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); write(myfd, "UID:", strlen("UID:")); @@ -57,11 +63,13 @@ void insert_event(char *file_name) { write(myfd, "DTSTAMP:", strlen("DTSTAMP:")); write(myfd, dtstamp, strlen(dtstamp)); write(myfd, "\r\n", strlen("\r\n")); + write(myfd, dtstart_buffer, strlen(dtstart_buffer)); write(myfd, summary_buf, strlen(summary_buf)); write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); close(myfd); free(time_zone); + free(dtstart_buffer); exit(0); } @@ -106,3 +114,45 @@ int binary_user_choice() { exit(1); } } + +void get_dtstart(char input_buffer[], int all_day_event) { + if (all_day_event) { + printf("Enter the start date in YYYY-mm-dd format!\n"); + if (fgets(input_buffer, 128, stdin) == NULL) { + perror ("fgets"); + exit(1); + } + if (strlen(input_buffer) != 11) { + printf ("Wrong format!\n"); + exit(1); + } + } else { + printf("Enter the start date in YYYY-mm-dd HH:MM:SS format!\n"); + if (fgets(input_buffer, 128, stdin) == NULL) { + perror ("fgets"); + exit(1); + } + if (strlen(input_buffer) != 20) { + printf ("Wrong format!\n"); + exit(1); + } + } +} + +void form_dtstart_string(char dtstart_buffer[], char time_zone[]) { + char dtstart_copy[strlen(dtstart_buffer)]; + strcpy(dtstart_copy, dtstart_buffer); + + // not all day event + if (strlen(dtstart_buffer) == 15) { + strcpy(dtstart_buffer, "DTSTART;TZID=/freeassociation.sourceforge.net"); + strcat(dtstart_buffer, time_zone); + strcat(dtstart_buffer, ":\r\n "); + strcat(dtstart_buffer, dtstart_copy); + } else { + // all day event + strcpy(dtstart_buffer, "DTSTART;VALUE=DATE:"); + strcat(dtstart_buffer, dtstart_copy); + } + strcat(dtstart_buffer, "\r\n"); +} diff --git a/src/insert_event.h b/src/insert_event.h index d9ce902..316ae60 100644 --- a/src/insert_event.h +++ b/src/insert_event.h @@ -3,3 +3,5 @@ void insert_event(char *file_name); void seek_cal_end(int fd); int binary_user_choice(); +void get_dtstart(char input_buffer[], int all_day_event); +void form_dtstart_string(char dtstart_buffer[], char time_zone[]); -- 2.45.2 From deddf0137c21803c0507511b2a67f92bad3b9c77 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Fri, 8 Sep 2023 19:38:25 +0200 Subject: [PATCH 11/16] updated docs --- docs/ics_format.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/ics_format.txt b/docs/ics_format.txt index c29bc2c..66a926e 100644 --- a/docs/ics_format.txt +++ b/docs/ics_format.txt @@ -3,10 +3,16 @@ ICS files from Microsoft Outlook differ from those that were created by Gnome Ev Evolution --------- +all line endings are \r\n + all day event: DTSTART;VALUE=DATE:20230908 DTEND;VALUE=DATE:20230909 +an all day event can span over multiple days and look like this: +DTSTART;VALUE=DATE:20230911^M$ +DTEND;VALUE=DATE:20230916^M$ + appointment: DTSTART;TZID=/freeassociation.sourceforge.net/Continent/City: 20230909T090000 -- 2.45.2 From 4910d9d7bbd1551646aaffc351e20c6fd15587b4 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Fri, 8 Sep 2023 20:01:42 +0200 Subject: [PATCH 12/16] started with getting the DTEND and updated docs --- docs/ics_format.txt | 8 +++++++- src/insert_event.c | 16 ++++++++++------ src/insert_event.h | 2 +- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/docs/ics_format.txt b/docs/ics_format.txt index 66a926e..ac7cf1b 100644 --- a/docs/ics_format.txt +++ b/docs/ics_format.txt @@ -19,6 +19,12 @@ DTSTART;TZID=/freeassociation.sourceforge.net/Continent/City: DTEND;TZID=/freeassociation.sourceforge.net/Continent/City: 20230909T093000 -This includes the continent and city of the used time zone. +appointments can also span over multiple days: +DTSTART;TZID=/freeassociation.sourceforge.net/Europe/Berlin: + 20230913T230000 +DTEND;TZID=/freeassociation.sourceforge.net/Europe/Berlin: + 20230914T040000 + +Appointments include the continent and city of the used time zone. "DESCRIPTION:" is an optional field. diff --git a/src/insert_event.c b/src/insert_event.c index f7d2965..4e5b455 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -18,11 +18,10 @@ void insert_event(char *file_name) { char dtstamp[] = "YYYYmmddTHHMMSSZ"; char *time_zone = get_tz(); char *dtstart_buffer = malloc(128); + char *dtend_buffer = malloc(128); remove_until_delim(time_zone, '/', 4); - printf ("tz is: %s\n", time_zone); - printf("Insert a new event\n"); printf("Is this an all day event? [y/n] "); @@ -51,10 +50,13 @@ void insert_event(char *file_name) { get_date(dtstamp); - get_dtstart(dtstart_buffer, all_day_event); + get_dtstart_dtend(dtstart_buffer, all_day_event, "start"); marshall_date_time(dtstart_buffer); form_dtstart_string(dtstart_buffer, time_zone); + get_dtstart_dtend(dtend_buffer, all_day_event, "end"); + printf ("dtend_buffer: %s\n", dtend_buffer); + seek_cal_end(myfd); write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); write(myfd, "UID:", strlen("UID:")); @@ -70,6 +72,7 @@ void insert_event(char *file_name) { close(myfd); free(time_zone); free(dtstart_buffer); + free(dtend_buffer); exit(0); } @@ -115,9 +118,10 @@ int binary_user_choice() { } } -void get_dtstart(char input_buffer[], int all_day_event) { +// char *start_or_end should contain "start" or "end" +void get_dtstart_dtend(char input_buffer[], int all_day_event, char *start_or_end) { if (all_day_event) { - printf("Enter the start date in YYYY-mm-dd format!\n"); + printf("Enter the %s date in YYYY-mm-dd format!\n", start_or_end); if (fgets(input_buffer, 128, stdin) == NULL) { perror ("fgets"); exit(1); @@ -127,7 +131,7 @@ void get_dtstart(char input_buffer[], int all_day_event) { exit(1); } } else { - printf("Enter the start date in YYYY-mm-dd HH:MM:SS format!\n"); + printf("Enter the %s date in YYYY-mm-dd HH:MM:SS format!\n", start_or_end); if (fgets(input_buffer, 128, stdin) == NULL) { perror ("fgets"); exit(1); diff --git a/src/insert_event.h b/src/insert_event.h index 316ae60..569a9b5 100644 --- a/src/insert_event.h +++ b/src/insert_event.h @@ -3,5 +3,5 @@ void insert_event(char *file_name); void seek_cal_end(int fd); int binary_user_choice(); -void get_dtstart(char input_buffer[], int all_day_event); +void get_dtstart_dtend(char input_buffer[], int all_day_event, char *start_or_end); void form_dtstart_string(char dtstart_buffer[], char time_zone[]); -- 2.45.2 From 2916e77056f586329ecfed657a9ca07579be69bd Mon Sep 17 00:00:00 2001 From: bjoernf Date: Fri, 8 Sep 2023 20:16:14 +0200 Subject: [PATCH 13/16] implemented DTEND --- src/insert_event.c | 28 +++++++++++++++++++++------- src/insert_event.h | 1 + 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/insert_event.c b/src/insert_event.c index 4e5b455..0cbb19a 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -27,12 +27,6 @@ void insert_event(char *file_name) { printf("Is this an all day event? [y/n] "); all_day_event = binary_user_choice(); - if (all_day_event) { - printf("this will be an all day event\n"); - } else { - printf("this will not be an all day event\n"); - } - printf("SUMMARY: "); fgets (input_buffer, (sizeof(summary_buf)-strlen(summary_buf)), stdin); @@ -55,7 +49,8 @@ void insert_event(char *file_name) { form_dtstart_string(dtstart_buffer, time_zone); get_dtstart_dtend(dtend_buffer, all_day_event, "end"); - printf ("dtend_buffer: %s\n", dtend_buffer); + marshall_date_time(dtend_buffer); + form_dtend_string(dtend_buffer, time_zone); seek_cal_end(myfd); write(myfd, "BEGIN:VEVENT\r\n", strlen("BEGIN:VEVENT\r\n")); @@ -66,6 +61,7 @@ void insert_event(char *file_name) { write(myfd, dtstamp, strlen(dtstamp)); write(myfd, "\r\n", strlen("\r\n")); write(myfd, dtstart_buffer, strlen(dtstart_buffer)); + write(myfd, dtend_buffer, strlen(dtend_buffer)); write(myfd, summary_buf, strlen(summary_buf)); write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); @@ -160,3 +156,21 @@ void form_dtstart_string(char dtstart_buffer[], char time_zone[]) { } strcat(dtstart_buffer, "\r\n"); } + +void form_dtend_string(char dtend_buffer[], char time_zone[]) { + char dtend_copy[strlen(dtend_buffer)]; + strcpy(dtend_copy, dtend_buffer); + + // not all day event + if (strlen(dtend_buffer) == 15) { + strcpy(dtend_buffer, "DTEND;TZID=/freeassociation.sourceforge.net"); + strcat(dtend_buffer, time_zone); + strcat(dtend_buffer, ":\r\n "); + strcat(dtend_buffer, dtend_copy); + } else { + // all day event + strcpy(dtend_buffer, "DTEND;VALUE=DATE:"); + strcat(dtend_buffer, dtend_copy); + } + strcat(dtend_buffer, "\r\n"); +} diff --git a/src/insert_event.h b/src/insert_event.h index 569a9b5..5d012a9 100644 --- a/src/insert_event.h +++ b/src/insert_event.h @@ -5,3 +5,4 @@ void seek_cal_end(int fd); int binary_user_choice(); void get_dtstart_dtend(char input_buffer[], int all_day_event, char *start_or_end); void form_dtstart_string(char dtstart_buffer[], char time_zone[]); +void form_dtend_string(char dtend_buffer[], char time_zone[]); -- 2.45.2 From c6da11c540be45c84585f09ebed5f41bb7e17e76 Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sat, 9 Sep 2023 08:09:08 +0200 Subject: [PATCH 14/16] inserting events was implemented --- docs/ics_format.txt | 3 +++ src/insert_event.c | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/docs/ics_format.txt b/docs/ics_format.txt index ac7cf1b..33db92b 100644 --- a/docs/ics_format.txt +++ b/docs/ics_format.txt @@ -25,6 +25,9 @@ DTSTART;TZID=/freeassociation.sourceforge.net/Europe/Berlin: DTEND;TZID=/freeassociation.sourceforge.net/Europe/Berlin: 20230914T040000 +SEQUENCE is the number of times the event was modified. +Evolution sets this to 2 after it has been generated. + Appointments include the continent and city of the used time zone. "DESCRIPTION:" is an optional field. diff --git a/src/insert_event.c b/src/insert_event.c index 0cbb19a..5c00896 100644 --- a/src/insert_event.c +++ b/src/insert_event.c @@ -62,7 +62,18 @@ void insert_event(char *file_name) { write(myfd, "\r\n", strlen("\r\n")); write(myfd, dtstart_buffer, strlen(dtstart_buffer)); write(myfd, dtend_buffer, strlen(dtend_buffer)); + write(myfd, "SEQUENCE:2\r\n", strlen("SEQUENCE:2\r\n")); write(myfd, summary_buf, strlen(summary_buf)); + write(myfd, "TRANSP:OPAQUE\r\n", strlen("TRANSP:OPAQUE\r\n")); + write(myfd, "CLASS:PUBLIC\r\n", strlen("CLASS:PUBLIC\r\n")); + write(myfd, "CREATED:", strlen("CREATED:")); + write(myfd, dtstamp, strlen(dtstamp)); + write(myfd, "\r\n", strlen("\r\n")); + write(myfd, "LAST-MODIFIED:", strlen("LAST-MODIFIED:")); + write(myfd, dtstamp, strlen(dtstamp)); + write(myfd, "\r\n", strlen("\r\n")); + write(myfd, "END:VEVENT\r\n", strlen("END:VEVENT\r\n")); + write(myfd, "END:VCALENDAR\r\n", strlen("END:VCALENDAR\r\n")); close(myfd); -- 2.45.2 From 24e05a990d227af66dd8f32b88a0940de6f14d6f Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sat, 9 Sep 2023 08:20:33 +0200 Subject: [PATCH 15/16] improved Makefile and usage --- makefile | 32 -------------------------------- src/Makefile | 29 +++++++++++------------------ src/cli_arg_parsing.c | 5 +++-- 3 files changed, 14 insertions(+), 52 deletions(-) delete mode 100644 makefile diff --git a/makefile b/makefile deleted file mode 100644 index dc2b1e2..0000000 --- a/makefile +++ /dev/null @@ -1,32 +0,0 @@ -all: - gcc -Wall ./src/*.c - -.PHONY: debug -debug: - gcc -Wall -g ./src/*.c - gdb a.out - -.PHONY: run -run: - gcc -Wall ./src/*.c - ./a.out - -.PHONY: install -install: a.out - cp a.out /usr/local/bin/ics_analyzer - -.PHONY: clean -clean: - rm a.out - -.PHONY: uninstall -uninstall: - rm /usr/local/bin/ics_analyzer - -.PHONY: test -test: - ./a.out - @echo - ./a.out -h - @echo - ./a.out -f tests/calendar.ics diff --git a/src/Makefile b/src/Makefile index 844c555..7985077 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,9 +8,11 @@ SRC_FILES = $(wildcard *.c) # Generate a list of object files by replacing the .c extension with .o OBJ_FILES = $(SRC_FILES:.c=.o) +EXECUTABLE = "icscli" + # linking -ics_analyzer: $(OBJ_FILES) - gcc -Wall $(OBJ_FILES) -o ics_analyzer $(LDFLAGS) +$(EXECUTABLE): $(OBJ_FILES) + gcc -Wall $(OBJ_FILES) -o $(EXECUTABLE) $(LDFLAGS) main.o: main.c $(CC) $(CFLAGS) -c $< @@ -19,31 +21,22 @@ main.o: main.c %.o: %.c %.h $(CC) $(CFLAGS) -c $< -.PHONY:all -all: - gcc -Wall *.c - -.PHONY:run -run: - gcc -Wall *.c - ./ics_analyzer - .PHONY:install -install: a.out - cp ics_analyzer /usr/local/bin/ics_analyzer +install: $(EXECUTABLE) + cp $(EXECUTABLE) /usr/local/bin/$(EXECUTABLE) .PHONY:clean clean: - -rm ics_analyzer *.o + -rm $(EXECUTABLE) *.o .PHONY:uninstall uninstall: - -rm /usr/local/bin/ics_analyzer + -rm /usr/local/bin/$(EXECUTABLE) .PHONY:test test: - ./ics_analyzer + ./$(EXECUTABLE) @echo - ./ics_analyzer -h + ./$(EXECUTABLE) -h @echo - ./ics_analyzer -f ../tests/calendar.ics + ./$(EXECUTABLE) -f ../tests/calendar.ics diff --git a/src/cli_arg_parsing.c b/src/cli_arg_parsing.c index db0c35e..c85ab56 100644 --- a/src/cli_arg_parsing.c +++ b/src/cli_arg_parsing.c @@ -6,8 +6,9 @@ #include void usage() { - printf ("-h\tprint this help\n"); - printf ("-f\tspecify ics file path\n"); + printf ("-f [FILE PATH]\t\tspecify ics file path\n"); + printf ("-h\t\t\tprint this help\n"); + printf ("-i\t\t\tinsert an event\n"); exit(0); } -- 2.45.2 From 2124d401b77358d5cfee02b251b38dcf4010a9ba Mon Sep 17 00:00:00 2001 From: bjoernf Date: Sat, 9 Sep 2023 08:25:30 +0200 Subject: [PATCH 16/16] updated readme --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7a71ee4..e2a722d 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,17 @@ sudo make install the default path is for evolution ics files at `~/.local/share/evolution/calendar/system/calendar.ics` ``` -ics_analyzer +icscli ``` for a custom path ``` -ics_analyzer -f path/to/ics/file.ics +icscli -f path/to/ics/file.ics ``` +``` +icscli -h +``` #### uninstall @@ -39,9 +42,6 @@ sudo make uninstall #### TODO -- option to add events (evolution does not care about duplicate uuids) -(but use libuuid to create uuids) - add option to print upcoming events only until a certain date -- improve makefile -- rename executable to ics_cli +- show end date for events that span over multiple days - tests -- 2.45.2