+/*
+ * Handle incoming data on an SSH-1 or SSH-2 agent-forwarding channel.
+ */
+static int ssh_agent_channel_data(struct ssh_channel *c, char *data,
+ int length)
+{
+ while (length > 0) {
+ if (c->u.a.lensofar < 4) {
+ unsigned int l = min(4 - c->u.a.lensofar, (unsigned)length);
+ memcpy(c->u.a.msglen + c->u.a.lensofar, data, l);
+ data += l;
+ length -= l;
+ c->u.a.lensofar += l;
+ }
+ if (c->u.a.lensofar == 4) {
+ c->u.a.totallen = 4 + GET_32BIT(c->u.a.msglen);
+ c->u.a.message = snewn(c->u.a.totallen, unsigned char);
+ memcpy(c->u.a.message, c->u.a.msglen, 4);
+ }
+ if (c->u.a.lensofar >= 4 && length > 0) {
+ unsigned int l = min(c->u.a.totallen - c->u.a.lensofar,
+ (unsigned)length);
+ memcpy(c->u.a.message + c->u.a.lensofar, data, l);
+ data += l;
+ length -= l;
+ c->u.a.lensofar += l;
+ }
+ if (c->u.a.lensofar == c->u.a.totallen) {
+ void *reply;
+ int replylen;
+ c->u.a.outstanding_requests++;
+ if (agent_query(c->u.a.message, c->u.a.totallen, &reply, &replylen,
+ ssh_agentf_callback, c))
+ ssh_agentf_callback(c, reply, replylen);
+ sfree(c->u.a.message);
+ c->u.a.message = NULL;
+ c->u.a.lensofar = 0;
+ }
+ }
+ return 0; /* agent channels never back up */
+}
+
+static int ssh_channel_data(struct ssh_channel *c, int is_stderr,
+ char *data, int length)
+{
+ switch (c->type) {
+ case CHAN_MAINSESSION:
+ return from_backend(c->ssh->frontend, is_stderr, data, length);
+ case CHAN_X11:
+ return x11_send(c->u.x11.xconn, data, length);
+ case CHAN_SOCKDATA:
+ return pfd_send(c->u.pfd.pf, data, length);
+ case CHAN_AGENT:
+ return ssh_agent_channel_data(c, data, length);
+ }
+ return 0;
+}
+