diff options
Diffstat (limited to 'proxy/interactor.c')
-rw-r--r-- | proxy/interactor.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/proxy/interactor.c b/proxy/interactor.c new file mode 100644 index 00000000..d069d226 --- /dev/null +++ b/proxy/interactor.c @@ -0,0 +1,119 @@ +/* + * Centralised functions for the Interactor trait. + */ + +#include "putty.h" + +Seat *interactor_borrow_seat(Interactor *itr) +{ + Seat *clientseat = interactor_get_seat(itr); + if (!clientseat) + return NULL; + + /* If the client has already had its Seat borrowed, then look + * through the existing TempSeat to find the underlying one. */ + if (is_tempseat(clientseat)) + return tempseat_get_real(clientseat); + + /* Otherwise, make a new TempSeat and give that to the client. */ + Seat *tempseat = tempseat_new(clientseat); + interactor_set_seat(itr, tempseat); + return clientseat; +} + +static Interactor *interactor_toplevel(Interactor *itr, unsigned *level_out) +{ + /* + * Find the Interactor at the top of the chain, so that all the + * Interactors in a stack can share that one's last-to-talk field. + * Also, count how far we had to go to get to it, to put in the + * message. + */ + Interactor *itr_top = itr; + unsigned level = 0; + while (itr_top->parent) { + itr_top = itr_top->parent; + level++; + } + + if (level_out) + *level_out = level; + return itr_top; +} + +void interactor_return_seat(Interactor *itr) +{ + Seat *tempseat = interactor_get_seat(itr); + if (!is_tempseat(tempseat)) + return; /* no-op */ + + /* + * We're about to hand this seat back to the parent Interactor to + * do its own thing with. It will typically expect to start in the + * same state as if the seat had never been borrowed, i.e. in the + * starting trust state. + * + * However, this may be overridden by the tempseat_flush call. + */ + Seat *realseat = tempseat_get_real(tempseat); + seat_set_trust_status(realseat, true); + + tempseat_flush(tempseat); + interactor_set_seat(itr, realseat); + tempseat_free(tempseat); + + /* + * If we have a parent Interactor, and anyone has ever called + * interactor_announce, then all Interactors from now on will + * announce themselves even if they have nothing to say. + */ + Interactor *itr_top = interactor_toplevel(itr, NULL); + if (itr_top->last_to_talk) + interactor_announce(itr); +} + +InteractionReadySeat interactor_announce(Interactor *itr) +{ + Seat *seat = interactor_get_seat(itr); + assert(!is_tempseat(seat) && + "Shouldn't call announce when someone else is using our seat"); + + InteractionReadySeat iseat; + iseat.seat = seat; + + unsigned level; + Interactor *itr_top = interactor_toplevel(itr, &level); + + /* + * Generally, we should announce ourself if the previous + * Interactor that said anything was not us. That includes if + * there was no previous Interactor to talk (i.e. if we're the + * first to say anything) - *except* that the primary Interactor + * doesn't need to announce itself, if no proxy has intervened + * before it. + */ + bool need_announcement = (itr_top->last_to_talk != itr); + if (!itr->parent && !itr_top->last_to_talk) + need_announcement = false; + + if (need_announcement) { + const char *prefix = ""; + if (itr_top->last_to_talk != NULL) + seat_antispoof_msg(iseat, ""); /* leave a separating blank line */ + + char *desc = interactor_description(itr); + char *adjective = (level == 0 ? dupstr("primary") : + level == 1 ? dupstr("proxy") : + dupprintf("proxy^%u", level)); + char *msg = dupprintf("%sMaking %s %s", prefix, adjective, desc); + sfree(adjective); + sfree(desc); + + seat_antispoof_msg(iseat, msg); + sfree(msg); + + itr_top->last_to_talk = itr; + } + + return iseat; +} |