X-Git-Url: http://git.dolda2000.com/gitweb/?a=blobdiff_plain;f=lib%2Fuimisc.c;h=6a30ffaa9eb76e77336397a449dfff96ae1a8ac2;hb=e5c8b0ca6215e635b774a5a4e60181e38c33480b;hp=be10115bd729b5bf6e7ac25a4fe3da35b50acd52;hpb=794c3e0286c6010b2504382a43865d0907db8320;p=doldaconnect.git diff --git a/lib/uimisc.c b/lib/uimisc.c index be10115..6a30ffa 100644 --- a/lib/uimisc.c +++ b/lib/uimisc.c @@ -1,6 +1,6 @@ /* * Dolda Connect - Modular multiuser Direct Connect-style client - * Copyright (C) 2004 Fredrik Tolf (fredrik@dolda2000.com) + * Copyright (C) 2004 Fredrik Tolf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,19 +18,24 @@ */ #include +#include +/* I'm very unsure about this, but for now it defines wcstoll (which + * should be defined anyway) and doesn't break anything... let's keep + * two eyes wide open, though. */ +#define __USE_ISOC99 #include #include #include #include -#include #include +#include #ifdef HAVE_CONFIG_H #include #endif #include #include -#include +#include #ifdef HAVE_KRB5 #include @@ -59,15 +64,49 @@ struct logindata struct authmech *mech; }; +struct synclogindata +{ + int aborted; + int err; + wchar_t *reason; +}; + struct gencbdata { void (*callback)(int resp, void *data); void *data; }; +struct fnetcbdata +{ + void (*callback)(struct dc_fnetnode *fn, int resp, void *data); + int fnid; + void *data; +}; + struct dc_fnetnode *dc_fnetnodes = NULL; struct dc_transfer *dc_transfers = NULL; +static void message(int bits, char *format, ...) +{ + static int hb = -1; + char *v; + va_list args; + + if(hb == -1) + { + hb = 0; + if((v = getenv("LIBDCUI_MSG")) != NULL) + hb = strtol(v, NULL, 0) & 65535; + } + if(hb & bits) + { + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + } +} + static void freelogindata(struct logindata *data) { if((data->mech != NULL) && (data->mech->release != NULL)) @@ -156,7 +195,7 @@ static void process_pam(struct dc_response *resp, struct logindata *data) data->callback(DC_LOGIN_ERR_CONV, NULL, data->data); freelogindata(data); } else { - dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL); + dc_queuecmd(logincallback, data, L"pass", L"%s", buf, NULL); } if(buf != NULL) { @@ -194,77 +233,6 @@ struct krb5data int valid, fwd, fwded; }; -static char *hexencode(char *data, size_t datalen) -{ - char *buf, this; - size_t bufsize, bufdata; - int dig; - - buf = NULL; - bufsize = bufdata = 0; - for(; datalen > 0; datalen--, data++) - { - dig = (*data & 0xF0) >> 4; - if(dig > 9) - this = 'A' + dig - 10; - else - this = dig + '0'; - addtobuf(buf, this); - dig = *data & 0x0F; - if(dig > 9) - this = 'A' + dig - 10; - else - this = dig + '0'; - addtobuf(buf, this); - } - addtobuf(buf, 0); - return(buf); -} - -static char *hexdecode(char *data, size_t *len) -{ - char *buf, this; - size_t bufsize, bufdata; - - buf = NULL; - bufsize = bufdata = 0; - for(; *data; data++) - { - if((*data >= 'A') && (*data <= 'F')) - { - this = (this & 0x0F) | ((*data - 'A' + 10) << 4); - } else if((*data >= '0') && (*data <= '9')) { - this = (this & 0x0F) | ((*data - '0') << 4); - } else { - if(buf != NULL) - free(buf); - return(NULL); - } - data++; - if(!*data) - { - if(buf != NULL) - free(buf); - return(NULL); - } - if((*data >= 'A') && (*data <= 'F')) - { - this = (this & 0xF0) | (*data - 'A' + 10); - } else if((*data >= '0') && (*data <= '9')) { - this = (this & 0xF0) | (*data - '0'); - } else { - if(buf != NULL) - free(buf); - return(NULL); - } - addtobuf(buf, this); - } - addtobuf(buf, 0); - if(len != NULL) - *len = bufdata - 1; - return(buf); -} - static void process_krb5(struct dc_response *resp, struct logindata *data) { int ret; @@ -286,7 +254,7 @@ static void process_krb5(struct dc_response *resp, struct logindata *data) { case 0: buf = hexencode(krb->reqbuf.data, krb->reqbuf.length); - dc_queuecmd(logincallback, data, L"pass", L"%%s", buf, NULL); + dc_queuecmd(logincallback, data, L"pass", L"%s", buf, NULL); free(buf); krb->state = 1; break; @@ -313,7 +281,7 @@ static void process_krb5(struct dc_response *resp, struct logindata *data) krb->reqbuf.data = NULL; if((ret = krb5_fwd_tgt_creds(krb->context, krb->authcon, NULL, krb->servcreds->client, krb->servcreds->server, 0, 1, &krb->reqbuf)) != 0) { - fprintf(stderr, "krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret)); + message(1, "krb5_fwd_tgt_creds reported an error: %s\n", error_message(ret)); dc_queuecmd(logincallback, data, L"pass", L"31", NULL); krb->fwd = 0; krb->state = 2; @@ -358,6 +326,11 @@ static int init_krb5(struct logindata *data) krb5_data cksum; krb5_creds creds; + if(dc_gethostname() == NULL) + { + message(1, "cannot use krb5 without a host name\n"); + return(1); + } krb = smalloc(sizeof(*krb)); memset(krb, 0, sizeof(*krb)); krb->fwd = 1; @@ -365,28 +338,28 @@ static int init_krb5(struct logindata *data) data->mechdata = krb; if((ret = krb5_init_context(&krb->context)) != 0) { - fprintf(stderr, "krb5_init_context reported an error: %s\n", error_message(ret)); + message(1, "krb5_init_context reported an error: %s\n", error_message(ret)); return(1); } if((ret = krb5_auth_con_init(krb->context, &krb->authcon)) != 0) { - fprintf(stderr, "krb5_auth_con_init reported an error: %s\n", error_message(ret)); + message(1, "krb5_auth_con_init reported an error: %s\n", error_message(ret)); return(1); } krb5_auth_con_setflags(krb->context, krb->authcon, KRB5_AUTH_CONTEXT_DO_SEQUENCE); if((ret = krb5_sname_to_principal(krb->context, dc_gethostname(), "doldacond", KRB5_NT_SRV_HST, &krb->sprinc)) != 0) { - fprintf(stderr, "krb5_sname_to_principal reported an error: %s\n", error_message(ret)); + message(1, "krb5_sname_to_principal reported an error: %s\n", error_message(ret)); return(1); } if((ret = krb5_cc_default(krb->context, &krb->ccache)) != 0) { - fprintf(stderr, "krb5_cc_default reported an error: %s\n", error_message(ret)); + message(1, "krb5_cc_default reported an error: %s\n", error_message(ret)); return(1); } if((ret = krb5_cc_get_principal(krb->context, krb->ccache, &krb->myprinc)) != 0) { - fprintf(stderr, "krb5_cc_default reported an error: %s\n", error_message(ret)); + message(1, "krb5_cc_default reported an error: %s\n", error_message(ret)); return(1); } memset(&creds, 0, sizeof(creds)); @@ -394,7 +367,7 @@ static int init_krb5(struct logindata *data) creds.server = krb->sprinc; if((ret = krb5_get_credentials(krb->context, 0, krb->ccache, &creds, &krb->servcreds)) != 0) { - fprintf(stderr, "krb5_get_credentials reported an error: %s\n", error_message(ret)); + message(1, "krb5_get_credentials reported an error: %s\n", error_message(ret)); return(1); } /* WTF is this checksum stuff?! The Krb docs don't say a word about it! */ @@ -402,7 +375,7 @@ static int init_krb5(struct logindata *data) cksum.length = strlen(cksum.data); if((ret = krb5_mk_req_extended(krb->context, &krb->authcon, AP_OPTS_MUTUAL_REQUIRED, &cksum, krb->servcreds, &krb->reqbuf)) != 0) { - fprintf(stderr, "krb5_mk_req_extended reported an error: %s\n", error_message(ret)); + message(1, "krb5_mk_req_extended reported an error: %s\n", error_message(ret)); return(1); } free(cksum.data); @@ -446,6 +419,12 @@ static struct authmech authmechs[] = }, #endif { + .name = L"unix", + .process = process_authless, + .init = NULL, + .release = NULL + }, + { .name = L"authless", .process = process_authless, .init = NULL, @@ -462,7 +441,7 @@ static struct authmech authmechs[] = } }; -static int builtinconv(int type, wchar_t *text, char **resp, void *data) +int dc_convtty(int type, wchar_t *text, char **resp, void *data) { char *buf, *pass; @@ -479,6 +458,11 @@ static int builtinconv(int type, wchar_t *text, char **resp, void *data) return(1); } +int dc_convnone(int type, wchar_t *text, char **resp, void *data) +{ + return(1); +} + static int logincallback(struct dc_response *resp) { int i; @@ -511,12 +495,13 @@ static int logincallback(struct dc_response *resp) { odata = data->mechdata; data->mechdata = NULL; + message(4, "trying auth mech %ls\n", authmechs[i].name); if((authmechs[i].init != NULL) && authmechs[i].init(data)) { if(authmechs[i].release != NULL) authmechs[i].release(data); data->mechdata = odata; - fprintf(stderr, "authentication mechanism %ls failed, trying further...\n", authmechs[i].name); + message(2, "authentication mechanism %ls failed, trying further...\n", authmechs[i].name); } else { if((data->mech != NULL) && data->mech->release != NULL) { @@ -548,7 +533,7 @@ static int logincallback(struct dc_response *resp) } username = pwent->pw_name; } - dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%%s", username, NULL); + dc_queuecmd(logincallback, data, L"login", data->mech->name, L"%s", username, NULL); } } } else if(!wcscmp(resp->cmdname, L"login") || !wcscmp(resp->cmdname, L"pass")) { @@ -563,7 +548,7 @@ void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, data = smalloc(sizeof(*data)); if(conv == NULL) - conv = builtinconv; + conv = dc_convtty; data->conv = conv; data->mech = NULL; data->data = udata; @@ -581,6 +566,203 @@ void dc_loginasync(char *username, int useauthless, int (*conv)(int, wchar_t *, dc_queuecmd(logincallback, data, L"lsauth", NULL); } +static void synclogincb(int err, wchar_t *reason, struct synclogindata *data) +{ + if(data->aborted) + { + free(data); + return; + } + data->err = err; + if(reason == NULL) + data->reason = NULL; + else + data->reason = swcsdup(reason); +} + +int dc_login(char *username, int useauthless, int (*conv)(int, wchar_t *, char **, void *), wchar_t **reason) +{ + int ret, abort; + struct synclogindata *dbuf; + struct pollfd pfd; + + dbuf = smalloc(sizeof(*dbuf)); + memset(dbuf, 0, sizeof(*dbuf)); + dbuf->err = -1; + dc_loginasync(username, useauthless, conv, (void (*)(int, wchar_t *, void *))synclogincb, dbuf); + while(dbuf->err == -1) + { + pfd.fd = dc_getfd(); + pfd.events = POLLIN; + if(dc_wantwrite()) + pfd.events |= POLLOUT; + abort = 0; + if(poll(&pfd, 1, -1) < 0) + abort = 1; + if(!abort && (pfd.revents & POLLIN) && dc_handleread()) + abort = 1; + if(!abort && (pfd.revents & POLLOUT) && dc_handlewrite()) + abort = 1; + if(abort) + { + dbuf->aborted = 1; + return(-1); + } + } + if(reason != NULL) + *reason = dbuf->reason; + else if(dbuf->reason != NULL) + free(dbuf->reason); + ret = dbuf->err; + free(dbuf); + return(ret); +} + +static struct dc_fnetpeerdatum *finddatum(struct dc_fnetnode *fn, wchar_t *id) +{ + struct dc_fnetpeerdatum *datum; + + for(datum = fn->peerdata; datum != NULL; datum = datum->next) + { + if(!wcscmp(datum->id, id)) + break; + } + return(datum); +} + +static struct dc_fnetpeerdatum *adddatum(struct dc_fnetnode *fn, wchar_t *id, int dt) +{ + struct dc_fnetpeerdatum *datum; + + datum = smalloc(sizeof(*datum)); + memset(datum, 0, sizeof(*datum)); + datum->refcount = 0; + datum->dt = dt; + datum->id = swcsdup(id); + datum->prev = NULL; + datum->next = fn->peerdata; + if(fn->peerdata != NULL) + fn->peerdata->prev = datum; + fn->peerdata = datum; + return(datum); +} + +static struct dc_fnetpeerdi *difindoradd(struct dc_fnetpeer *peer, struct dc_fnetpeerdatum *datum) +{ + int i; + + for(i = 0; i < peer->dinum; i++) + { + if(peer->di[i].datum == datum) + return(&peer->di[i]); + } + peer->di = srealloc(peer->di, sizeof(struct dc_fnetpeerdi) * ++(peer->dinum)); + memset(&peer->di[i], 0, sizeof(struct dc_fnetpeerdi)); + peer->di[i].datum = datum; + datum->refcount++; + return(&peer->di[i]); +} + +static void putdatum(struct dc_fnetnode *fn, struct dc_fnetpeerdatum *datum) +{ + if(--datum->refcount > 0) + return; + if(datum->next != NULL) + datum->next->prev = datum->prev; + if(datum->prev != NULL) + datum->prev->next = datum->next; + if(fn->peerdata == datum) + fn->peerdata = datum->next; + free(datum->id); + free(datum); +} + +static void peersetnum(struct dc_fnetpeer *peer, wchar_t *id, int value) +{ + struct dc_fnetpeerdatum *datum; + struct dc_fnetpeerdi *di; + + if((datum = finddatum(peer->fn, id)) == NULL) + datum = adddatum(peer->fn, id, DC_FNPD_INT); + di = difindoradd(peer, datum); + di->d.num = value; +} + +static void peersetlnum(struct dc_fnetpeer *peer, wchar_t *id, long long value) +{ + struct dc_fnetpeerdatum *datum; + struct dc_fnetpeerdi *di; + + if((datum = finddatum(peer->fn, id)) == NULL) + datum = adddatum(peer->fn, id, DC_FNPD_INT); + di = difindoradd(peer, datum); + di->d.lnum = value; +} + +static void peersetstr(struct dc_fnetpeer *peer, wchar_t *id, wchar_t *value) +{ + struct dc_fnetpeerdatum *datum; + struct dc_fnetpeerdi *di; + + if((datum = finddatum(peer->fn, id)) == NULL) + datum = adddatum(peer->fn, id, DC_FNPD_INT); + di = difindoradd(peer, datum); + if(di->d.str != NULL) + free(di->d.str); + di->d.str = swcsdup(value); +} + +struct dc_fnetpeer *dc_fnetfindpeer(struct dc_fnetnode *fn, wchar_t *id) +{ + struct dc_fnetpeer *peer; + + for(peer = fn->peers; peer != NULL; peer = peer->next) + { + if(!wcscmp(peer->id, id)) + break; + } + return(peer); +} + +static struct dc_fnetpeer *addpeer(struct dc_fnetnode *fn, wchar_t *id, wchar_t *nick) +{ + struct dc_fnetpeer *peer; + + peer = smalloc(sizeof(*peer)); + memset(peer, 0, sizeof(*peer)); + peer->fn = fn; + peer->id = swcsdup(id); + peer->nick = swcsdup(nick); + peer->next = fn->peers; + peer->prev = NULL; + if(fn->peers != NULL) + fn->peers->prev = peer; + fn->peers = peer; + return(peer); +} + +static void delpeer(struct dc_fnetpeer *peer) +{ + int i; + + if(peer->next != NULL) + peer->next->prev = peer->prev; + if(peer->prev != NULL) + peer->prev->next = peer->next; + if(peer->fn->peers == peer) + peer->fn->peers = peer->next; + free(peer->id); + free(peer->nick); + for(i = 0; i < peer->dinum; i++) + { + if((peer->di[i].datum->dt == DC_FNPD_STR) && (peer->di[i].d.str != NULL)) + free(peer->di[i].d.str); + putdatum(peer->fn, peer->di[i].datum); + } + free(peer->di); + free(peer); +} + static struct dc_fnetnode *newfn(void) { struct dc_fnetnode *fn; @@ -611,6 +793,13 @@ static void freefn(struct dc_fnetnode *fn) dc_fnetnodes = fn->next; if(fn->destroycb != NULL) fn->destroycb(fn); + while(fn->peers != NULL) + delpeer(fn->peers); + while(fn->peerdata != NULL) + { + fn->peerdata->refcount = 0; + putdatum(fn, fn->peerdata); + } if(fn->name != NULL) free(fn->name); if(fn->fnet != NULL) @@ -707,6 +896,9 @@ static int getfnlistcallback(struct dc_response *resp) fn->name = swcsdup(ires->argv[2].val.str); fn->numusers = ires->argv[3].val.num; fn->state = ires->argv[4].val.num; + if(fn->pubid != NULL) + free(fn->pubid); + fn->pubid = swcsdup(ires->argv[5].val.str); } else { fn = newfn(); fn->id = ires->argv[0].val.num; @@ -714,6 +906,7 @@ static int getfnlistcallback(struct dc_response *resp) fn->name = swcsdup(ires->argv[2].val.str); fn->numusers = ires->argv[3].val.num; fn->state = ires->argv[4].val.num; + fn->pubid = swcsdup(ires->argv[5].val.str); fn->found = 1; } dc_freeires(ires); @@ -823,6 +1016,135 @@ static int gettrlistcallback(struct dc_response *resp) return(1); } +static int sortlist1(const struct dc_respline *l1, const struct dc_respline *l2) +{ + return(wcscmp(l1->argv[1], l2->argv[1])); +} + +static int sortlist2(const struct dc_fnetpeer **p1, const struct dc_fnetpeer **p2) +{ + return(wcscmp((*p1)->id, (*p2)->id)); +} + +static void fillpeer(struct dc_fnetpeer *peer, struct dc_respline *r) +{ + int i; + struct dc_fnetpeerdatum *datum; + + for(i = 3; i < r->argc; i += 2) + { + if((datum = finddatum(peer->fn, r->argv[i])) != NULL) + { + switch(datum->dt) + { + case DC_FNPD_INT: + peersetnum(peer, datum->id, wcstol(r->argv[i + 1], NULL, 10)); + break; + case DC_FNPD_LL: + peersetlnum(peer, datum->id, wcstoll(r->argv[i + 1], NULL, 10)); + break; + case DC_FNPD_STR: + peersetstr(peer, datum->id, r->argv[i + 1]); + break; + } + } + } +} + +static int getpeerlistcallback(struct dc_response *resp) +{ + int i, o, c; + struct dc_fnetnode *fn; + struct fnetcbdata *data; + struct dc_fnetpeer *peer; + struct dc_fnetpeer **plist; + size_t plistsize, plistdata; + + data = resp->data; + if((fn = dc_findfnetnode(data->fnid)) == NULL) + { + data->callback(NULL, -1, data->data); + free(data); + return(1); + } + if(resp->code == 200) + { + qsort(resp->rlines, resp->numlines, sizeof(*resp->rlines), (int (*)(const void *, const void *))sortlist1); + plist = NULL; + plistsize = plistdata = 0; + for(i = 0, peer = fn->peers; peer != NULL; peer = peer->next) + addtobuf(plist, peer); + qsort(plist, plistdata, sizeof(*plist), (int (*)(const void *, const void *))sortlist2); + i = o = 0; + while(1) + { + if((i < resp->numlines) && (o < plistdata)) + { + c = wcscmp(resp->rlines[i].argv[1], plist[o]->id); + if(c < 0) + { + peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]); + fillpeer(peer, resp->rlines + i); + i++; + } else if(c > 0) { + delpeer(plist[o]); + o++; + } else { + fillpeer(plist[o], resp->rlines + i); + i++; + o++; + } + } else if(i < resp->numlines) { + peer = addpeer(fn, resp->rlines[i].argv[1], resp->rlines[i].argv[2]); + fillpeer(peer, resp->rlines + i); + i++; + } else if(o < plistdata) { + delpeer(plist[o]); + o++; + } else { + break; + } + } + free(plist); + } else if(resp->code == 201) { + while(fn->peers != NULL) + delpeer(fn->peers); + } + data->callback(fn, resp->code, data->data); + free(data); + return(1); +} + +static int getpalistcallback(struct dc_response *resp) +{ + struct dc_fnetnode *fn; + struct dc_intresp *ires; + struct fnetcbdata *data; + + data = resp->data; + if((fn = dc_findfnetnode(data->fnid)) == NULL) + { + data->callback(NULL, -1, data->data); + free(data); + return(1); + } + if(resp->code == 200) + { + while((ires = dc_interpret(resp)) != NULL) + { + adddatum(fn, ires->argv[0].val.str, ires->argv[1].val.num); + dc_freeires(ires); + } + dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL); + } else if(resp->code == 201) { + dc_queuecmd(getpeerlistcallback, data, L"lspeers", L"%i", fn->id, NULL); + } else { + data->callback(fn, resp->code, data->data); + free(data); + } + return(1); +} + void dc_getfnlistasync(void (*callback)(int, void *), void *udata) { struct gencbdata *data; @@ -843,6 +1165,17 @@ void dc_gettrlistasync(void (*callback)(int, void *), void *udata) dc_queuecmd(gettrlistcallback, data, L"lstrans", NULL); } +void dc_getpeerlistasync(struct dc_fnetnode *fn, void (*callback)(struct dc_fnetnode *, int, void *), void *udata) +{ + struct fnetcbdata *data; + + data = smalloc(sizeof(*data)); + data->callback = callback; + data->fnid = fn->id; + data->data = udata; + dc_queuecmd(getpalistcallback, data, L"lspa", L"%i", fn->id, NULL); +} + void dc_uimisc_disconnected(void) { while(dc_fnetnodes != NULL) @@ -853,8 +1186,10 @@ void dc_uimisc_disconnected(void) void dc_uimisc_handlenotify(struct dc_response *resp) { + int i; struct dc_fnetnode *fn; struct dc_transfer *transfer; + struct dc_fnetpeer *peer; struct dc_intresp *ires; if((ires = dc_interpret(resp)) == NULL) @@ -951,6 +1286,58 @@ void dc_uimisc_handlenotify(struct dc_response *resp) transfer->hash = swcsdup(ires->argv[1].val.str); } break; + case 630: + if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL) + { + if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) == NULL) + { + peer = addpeer(fn, ires->argv[1].val.str, ires->argv[2].val.str); + if(fn->newpeercb != NULL) + fn->newpeercb(peer); + } + } + break; + case 631: + if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL) + { + if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL) + { + if(fn->delpeercb != NULL) + fn->delpeercb(peer); + delpeer(peer); + } + } + break; + case 632: + if((fn = dc_findfnetnode(ires->argv[0].val.num)) != NULL) + { + if((peer = dc_fnetfindpeer(fn, ires->argv[1].val.str)) != NULL) + { + if(wcscmp(ires->argv[2].val.str, peer->nick)) + { + free(peer->nick); + peer->nick = swcsdup(ires->argv[2].val.str); + } + for(i = 4; i < resp->rlines[0].argc; i += 3) + { + switch(wcstol(resp->rlines[0].argv[i + 1], NULL, 10)) + { + case DC_FNPD_INT: + peersetnum(peer, resp->rlines[0].argv[i], wcstol(resp->rlines[0].argv[i + 2], NULL, 10)); + break; + case DC_FNPD_LL: + peersetlnum(peer, resp->rlines[0].argv[i], wcstoll(resp->rlines[0].argv[i + 2], NULL, 10)); + break; + case DC_FNPD_STR: + peersetstr(peer, resp->rlines[0].argv[i], resp->rlines[0].argv[i + 2]); + break; + } + } + if(fn->chpeercb != NULL) + fn->chpeercb(peer); + } + } + break; default: break; }