From 7e1e41030772e0e28137f09077670d7471e1b31e Mon Sep 17 00:00:00 2001 From: jfreegman Date: Tue, 17 Nov 2020 16:05:20 -0500 Subject: [PATCH] Refactor logging - Conference logging now behaves the same as 1-on-1 chats: Instead of creating a new log file every time we restat the client we use the unique conference ID to keep track of path names. This also allows us to load history for saved groups on client startup - Added a log init function / general code refactor. - Fixed a bug that caused log files to be created even when logging is disabled. --- src/chat.c | 37 ++++-- src/conference.c | 97 ++++++++++++--- src/conference.h | 12 +- src/conference_commands.c | 14 ++- src/friendlist.c | 4 +- src/global_commands.c | 16 +-- src/log.c | 256 ++++++++++++++++++++++++++------------ src/log.h | 35 ++++-- src/prompt.c | 28 +++-- 9 files changed, 351 insertions(+), 148 deletions(-) diff --git a/src/chat.c b/src/chat.c index 32419d2..eee0d5f 100644 --- a/src/chat.c +++ b/src/chat.c @@ -1330,6 +1330,29 @@ static void chat_onDraw(ToxWindow *self, Tox *m) pthread_mutex_unlock(&Winthread.lock); } +static void chat_init_log(ToxWindow *self, Tox *m, const char *self_nick) +{ + ChatContext *ctx = self->chatwin; + + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); + + if (log_init(ctx->log, self_nick, myid, Friends.list[self->num].pub_key, LOG_TYPE_CHAT) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to initialize chat log."); + return; + } + + if (load_chat_history(self, ctx->log) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history."); + } + + if (Friends.list[self->num].logging_on) { + if (log_enable(ctx->log) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log."); + } + } +} + static void chat_onInit(ToxWindow *self, Tox *m) { curs_set(1); @@ -1380,19 +1403,9 @@ static void chat_onInit(ToxWindow *self, Tox *m) line_info_init(ctx->hst); - char myid[TOX_ADDRESS_SIZE]; - tox_self_get_address(m, (uint8_t *) myid); + chat_init_log(self, m, nick); - int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT); - load_chat_history(self, ctx->log); - - if (!Friends.list[self->num].logging_on) { - log_disable(ctx->log); - } else if (log_ret == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); - } - - execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); + execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); // Print log status to screen scrollok(ctx->history, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0); diff --git a/src/conference.c b/src/conference.c index 863b85f..2a3263c 100644 --- a/src/conference.c +++ b/src/conference.c @@ -114,6 +114,25 @@ static const char *conference_cmd_list[] = { static ToxWindow *new_conference_chat(uint32_t conferencenum); +void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length) +{ + ConferenceChat *chat = &conferences[conferencesnum]; + + if (!chat->active) { + return; + } + + if (length > CONFERENCE_MAX_TITLE_LENGTH) { + length = CONFERENCE_MAX_TITLE_LENGTH; + } + + memcpy(chat->title, title, length); + chat->title[length] = 0; + chat->title_length = length; + + set_window_title(self, title, length); +} + static void kill_conference_window(ToxWindow *self) { ChatContext *ctx = self->chatwin; @@ -130,8 +149,35 @@ static void kill_conference_window(ToxWindow *self) del_window(self); } -int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, - size_t title_length) +static void init_conference_logging(ToxWindow *self, Tox *m, uint32_t conferencenum) +{ + ChatContext *ctx = self->chatwin; + + char my_id[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) my_id); + + char conference_id[TOX_CONFERENCE_ID_SIZE]; + tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id); + + if (log_init(ctx->log, conferences[conferencenum].title, my_id, conference_id, LOG_TYPE_CHAT) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); + return; + } + + if (load_chat_history(self, ctx->log) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to load chat history."); + } + + if (user_settings->autolog == AUTOLOG_ON) { + if (log_enable(ctx->log) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to enable chat log."); + } + } + + execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); // print log state to screen +} + +int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length) { if (conferencenum > MAX_CONFERENCE_NUM) { return -1; @@ -155,7 +201,10 @@ int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char conferences[i].last_sent_audio = 0; set_active_window_index(conferences[i].chatwin); - set_window_title(self, title, title_length); + + conference_set_title(self, conferencenum, title, length); + + init_conference_logging(self, m, conferencenum); if (i == max_conference_index) { ++max_conference_index; @@ -225,6 +274,25 @@ static void delete_conference(ToxWindow *self, Tox *m, uint32_t conferencenum) free_conference(self, conferencenum); } +void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title) +{ + ConferenceChat *chat = &conferences[conferencenum]; + + if (!chat->active) { + return; + } + + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); + + char conference_id[TOX_CONFERENCE_ID_SIZE]; + tox_conference_get_id(m, conferencenum, (uint8_t *) conference_id); + + if (rename_logfile(chat->title, new_title, myid, conference_id, chat->chatwin) != 0) { + fprintf(stderr, "Failed to rename conference log to `%s`\n", new_title); + } +} + /* destroys and re-creates conference window with or without the peerlist */ void redraw_conference_win(ToxWindow *self) { @@ -319,13 +387,21 @@ static void conference_onConferenceTitleChange(ToxWindow *self, Tox *m, uint32_t return; } - set_window_title(self, title, length); + ConferenceChat *chat = &conferences[conferencenum]; + + if (!chat->active) { + return; + } + + conference_rename_log_path(m, conferencenum, title); // must be called first + + conference_set_title(self, conferencenum, title, length); char timefrmt[TIME_STR_SIZE]; get_time_str(timefrmt, sizeof(timefrmt)); /* don't announce title when we join the room */ - if (!timed_out(conferences[self->num].start_time, CONFERENCE_EVENT_WAIT)) { + if (!timed_out(conferences[conferencenum].start_time, CONFERENCE_EVENT_WAIT)) { return; } @@ -1038,17 +1114,6 @@ static void conference_onInit(ToxWindow *self, Tox *m) line_info_init(ctx->hst); - if (user_settings->autolog == AUTOLOG_ON) { - char myid[TOX_ADDRESS_SIZE]; - tox_self_get_address(m, (uint8_t *) myid); - - if (log_enable(self->name, myid, NULL, ctx->log, LOG_CONFERENCE) == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); - } - } - - execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); - scrollok(ctx->history, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0); } diff --git a/src/conference.h b/src/conference.h index 6a12684..726fb36 100644 --- a/src/conference.h +++ b/src/conference.h @@ -27,8 +27,9 @@ #include "windows.h" #define SIDEBAR_WIDTH 16 -#define MAX_CONFERENCE_NUM MAX_WINDOWS_NUM - 2 +#define MAX_CONFERENCE_NUM (MAX_WINDOWS_NUM - 2) #define CONFERENCE_EVENT_WAIT 3 +#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH typedef struct ConferencePeer { bool active; @@ -64,6 +65,9 @@ typedef struct { int side_pos; /* current position of the sidebar - used for scrolling up and down */ time_t start_time; + char title[CONFERENCE_MAX_TITLE_LENGTH + 1]; + size_t title_length; + ConferencePeer *peer_list; uint32_t max_idx; @@ -79,11 +83,15 @@ typedef struct { /* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */ void free_conference(ToxWindow *self, uint32_t conferencenum); -int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t title_length); +int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, size_t length); /* destroys and re-creates conference window with or without the peerlist */ void redraw_conference_win(ToxWindow *self); +void conference_set_title(ToxWindow *self, uint32_t conferencesnum, const char *title, size_t length); +void conference_rename_log_path(Tox *m, uint32_t conferencenum, const char *new_title); +int conference_enable_logging(ToxWindow *self, Tox *m, uint32_t conferencenum, struct chatlog *log); + /* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum * of `maxpeers`. * Maches each peer whose name or pubkey begins with `prefix`. diff --git a/src/conference_commands.c b/src/conference_commands.c index 4bd9f2d..e9ad7e9 100644 --- a/src/conference_commands.c +++ b/src/conference_commands.c @@ -40,7 +40,7 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, UNUSED_VAR(window); Tox_Err_Conference_Title err; - char title[MAX_STR_SIZE]; + char title[CONFERENCE_MAX_TITLE_LENGTH + 1]; if (argc < 1) { size_t tlen = tox_conference_get_title_size(m, self->num, &err); @@ -61,15 +61,23 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc, return; } + size_t len = strlen(argv[1]); + + if (len >= sizeof(title)) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title: max length exceeded."); + return; + } + snprintf(title, sizeof(title), "%s", argv[1]); - int len = strlen(title); if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err); return; } - set_window_title(self, title, len); + conference_rename_log_path(m, self->num, title); // must be called first + + conference_set_title(self, self->num, title, len); char timefrmt[TIME_STR_SIZE]; char selfnick[TOX_MAX_NAME_LENGTH]; diff --git a/src/friendlist.c b/src/friendlist.c index 42a88f5..60821e5 100644 --- a/src/friendlist.c +++ b/src/friendlist.c @@ -453,7 +453,9 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const tox_self_get_address(m, (uint8_t *) myid); if (strcmp(oldname, newnamecpy) != 0) { - rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin); + if (rename_logfile(oldname, newnamecpy, myid, Friends.list[num].pub_key, Friends.list[num].chatwin) != 0) { + fprintf(stderr, "Failed to rename friend chat log from `%s` to `%s`\n", oldname, newnamecpy); + } } sort_friendlist_index(); diff --git a/src/global_commands.c b/src/global_commands.c index 6918465..bc017cb 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -434,21 +434,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX const char *swch = argv[1]; if (!strcmp(swch, "1") || !strcmp(swch, "on")) { - char myid[TOX_ADDRESS_SIZE]; - tox_self_get_address(m, (uint8_t *) myid); - - int log_ret = -1; - - if (self->type == WINDOW_TYPE_CHAT) { - Friends.list[self->num].logging_on = true; - log_ret = log_enable(self->name, myid, Friends.list[self->num].pub_key, log, LOG_CHAT); - } else if (self->type == WINDOW_TYPE_PROMPT) { - log_ret = log_enable(self->name, myid, NULL, log, LOG_PROMPT); - } else if (self->type == WINDOW_TYPE_CONFERENCE) { - log_ret = log_enable(self->name, myid, NULL, log, LOG_CONFERENCE); - } - - msg = log_ret == 0 ? "Logging enabled." : "Warning: Log failed to initialize."; + msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log."; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); return; } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) { diff --git a/src/log.c b/src/log.c index 0d0eab7..4460500 100644 --- a/src/log.c +++ b/src/log.c @@ -35,29 +35,33 @@ extern struct user_settings *user_settings; -/* There are three types of logs: chat logs, conference logs, and prompt logs (see LOG_TYPE in log.h) - A prompt log is in the format: LOGDIR/selfkey-home.log - A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log - A conference log is in the format: LOGDIR/selfkey-conferencename-date[time].log - - Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used. - - Returns 0 on success, -1 if the path is too long */ -static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype) +/* Creates a log path and puts it in `dest. + * + * There are two types of logs: chat logs and prompt logs (see LOG_TYPE in log.h) + * A prompt log is in the format: LOGDIR/selfkey-home.log + * A chat log is in the format: LOGDIR/selfkey-name-otherkey.log + * + * For friend chats `otherkey` is the first 6 bytes of the friend's Tox ID. + * For Conferences/groups `otherkey` is the first 6 bytes of the group's unique ID. + * + * Return path length on success. + * Return -1 if the path is too long. + */ +static int get_log_path(char *dest, int destsize, const char *name, const char *selfkey, const char *otherkey) { if (!valid_nick(name)) { name = UNKNOWN_NAME; } - const char *namedash = logtype == LOG_PROMPT ? "" : "-"; + const char *namedash = otherkey ? "-" : ""; const char *set_path = user_settings->chatlogs_path; char *user_config_dir = get_user_config_dir(); int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash); path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR); - /* first 6 digits of selfkey */ - char self_id[32]; + /* first 6 bytes of selfkey */ + char self_id[32] = {0}; path_len += KEY_IDENT_DIGITS * 2; sprintf(&self_id[0], "%02X", selfkey[0] & 0xff); sprintf(&self_id[2], "%02X", selfkey[1] & 0xff); @@ -66,19 +70,13 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke char other_id[32] = {0}; - switch (logtype) { - case LOG_CHAT: - path_len += KEY_IDENT_DIGITS * 2; - sprintf(&other_id[0], "%02X", otherkey[0] & 0xff); - sprintf(&other_id[2], "%02X", otherkey[1] & 0xff); - sprintf(&other_id[4], "%02X", otherkey[2] & 0xff); - other_id[KEY_IDENT_DIGITS * 2] = '\0'; - break; - - case LOG_CONFERENCE: - strftime(other_id, sizeof(other_id), "%Y-%m-%d[%H:%M:%S]", get_time()); - path_len += strlen(other_id); - break; + if (otherkey) { + /* first 6 bytes of otherkey */ + path_len += KEY_IDENT_DIGITS * 2; + sprintf(&other_id[0], "%02X", otherkey[0] & 0xff); + sprintf(&other_id[2], "%02X", otherkey[1] & 0xff); + sprintf(&other_id[4], "%02X", otherkey[2] & 0xff); + other_id[KEY_IDENT_DIGITS * 2] = '\0'; } if (path_len >= destsize) { @@ -94,28 +92,35 @@ static int get_log_path(char *dest, int destsize, char *name, const char *selfke free(user_config_dir); - return 0; + return path_len; } -/* Opens log file or creates a new one */ -static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype) +/* Initializes log path for `log`. + * + * Return 0 on success. + * Return -1 on failure. + */ +static int init_logging_session(const char *name, const char *selfkey, const char *otherkey, struct chatlog *log, + LOG_TYPE type) { - if (selfkey == NULL || (logtype == LOG_CHAT && otherkey == NULL)) { + if (log == NULL) { + return -1; + } + + if (selfkey == NULL || (type == LOG_TYPE_CHAT && otherkey == NULL)) { return -1; } char log_path[MAX_STR_SIZE]; - if (get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey, logtype) == -1) { + int path_len = get_log_path(log_path, sizeof(log_path), name, selfkey, otherkey); + + if (path_len == -1 || path_len >= sizeof(log->path)) { return -1; } - log->file = fopen(log_path, "a+"); - snprintf(log->path, sizeof(log->path), "%s", log_path); - - if (log->file == NULL) { - return -1; - } + memcpy(log->path, log_path, path_len); + log->path[path_len] = 0; return 0; } @@ -124,6 +129,10 @@ static int init_logging_session(char *name, const char *selfkey, const char *oth void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event) { + if (log == NULL) { + return; + } + if (!log->log_on) { return; } @@ -154,94 +163,162 @@ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool e void log_disable(struct chatlog *log) { - if (log->file != NULL) { - fclose(log->file); + if (log == NULL) { + return; } - *log = (struct chatlog) { - 0 - }; + if (log->file != NULL) { + fclose(log->file); + log->file = NULL; + } + + log->lastwrite = 0; + log->log_on = false; } -int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype) +int log_enable(struct chatlog *log) { - log->log_on = true; + if (log == NULL) { + return -1; + } - if (log->file != NULL) { + if (log->log_on) { return 0; } - if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) { - log_disable(log); + if (*log->path == 0) { return -1; } + if (log->file != NULL) { + return -1; + } + + log->file = fopen(log->path, "a+"); + + if (log->file == NULL) { + return -1; + } + + log->log_on = true; + return 0; } -/* Loads previous history from chat log */ -void load_chat_history(ToxWindow *self, struct chatlog *log) +/* Initializes a log. This function must be called before any other logging operations. + * + * Return 0 on success. + * Return -1 on failure. + */ +int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type) { - if (log->file == NULL) { - return; + if (log == NULL) { + return -1; + } + + if (log->file != NULL || log->log_on) { + fprintf(stderr, "Warning: Called log_init() on an already initialized log\n"); + return -1; + } + + if (init_logging_session(name, selfkey, otherkey, log, type) == -1) { + return -1; + } + + log_disable(log); + + return 0; +} + +/* Loads chat log history and prints it to `self` window. + * + * Return 0 on success or if log file doesn't exist. + * Return -1 on failure. + */ +int load_chat_history(ToxWindow *self, struct chatlog *log) +{ + if (log == NULL) { + return -1; + } + + if (*log->path == 0) { + return -1; } off_t sz = file_size(log->path); if (sz <= 0) { - return; + return 0; } - char *hstbuf = malloc(sz + 1); + FILE *fp = fopen(log->path, "r"); - if (hstbuf == NULL) { - exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY); + if (fp == NULL) { + return -1; } - if (fseek(log->file, 0L, SEEK_SET) == -1) { - free(hstbuf); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file"); - return; + char *buf = malloc(sz + 1); + + if (buf == NULL) { + fclose(fp); + return -1; } - if (fread(hstbuf, sz, 1, log->file) != 1) { - free(hstbuf); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file"); - return; + if (fseek(fp, 0L, SEEK_SET) == -1) { + free(buf); + fclose(fp); + return -1; } - hstbuf[sz] = '\0'; + if (fread(buf, sz, 1, fp) != 1) { + free(buf); + fclose(fp); + return -1; + } + + fclose(fp); + + buf[sz] = 0; /* Number of history lines to load: must not be larger than MAX_LINE_INFO_QUEUE - 2 */ int L = MIN(MAX_LINE_INFO_QUEUE - 2, user_settings->history_size); - int start, count = 0; + + int start = 0; + int count = 0; /* start at end and backtrace L lines or to the beginning of buffer */ for (start = sz - 1; start >= 0 && count < L; --start) { - if (hstbuf[start] == '\n') { + if (buf[start] == '\n') { ++count; } } - const char *line = strtok(&hstbuf[start + 1], "\n"); + char *tmp = NULL; + const char *line = strtok_r(&buf[start + 1], "\n", &tmp); if (line == NULL) { - free(hstbuf); - return; + free(buf); + return -1; } while (line != NULL && count--) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line); - line = strtok(NULL, "\n"); + line = strtok_r(NULL, "\n", &tmp); } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); - free(hstbuf); + + free(buf); + + return 0; } -/* renames chatlog file replacing src with dest. - Returns 0 on success or if no log exists, -1 on failure. */ -int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum) +/* Renames chatlog file `src` to `dest`. + * + * Return 0 on success or if no log exists. + * Return -1 on failure. + */ +int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum) { ToxWindow *toxwin = get_window_ptr(winnum); struct chatlog *log = NULL; @@ -250,6 +327,11 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other /* disable log if necessary and save its state */ if (toxwin != NULL) { log = toxwin->chatwin->log; + + if (log == NULL) { + return -1; + } + log_on = log->log_on; } @@ -260,24 +342,38 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other char newpath[MAX_STR_SIZE]; char oldpath[MAX_STR_SIZE]; - if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey, LOG_CHAT) == -1) { + if (get_log_path(oldpath, sizeof(oldpath), src, selfkey, otherkey) == -1) { goto on_error; } if (!file_exists(oldpath)) { + init_logging_session(dest, selfkey, otherkey, log, LOG_TYPE_CHAT); // still need to rename path return 0; } - if (get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey, LOG_CHAT) == -1) { + int new_path_len = get_log_path(newpath, sizeof(newpath), dest, selfkey, otherkey); + + if (new_path_len == -1 || new_path_len >= MAX_STR_SIZE) { goto on_error; } - if (rename(oldpath, newpath) != 0) { - goto on_error; + if (file_exists(newpath)) { + if (remove(oldpath) != 0) { + fprintf(stderr, "Failed to remove old path `%s`\n", oldpath); + } + } else { + if (rename(oldpath, newpath) != 0) { + goto on_error; + } } - if (log_on) { - log_enable(dest, selfkey, otherkey, log, LOG_CHAT); + if (log != NULL) { + memcpy(log->path, newpath, new_path_len); + log->path[new_path_len] = 0; + + if (log_on) { + log_enable(log); + } } return 0; @@ -285,7 +381,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other on_error: if (log_on) { - log_enable(src, selfkey, otherkey, log, LOG_CHAT); + log_enable(log); } return -1; diff --git a/src/log.h b/src/log.h index 6c4c61d..eb1c965 100644 --- a/src/log.h +++ b/src/log.h @@ -30,30 +30,43 @@ struct chatlog { bool log_on; /* specific to current chat window */ }; -typedef enum { - LOG_CONFERENCE, - LOG_PROMPT, - LOG_CHAT, +typedef enum LOG_TYPE { + LOG_TYPE_PROMPT, + LOG_TYPE_CHAT, } LOG_TYPE; +/* Initializes a log. This function must be called before any other logging operations. + * + * Return 0 on success. + * Return -1 on failure. + */ +int log_init(struct chatlog *log, const char *name, const char *selfkey, const char *otherkey, LOG_TYPE type); + /* formats/writes line to log file */ void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event); -/* enables logging for specified log and creates/fetches file if necessary. +/* enables logging for specified log. * * Returns 0 on success. * Returns -1 on failure. */ -int log_enable(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype); +int log_enable(struct chatlog *log); /* disables logging for specified log and closes file */ void log_disable(struct chatlog *log); -/* Loads previous history from chat log */ -void load_chat_history(ToxWindow *self, struct chatlog *log); +/* Loads chat log history and prints it to `self` window. + * + * Return 0 on success or if log file doesn't exist. + * Return -1 on failure. + */ +int load_chat_history(ToxWindow *self, struct chatlog *log); -/* renames chatlog file replacing src with dest. - Returns 0 on success or if no log exists, -1 on failure. */ -int rename_logfile(char *src, char *dest, const char *selfkey, const char *otherkey, int winnum); +/* Renames chatlog file `src` to `dest`. + * + * Return 0 on success or if no log exists. + * Return -1 on failure. + */ +int rename_logfile(const char *src, const char *dest, const char *selfkey, const char *otherkey, int winnum); #endif /* LOG_H */ diff --git a/src/prompt.c b/src/prompt.c index b5960ae..8cdedb1 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -554,6 +554,25 @@ static void print_welcome_msg(ToxWindow *self) line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); } +static void prompt_init_log(ToxWindow *self, Tox *m, const char *self_name) +{ + ChatContext *ctx = self->chatwin; + + char myid[TOX_ADDRESS_SIZE]; + tox_self_get_address(m, (uint8_t *) myid); + + if (log_init(ctx->log, self->name, myid, NULL, LOG_TYPE_PROMPT) != 0) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); + return; + } + + if (user_settings->autolog == AUTOLOG_ON) { + if (log_enable(ctx->log) == -1) { + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Failed to enable log."); + } + } +} + static void prompt_onInit(ToxWindow *self, Tox *m) { curs_set(1); @@ -577,14 +596,7 @@ static void prompt_onInit(ToxWindow *self, Tox *m) line_info_init(ctx->hst); - if (user_settings->autolog == AUTOLOG_ON) { - char myid[TOX_ADDRESS_SIZE]; - tox_self_get_address(m, (uint8_t *) myid); - - if (log_enable(self->name, myid, NULL, ctx->log, LOG_PROMPT) == -1) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Warning: Log failed to initialize."); - } - } + prompt_init_log(self, m, self->name); scrollok(ctx->history, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0);