diff --git a/build/Makefile b/build/Makefile index 7400400..1dfb585 100644 --- a/build/Makefile +++ b/build/Makefile @@ -13,7 +13,7 @@ LDFLAGS = $(USER_LDFLAGS) OBJ = chat.o chat_commands.o configdir.o dns.o execute.o file_senders.o notify.o OBJ += friendlist.o global_commands.o groupchat.o line_info.o input.o help.o autocomplete.o -OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o +OBJ += log.o misc_tools.o prompt.o settings.o toxic.o toxic_strings.o windows.o message_queue.o # Check on wich system we are running UNAME_S = $(shell uname -s) diff --git a/src/chat.c b/src/chat.c index 62e9b29..54aa4d1 100644 --- a/src/chat.c +++ b/src/chat.c @@ -43,6 +43,7 @@ #include "help.h" #include "autocomplete.h" #include "notify.h" +#include "message_queue.h" #ifdef _AUDIO #include "audio_call.h" @@ -134,6 +135,7 @@ void kill_chat_window(ToxWindow *self, Tox *m) close_all_file_receivers(m, self->num); log_disable(ctx->log); line_info_cleanup(ctx->hst); + cqueue_cleanup(ctx->cqueue); #ifdef _AUDIO stop_current_call(self); @@ -144,7 +146,6 @@ void kill_chat_window(ToxWindow *self, Tox *m) delwin(statusbar->topline); free(ctx->log); - free(ctx->hst); free(ctx); free(self->help); free(statusbar); @@ -293,8 +294,6 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t if (self->num != num) return; - const char *errmsg; - /* holds the filename appended to the user specified path */ char filename_path[MAX_STR_SIZE] = {0}; @@ -308,8 +307,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filename_nopath, sizestr); if (filenum >= MAX_FILES) { - errmsg = "Too many pending file requests; discarding."; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding."); return; } @@ -320,8 +318,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t } if (len >= sizeof(Friends.list[num].file_receiver[filenum].filename)) { - errmsg = "File name too long; discarding."; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File name too long; discarding."); return; } @@ -351,8 +348,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t filename[len + d_len] = '\0'; if (count > 999) { - errmsg = "Error saving file to disk."; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk."); return; } } @@ -494,7 +490,10 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec case TOX_FILECONTROL_FINISHED: if (receive_send == 0) { print_progress_bar(self, filenum, num, 100.0); - snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename); + + char filename_nopath[MAX_STR_SIZE]; + get_file_name(filename_nopath, sizeof(filename_nopath), filename); + snprintf(msg, sizeof(msg), "File transfer for '%s' complete.", filename_nopath); chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_FINISHED); } else { snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", filename); @@ -833,12 +832,8 @@ static void send_action(ToxWindow *self, ChatContext *ctx, Tox *m, char *action) get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, selfname, NULL, ACTION, 0, 0, "%s", action); - - if (tox_send_action(m, self->num, (uint8_t *) action, strlen(action)) == 0) { - line_info_add(self, NULL, selfname, NULL, SYS_MSG, 0, RED, " * Failed to send action."); - } else { - write_to_log(action, selfname, ctx->log, true); - } + write_to_log(action, selfname, ctx->log, true); + cqueue_add(ctx->cqueue, action, strlen(action), QACTION, ctx->hst->line_end->id); } static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) @@ -919,12 +914,8 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) get_time_str(timefrmt, sizeof(timefrmt)); line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line); - - if (!statusbar->is_online || tox_send_message(m, self->num, (uint8_t *) line, strlen(line)) == 0) { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Failed to send message."); - } else { - write_to_log(line, selfname, ctx->log, false); - } + write_to_log(line, selfname, ctx->log, false); + cqueue_add(ctx->cqueue, line, strlen(line), QMESSAGE, ctx->hst->line_end->id); } wclear(ctx->linewin); @@ -1090,11 +1081,13 @@ static void chat_onInit(ToxWindow *self, Tox *m) ctx->hst = calloc(1, sizeof(struct history)); ctx->log = calloc(1, sizeof(struct chatlog)); + ctx->cqueue = calloc(1, sizeof(struct chat_queue)); - if (ctx->log == NULL || ctx->hst == NULL) + if (ctx->log == NULL || ctx->hst == NULL || ctx->cqueue == NULL) exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY); line_info_init(ctx->hst); + ctx->cqueue->friendnum = self->num; if (Friends.list[self->num].logging_on) log_enable(nick, Friends.list[self->num].pub_key, ctx->log); diff --git a/src/file_senders.c b/src/file_senders.c index 6203d34..6022886 100644 --- a/src/file_senders.c +++ b/src/file_senders.c @@ -276,6 +276,7 @@ void do_file_senders(Tox *m) box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg); else box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg); + continue; } diff --git a/src/groupchat.c b/src/groupchat.c index 1bde98c..10ede90 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -97,7 +97,6 @@ void kill_groupchat_window(ToxWindow *self) delwin(ctx->history); delwin(ctx->sidebar); free(ctx->log); - free(ctx->hst); free(ctx); free(self->help); del_window(self); diff --git a/src/line_info.c b/src/line_info.c index f216aec..54f2950 100644 --- a/src/line_info.c +++ b/src/line_info.c @@ -89,6 +89,8 @@ void line_info_cleanup(struct history *hst) if (hst->queue[i]) free(hst->queue[i]); } + + free(hst); } /* moves root forward and frees previous root */ diff --git a/src/message_queue.c b/src/message_queue.c new file mode 100644 index 0000000..085bc61 --- /dev/null +++ b/src/message_queue.c @@ -0,0 +1,87 @@ +/* message_queue.c + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#include + +#include "toxic.h" +#include "windows.h" +#include "message_queue.h" + +void cqueue_cleanup(struct chat_queue *q) +{ + struct cqueue_msg *tmp1 = q->root; + + while (tmp1) { + struct cqueue_msg *tmp2 = tmp1->next; + free(tmp1); + tmp1 = tmp2; + } + + free(q); +} + +void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id) +{ + struct cqueue_msg *new_m = malloc(sizeof(struct cqueue_msg)); + + if (new_m == NULL) + exit_toxic_err("failed in cqueue_message", FATALERR_MEMORY); + + snprintf(new_m->message, sizeof(new_m->message), "%s", msg); + new_m->len = len; + new_m->type = type; + new_m->line_id = line_id; + new_m->next = NULL; + + if (q->root == NULL) + q->root = new_m; + else + q->end->next = new_m; + + q->end = new_m; +} + +static void cqueue_remove(struct chat_queue *q) +{ + struct cqueue_msg *new_root = q->root->next; + free(q->root); + q->root = new_root; +} + +void cqueue_try_send(Tox *m, struct chat_queue *q) +{ + if (q->root == NULL) + return; + + struct cqueue_msg *q_msg = q->root; + uint32_t receipt; + + if (q_msg->type == QMESSAGE) + receipt = tox_send_message(m, q->friendnum, (uint8_t *) q_msg->message, q_msg->len); + else + receipt = tox_send_action(m, q->friendnum, (uint8_t *) q_msg->message, q_msg->len); + + if (receipt == 0) + return; + + cqueue_remove(q); +} diff --git a/src/message_queue.h b/src/message_queue.h new file mode 100644 index 0000000..b8c9b23 --- /dev/null +++ b/src/message_queue.h @@ -0,0 +1,46 @@ +/* message_queue.h + * + * + * Copyright (C) 2014 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +enum { + QMESSAGE, + QACTION, +} MESSAGE_TYPE; + +struct cqueue_msg { + char message[MAX_STR_SIZE]; + int len; + int line_id; + uint8_t type; + uint32_t receipt; + struct cqueue_msg *next; +}; + +struct chat_queue { + struct cqueue_msg *root; + struct cqueue_msg *end; + int friendnum; +}; + +void cqueue_cleanup(struct chat_queue *q); +void cqueue_add(struct chat_queue *q, const char *msg, int len, uint8_t type, uint32_t line_id); +void cqueue_check(Tox *m); +void cqueue_try_send(Tox *m, struct chat_queue *q); diff --git a/src/notify.c b/src/notify.c index 37a8596..e8d96e3 100644 --- a/src/notify.c +++ b/src/notify.c @@ -166,7 +166,7 @@ bool is_playing(int source) return ready == AL_PLAYING; } -/* Terminate all sounds but wait them to finish first */ +/* Terminate all sounds but wait for them to finish first */ void graceful_clear() { int i; @@ -192,7 +192,6 @@ void graceful_clear() else break; } } - } if (i == ACTIVE_NOTIFS_MAX) { diff --git a/src/prompt.c b/src/prompt.c index 5f8dfc4..8670bf4 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -88,7 +88,6 @@ void kill_prompt_window(ToxWindow *self) delwin(statusbar->topline); free(ctx->log); - free(ctx->hst); free(ctx); free(self->help); free(statusbar); diff --git a/src/toxic.c b/src/toxic.c index 35c59fb..0bfd738 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -53,6 +53,7 @@ #include "log.h" #include "notify.h" #include "device.h" +#include "message_queue.h" #ifdef _AUDIO #include "audio_call.h" @@ -74,6 +75,7 @@ ToxWindow *prompt = NULL; #define AUTOSAVE_FREQ 60 struct _Winthread Winthread; +struct _cqueue_thread cqueue_thread; struct arg_opts arg_opts; struct user_settings *user_settings_ = NULL; @@ -573,6 +575,26 @@ void *thread_winref(void *data) } } +void *thread_cqueue(void *data) +{ + Tox *m = (Tox *) data; + + while (true) { + pthread_mutex_lock(&Winthread.lock); + int i; + + for (i = 0; i < MAX_WINDOWS_NUM; ++i) { + ToxWindow *toxwin = get_window_ptr(i); + + if (toxwin != NULL && toxwin->is_chat && tox_get_friend_connection_status(m, toxwin->num) == 1) + cqueue_try_send(m, toxwin->chatwin->cqueue); + } + + pthread_mutex_unlock(&Winthread.lock); + usleep(100000); /* 0.1 second */ + } +} + static void print_usage(void) { fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n"); @@ -811,11 +833,14 @@ int main(int argc, char *argv[]) if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0) exit_toxic_err("failed in main", FATALERR_THREAD_CREATE); + /* thread for message queue */ + if (pthread_create(&cqueue_thread.tid, NULL, thread_cqueue, (void *) m) != 0) + exit_toxic_err("failed in main", FATALERR_THREAD_CREATE); + #ifdef _AUDIO av = init_audio(prompt, m); - set_primary_device(input, user_settings_->audio_in_dev); set_primary_device(output, user_settings_->audio_out_dev); diff --git a/src/windows.h b/src/windows.h index 9b1bb08..8ba2fd9 100644 --- a/src/windows.h +++ b/src/windows.h @@ -71,6 +71,10 @@ struct _Winthread { bool flag_resize; }; +struct _cqueue_thread { + pthread_t tid; +}; + struct arg_opts { int ignore_data_file; int use_ipv4; @@ -208,6 +212,7 @@ struct ChatContext { struct history *hst; struct chatlog *log; + struct chat_queue *cqueue; #ifdef _AUDIO struct infobox infobox;