/* Fonctions d'interaction avec la base de données */ #include #include #include #include #include #include #include "include/colors.h" #include "include/config.h" #include "include/struct.h" #include "include/utils.h" #include "include/db.h" char* get_db_path() { #ifndef DB_FILE //! We should check that $HOME/.config already exists even if it should be the case char* base_path = ".config/takl.sqlite3"; char* home_dir = getenv("HOME"); assert(home_dir != NULL); char* db_path = malloc(sizeof(char)*(strlen(base_path)+strlen(home_dir)+1)); sprintf(db_path, "%s/%s", home_dir, base_path); return db_path; #else char* db_path = malloc(sizeof(char)*(strlen(DB_FILE)+1)); memcpy(db_path, DB_FILE, sizeof(char)*(strlen(DB_FILE)+1)); return db_path; #endif } sqlite3* get_db() { sqlite3* db; char* db_path = get_db_path(); if (access(db_path, F_OK) != 0) { // Create DB sqlite3_open(db_path, &db); char* zErrMsg = NULL; int ret = sqlite3_exec( db, "CREATE TABLE tasks ( \ id INTEGER PRIMARY KEY,\ text TEXT NOT NULL,\ done INTEGER, \ due_to INTEGER \ );", NULL, NULL, &zErrMsg ); if (ret != SQLITE_OK) { fprintf(stderr, "(db creation) SQL error: %s\n", zErrMsg); sqlite3_free(zErrMsg); } sqlite3_close(db); printf(GREEN "OK" RESET " Base de données créée\n"); } int ret = sqlite3_open(db_path, &db); if (ret != SQLITE_OK) { fprintf(stderr, "(get_db) Unable to open db\n"); } free(db_path); return db; } void notify_change() { char* socket_path = get_socket_path(); if (access(socket_path, F_OK) == 0) { FILE* fp = fopen(socket_path, "r"); int pid; fscanf(fp, "%d", &pid); // Trigger IN_ACCESS (void)pid; fclose(fp); } free(socket_path); } int add_task(task_t t) { sqlite3* db = get_db(); sqlite3_stmt* stmt; int ret = sqlite3_prepare_v2(db, "INSERT INTO tasks (id, text, done, due_to) VALUES (?1, ?2, ?3, ?4);", -1, &stmt, 0); if (ret != SQLITE_OK) { printf("(get_task) failure fetching data\n"); return 1; } char str_id[10]; sprintf(str_id, "%d", (int)t.id); sqlite3_bind_text(stmt, 1, str_id, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, t.text, -1, SQLITE_STATIC); char str_done[2]; // Just a boolean sprintf(str_done, "%d", t.done); sqlite3_bind_text(stmt, 3, str_done, -1, SQLITE_STATIC); char str_due_to[15]; sprintf(str_due_to, "%ld", t.due_to); sqlite3_bind_text(stmt, 4, str_due_to, -1, SQLITE_STATIC); ret = sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_close(db); notify_change(); if (ret != SQLITE_DONE) { if (ret == 19) { printf("Identifiant déjà utilisé\n"); } else { printf("Return value: %d\n", ret); } return 1; } return 0; } int update_task(task_t t) { sqlite3* db = get_db(); sqlite3_stmt* stmt; int ret = sqlite3_prepare_v2(db, "UPDATE tasks SET text=?2, done=?3, due_to=?4 WHERE id=?1;", -1, &stmt, 0); if (ret != SQLITE_OK) { printf("(get_task) failure fetching data\n"); return 1; } char str_id[10]; sprintf(str_id, "%d", (int)t.id); sqlite3_bind_text(stmt, 1, str_id, -1, SQLITE_STATIC); sqlite3_bind_text(stmt, 2, t.text, -1, SQLITE_STATIC); char str_done[2]; // Just a boolean sprintf(str_done, "%d", t.done); sqlite3_bind_text(stmt, 3, str_done, -1, SQLITE_STATIC); char str_due_to[15]; sprintf(str_due_to, "%ld", t.due_to); sqlite3_bind_text(stmt, 4, str_due_to, -1, SQLITE_STATIC); ret = sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_close(db); notify_change(); if (ret != SQLITE_DONE) { printf("Return value: %d\n", ret); return 1; } return 0; } void delete_task(int id) { sqlite3* db = get_db(); sqlite3_stmt* stmt; int ret = sqlite3_prepare_v2(db, "DELETE FROM tasks WHERE id=?1;", -1, &stmt, 0); if (ret != SQLITE_OK) { printf("(get_task) failure fetching data\n"); exit(1); } char str_id[10]; sprintf(str_id, "%d", id); sqlite3_bind_text(stmt, 1, str_id, -1, SQLITE_STATIC); sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_close(db); notify_change(); } void get_task(int id, task_t* t) { t->id = -1; sqlite3* db = get_db(); sqlite3_stmt* stmt; int ret = sqlite3_prepare_v2(db, "SELECT id, text, done, due_to FROM tasks WHERE id=?1;", -1, &stmt, 0); if (ret != SQLITE_OK) { printf("(get_task) failure fetching data\n"); exit(1); } char str_id[10]; sprintf(str_id, "%d", id); sqlite3_bind_text(stmt, 1, str_id, -1, SQLITE_STATIC); ret = sqlite3_step(stmt); if (ret == SQLITE_ROW) { t->id = strtol((char*)sqlite3_column_text(stmt, 0), NULL, 10); t->done = strtol((char*)sqlite3_column_text(stmt, 2), NULL, 10); t->due_to = strtol((char*)sqlite3_column_text(stmt, 3), NULL, 10); char* text = (char*)sqlite3_column_text(stmt, 1); t->text = malloc(sizeof(char)*(strlen(text)+1)); strcpy(t->text, text); } sqlite3_finalize(stmt); sqlite3_close(db); // t->id will be (-1) if not found } task_list_t* get_task_list(bool include_completed) { sqlite3* db = get_db(); sqlite3_stmt *stmt; int ret = sqlite3_prepare_v2(db, "SELECT id, text, done, due_to FROM tasks;", -1, &stmt, NULL); if (ret != SQLITE_OK) { printf("(get_task) failure fetching data\n"); return NULL; } task_list_t* list = NULL; while (sqlite3_step(stmt) == SQLITE_ROW) { task_t t; t.id = strtol((char*)sqlite3_column_text(stmt, 0), NULL, 10); t.done = strtol((char*)sqlite3_column_text(stmt, 2), NULL, 10); t.due_to = strtol((char*)sqlite3_column_text(stmt, 3), NULL, 10); if (!t.done || include_completed) { // We don't want to allocate memory for things that will not be used char* text = (char*)sqlite3_column_text(stmt, 1); t.text = malloc(sizeof(char)*(strlen(text)+1)); strcpy(t.text, text); task_list_t* cur = malloc(sizeof(task_list_t)); // Add the parsed task to the beginning of the list cur->task = t; cur->next = list; list = cur; } } sqlite3_finalize(stmt); sqlite3_close(db); return list; } int get_new_task_id() { task_t t; int new_id = rand() %MAX_TASK_ID; t.id = new_id; int i=0; while (t.id != -1 && i < NEW_TASK_ID_MAX_RETRIES) { // If t.id==-1, task is not found so the id is sage to use new_id = rand() %MAX_TASK_ID; get_task(new_id, &t); i++; } if (i == NEW_TASK_ID_MAX_RETRIES) { printf(RED BOLD "Il semblerait que vous ayez un nombre de tâches se rapprochant de %d.\n" RESET, MAX_TASK_ID); printf(YELLOW "Il peut être judicieux de supprimer les tâches effectuées pour libérer de la place (et des identifiants).\n"); printf("Vous pouvez également modifier la limite du nombre d'identifiants et recompiler le projet.\n" RESET); return -1; } return new_id; }