mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-26 16:03:27 +01:00
message sending queue for fake offline messaging
This commit is contained in:
parent
6876df4a45
commit
3c2c1f15ce
@ -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 = 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 += 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
|
# Check on wich system we are running
|
||||||
UNAME_S = $(shell uname -s)
|
UNAME_S = $(shell uname -s)
|
||||||
|
35
src/chat.c
35
src/chat.c
@ -43,6 +43,7 @@
|
|||||||
#include "help.h"
|
#include "help.h"
|
||||||
#include "autocomplete.h"
|
#include "autocomplete.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
|
#include "message_queue.h"
|
||||||
|
|
||||||
#ifdef _AUDIO
|
#ifdef _AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
@ -134,6 +135,7 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
close_all_file_receivers(m, self->num);
|
close_all_file_receivers(m, self->num);
|
||||||
log_disable(ctx->log);
|
log_disable(ctx->log);
|
||||||
line_info_cleanup(ctx->hst);
|
line_info_cleanup(ctx->hst);
|
||||||
|
cqueue_cleanup(ctx->cqueue);
|
||||||
|
|
||||||
#ifdef _AUDIO
|
#ifdef _AUDIO
|
||||||
stop_current_call(self);
|
stop_current_call(self);
|
||||||
@ -144,7 +146,6 @@ void kill_chat_window(ToxWindow *self, Tox *m)
|
|||||||
delwin(statusbar->topline);
|
delwin(statusbar->topline);
|
||||||
|
|
||||||
free(ctx->log);
|
free(ctx->log);
|
||||||
free(ctx->hst);
|
|
||||||
free(ctx);
|
free(ctx);
|
||||||
free(self->help);
|
free(self->help);
|
||||||
free(statusbar);
|
free(statusbar);
|
||||||
@ -293,8 +294,6 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
|||||||
if (self->num != num)
|
if (self->num != num)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const char *errmsg;
|
|
||||||
|
|
||||||
/* holds the filename appended to the user specified path */
|
/* holds the filename appended to the user specified path */
|
||||||
char filename_path[MAX_STR_SIZE] = {0};
|
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);
|
filename_nopath, sizestr);
|
||||||
|
|
||||||
if (filenum >= MAX_FILES) {
|
if (filenum >= MAX_FILES) {
|
||||||
errmsg = "Too many pending file requests; discarding.";
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Too many pending file requests; discarding.");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
|
||||||
return;
|
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)) {
|
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, "File name too long; discarding.");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,8 +348,7 @@ static void chat_onFileSendRequest(ToxWindow *self, Tox *m, int32_t num, uint8_t
|
|||||||
filename[len + d_len] = '\0';
|
filename[len + d_len] = '\0';
|
||||||
|
|
||||||
if (count > 999) {
|
if (count > 999) {
|
||||||
errmsg = "Error saving file to disk.";
|
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error saving file to disk.");
|
||||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,7 +490,10 @@ static void chat_onFileControl(ToxWindow *self, Tox *m, int32_t num, uint8_t rec
|
|||||||
case TOX_FILECONTROL_FINISHED:
|
case TOX_FILECONTROL_FINISHED:
|
||||||
if (receive_send == 0) {
|
if (receive_send == 0) {
|
||||||
print_progress_bar(self, filenum, num, 100.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);
|
chat_close_file_receiver(m, filenum, num, TOX_FILECONTROL_FINISHED);
|
||||||
} else {
|
} else {
|
||||||
snprintf(msg, sizeof(msg), "File '%s' successfuly sent.", filename);
|
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));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
line_info_add(self, timefrmt, selfname, NULL, ACTION, 0, 0, "%s", action);
|
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)
|
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));
|
get_time_str(timefrmt, sizeof(timefrmt));
|
||||||
|
|
||||||
line_info_add(self, timefrmt, selfname, NULL, OUT_MSG, 0, 0, "%s", line);
|
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);
|
wclear(ctx->linewin);
|
||||||
@ -1090,11 +1081,13 @@ static void chat_onInit(ToxWindow *self, Tox *m)
|
|||||||
|
|
||||||
ctx->hst = calloc(1, sizeof(struct history));
|
ctx->hst = calloc(1, sizeof(struct history));
|
||||||
ctx->log = calloc(1, sizeof(struct chatlog));
|
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);
|
exit_toxic_err("failed in chat_onInit", FATALERR_MEMORY);
|
||||||
|
|
||||||
line_info_init(ctx->hst);
|
line_info_init(ctx->hst);
|
||||||
|
ctx->cqueue->friendnum = self->num;
|
||||||
|
|
||||||
if (Friends.list[self->num].logging_on)
|
if (Friends.list[self->num].logging_on)
|
||||||
log_enable(nick, Friends.list[self->num].pub_key, ctx->log);
|
log_enable(nick, Friends.list[self->num].pub_key, ctx->log);
|
||||||
|
@ -276,6 +276,7 @@ void do_file_senders(Tox *m)
|
|||||||
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
box_notify2(self, error, NT_NOFOCUS | NT_WNDALERT_2, self->active_box, "%s", msg);
|
||||||
else
|
else
|
||||||
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
|
box_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, &self->active_box, self->name, "%s", msg);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,6 @@ void kill_groupchat_window(ToxWindow *self)
|
|||||||
delwin(ctx->history);
|
delwin(ctx->history);
|
||||||
delwin(ctx->sidebar);
|
delwin(ctx->sidebar);
|
||||||
free(ctx->log);
|
free(ctx->log);
|
||||||
free(ctx->hst);
|
|
||||||
free(ctx);
|
free(ctx);
|
||||||
free(self->help);
|
free(self->help);
|
||||||
del_window(self);
|
del_window(self);
|
||||||
|
@ -89,6 +89,8 @@ void line_info_cleanup(struct history *hst)
|
|||||||
if (hst->queue[i])
|
if (hst->queue[i])
|
||||||
free(hst->queue[i]);
|
free(hst->queue[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(hst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* moves root forward and frees previous root */
|
/* moves root forward and frees previous root */
|
||||||
|
87
src/message_queue.c
Normal file
87
src/message_queue.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
46
src/message_queue.h
Normal file
46
src/message_queue.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
@ -166,7 +166,7 @@ bool is_playing(int source)
|
|||||||
return ready == AL_PLAYING;
|
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()
|
void graceful_clear()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -192,7 +192,6 @@ void graceful_clear()
|
|||||||
else break;
|
else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == ACTIVE_NOTIFS_MAX) {
|
if (i == ACTIVE_NOTIFS_MAX) {
|
||||||
|
@ -88,7 +88,6 @@ void kill_prompt_window(ToxWindow *self)
|
|||||||
delwin(statusbar->topline);
|
delwin(statusbar->topline);
|
||||||
|
|
||||||
free(ctx->log);
|
free(ctx->log);
|
||||||
free(ctx->hst);
|
|
||||||
free(ctx);
|
free(ctx);
|
||||||
free(self->help);
|
free(self->help);
|
||||||
free(statusbar);
|
free(statusbar);
|
||||||
|
27
src/toxic.c
27
src/toxic.c
@ -53,6 +53,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "notify.h"
|
#include "notify.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
#include "message_queue.h"
|
||||||
|
|
||||||
#ifdef _AUDIO
|
#ifdef _AUDIO
|
||||||
#include "audio_call.h"
|
#include "audio_call.h"
|
||||||
@ -74,6 +75,7 @@ ToxWindow *prompt = NULL;
|
|||||||
#define AUTOSAVE_FREQ 60
|
#define AUTOSAVE_FREQ 60
|
||||||
|
|
||||||
struct _Winthread Winthread;
|
struct _Winthread Winthread;
|
||||||
|
struct _cqueue_thread cqueue_thread;
|
||||||
struct arg_opts arg_opts;
|
struct arg_opts arg_opts;
|
||||||
struct user_settings *user_settings_ = NULL;
|
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)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: toxic [OPTION] [FILE ...]\n");
|
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)
|
if (pthread_create(&Winthread.tid, NULL, thread_winref, (void *) m) != 0)
|
||||||
exit_toxic_err("failed in main", FATALERR_THREAD_CREATE);
|
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
|
#ifdef _AUDIO
|
||||||
|
|
||||||
av = init_audio(prompt, m);
|
av = init_audio(prompt, m);
|
||||||
|
|
||||||
|
|
||||||
set_primary_device(input, user_settings_->audio_in_dev);
|
set_primary_device(input, user_settings_->audio_in_dev);
|
||||||
set_primary_device(output, user_settings_->audio_out_dev);
|
set_primary_device(output, user_settings_->audio_out_dev);
|
||||||
|
|
||||||
|
@ -71,6 +71,10 @@ struct _Winthread {
|
|||||||
bool flag_resize;
|
bool flag_resize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _cqueue_thread {
|
||||||
|
pthread_t tid;
|
||||||
|
};
|
||||||
|
|
||||||
struct arg_opts {
|
struct arg_opts {
|
||||||
int ignore_data_file;
|
int ignore_data_file;
|
||||||
int use_ipv4;
|
int use_ipv4;
|
||||||
@ -208,6 +212,7 @@ struct ChatContext {
|
|||||||
|
|
||||||
struct history *hst;
|
struct history *hst;
|
||||||
struct chatlog *log;
|
struct chatlog *log;
|
||||||
|
struct chat_queue *cqueue;
|
||||||
|
|
||||||
#ifdef _AUDIO
|
#ifdef _AUDIO
|
||||||
struct infobox infobox;
|
struct infobox infobox;
|
||||||
|
Loading…
Reference in New Issue
Block a user