Esempio n. 1
0
static void
user_request_fd_writable(DCUserConn *uc)
{
    int res;

    res = msgq_write(uc->put_mq);
    if (res == 0 || (res < 0 && errno != EAGAIN)) {
        warn_socket_error(res, true, _("user process %s"), quote(uc->name));
        user_disconnect(uc); /* MSG: socket error above */
        return;
    }
    if (!msgq_has_partial_msg(uc->put_mq))
        FD_CLR(uc->put_mq->fd, &write_fds);
}
Esempio n. 2
0
static void
user_result_fd_readable(DCUserConn *uc)
{
    int res;

    res = msgq_read(uc->get_mq);
    if (res == 0 || (res < 0 && errno != EAGAIN)) {
        warn_socket_error(res, false, _("user process %s"), quote(uc->name));
        user_disconnect(uc); /* MSG: socket error above */
        return;
    }
    while (msgq_has_complete_msg(uc->get_mq)) {
        int id;

        msgq_peek(uc->get_mq, MSGQ_INT, &id, MSGQ_END);
        switch (id) {
        case DC_MSG_SCREEN_PUT: {
            char *msg;
            uint32_t flag;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_INT32, &flag, MSGQ_STR, &msg, MSGQ_END);
            flag_putf((DCDisplayFlag)flag, _("User %s: %s"), quotearg(uc->name), msg); /* msg already quoted */
            free(msg);
            break;
        }
        case DC_MSG_WANT_DOWNLOAD: {
            bool reply;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_END);
            reply = !has_user_conn(uc->info, DC_DIR_RECEIVE)
                    && (uc->queue_pos < uc->info->download_queue->cur);
            msgq_put(uc->put_mq, MSGQ_BOOL, reply, MSGQ_END);
            FD_SET(uc->put_mq->fd, &write_fds);
            break;
        }
        case DC_MSG_VALIDATE_DIR: {
            DCTransferDirection dir;
            bool reply;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_INT, &dir, MSGQ_END);
            reply = validate_direction(uc, dir);
            msgq_put(uc->put_mq, MSGQ_BOOL, reply, MSGQ_END);
            FD_SET(uc->put_mq->fd, &write_fds);
            break;
        }
        case DC_MSG_VALIDATE_NICK: {
            char *nick;
            bool reply;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_STR, &nick, MSGQ_END);
            reply = validate_nick(uc, nick);
            free(nick);
            if (uc->info != NULL) {
                /* The user can only be DC_ACTIVE_SENT_PASSIVE if we are passive.
                 * So if we managed to connect to them even though we were passive,
                 * they must be active.
                 */
                if (uc->info->active_state == DC_ACTIVE_SENT_PASSIVE)
                    uc->info->active_state = DC_ACTIVE_KNOWN_ACTIVE;
                /* The user can only be DC_ACTIVE_SENT_ACTIVE if we are active.
                 * We must set to DC_ACTIVE_UNKNOWN because otherwise
                 * hub.c:hub_connect_user might say "ConnectToMe already sent to
                 * user" next time we're trying to connect to them.
                 */
                if (uc->info->active_state == DC_ACTIVE_SENT_ACTIVE)
                    uc->info->active_state = DC_ACTIVE_UNKNOWN;
            }
            msgq_put(uc->put_mq, MSGQ_BOOL, reply, MSGQ_END);
            FD_SET(uc->put_mq->fd, &write_fds);
            break;
        }
        case DC_MSG_GET_MY_NICK:
            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_END);
            msgq_put(uc->put_mq, MSGQ_STR, my_nick, MSGQ_END);
            FD_SET(uc->put_mq->fd, &write_fds);
            break;
        case DC_MSG_TRANSFER_STATUS:
            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_INT64, &uc->transfer_pos, MSGQ_END);
            break;
        case DC_MSG_TRANSFER_START: {
            char *share_filename, *local_filename;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_STR, &local_filename, MSGQ_STR, &share_filename, MSGQ_INT64
                , &uc->transfer_start, MSGQ_INT64, &uc->transfer_total, MSGQ_END);
            if (uc->transfer_start != 0) {
                flag_putf(DC_DF_CONNECTIONS, _("%s: Starting %s of %s (%" PRIu64 " of %" PRIu64 " %s).\n"),
                          quotearg_n(0, uc->info->nick),
                          uc->dir == DC_DIR_SEND ? _("upload") : _("download"),
                          quote_n(1, base_name(share_filename)),
                          uc->transfer_total - uc->transfer_start,
                          uc->transfer_total,
                          ngettext("byte", "bytes", uc->transfer_total));
            } else {
                flag_putf(DC_DF_CONNECTIONS, _("%s: Starting %s of %s (%" PRIu64 " %s).\n"),
                          quotearg_n(0, uc->info->nick),
                          uc->dir == DC_DIR_SEND ? _("upload") : _("download"),
                          quote_n(1, base_name(share_filename)),
                          uc->transfer_total,
                          ngettext("byte", "bytes", uc->transfer_total));
            }
            free(uc->transfer_file);
            uc->transfer_file = share_filename;
            free(uc->local_file);
            uc->local_file = local_filename;
            uc->transferring = true;
            uc->transfer_pos = uc->transfer_start;
            uc->transfer_time = time(NULL);
            if (uc->transfer_time == (time_t) -1)
                warn(_("Cannot get current time - %s\n"), errstr);
            break;
        }
        case DC_MSG_CHECK_DOWNLOAD:
            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_END);
            for (; uc->queue_pos < uc->info->download_queue->cur; uc->queue_pos++) {
                DCQueuedFile *queued;
                char *local_file;

                queued = (DCQueuedFile*) uc->info->download_queue->buf[uc->queue_pos];
                if (queued->status != DC_QS_DONE) {
                    local_file = resolve_download_file(uc->info, queued);
                    uc->queued_valid = true;
                    uc->transfer_file = xstrdup(queued->filename);
                    uc->local_file = xstrdup(local_file);
                    uc->occupied_slot = true;
                    queued->status = DC_QS_PROCESSING;
                    used_dl_slots++;
                    msgq_put(uc->put_mq, MSGQ_STR, local_file, MSGQ_STR, uc->transfer_file, MSGQ_INT64, queued->length, MSGQ_INT, queued->flag, MSGQ_END);
                    FD_SET(uc->put_mq->fd, &write_fds);
                    free(local_file);
                    return;
                }
            }
            msgq_put(uc->put_mq, MSGQ_STR, NULL, MSGQ_STR, NULL, MSGQ_INT64, (uint64_t) 0, MSGQ_INT, DC_TF_NORMAL, MSGQ_END);
            FD_SET(uc->put_mq->fd, &write_fds);
            break;
        case DC_MSG_DOWNLOAD_ENDED: {
            bool success;
            char *reason;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_BOOL, &success, MSGQ_STR, &reason, MSGQ_END);
            handle_ended_download(uc, success, reason);
            free(reason);
            break;
        }
        case DC_MSG_CHECK_UPLOAD: {
            char *remote_file;
            char *local_file;
            int type;
            uint64_t size = 0;
            DCTransferFlag flag = DC_TF_NORMAL;
            bool permit_transfer = false;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_INT, &type, MSGQ_STR, &remote_file, MSGQ_END);
            local_file = (char*) resolve_upload_file(uc->info, (DCAdcgetType) type, remote_file, &flag, &size);
            free(remote_file);
            uc->transfer_file = NULL;
            if (local_file != NULL) {
                if (flag == DC_TF_LIST || (flag == DC_TF_NORMAL && size <= minislot_size)) {
                    if (used_mini_slots < minislot_count) {
                        used_mini_slots ++;
                        uc->occupied_minislot = true;
                        permit_transfer = true;
                    } else if (used_ul_slots < my_ul_slots || uc->info->slot_granted) {
                        used_ul_slots ++;
                        uc->occupied_slot = true;
                        permit_transfer = true;
                    }
                } else if (flag == DC_TF_NORMAL && size > minislot_size) {
                    if (used_ul_slots < my_ul_slots || uc->info->slot_granted) {
                        used_ul_slots ++;
                        uc->occupied_slot = true;
                        permit_transfer = true;
                    }
                }
                if (permit_transfer) {
                    uc->transfer_file = local_file;
                } else {
                    free(local_file);
                    local_file = NULL;
                }
            } else {
                permit_transfer = true;
            }
            msgq_put(uc->put_mq, MSGQ_BOOL, permit_transfer, MSGQ_STR, local_file, MSGQ_END);
            FD_SET(uc->put_mq->fd, &write_fds);
            break;
        }
        case DC_MSG_UPLOAD_ENDED: {
            bool success;
            char *reason;

            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_BOOL, &success, MSGQ_STR, &reason, MSGQ_END);
            handle_ended_upload(uc, success, reason);
            free(reason);
            break;
        }
        case DC_MSG_TERMINATING:
            /* The TERMINATING message will be sent from users when they're about to
             * shut down properly.
            * XXX: This message may contain the reason it was terminated in the future.
            */
            msgq_get(uc->get_mq, MSGQ_INT, &id, MSGQ_END);
            user_disconnect(uc); /* MSG: reason from DC_MSG_TERMINATING */
            return; /* not break! this is the last message. */
        default:
            warn(_("Received unknown message %d from user process, shutting down process.\n"), id);
            user_disconnect(uc); /* MSG: local communication error? */
            return; /* not break! this is the last message. */
        }
    }
}
Esempio n. 3
0
/* This function should be called when the user process it to be notified
 * about the termination (when it isn't terminating by itself).
 */
void
user_conn_cancel(DCUserConn *uc)
{
    user_disconnect(uc); /* MSG: "connection terminated by request" */
}
Esempio n. 4
0
void user_disconnect_cb(void *arg) {
	LOG("%s", __func__);
	user_t *user = (user_t*)arg;
	user_disconnect(user);
}