Beispiel #1
0
/* Get the current local time */
struct tm *get_time(void)
{
    struct tm *timeinfo;
    uint64_t t = get_unix_time();
    timeinfo = localtime((const time_t*) &t);
    return timeinfo;
}
Beispiel #2
0
static void send_file_data(ToxWindow *self, Tox *m, int i, int32_t friendnum, int filenum, const char *filename)
{
    FILE *fp = file_senders[i].file;

    while (true) {
        if (tox_file_send_data(m, friendnum, filenum, (uint8_t *) file_senders[i].nextpiece,
                               file_senders[i].piecelen) == -1)
            return;

        uint64_t curtime = get_unix_time();
        file_senders[i].timestamp = curtime;
        file_senders[i].bps += file_senders[i].piecelen;            
        file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
                                         tox_file_data_size(m, friendnum), fp);

        double remain = (double) tox_file_data_remaining(m, friendnum, filenum, 0);

        /* refresh line with percentage complete and transfer speed (must be called once per second) */
        if (timed_out(file_senders[i].last_progress, curtime, 1) || (!remain && !file_senders[i].finished)) {
            file_senders[i].last_progress = curtime;
            double pct_done = remain > 0 ? (1 - (remain / file_senders[i].size)) * 100 : 100;
            print_progress_bar(self, i, -1, pct_done);
            file_senders[i].bps = 0;
        }

        /* file sender is closed in chat_onFileControl callback after receiving reply */
        if (file_senders[i].piecelen == 0 && !file_senders[i].finished) {
            tox_file_send_control(m, friendnum, 0, filenum, TOX_FILECONTROL_FINISHED, 0, 0);
            file_senders[i].finished = true;
        }
    }
}
Beispiel #3
0
/* Waits GROUP_EVENT_WAIT seconds for a new peer to set their name before announcing them */
void *group_add_wait(void *data)
{
    struct group_add_thrd *thrd = (struct group_add_thrd *) data;
    ToxWindow *self = thrd->self;
    Tox *m = thrd->m;
    char peername[TOX_MAX_NAME_LENGTH];

    /* keep polling for a name that differs from the default until we run out of time */
    while (true) {
        usleep(100000);

        pthread_mutex_lock(&Winthread.lock);
        get_group_nick_truncate(m, peername, thrd->peernum, thrd->groupnum);

        if (strcmp(peername, DEFAULT_TOX_NAME) || timed_out(thrd->timestamp, get_unix_time(), GROUP_EVENT_WAIT)) {
            pthread_mutex_unlock(&Winthread.lock);
            break;
        }

        pthread_mutex_unlock(&Winthread.lock);
    }

    const char *event = "has joined the room";
    char timefrmt[TIME_STR_SIZE];
    get_time_str(timefrmt, sizeof(timefrmt));

    pthread_mutex_lock(&Winthread.lock);
    line_info_add(self, timefrmt, (char *) peername, NULL, CONNECTION, 0, GREEN, event);
    write_to_log(event, (char *) peername, self->chatwin->log, true);
    pthread_mutex_unlock(&Winthread.lock);

    pthread_attr_destroy(&thrd->attr);
    free(thrd);
    pthread_exit(NULL);
}
Beispiel #4
0
void write_to_log(const char *msg, const char *name, struct chatlog *log, bool event)
{
    if (!log->log_on)
        return;

    if (log->file == NULL) {
        log->log_on = false;
        return;
    }

    char name_frmt[TOXIC_MAX_NAME_LENGTH + 3];

    if (event)
        snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
    else
        snprintf(name_frmt, sizeof(name_frmt), "%s:", name);

    const char *t = user_settings->log_timestamp_format;
    char s[MAX_STR_SIZE];
    strftime(s, MAX_STR_SIZE, t, get_time());
    fprintf(log->file, "%s %s %s\n", s, name_frmt, msg);

    if (timed_out(log->lastwrite, LOG_FLUSH_LIMIT)) {
        fflush(log->file);
        log->lastwrite = get_unix_time();
    }
}
Beispiel #5
0
static void groupchat_onGroupTitleChange(ToxWindow *self, Tox *m, int groupnum, int peernum, const char *title,
                                         uint8_t length)
{
    ChatContext *ctx = self->chatwin;

    if (self->num != groupnum)
        return;

    set_window_title(self, 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(groupchats[self->num].start_time, get_unix_time(), GROUP_EVENT_WAIT))
        return;

    char nick[TOX_MAX_NAME_LENGTH];
    get_group_nick_truncate(m, nick, peernum, groupnum);
    line_info_add(self, timefrmt, nick, NULL, NAME_CHANGE, 0, 0, " set the group title to: %s", title);

    char tmp_event[MAX_STR_SIZE];
    snprintf(tmp_event, sizeof(tmp_event), "set title to %s", title);
    write_to_log(tmp_event, nick, ctx->log, true);
}
Beispiel #6
0
void write_to_log(const uint8_t *msg, uint8_t *name, struct chatlog *log, bool event)
{
    if (!log->log_on)
        return;

    if (log->file == NULL) {
        log->log_on = false;
        return;
    }

    uint8_t name_frmt[TOXIC_MAX_NAME_LENGTH + 3];

    if (event)
        snprintf(name_frmt, sizeof(name_frmt), "* %s", name);
    else
        snprintf(name_frmt, sizeof(name_frmt), "%s:", name);

    uint8_t s[MAX_STR_SIZE];
    strftime(s, MAX_STR_SIZE, "%Y/%m/%d [%H:%M:%S]", get_time());
    fprintf(log->file,"%s %s %s\n", s, name_frmt, msg);

    uint64_t curtime = get_unix_time();

    if (timed_out(log->lastwrite, curtime, LOG_FLUSH_LIMIT)) {
        fflush(log->file);
        log->lastwrite = curtime;
    }
}
Beispiel #7
0
static void do_connection(Tox *m, ToxWindow *prompt)
{
    char msg[MAX_STR_SIZE] = {0};

    static int conn_err = 0;
    static bool was_connected = false;
    static uint64_t last_conn_try = 0;
    uint64_t curtime = get_unix_time();
    bool is_connected = tox_isconnected(m);

    if (was_connected && is_connected)
        return;

    if (!was_connected && is_connected) {
        was_connected = true;
        prompt_update_connectionstatus(prompt, was_connected);
        snprintf(msg, sizeof(msg), "DHT connected.");
    } else if (was_connected && !is_connected) {
        was_connected = false;
        prompt_update_connectionstatus(prompt, was_connected);
        snprintf(msg, sizeof(msg), "DHT disconnected. Attempting to reconnect.");
    } else if (!was_connected && !is_connected && timed_out(last_conn_try, curtime, TRY_CONNECT)) {
        /* if autoconnect has already failed there's no point in trying again */
        if (conn_err == 0) {
            last_conn_try = curtime;

            if ((conn_err = init_connection(m)) != 0)
                snprintf(msg, sizeof(msg), "Auto-connect failed with error code %d", conn_err);
        }
    }

    if (msg[0])
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
}
Beispiel #8
0
static void chat_onFileData(ToxWindow *self, Tox *m, int32_t num, uint8_t filenum, const char *data,
                            uint16_t length)
{
    if (self->num != num)
        return;

    FILE *fp = friends[num].file_receiver.files[filenum];

    if (fp) {
        if (fwrite(data, length, 1, fp) != 1) {
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, RED, " * Error writing to file.");
            tox_file_send_control(m, num, 1, filenum, TOX_FILECONTROL_KILL, 0, 0);
            chat_close_file_receiver(num, filenum);
        }
    }

    friends[num].file_receiver.bps[filenum] += length;
    double remain = (double) tox_file_data_remaining(m, num, filenum, 1);
    uint64_t curtime = get_unix_time();

    /* refresh line with percentage complete and transfer speed (must be called once per second) */
    if (!remain || timed_out(friends[num].file_receiver.last_progress[filenum], curtime, 1)) {
        friends[num].file_receiver.last_progress[filenum] = curtime;
        uint64_t size = friends[num].file_receiver.size[filenum];
        double pct_remain = remain > 0 ? (1 - (remain / size)) * 100 : 100;
        print_progress_bar(self, filenum, num, pct_remain);
        friends[num].file_receiver.bps[filenum] = 0;
    }
}
Beispiel #9
0
/**
 * @brief UNIX time shiznazzlage. */
static char *scrob_utime(char *dst, size_t sz)
{
        unsigned long int utime;

        utime = get_unix_time();
        snprintf(dst, sz, "%lu", utime);

        return dst;
}
Beispiel #10
0
int box_notify(ToxWindow* self, Notification notif, uint64_t flags, int* id_indicator, const char* title, const char* format, ...)
{
    if (notifications_are_disabled(flags)) {
        tab_notify(self, flags);
        return -1;
    }

#ifdef BOX_NOTIFY

    int id = sound_notify(self, notif, flags, id_indicator);

    control_lock();

#ifdef SOUND_NOTIFY
    if (id == -1) { /* Could not play */

        for (id = 0; id < ACTIVE_NOTIFS_MAX && actives[id].active; id ++);
        if ( id == ACTIVE_NOTIFS_MAX ) {
            control_unlock();
            return -1; /* Full */
        }

        actives[id].active = 1;
        actives[id].id_indicator = id_indicator;
        if (id_indicator) *id_indicator = id;
    }
#else
    if (id == -1)
        return -1;
#endif    /* SOUND_NOTIFY */

    snprintf(actives[id].title, sizeof(actives[id].title), "%s", title);
    if (strlen(title) > 23) strcpy(actives[id].title + 20, "...");

    va_list __ARGS__; va_start (__ARGS__, format);
    vsnprintf (actives[id].messages[0], MAX_BOX_MSG_LEN, format, __ARGS__);
    va_end (__ARGS__);

    if (strlen(actives[id].messages[0]) > MAX_BOX_MSG_LEN - 3)
        strcpy(actives[id].messages[0] + MAX_BOX_MSG_LEN - 3, "...");

    actives[id].box = notify_notification_new(actives[id].title, actives[id].messages[0], NULL);
    actives[id].size++;
    actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;

    notify_notification_set_timeout(actives[id].box, Control.notif_timeout);
    notify_notification_set_app_name(actives[id].box, "toxic");
    /*notify_notification_add_action(actives[id].box, "lel", "default", m_notify_action, self, NULL);*/
    notify_notification_show(actives[id].box, NULL);

    control_unlock();
    return id;
#else
    return sound_notify(self, notif, flags, id_indicator);
#endif   /* BOX_NOTIFY */
}
Beispiel #11
0
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, int32_t num, uint8_t status)
{
    if (num >= Friends.max_idx)
        return;

    Friends.list[num].online = status;
    update_friend_last_online(num, get_unix_time());
    store_data(m, DATA_FILE);
    sort_friendlist_index();
}
Beispiel #12
0
/* Opens primary device. Returns true on succe*/
void m_open_device()
{
    last_opened_update = get_unix_time();

    if (device_opened) return;

    /* Blah error check */
    open_primary_device(output, &Control.device_idx, 48000, 20, 1);

    device_opened = true;
}
Beispiel #13
0
static bool notifications_are_disabled(uint64_t flags)
{
    if (user_settings->alerts != ALERTS_ENABLED)
        return true;

    bool res = (flags & NT_RESTOL) && (Control.cooldown > get_unix_time());
#ifdef X11
    return res || ((flags & NT_NOFOCUS) && is_focused());
#else
    return res;
#endif
}
Beispiel #14
0
/* update infobox info and draw in respective chat window */
static void draw_infobox(ToxWindow *self)
{
    struct infobox *infobox = &self->chatwin->infobox;

    if (infobox->win == NULL)
        return;

    int x2, y2;
    getmaxyx(self->window, y2, x2);

    if (x2 < INFOBOX_WIDTH || y2 < INFOBOX_HEIGHT)
        return;

    uint64_t curtime = get_unix_time();

    /* update elapsed time string once per second */
    if (curtime > infobox->lastupdate)
        get_elapsed_time_str(infobox->timestr, sizeof(infobox->timestr), curtime - infobox->starttime);

    infobox->lastupdate = curtime;

    const char *in_is_muted = infobox->in_is_muted ? "yes" : "no";
    const char *out_is_muted = infobox->out_is_muted ? "yes" : "no";

    wmove(infobox->win, 1, 1);
    wattron(infobox->win, COLOR_PAIR(RED) | A_BOLD);
    wprintw(infobox->win, "    Call Active\n");
    wattroff(infobox->win, COLOR_PAIR(RED) | A_BOLD);

    wattron(infobox->win, A_BOLD);
    wprintw(infobox->win, " Duration: ");
    wattroff(infobox->win, A_BOLD);
    wprintw(infobox->win, "%s\n", infobox->timestr);

    wattron(infobox->win, A_BOLD);
    wprintw(infobox->win, " In muted: ");
    wattroff(infobox->win, A_BOLD);
    wprintw(infobox->win, "%s\n", in_is_muted);

    wattron(infobox->win, A_BOLD);
    wprintw(infobox->win, " Out muted: ");
    wattroff(infobox->win, A_BOLD);
    wprintw(infobox->win, "%s\n", out_is_muted);

    wattron(infobox->win, A_BOLD);
    wprintw(infobox->win, " VAD level: ");
    wattroff(infobox->win, A_BOLD);
    wprintw(infobox->win, "%.2f\n", infobox->vad_lvl);

    wborder(infobox->win, ACS_VLINE, ' ', ACS_HLINE, ACS_HLINE, ACS_TTEE, ' ', ACS_LLCORNER, ' ');
    wrefresh(infobox->win);
}
Beispiel #15
0
int box_notify2(ToxWindow* self, Notification notif, uint64_t flags, int id, const char* format, ...)
{
    if (notifications_are_disabled(flags)) {
        tab_notify(self, flags);
        return -1;
    }

#ifdef BOX_NOTIFY

    if (sound_notify2(self, notif, flags, id) == -1)
        return -1;

    control_lock();

    if (!actives[id].box || actives[id].size >= MAX_BOX_MSG_LEN + 1) {
        control_unlock();
        return -1;
    }

    va_list __ARGS__; va_start (__ARGS__, format);
    vsnprintf (actives[id].messages[actives[id].size], MAX_BOX_MSG_LEN, format, __ARGS__);
    va_end (__ARGS__);

    if (strlen(actives[id].messages[actives[id].size]) > MAX_BOX_MSG_LEN - 3)
        strcpy(actives[id].messages[actives[id].size] + MAX_BOX_MSG_LEN - 3, "...");

    actives[id].size++;
    actives[id].n_timeout = get_unix_time() + Control.notif_timeout / 1000;

    char formated[128 * 129] = {'\0'};

    int i = 0;
    for (; i <actives[id].size; i ++) {
        strcat(formated, actives[id].messages[i]);
        strcat(formated, "\n");
    }

    formated[strlen(formated) - 1] = '\0';

    notify_notification_update(actives[id].box, actives[id].title, formated, NULL);
    notify_notification_show(actives[id].box, NULL);

    control_unlock();

    return id;
#else
    return sound_notify2(self, notif, flags, id);
#endif
}
Beispiel #16
0
static void init_infobox(ToxWindow *self)
{
    ChatContext *ctx = self->chatwin;

    int x2, y2;
    getmaxyx(self->window, y2, x2);
    (void) y2;

    memset(&ctx->infobox, 0, sizeof(struct infobox));

    ctx->infobox.win = newwin(INFOBOX_HEIGHT, INFOBOX_WIDTH + 1, 1, x2 - INFOBOX_WIDTH);
    ctx->infobox.starttime = get_unix_time();
    ctx->infobox.vad_lvl = user_settings_->VAD_treshold;
    ctx->infobox.active = true;
    strcpy(ctx->infobox.timestr, "00");
}
Beispiel #17
0
static void refresh_progress_helper(ToxWindow *self, Tox *m, struct FileTransfer *ft)
{
    if (ft->state == FILE_TRANSFER_INACTIVE)
        return;

    /* Timeout must be set to 1 second to show correct bytes per second */
    if (!timed_out(ft->last_line_progress, 1))
        return;

    double remain = ft->file_size - ft->position;
    double pct_done = remain > 0 ? (1 - (remain / ft->file_size)) * 100 : 100;
    print_progress_bar(self, ft->bps, pct_done, ft->line_id);

    ft->bps = 0;
    ft->last_line_progress = get_unix_time();
}
Beispiel #18
0
int init_groupchat_win(ToxWindow *prompt, Tox *m, int groupnum, uint8_t type)
{
    if (groupnum > MAX_GROUPCHAT_NUM)
        return -1;

    ToxWindow self = new_group_chat(m, groupnum);
    int i;

    for (i = 0; i <= max_groupchat_index; ++i) {
        if (!groupchats[i].active) {
            groupchats[i].chatwin = add_window(m, self);
            groupchats[i].active = true;
            groupchats[i].num_peers = 0;
            groupchats[i].type = type;
            groupchats[i].start_time = get_unix_time();

            groupchats[i].peer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
            groupchats[i].oldpeer_names = malloc(sizeof(uint8_t) * TOX_MAX_NAME_LENGTH);
            groupchats[i].peer_name_lengths = malloc(sizeof(uint16_t));
            groupchats[i].oldpeer_name_lengths = malloc(sizeof(uint16_t));

            if (groupchats[i].peer_names == NULL || groupchats[i].oldpeer_names == NULL
                || groupchats[i].peer_name_lengths == NULL || groupchats[i].oldpeer_name_lengths == NULL)
                exit_toxic_err("failed in init_groupchat_win", FATALERR_MEMORY);

            memcpy(&groupchats[i].oldpeer_names[0], UNKNOWN_NAME, sizeof(UNKNOWN_NAME));
            groupchats[i].oldpeer_name_lengths[0] = (uint16_t) strlen(UNKNOWN_NAME);

#ifdef AUDIO
            if (type == TOX_GROUPCHAT_TYPE_AV) {
                if (group_audio_open_out_device(i) != 0)
                    fprintf(stderr, "audio failed\n");
            }
#endif /* AUDIO */

            set_active_window(groupchats[i].chatwin);

            if (i == max_groupchat_index)
                ++max_groupchat_index;

            return 0;
        }
    }

    return -1;
}
Beispiel #19
0
static void friendlist_onConnectionChange(ToxWindow *self, Tox *m, uint32_t num, TOX_CONNECTION connection_status)
{
    if (num >= Friends.max_idx)
        return;

    if (connection_status == TOX_CONNECTION_NONE) {
        --Friends.num_online;
    } else if (Friends.list[num].connection_status == TOX_CONNECTION_NONE) {
        ++Friends.num_online;

        if (avatar_send(m, num) == -1)
            fprintf(stderr, "avatar_send failed for friend %d\n", num);
    }

    Friends.list[num].connection_status = connection_status;
    update_friend_last_online(num, get_unix_time());
    store_data(m, DATA_FILE);
    sort_friendlist_index();
}
Beispiel #20
0
static void do_bootstrap(Tox *m)
{
    static int conn_err = 0;

    if (!timed_out(last_bootstrap_time, TRY_BOOTSTRAP_INTERVAL))
        return;

    if (tox_self_get_connection_status(m) != TOX_CONNECTION_NONE)
        return;

    if (conn_err != 0)
        return;

    last_bootstrap_time = get_unix_time();
    conn_err = init_connection(m);

    if (conn_err != 0)
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Auto-connect failed with error code %d", conn_err);
}
Beispiel #21
0
void do_file_senders(Tox *m)
{
    int i;

    for (i = 0; i < max_file_senders_index; ++i) {
        if (!file_senders[i].active)
            continue;

        if (file_senders[i].queue_pos > 0) {
            --file_senders[i].queue_pos;
            continue;
        }

        ToxWindow *self = file_senders[i].toxwin;
        char *filename = file_senders[i].filename;
        int filenum = file_senders[i].filenum;
        int32_t friendnum = file_senders[i].friendnum;

        /* kill file transfer if chatwindow is closed */
        if (self->chatwin == NULL) {
            close_file_sender(self, m, i, NULL, TOX_FILECONTROL_KILL, filenum, friendnum);
            continue;
        }

        /* If file transfer has timed out kill transfer and send kill control */
        if (timed_out(file_senders[i].timestamp, get_unix_time(), TIMEOUT_FILESENDER)) {
            char msg[MAX_STR_SIZE];
            snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", filename);
            close_file_sender(self, m, i, msg, TOX_FILECONTROL_KILL, filenum, friendnum);
            sound_notify(self, error, NT_NOFOCUS | NT_WNDALERT_2, NULL);
            
            if (self->active_box != -1)
                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;
        }

        send_file_data(self, m, i, friendnum, filenum, filename);
        file_senders[i].queue_pos = num_active_file_senders - 1;
    }
}
Beispiel #22
0
void start_observation(char* keyword, u8 field_cnt, u8 to_srv,
                       struct packet_flow* f) {

    if (obs_fields) printf("\n FATAL: Premature end of observation.");

    if (!daemon_mode) {

        SAYF(".-[ %s/%u -> ", addr_to_str(f->client->addr, f->client->ip_ver),
             f->cli_port);
        SAYF("%s/%u (%s) ]-\n|\n", addr_to_str(f->server->addr, f->client->ip_ver),
             f->srv_port, keyword);

        SAYF("| %-8s = %s/%u\n", to_srv ? "client" : "server",
             addr_to_str(to_srv ? f->client->addr :
                         f->server->addr, f->client->ip_ver),
             to_srv ? f->cli_port : f->srv_port);

    }

    if (log_file) {

        u8 tmp[64];

        time_t ut = get_unix_time();
        struct tm* lt = localtime(&ut);

        strftime((char*)tmp, 64, "%Y/%m/%d %H:%M:%S", lt);

        LOGF("[%s] mod=%s|cli=%s/%u|",tmp, keyword, addr_to_str(f->client->addr,
                f->client->ip_ver), f->cli_port);

        LOGF("srv=%s/%u|subj=%s", addr_to_str(f->server->addr, f->server->ip_ver),
             f->srv_port, to_srv ? "cli" : "srv");

    }

    obs_fields = field_cnt;

}
Beispiel #23
0
/* Returns a pointer to an unused file receiver.
 * Returns NULL if all file receivers are in use.
 */
static struct FileTransfer *new_file_receiver(ToxWindow *window, uint32_t friendnum, uint32_t filenum, uint8_t type)
{
    size_t i;

    for (i = 0; i < MAX_FILES; ++i) {
        struct FileTransfer *ft = &Friends.list[friendnum].file_receiver[i];

        if (ft->state == FILE_TRANSFER_INACTIVE) {
            memset(ft, 0, sizeof(struct FileTransfer));
            ft->window = window;
            ft->index = i;
            ft->friendnum = friendnum;
            ft->filenum = filenum;
            ft->file_type = type;
            ft->last_keep_alive = get_unix_time();
            ft->state = FILE_TRANSFER_PENDING;
            ft->direction = FILE_TRANSFER_RECV;
            return ft;
        }
    }

    return NULL;
}
Beispiel #24
0
void check_file_transfer_timeouts(Tox *m)
{
    char msg[MAX_STR_SIZE];
    static uint64_t last_check = 0;

    if (!timed_out(last_check, CHECK_FILE_TIMEOUT_INTERAVAL))
        return;

    last_check = get_unix_time();

    size_t i, j;

    for (i = 0; i < Friends.max_idx; ++i) {
        if (!Friends.list[i].active)
            continue;

        for (j = 0; j < MAX_FILES; ++j) {
            struct FileTransfer *ft_send = &Friends.list[i].file_sender[j];

            if (ft_send->state > FILE_TRANSFER_PAUSED) {
                if (timed_out(ft_send->last_keep_alive, TIMEOUT_FILESENDER)) {
                    snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_send->file_name);
                    close_file_transfer(ft_send->window, m, ft_send, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
                }
            }

            struct FileTransfer *ft_recv = &Friends.list[i].file_receiver[j];

            if (ft_recv->state > FILE_TRANSFER_PAUSED) {
                if (timed_out(ft_recv->last_keep_alive, TIMEOUT_FILESENDER)) {
                    snprintf(msg, sizeof(msg), "File transfer for '%s' timed out.", ft_recv->file_name);
                    close_file_transfer(ft_recv->window, m, ft_recv, TOX_FILE_CONTROL_CANCEL, msg, notif_error);
                }
            }
        }
    }
}
Beispiel #25
0
int main(int argc, char *argv[])
{
    char *user_config_dir = get_user_config_dir();
    int config_err = 0;

    parse_args(argc, argv);

    /* Make sure all written files are read/writeable only by the current user. */
    umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);

    signal(SIGINT, catch_SIGINT);

    config_err = create_user_config_dir(user_config_dir);

    if (DATA_FILE == NULL ) {
        if (config_err) {
            DATA_FILE = strdup("data");

            if (DATA_FILE == NULL)
                exit_toxic_err("failed in main", FATALERR_MEMORY);
        } else {
            DATA_FILE = malloc(strlen(user_config_dir) + strlen(CONFIGDIR) + strlen("data") + 1);

            if (DATA_FILE == NULL)
                exit_toxic_err("failed in main", FATALERR_MEMORY);

            strcpy(DATA_FILE, user_config_dir);
            strcat(DATA_FILE, CONFIGDIR);
            strcat(DATA_FILE, "data");
        }
    }

    free(user_config_dir);

    /* init user_settings struct and load settings from conf file */
    user_settings_ = calloc(1, sizeof(struct user_settings));

    if (user_settings_ == NULL)
        exit_toxic_err("failed in main", FATALERR_MEMORY);

    char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
    int settings_err = settings_load(user_settings_, p);

    Tox *m = init_tox(arg_opts.use_ipv4);
    init_term();

    if (m == NULL)
        exit_toxic_err("failed in main", FATALERR_NETWORKINIT);

    if (!arg_opts.ignore_data_file)
        load_data(m, DATA_FILE);

    prompt = init_windows(m);
    prompt_init_statusbar(prompt, m);

    /* thread for ncurses stuff */
    if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
        exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);

    if (pthread_create(&Winthread.tid, NULL, thread_winref, (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);
#elif _SOUND_NOTIFY
    if ( init_devices() == de_InternalError )
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");

#endif /* _AUDIO */
    
    init_notify(60, 3000);

#ifdef _SOUND_NOTIFY
    notify(prompt, self_log_in, 0);
#endif /* _SOUND_NOTIFY */
    
    const char *msg;

    if (config_err) {
        msg = "Unable to determine configuration directory. Defaulting to 'data' for a keyfile...";
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
    }

    if (settings_err == -1) {
        msg = "Failed to load user settings";
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
    }

    sort_friendlist_index();

    uint64_t last_save = (uint64_t) time(NULL);

    while (true) {
        update_unix_time();
        do_toxic(m, prompt);
        uint64_t cur_time = get_unix_time();

        if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
            pthread_mutex_lock(&Winthread.lock);
            store_data(m, DATA_FILE);
            pthread_mutex_unlock(&Winthread.lock);

            last_save = cur_time;
        }

        usleep(40000);
    }

    return 0;
}
Beispiel #26
0
static void groupchat_onGroupNamelistChange(ToxWindow *self, Tox *m, int groupnum, int peernum, uint8_t change)
{
    if (self->num != groupnum)
        return;

    if (groupnum > max_groupchat_index)
        return;

    groupchats[groupnum].num_peers = tox_group_number_peers(m, groupnum);
    int num_peers = groupchats[groupnum].num_peers;

    if (peernum > num_peers)
        return;

    /* get old peer name before updating name list */
    uint8_t oldpeername[TOX_MAX_NAME_LENGTH];

    if (change != TOX_CHAT_CHANGE_PEER_ADD) {
        memcpy(oldpeername, &groupchats[groupnum].oldpeer_names[peernum * TOX_MAX_NAME_LENGTH],
               sizeof(oldpeername));
        uint16_t old_n_len = groupchats[groupnum].oldpeer_name_lengths[peernum];
        oldpeername[old_n_len] = '\0';
    }

    /* Update name/len lists */
    uint8_t tmp_peerlist[num_peers][TOX_MAX_NAME_LENGTH];
    uint16_t tmp_peerlens[num_peers];

    if (tox_group_get_names(m, groupnum, tmp_peerlist, tmp_peerlens, num_peers) == -1) {
        memset(tmp_peerlist, 0, sizeof(tmp_peerlist));
        memset(tmp_peerlens, 0, sizeof(tmp_peerlens));
    }

    copy_peernames(groupnum, tmp_peerlist, tmp_peerlens, num_peers);

    /* get current peername then sort namelist */
    uint8_t peername[TOX_MAX_NAME_LENGTH];

    if (change != TOX_CHAT_CHANGE_PEER_DEL) {
        uint16_t n_len = groupchats[groupnum].peer_name_lengths[peernum];
        memcpy(peername, &groupchats[groupnum].peer_names[peernum * TOX_MAX_NAME_LENGTH], sizeof(peername));
        peername[n_len] = '\0';
    }

    qsort(groupchats[groupnum].peer_names, groupchats[groupnum].num_peers, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr);

    ChatContext *ctx = self->chatwin;

    const char *event;
    char timefrmt[TIME_STR_SIZE];
    get_time_str(timefrmt, sizeof(timefrmt));

    switch (change) {
    case TOX_CHAT_CHANGE_PEER_ADD:
        if (!timed_out(groupchats[groupnum].start_time, GROUP_EVENT_WAIT))
            break;

        struct group_add_thrd *thrd = malloc(sizeof(struct group_add_thrd));
        thrd->m = m;
        thrd->peernum = peernum;
        thrd->groupnum = groupnum;
        thrd->self = self;
        thrd->timestamp = get_unix_time();

        if (pthread_attr_init(&thrd->attr) != 0) {
            free(thrd);
            return;
        }

        if (pthread_attr_setdetachstate(&thrd->attr, PTHREAD_CREATE_DETACHED) != 0) {
            pthread_attr_destroy(&thrd->attr);
            free(thrd);
            return;
        }

        if (pthread_create(&thrd->tid, &thrd->attr, group_add_wait, (void *) thrd) != 0) {
            pthread_attr_destroy(&thrd->attr);
            free(thrd);
            return;
        }

        break;

    case TOX_CHAT_CHANGE_PEER_DEL:
        event = "has left the room";
        line_info_add(self, timefrmt, (char *) oldpeername, NULL, DISCONNECTION, 0, RED, event);

        if (groupchats[self->num].side_pos > 0)
            --groupchats[self->num].side_pos;

        write_to_log(event, (char *) oldpeername, ctx->log, true);
        break;

    case TOX_CHAT_CHANGE_PEER_NAME:
        if (!timed_out(groupchats[self->num].start_time, GROUP_EVENT_WAIT))
            return;

        /* ignore initial name change (TODO: this is a bad way to do this) */
        if (strcmp((char *) oldpeername, DEFAULT_TOX_NAME) == 0)
            return;

        event = " is now known as ";
        line_info_add(self, timefrmt, (char *) oldpeername, (char *) peername, NAME_CHANGE, 0, 0, event);

        char tmp_event[TOXIC_MAX_NAME_LENGTH * 2 + 32];
        snprintf(tmp_event, sizeof(tmp_event), "is now known as %s", (char *) peername);
        write_to_log(tmp_event, (char *) oldpeername, ctx->log, true);
        break;
    }

    sound_notify(self, silent, NT_WNDALERT_2, NULL);
}
Beispiel #27
0
void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
{
    if (max_file_senders_index >= (MAX_FILES - 1)) {
        const char *errmsg = "Please wait for some of your outgoing file transfers to complete.";
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg);
        return;
    }

    if (argc < 1) {
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path required.");
        return;
    }

    if (argv[1][0] != '\"') {
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes.");
        return;
    }

    /* remove opening and closing quotes */
    char path[MAX_STR_SIZE];
    snprintf(path, sizeof(path), "%s", &argv[1][1]);
    int path_len = strlen(path) - 1;
    path[path_len] = '\0';

    if (path_len >= MAX_STR_SIZE) {
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit.");
        return;
    }

    FILE *file_to_send = fopen(path, "r");

    if (file_to_send == NULL) {
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File not found.");
        return;
    }

    off_t filesize = file_size(path);

    if (filesize == -1) {
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File corrupt.");
        fclose(file_to_send);
        return;
    }

    char filename[MAX_STR_SIZE] = {0};
    get_file_name(filename, sizeof(filename), path);
    int namelen = strlen(filename);
    int filenum = tox_new_file_sender(m, self->num, filesize, (const uint8_t *) filename, namelen);

    if (filenum == -1) {
        line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Error sending file.");
        fclose(file_to_send);
        return;
    }

    int i;

    for (i = 0; i < MAX_FILES; ++i) {
        if (!file_senders[i].active) {
            memcpy(file_senders[i].filename, filename, namelen + 1);
            file_senders[i].active = true;
            file_senders[i].toxwin = self;
            file_senders[i].file = file_to_send;
            file_senders[i].filenum = filenum;
            file_senders[i].friendnum = self->num;
            file_senders[i].timestamp = get_unix_time();
            file_senders[i].size = filesize;
            file_senders[i].piecelen = fread(file_senders[i].nextpiece, 1,
                                             tox_file_data_size(m, self->num), file_to_send);

            char sizestr[32];
            bytes_convert_str(sizestr, sizeof(sizestr), filesize);
            line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, 
                          "Sending file [%d]: '%s' (%s)", filenum, filename, sizestr);

            ++num_active_file_senders;

            if (i == max_file_senders_index)
                ++max_file_senders_index;

            reset_file_sender_queue();
            return;
        }
    }
}
Beispiel #28
0
static void friendlist_onDraw(ToxWindow *self, Tox *m)
{
    curs_set(0);
    werase(self->window);
    int x2, y2;
    getmaxyx(self->window, y2, x2);

    bool fix_statuses = x2 != self->x;    /* true if window max x value has changed */

    wattron(self->window, COLOR_PAIR(CYAN));
    wprintw(self->window, " Press the");
    wattron(self->window, A_BOLD);
    wprintw(self->window, " h ");
    wattroff(self->window, A_BOLD);
    wprintw(self->window, "key for help\n\n");
    wattroff(self->window, COLOR_PAIR(CYAN));

    if (blocklist_view == 1) {
        blocklist_onDraw(self, m, y2, x2);
        return;
    }

    uint64_t cur_time = get_unix_time();
    struct tm cur_loc_tm = *localtime((const time_t *) &cur_time);

    pthread_mutex_lock(&Winthread.lock);
    int nf = tox_get_num_online_friends(m);
    pthread_mutex_unlock(&Winthread.lock);

    wattron(self->window, A_BOLD);
    wprintw(self->window, " Online: ");
    wattroff(self->window, A_BOLD);
    wprintw(self->window, "%d/%d \n\n", nf, Friends.num_friends);

    if ((y2 - FLIST_OFST) <= 0)
        return;

    int selected_num = 0;

    /* Determine which portion of friendlist to draw based on current position */
    int page = Friends.num_selected / (y2 - FLIST_OFST);
    int start = (y2 - FLIST_OFST) * page;
    int end = y2 - FLIST_OFST + start;

    int i;

    for (i = start; i < Friends.num_friends && i < end; ++i) {
        int f = Friends.index[i];
        bool f_selected = false;

        if (Friends.list[f].active) {
            if (i == Friends.num_selected) {
                wattron(self->window, A_BOLD);
                wprintw(self->window, " > ");
                wattroff(self->window, A_BOLD);
                selected_num = f;
                f_selected = true;
            } else {
                wprintw(self->window, "   ");
            }

            if (Friends.list[f].online) {
                uint8_t status = Friends.list[f].status;
                int colour = WHITE;

                switch (status) {
                    case TOX_USERSTATUS_NONE:
                        colour = GREEN;
                        break;

                    case TOX_USERSTATUS_AWAY:
                        colour = YELLOW;
                        break;

                    case TOX_USERSTATUS_BUSY:
                        colour = RED;
                        break;

                    case TOX_USERSTATUS_INVALID:
                        colour = MAGENTA;
                        break;
                }

                wattron(self->window, COLOR_PAIR(colour) | A_BOLD);
                wprintw(self->window, "%s ", ONLINE_CHAR);
                wattroff(self->window, COLOR_PAIR(colour) | A_BOLD);

                if (f_selected)
                    wattron(self->window, COLOR_PAIR(BLUE));

                wattron(self->window, A_BOLD);
                wprintw(self->window, "%s", Friends.list[f].name);
                wattroff(self->window, A_BOLD);

                if (f_selected)
                    wattroff(self->window, COLOR_PAIR(BLUE));

                /* Reset Friends.list[f].statusmsg on window resize */
                if (fix_statuses) {
                    char statusmsg[TOX_MAX_STATUSMESSAGE_LENGTH];

                    pthread_mutex_lock(&Winthread.lock);
                    int s_len = tox_get_status_message(m, Friends.list[f].num, (uint8_t *) statusmsg,
                                                       TOX_MAX_STATUSMESSAGE_LENGTH);
                    pthread_mutex_unlock(&Winthread.lock);

                    filter_str(statusmsg, s_len);
                    snprintf(Friends.list[f].statusmsg, sizeof(Friends.list[f].statusmsg), "%s", statusmsg);
                    Friends.list[f].statusmsg_len = strlen(Friends.list[f].statusmsg);
                }

                /* Truncate note if it doesn't fit on one line */
                uint16_t maxlen = x2 - getcurx(self->window) - 2;

                if (Friends.list[f].statusmsg_len > maxlen) {
                    Friends.list[f].statusmsg[maxlen - 3] = '\0';
                    strcat(Friends.list[f].statusmsg, "...");
                    Friends.list[f].statusmsg[maxlen] = '\0';
                    Friends.list[f].statusmsg_len = maxlen;
                }

                if (Friends.list[f].statusmsg[0])
                    wprintw(self->window, " %s", Friends.list[f].statusmsg);

                wprintw(self->window, "\n");
            } else {
                wprintw(self->window, "%s ", OFFLINE_CHAR);

                if (f_selected)
                    wattron(self->window, COLOR_PAIR(BLUE));

                wattron(self->window, A_BOLD);
                wprintw(self->window, "%s", Friends.list[f].name);
                wattroff(self->window, A_BOLD);

                if (f_selected)
                    wattroff(self->window, COLOR_PAIR(BLUE));

                uint64_t last_seen = Friends.list[f].last_online.last_on;

                if (last_seen != 0) {
                    int day_dist = (cur_loc_tm.tm_yday - Friends.list[f].last_online.tm.tm_yday) % 365;
                    const char *hourmin = Friends.list[f].last_online.hour_min_str;

                    switch (day_dist) {
                        case 0:
                            wprintw(self->window, " Last seen: Today %s\n", hourmin);
                            break;

                        case 1:
                            wprintw(self->window, " Last seen: Yesterday %s\n", hourmin);
                            break;

                        default:
                            wprintw(self->window, " Last seen: %d days ago\n", day_dist);
                            break;
                    }
                } else {
                    wprintw(self->window, " Last seen: Never\n");
                }
            }
        }
    }

    self->x = x2;

    if (Friends.num_friends) {
        wmove(self->window, y2 - 1, 1);

        wattron(self->window, A_BOLD);
        wprintw(self->window, "Key: ");
        wattroff(self->window, A_BOLD);

        int i;

        for (i = 0; i < TOX_CLIENT_ID_SIZE; ++i)
            wprintw(self->window, "%02X", Friends.list[selected_num].pub_key[i] & 0xff);
    }

    wrefresh(self->window);
    draw_del_popup();

    if (self->help->active)
        help_onDraw(self);
}
Beispiel #29
0
int main(int argc, char *argv[])
{
    init_signal_catchers();
    parse_args(argc, argv);

    /* Make sure all written files are read/writeable only by the current user. */
    umask(S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    int config_err = init_data_files();

    /* init user_settings struct and load settings from conf file */
    user_settings_ = calloc(1, sizeof(struct user_settings));

    if (user_settings_ == NULL)
        exit_toxic_err("failed in main", FATALERR_MEMORY);

    char *p = arg_opts.config_path[0] ? arg_opts.config_path : NULL;
    int settings_err = settings_load(user_settings_, p);

    Tox *m = init_tox();
    init_term();

    /* enable stderr for debugging */
    if (!arg_opts.debug)
        freopen("/dev/null", "w", stderr);

    if (m == NULL)
        exit_toxic_err("failed in main", FATALERR_NETWORKINIT);

    if (!arg_opts.ignore_data_file)
        load_data(m, DATA_FILE);

    prompt = init_windows(m);
    prompt_init_statusbar(prompt, m);

    /* thread for ncurses stuff */
    if (pthread_mutex_init(&Winthread.lock, NULL) != 0)
        exit_toxic_err("failed in main", FATALERR_MUTEX_INIT);

    if (pthread_create(&Winthread.tid, NULL, thread_winref, (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);
#elif _SOUND_NOTIFY
    if ( init_devices() == de_InternalError )
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to init devices");

#endif /* _AUDIO */
    
    init_notify(60, 3000);

#ifdef _SOUND_NOTIFY
//     sound_notify(prompt, self_log_in, 0, NULL);
#endif /* _SOUND_NOTIFY */
    
    const char *msg;
    
    if (config_err) {
        msg = "Unable to determine configuration directory. Defaulting to 'data' for data file...";
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
    }

    if (settings_err == -1)
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, "Failed to load user settings");

    if (arg_opts.use_proxy && !arg_opts.force_tcp) {
        msg = "* WARNING: Using a proxy without disabling UDP may leak your real IP address.";
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "%s", msg);
        msg = "  Use the -t option to disable UDP.";
        line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, RED, "%s", msg);
    }

    uint64_t last_save = (uint64_t) time(NULL);
    uint64_t looptimer = last_save;
    useconds_t msleepval = 40000;
    uint64_t loopcount = 0;

    while (true) {
        update_unix_time();
        do_toxic(m, prompt);
        uint64_t cur_time = get_unix_time();

        if (timed_out(last_save, cur_time, AUTOSAVE_FREQ)) {
            pthread_mutex_lock(&Winthread.lock);
            store_data(m, DATA_FILE);
            pthread_mutex_unlock(&Winthread.lock);

            last_save = cur_time;
        }

        msleepval = optimal_msleepval(&looptimer, &loopcount, cur_time, msleepval);
        usleep(msleepval);
    }

    return 0;
}
Beispiel #30
0
void line_info_print(ToxWindow *self)
{
    ChatContext *ctx = self->chatwin;

    if (ctx == NULL)
        return;

    struct history *hst = ctx->hst;

    /* Only allow one new item to be added to chat window per call to this function */
    line_info_check_queue(self);

    WINDOW *win = ctx->history;
    wclear(win);
    int y2, x2;
    getmaxyx(self->window, y2, x2);

    if (x2 <= SIDEBAR_WIDTH)
        return;

    if (self->is_groupchat)
        wmove(win, 0, 0);
    else
        wmove(win, 2, 0);

    struct line_info *line = hst->line_start->next;
    int numlines = 0;

    while (line && numlines++ <= y2) {
        uint8_t type = line->type;

        switch (type) {
        case OUT_MSG:
        /* fallthrough */
        case OUT_MSG_READ:
        /* fallthrough */
        case IN_MSG:
            wattron(win, COLOR_PAIR(BLUE));
            wprintw(win, "%s ", line->timestr);
            wattroff(win, COLOR_PAIR(BLUE));

            int nameclr = GREEN;

            if (line->colour)
                nameclr = line->colour;
            else if (type == IN_MSG)
                nameclr = CYAN;

            wattron(win, COLOR_PAIR(nameclr));
            wprintw(win, "%s %s: ", user_settings->line_normal, line->name1);
            wattroff(win, COLOR_PAIR(nameclr));

            if (line->msg[0] == '>')
                wattron(win, COLOR_PAIR(GREEN));

            wprintw(win, "%s", line->msg);

            if (line->msg[0] == '>')
                wattroff(win, COLOR_PAIR(GREEN));

            if (type == OUT_MSG && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
                wattron(win, COLOR_PAIR(RED));
                wprintw(win, " x", line->msg);
                wattroff(win, COLOR_PAIR(RED));

                if (line->noread_flag == false) {
                    line->noread_flag = true;
                    line->len += 2;
                }
            }

            wprintw(win, "\n", line->msg);
            break;

        case OUT_ACTION_READ:
        /* fallthrough */
        case OUT_ACTION:
        /* fallthrough */
        case IN_ACTION:
            wattron(win, COLOR_PAIR(BLUE));
            wprintw(win, "%s ", line->timestr);
            wattroff(win, COLOR_PAIR(BLUE));

            wattron(win, COLOR_PAIR(YELLOW));
            wprintw(win, "%s %s %s", user_settings->line_normal, line->name1, line->msg);
            wattroff(win, COLOR_PAIR(YELLOW));

            if (type == OUT_ACTION && timed_out(line->timestamp, get_unix_time(), NOREAD_FLAG_TIMEOUT)) {
                wattron(win, COLOR_PAIR(RED));
                wprintw(win, " x", line->msg);
                wattroff(win, COLOR_PAIR(RED));

                if (line->noread_flag == false) {
                    line->noread_flag = true;
                    line->len += 2;
                }
            }

            wprintw(win, "\n", line->msg);
            break;

        case SYS_MSG:
            if (line->timestr[0]) {
                wattron(win, COLOR_PAIR(BLUE));
                wprintw(win, "%s ", line->timestr);
                wattroff(win, COLOR_PAIR(BLUE));
            }

            if (line->bold)
                wattron(win, A_BOLD);

            if (line->colour)
                wattron(win, COLOR_PAIR(line->colour));

            wprintw(win, "%s\n", line->msg);

            if (line->bold)
                wattroff(win, A_BOLD);

            if (line->colour)
                wattroff(win, COLOR_PAIR(line->colour));

            break;

        case PROMPT:
            wattron(win, COLOR_PAIR(GREEN));
            wprintw(win, "$ ");
            wattroff(win, COLOR_PAIR(GREEN));

            if (line->msg[0])
                wprintw(win, "%s", line->msg);

            wprintw(win, "\n");
            break;

        case CONNECTION:
            wattron(win, COLOR_PAIR(BLUE));
            wprintw(win, "%s ", line->timestr);
            wattroff(win, COLOR_PAIR(BLUE));

            wattron(win, COLOR_PAIR(line->colour));
            wprintw(win, "%s ", user_settings->line_join);

            wattron(win, A_BOLD);
            wprintw(win, "%s ", line->name1);
            wattroff(win, A_BOLD);

            wprintw(win, "%s\n", line->msg);
            wattroff(win, COLOR_PAIR(line->colour));

            break;

        case DISCONNECTION:
            wattron(win, COLOR_PAIR(BLUE));
            wprintw(win, "%s ", line->timestr);
            wattroff(win, COLOR_PAIR(BLUE));

            wattron(win, COLOR_PAIR(line->colour));
            wprintw(win, "%s ", user_settings->line_quit);

            wattron(win, A_BOLD);
            wprintw(win, "%s ", line->name1);
            wattroff(win, A_BOLD);

            wprintw(win, "%s\n", line->msg);
            wattroff(win, COLOR_PAIR(line->colour));

            break;

        case NAME_CHANGE:
            wattron(win, COLOR_PAIR(BLUE));
            wprintw(win, "%s ", line->timestr);
            wattroff(win, COLOR_PAIR(BLUE));

            wattron(win, COLOR_PAIR(MAGENTA));
            wprintw(win, "%s ", user_settings->line_alert);
            wattron(win, A_BOLD);
            wprintw(win, "%s", line->name1);
            wattroff(win, A_BOLD);

            wprintw(win, "%s", line->msg);

            wattron(win, A_BOLD);
            wprintw(win, "%s\n", line->name2);
            wattroff(win, A_BOLD);
            wattroff(win, COLOR_PAIR(MAGENTA));

            break;
        }

        line = line->next;
    }

    /* keep calling until queue is empty */
    if (hst->queue_sz > 0)
        line_info_print(self);
}