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); }
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. */ } } }
/* 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" */ }
void user_disconnect_cb(void *arg) { LOG("%s", __func__); user_t *user = (user_t*)arg; user_disconnect(user); }