1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 17:03:03 +01:00

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.
This commit is contained in:
jfreegman 2020-11-17 16:05:20 -05:00
parent c135c812c2
commit 7e1e410307
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
9 changed files with 351 additions and 148 deletions

View File

@ -1330,6 +1330,29 @@ static void chat_onDraw(ToxWindow *self, Tox *m)
pthread_mutex_unlock(&Winthread.lock); 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) static void chat_onInit(ToxWindow *self, Tox *m)
{ {
curs_set(1); curs_set(1);
@ -1380,19 +1403,9 @@ static void chat_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst); line_info_init(ctx->hst);
char myid[TOX_ADDRESS_SIZE]; chat_init_log(self, m, nick);
tox_self_get_address(m, (uint8_t *) myid);
int log_ret = log_enable(nick, myid, Friends.list[self->num].pub_key, ctx->log, LOG_CHAT); execute(ctx->history, self, m, "/log", GLOBAL_COMMAND_MODE); // Print log status to screen
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);
scrollok(ctx->history, 0); scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0);

View File

@ -114,6 +114,25 @@ static const char *conference_cmd_list[] = {
static ToxWindow *new_conference_chat(uint32_t conferencenum); 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) static void kill_conference_window(ToxWindow *self)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
@ -130,8 +149,35 @@ static void kill_conference_window(ToxWindow *self)
del_window(self); del_window(self);
} }
int init_conference_win(Tox *m, uint32_t conferencenum, uint8_t type, const char *title, static void init_conference_logging(ToxWindow *self, Tox *m, uint32_t conferencenum)
size_t title_length) {
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) { if (conferencenum > MAX_CONFERENCE_NUM) {
return -1; 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; conferences[i].last_sent_audio = 0;
set_active_window_index(conferences[i].chatwin); 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) { if (i == max_conference_index) {
++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); 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 */ /* destroys and re-creates conference window with or without the peerlist */
void redraw_conference_win(ToxWindow *self) void redraw_conference_win(ToxWindow *self)
{ {
@ -319,13 +387,21 @@ static void conference_onConferenceTitleChange(ToxWindow *self, Tox *m, uint32_t
return; 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]; char timefrmt[TIME_STR_SIZE];
get_time_str(timefrmt, sizeof(timefrmt)); get_time_str(timefrmt, sizeof(timefrmt));
/* don't announce title when we join the room */ /* 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; return;
} }
@ -1038,17 +1114,6 @@ static void conference_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst); 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); scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0);
} }

View File

@ -27,8 +27,9 @@
#include "windows.h" #include "windows.h"
#define SIDEBAR_WIDTH 16 #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_EVENT_WAIT 3
#define CONFERENCE_MAX_TITLE_LENGTH TOX_MAX_NAME_LENGTH
typedef struct ConferencePeer { typedef struct ConferencePeer {
bool active; bool active;
@ -64,6 +65,9 @@ typedef struct {
int side_pos; /* current position of the sidebar - used for scrolling up and down */ int side_pos; /* current position of the sidebar - used for scrolling up and down */
time_t start_time; time_t start_time;
char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
size_t title_length;
ConferencePeer *peer_list; ConferencePeer *peer_list;
uint32_t max_idx; 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() ) */ /* Frees all Toxic associated data structures for a conference (does not call tox_conference_delete() ) */
void free_conference(ToxWindow *self, uint32_t conferencenum); 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 */ /* destroys and re-creates conference window with or without the peerlist */
void redraw_conference_win(ToxWindow *self); 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 /* Puts `(NameListEntry *)`s in `entries` for each matched peer, up to a maximum
* of `maxpeers`. * of `maxpeers`.
* Maches each peer whose name or pubkey begins with `prefix`. * Maches each peer whose name or pubkey begins with `prefix`.

View File

@ -40,7 +40,7 @@ void cmd_conference_set_title(WINDOW *window, ToxWindow *self, Tox *m, int argc,
UNUSED_VAR(window); UNUSED_VAR(window);
Tox_Err_Conference_Title err; Tox_Err_Conference_Title err;
char title[MAX_STR_SIZE]; char title[CONFERENCE_MAX_TITLE_LENGTH + 1];
if (argc < 1) { if (argc < 1) {
size_t tlen = tox_conference_get_title_size(m, self->num, &err); 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; 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]); snprintf(title, sizeof(title), "%s", argv[1]);
int len = strlen(title);
if (!tox_conference_set_title(m, self->num, (uint8_t *) title, len, &err)) { 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); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to set title (error %d)", err);
return; 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 timefrmt[TIME_STR_SIZE];
char selfnick[TOX_MAX_NAME_LENGTH]; char selfnick[TOX_MAX_NAME_LENGTH];

View File

@ -453,7 +453,9 @@ static void friendlist_onNickChange(ToxWindow *self, Tox *m, uint32_t num, const
tox_self_get_address(m, (uint8_t *) myid); tox_self_get_address(m, (uint8_t *) myid);
if (strcmp(oldname, newnamecpy) != 0) { 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(); sort_friendlist_index();

View File

@ -434,21 +434,7 @@ void cmd_log(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX
const char *swch = argv[1]; const char *swch = argv[1];
if (!strcmp(swch, "1") || !strcmp(swch, "on")) { if (!strcmp(swch, "1") || !strcmp(swch, "on")) {
char myid[TOX_ADDRESS_SIZE]; msg = log_enable(log) == 0 ? "Logging enabled." : "Warning: Failed to enable log.";
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.";
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
return; return;
} else if (!strcmp(swch, "0") || !strcmp(swch, "off")) { } else if (!strcmp(swch, "0") || !strcmp(swch, "off")) {

244
src/log.c
View File

@ -35,29 +35,33 @@
extern struct user_settings *user_settings; 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) /* Creates a log path and puts it in `dest.
A prompt log is in the format: LOGDIR/selfkey-home.log *
A chat log is in the format: LOGDIR/selfkey-friendname-otherkey.log * There are two types of logs: chat logs and prompt logs (see LOG_TYPE in log.h)
A conference log is in the format: LOGDIR/selfkey-conferencename-date[time].log * A prompt log is in the format: LOGDIR/selfkey-home.log
* A chat log is in the format: LOGDIR/selfkey-name-otherkey.log
Only the first (KEY_IDENT_DIGITS * 2) numbers of the key are used. *
* For friend chats `otherkey` is the first 6 bytes of the friend's Tox ID.
Returns 0 on success, -1 if the path is too long */ * For Conferences/groups `otherkey` is the first 6 bytes of the group's unique ID.
static int get_log_path(char *dest, int destsize, char *name, const char *selfkey, const char *otherkey, int logtype) *
* 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)) { if (!valid_nick(name)) {
name = UNKNOWN_NAME; name = UNKNOWN_NAME;
} }
const char *namedash = logtype == LOG_PROMPT ? "" : "-"; const char *namedash = otherkey ? "-" : "";
const char *set_path = user_settings->chatlogs_path; const char *set_path = user_settings->chatlogs_path;
char *user_config_dir = get_user_config_dir(); char *user_config_dir = get_user_config_dir();
int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash); int path_len = strlen(name) + strlen(".log") + strlen("-") + strlen(namedash);
path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR); path_len += strlen(set_path) ? *set_path : strlen(user_config_dir) + strlen(LOGDIR);
/* first 6 digits of selfkey */ /* first 6 bytes of selfkey */
char self_id[32]; char self_id[32] = {0};
path_len += KEY_IDENT_DIGITS * 2; path_len += KEY_IDENT_DIGITS * 2;
sprintf(&self_id[0], "%02X", selfkey[0] & 0xff); sprintf(&self_id[0], "%02X", selfkey[0] & 0xff);
sprintf(&self_id[2], "%02X", selfkey[1] & 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}; char other_id[32] = {0};
switch (logtype) { if (otherkey) {
case LOG_CHAT: /* first 6 bytes of otherkey */
path_len += KEY_IDENT_DIGITS * 2; path_len += KEY_IDENT_DIGITS * 2;
sprintf(&other_id[0], "%02X", otherkey[0] & 0xff); sprintf(&other_id[0], "%02X", otherkey[0] & 0xff);
sprintf(&other_id[2], "%02X", otherkey[1] & 0xff); sprintf(&other_id[2], "%02X", otherkey[1] & 0xff);
sprintf(&other_id[4], "%02X", otherkey[2] & 0xff); sprintf(&other_id[4], "%02X", otherkey[2] & 0xff);
other_id[KEY_IDENT_DIGITS * 2] = '\0'; 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 (path_len >= destsize) { 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); free(user_config_dir);
return 0; return path_len;
} }
/* Opens log file or creates a new one */ /* Initializes log path for `log`.
static int init_logging_session(char *name, const char *selfkey, const char *otherkey, struct chatlog *log, int logtype) *
* 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; return -1;
} }
char log_path[MAX_STR_SIZE]; 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; return -1;
} }
log->file = fopen(log_path, "a+"); memcpy(log->path, log_path, path_len);
snprintf(log->path, sizeof(log->path), "%s", log_path); log->path[path_len] = 0;
if (log->file == NULL) {
return -1;
}
return 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) void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
{ {
if (log == NULL) {
return;
}
if (!log->log_on) { if (!log->log_on) {
return; 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) void log_disable(struct chatlog *log)
{ {
if (log == NULL) {
return;
}
if (log->file != NULL) { if (log->file != NULL) {
fclose(log->file); fclose(log->file);
log->file = NULL;
} }
*log = (struct chatlog) { log->lastwrite = 0;
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) {
if (log->file != NULL) {
return 0;
}
if (init_logging_session(name, selfkey, otherkey, log, logtype) == -1) {
log_disable(log);
return -1; return -1;
} }
if (log->log_on) {
return 0; return 0;
} }
/* Loads previous history from chat log */ if (*log->path == 0) {
void load_chat_history(ToxWindow *self, struct chatlog *log) return -1;
{ }
if (log->file != NULL) {
return -1;
}
log->file = fopen(log->path, "a+");
if (log->file == NULL) { if (log->file == NULL) {
return; return -1;
}
log->log_on = true;
return 0;
}
/* 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 == 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); off_t sz = file_size(log->path);
if (sz <= 0) { if (sz <= 0) {
return; return 0;
} }
char *hstbuf = malloc(sz + 1); FILE *fp = fopen(log->path, "r");
if (hstbuf == NULL) { if (fp == NULL) {
exit_toxic_err("failed in load_chat_history", FATALERR_MEMORY); return -1;
} }
if (fseek(log->file, 0L, SEEK_SET) == -1) { char *buf = malloc(sz + 1);
free(hstbuf);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file"); if (buf == NULL) {
return; fclose(fp);
return -1;
} }
if (fread(hstbuf, sz, 1, log->file) != 1) { if (fseek(fp, 0L, SEEK_SET) == -1) {
free(hstbuf); free(buf);
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to read log file"); fclose(fp);
return; 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 */ /* 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 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 */ /* start at end and backtrace L lines or to the beginning of buffer */
for (start = sz - 1; start >= 0 && count < L; --start) { for (start = sz - 1; start >= 0 && count < L; --start) {
if (hstbuf[start] == '\n') { if (buf[start] == '\n') {
++count; ++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) { if (line == NULL) {
free(hstbuf); free(buf);
return; return -1;
} }
while (line != NULL && count--) { while (line != NULL && count--) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", line); 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, ""); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
free(hstbuf);
free(buf);
return 0;
} }
/* renames chatlog file replacing src with dest. /* Renames chatlog file `src` to `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) * 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); ToxWindow *toxwin = get_window_ptr(winnum);
struct chatlog *log = NULL; 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 */ /* disable log if necessary and save its state */
if (toxwin != NULL) { if (toxwin != NULL) {
log = toxwin->chatwin->log; log = toxwin->chatwin->log;
if (log == NULL) {
return -1;
}
log_on = log->log_on; 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 newpath[MAX_STR_SIZE];
char oldpath[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; goto on_error;
} }
if (!file_exists(oldpath)) { if (!file_exists(oldpath)) {
init_logging_session(dest, selfkey, otherkey, log, LOG_TYPE_CHAT); // still need to rename path
return 0; 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; 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) { if (rename(oldpath, newpath) != 0) {
goto on_error; goto on_error;
} }
}
if (log != NULL) {
memcpy(log->path, newpath, new_path_len);
log->path[new_path_len] = 0;
if (log_on) { if (log_on) {
log_enable(dest, selfkey, otherkey, log, LOG_CHAT); log_enable(log);
}
} }
return 0; return 0;
@ -285,7 +381,7 @@ int rename_logfile(char *src, char *dest, const char *selfkey, const char *other
on_error: on_error:
if (log_on) { if (log_on) {
log_enable(src, selfkey, otherkey, log, LOG_CHAT); log_enable(log);
} }
return -1; return -1;

View File

@ -30,30 +30,43 @@ struct chatlog {
bool log_on; /* specific to current chat window */ bool log_on; /* specific to current chat window */
}; };
typedef enum { typedef enum LOG_TYPE {
LOG_CONFERENCE, LOG_TYPE_PROMPT,
LOG_PROMPT, LOG_TYPE_CHAT,
LOG_CHAT,
} LOG_TYPE; } 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 */ /* formats/writes line to log file */
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event); 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 0 on success.
* Returns -1 on failure. * 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 */ /* disables logging for specified log and closes file */
void log_disable(struct chatlog *log); void log_disable(struct chatlog *log);
/* Loads previous history from chat log */ /* Loads chat log history and prints it to `self` window.
void load_chat_history(ToxWindow *self, struct chatlog *log); *
* 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. /* Renames chatlog file `src` to `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); * 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 */ #endif /* LOG_H */

View File

@ -554,6 +554,25 @@ static void print_welcome_msg(ToxWindow *self)
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); 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) static void prompt_onInit(ToxWindow *self, Tox *m)
{ {
curs_set(1); curs_set(1);
@ -577,14 +596,7 @@ static void prompt_onInit(ToxWindow *self, Tox *m)
line_info_init(ctx->hst); line_info_init(ctx->hst);
if (user_settings->autolog == AUTOLOG_ON) { prompt_init_log(self, m, self->name);
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.");
}
}
scrollok(ctx->history, 0); scrollok(ctx->history, 0);
wmove(self->window, y2 - CURS_Y_OFFSET, 0); wmove(self->window, y2 - CURS_Y_OFFSET, 0);