+ struct dcexppeer *expect;
+ struct dchub *hub;
+
+ if(peer->nativename != NULL)
+ free(peer->nativename);
+ peer->nativename = sstrdup(args);
+ if(peer->wcsname != NULL)
+ free(peer->wcsname);
+ if((peer->wcsname = icmbstowcs(peer->nativename, peer->charset)) == NULL)
+ {
+ peer->close = 1;
+ return;
+ }
+ if(peer->accepted)
+ {
+ for(expect = expected; expect != NULL; expect = expect->next)
+ {
+ if(!strcmp(expect->nick, args))
+ break;
+ }
+ if(expect == NULL)
+ {
+ peer->fn = NULL;
+ } else {
+ hub = expect->fn->data;
+ peer->fn = expect->fn;
+ getfnetnode(peer->fn);
+ peer->dcppemu = hub->dcppemu;
+ freeexppeer(expect);
+ }
+ }
+}
+
+static void peerattach(struct dcpeer *peer, struct transfer *transfer)
+{
+ peer->transfer = transfer;
+ CBREG(peer->transfer, trans_filterout, (int (*)(struct transfer *, wchar_t *, wchar_t *, void *))trresumecb, NULL, peer);
+ CBREG(peer->transfer, trans_destroy, (int (*)(struct transfer *, void *))trdestroycb, NULL, peer);
+}
+
+static void cmd_direction(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
+{
+ char *p;
+ int mydir;
+ struct transfer *transfer;
+
+ if((p = strchr(args, ' ')) == NULL)
+ return;
+ *p = 0;
+ if(!strcmp(args, "Upload"))
+ mydir = TRNSD_DOWN;
+ if(!strcmp(args, "Download"))
+ mydir = TRNSD_UP;
+ if(peer->accepted)
+ {
+ if((peer->transfer == NULL) || (mydir != peer->direction))
+ {
+ peer->close = 1;
+ return;
+ }
+ if(peer->direction == TRNSD_DOWN)
+ requestfile(peer);
+ } else {
+ if(peer->wcsname == NULL)
+ {
+ peer->close = 1;
+ return;
+ }
+ peer->direction = mydir;
+ if(peer->direction == TRNSD_UP)
+ {
+ if(confgetint("transfer", "ulquota") && hasupload(&dcnet, peer->wcsname))
+ {
+ peer->close = 1;
+ return;
+ }
+ transfer = newupload(peer->fn, &dcnet, peer->wcsname, (peer->trpipe = mktrpipe(peer))->back);
+ } else {
+ if((transfer = finddownload(peer->wcsname)) == NULL)
+ {
+ peer->close = 1;
+ return;
+ }
+ transferattach(transfer, (peer->trpipe = mktrpipe(peer))->back);
+ transfersetstate(transfer, TRNS_HS);
+ }
+ transfersetnick(transfer, peer->wcsname);
+ peerattach(peer, transfer);
+ if(peer->extended)
+ sendsupports(peer);
+ qstrf(sk, "$Direction %s %i|", (peer->direction == TRNSD_UP)?"Upload":"Download", rand() % 10000);
+ if(peer->key != NULL)
+ qstrf(sk, "$Key %s|", peer->key);
+ if(peer->direction == TRNSD_DOWN)
+ requestfile(peer);
+ }
+}
+
+static void cmd_peerlock(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
+{
+ char *p, *key;
+ struct transfer *transfer;
+
+ if((p = strchr(args, ' ')) == NULL)
+ return;
+ *p = 0;
+ if(!strncmp(args, "EXTENDEDPROTOCOL", 16))
+ peer->extended = 1;
+ key = dcmakekey(args);
+ if(peer->accepted)
+ {
+ if(peer->wcsname == NULL)
+ {
+ peer->close = 1;
+ return;
+ }
+ sendmynick(peer);
+ sendpeerlock(peer);
+ if(peer->extended)
+ sendsupports(peer);
+ if((transfer = finddownload(peer->wcsname)) == NULL)
+ {
+ if(confgetint("transfer", "ulquota") && hasupload(&dcnet, peer->wcsname))
+ {
+ peer->close = 1;
+ return;
+ }
+ peer->direction = TRNSD_UP;
+ transfer = newupload(peer->fn, &dcnet, peer->wcsname, (peer->trpipe = mktrpipe(peer))->back);
+ } else {
+ peer->direction = TRNSD_DOWN;
+ transferattach(transfer, (peer->trpipe = mktrpipe(peer))->back);
+ transfersetstate(transfer, TRNS_HS);
+ }
+ transfersetnick(transfer, peer->wcsname);
+ peerattach(peer, transfer);
+ qstrf(sk, "$Direction %s %i|", (peer->direction == TRNSD_UP)?"Upload":"Download", rand() % 10000);
+ qstrf(sk, "$Key %s|", key);
+ free(key);
+ } else {
+ if(peer->key != NULL)
+ free(peer->key);
+ peer->key = key;
+ }
+}
+
+static void cmd_key(struct socket *sk, struct dcpeer *peer, char *cmd, char *args)
+{
+ /* NOP */
+}
+
+static void startdl(struct dcpeer *peer)
+{
+ if(peer->timeout != NULL)
+ canceltimer(peer->timeout);
+ peer->state = PEER_TRNS;
+ transferstartdl(peer->transfer, peer->sk);
+ peer->sk->readcb = (void (*)(struct socket *, void *))transread;
+ peer->sk->errcb = (void (*)(struct socket *, int, void *))transerr;
+}
+
+static void startul(struct dcpeer *peer)
+{
+ if(peer->timeout != NULL)
+ canceltimer(peer->timeout);
+ peer->state = PEER_TRNS;
+ transferstartul(peer->transfer, peer->sk);
+ peer->sk->writecb = (void (*)(struct socket *, void *))transwrite;
+ transwrite(peer->sk, peer);