📄 scmds.c
字号:
/* see if global or per-user upload limit exceeded */ r = upload_limit_reached(tok[0]); if (r) { /* sendpack(s, NAP_GFR, "%s", str); */ /* why is this here ? */ /* apparently the official napster server does not forward QLIMIT packets to the requestor, thus keeping them waiting forever. However, this is too bad, I don't think we should use NAP_GFR here. Do the opennap servers react differently? ### check this another time. */ sendpack(s, NAP_QLIMIT, "%s \"%s\" %li", tok[0], tok[1], r==2 ? nvar("maxuploads") : nvar("maxupuser")); if (nvar_default("showtoomanyuploads", 0)) { wp(win, "%s* Too many uploads %s(can't send \"%s\" to %s)%s\n", RED, r==2 ? "" : "for this user ", tok[1], tok[0], WHITE); drw(win); } free(lfn); return(1); } /* otherwise, accept the upload. Create an item in the upload list */ task = (upload_t *)malloc(sizeof(upload_t)); task->state = WAITING; task->nick = strdup(tok[0]); task->rfn = strdup(tok[1]); task->fn = strdup(fn); task->lfn = lfn; /* already allocated with strdup */ task->linespeed = num>=3 ? atoi(tok[2]) : 0; task->c_time = time(0); /* add it to the upload list */ list_append(upload_t, up, task); /* sendpack(s, NAP_SX, "%s", task->nm); */ /* why send a link speed query? */ /* accept upload request: <nick> "<filename>" */ sendpack(s, NAP_GFR, "%s", str); return(1);}/* link speed response: <nick> <linespeed> */I_NAP_FUNC(sry){ return(1);}/* 501 (0x1f5) alternate download ack: * <nick> <ip> <port> "<filename>" <md5> <speed> * we are being asked to UPLOAD a file to a remote client (presumably * because we are firewalled and cannot accept incoming connections) */I_NAP_FUNC(ssf){ upload_t *task; sock_t *sk=NULL; int k, r; struct sockaddr_in dst; /* find the corresponding upload */ list_find(task, up, task->state == WAITING && !strcasecmp(task->nick, tok[0]) && !strcasecmp(task->rfn, tok[3])); if (!task) { /* we were not waiting for this upload. Ignore silently. */ /* note: if in the future, we choose to accept 501 without prior 607, we must then also do the security checks; check the file is actually shared, /tquit is not active, etc */ return(1); } /* contact remote client */ /* note: the integer which represents the IP address is sent by the * napster protocol in "twisted" form. For instance, 1.0.0.0 = 1, * 0.1.0.0 = 256, etc. If this integer is stored in its native * format on a given host, it will end up representing the IP * address in *non-host* byte order. On little-endian machines, such * as x86 and Alpha, this happens to be the correct network * byteorder (=big-endian), but on big-endian machines, it is * not. Thus, the correct thing to do is to first swap the byte * order to convert from *non-host* to *host* byte order, then apply * htonl(3) to convert from *host* to *network* byte order. This * causes some unnecessary work on little-endian machines, but * to heck with that. -PS */ dst.sin_addr.s_addr = htonl(swapl(strtoul(tok[1], (char **)NULL, 10))); dst.sin_port = htons(atoi(tok[2])); dst.sin_family = AF_INET; k = socket(AF_INET, SOCK_STREAM, 0); /* use non-blocking i/o so that connect will not hang */ fcntl(k, F_SETFL, O_NONBLOCK); r = connect(k, (struct sockaddr *)&dst, sizeof(dst)); if (r == -1 && errno != EINPROGRESS) { wp(win, ""RED"* Error sending file (%s) to %s: %s"WHITE"\n", task->fn, task->nick, strerror(errno)); drw(win); task->state = FAILED; task->d_time = time(0); close(k); return(1); } setkeepalive(k); sk = addsock(k, gnum(1), S_R, initsend); /* update task */ task->state = CONNECTING; task->sk = sk; /* connect task to socket */ sk->utask = task; return(1);}/* 0xcc: got a download ack from the server. It is a string of the form: * <nick> <ip> <port> "<filename>" <md5> <linespeed> * 0 1 2 3 4 5 <-- token numbers */I_NAP_FUNC(sget){ download_t *task; int rport; int r, k; sock_t *sk; /* find matching REQUESTED or RRQUEUED item in the download list */ list_find(task, down, !strcasecmp(task->nick, tok[0]) && !strcasecmp(task->rfn, tok[3]) && (task->state == REQUESTED || task->state == RRQUEUED)); if (!task) /* we received an ack for an item we had not requested. */ return(1); /* ignore it silently. */ rport = atoi(tok[2]); if (!rport && !info.port) { wp(win, "%s* Unable to get \"%s\" from %s because both parties are " \ "firewalled%s\n", RED, task->fn, task->nick, WHITE); drw(win); task->state = FAILED; task->d_time = time(0); return(1); } task->check = strdup(tok[4]); task->linespeed = atoi(tok[5]); task->addr.sin_family = AF_INET; task->addr.sin_port = htons(rport); task->addr.sin_addr.s_addr = htonl(swapl(strtoul(tok[1], 0, 10))); if (!rport) /* firewalled client, send push request and go WAITING */ { sendpack(s, NAP_DSF, "%s \"%s\"", tok[0], tok[3]); task->state = WAITING; return(1); } /* else connect to the remote client and go CONNECTING */ /* sendpack(s, NAP_SX, "%s", tok[0]); */ /* why send a link speed query? */ k = socket(AF_INET, SOCK_STREAM, 0); /* make socket non-blocking, so that connect will return immediately */ fcntl(k, F_SETFL, O_NONBLOCK); r = connect(k, (struct sockaddr *)&task->addr, sizeof(task->addr)); if (r == -1 && errno != EINPROGRESS) { wp(win, ""RED"* Error getting file (%s) from %s: %s"WHITE"\n", task->fn, tok[0], strerror(errno)); drw(win); free(task->check); task->state = FAILED; task->d_time = time(0); close(k); return(1); } setkeepalive(k); if (task->state == RRQUEUED) { wp(win, "* Getting \"%s\" from %s\n", task->fn, task->nick); drw(win); } sk = addsock(k, gnum(0), S_R, initget); sk->dtask = task; task->sk = sk; task->state = CONNECTING; return(1);}/* 209 (0xd1) <user> <speed>: user signon [SERVER]. server is notifying client that a user in their hotlist, <user>, has signed on the server with link <speed> */I_NAP_FUNC(suon){ hotlist_t *elt; list_find(elt, hlist, !strcmp(elt->nm, tok[0])); if (elt) { elt->conn = atoi(tok[1]); elt->on = 1; wp(win, "%s* %s (%s) is on napster%s\n", BRIGHT(GREEN), tok[0], conns[atoi(tok[1])], WHITE); drw(win); } return(1);}/* 210 (0xd2) <user>: user signoff [SERVER]. server is notifying client that a user on their hotlist, <user>, has signed off the server. this message is also sent by the server when the client attempts to browse a nonexistent client. [why don't they just use 404 for this? -ed]*/I_NAP_FUNC(suoff){ hotlist_t *elt; list_find(elt, hlist, !strcmp(elt->nm, tok[0])); if (elt && elt->on) { elt->on = 0; wp(win, "%s* %s has left napster%s\n", GREEN, tok[0], WHITE); drw(win); } return(1);}/* 201 (0xc9) search response: * "<filename>" <md5> <size> <bitrate> <frequency> <length> <nick> <ip> * <link-type> [weight] */I_NAP_FUNC(ssret){ ssearch_t *elt; char *t; if (num < 9) return(1); /* calculate short filename */ t = ud_basename(tok[0]); /* create a new search list element */ elt = (ssearch_t *)malloc(sizeof(ssearch_t)); elt->song = strdup(quote(t)); elt->rfn = strdup(tok[0]); elt->sz = atoi(tok[2]); elt->brate = atoi(tok[3]); elt->freq = atoi(tok[4]); elt->time = atoi(tok[5]); elt->nick = strdup(tok[6]); elt->nip = htonl(swapl(strtoul(tok[7], (char **)NULL, 10))); elt->conn = atoi(tok[8]); if (elt->conn > 10 || elt->conn < 0) elt->conn = 0; elt->ping = -3; elt->next = NULL; /* and add it to the list. Note that it is faster to order the list at the end, rather than keeping it ordered here. */ list_prepend(search, elt); return(1);}/* 202 (0xca) end of search response from server */I_NAP_FUNC(ssend){ ssearch_t *cur, *cur1; sock_t *sk; int pin[2], pout[2], perr[2]; FILE *fin; struct in_addr addr; char *args[2]; char *napping; int i; list_length(ssearch_t, search, i); wp(win, "* Received %d search %s\n", i, i==1 ? "result" : "results"); drw(win); /* the easy case is if we can skip sending out pings. */ if (noping || !search) { showresults(win, 1); return(1); } /* attempt to run "napping" application, which will collect ping information for us. */ /* first create pipes to and from */ /* do we need to do anything to avoid file descriptors 0-2? */ if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) { wp(win, "* Could not collect ping results. pipe: %s\n", strerror(errno)); drw(win); showresults(win, 1); return(1); } switch(fork()) { case -1: /* error */ wp(win, "* Could not collect ping results. fork: %s\n", strerror(errno)); drw(win); showresults(win, 1); return(1); break; case 0: /* child */ /* attach pipes to stdin, stdout, stderr */ close(pin[1]); close(pout[0]); close(perr[0]); dup2(pin[0], 0); dup2(pout[1], 1); dup2(perr[1], 2); close(pin[0]); close(pout[1]); close(perr[1]); napping = getval("napping"); if (!napping) napping = NAPPING; args[0] = napping; args[1] = NULL; execvp(napping, args); /* execlp only returns if there is an error. */ if (errno == ENOENT && getval("napping")==NULL) { /* if napping was neither found nor explicitly requested, just ignore it silently and proceed without pings */ exit(1); } else if (errno == EACCES) { fprintf(stderr, "%s is not executable\n", napping); exit(1); } else { fprintf(stderr, "%s: %s\n", napping, strerror(errno)); exit(1); } break; default: /* parent */ close(pin[0]); close(pout[1]); close(perr[1]); fin = fdopen(pin[1], "w"); /* send the IP addresses to napping */ for (cur=search; cur; cur=cur->next) { if (cur->ping == -2) continue; addr.s_addr = cur->nip; fprintf(fin, "%s\n", inet_ntoa(addr)); for (cur1=search;cur1;cur1=cur1->next) if (cur1->nip == cur->nip) cur1->ping = -2; } fprintf(fin, "\n"); fclose(fin); /* hook up sockets to receive ping results */ addsock(pout[0], "icmp", S_R, icmpin); addsock(perr[0], "icmperr", S_R, icmperr); sk = findsock("icmp"); sk->f = fdopen(dup(pout[0]), "r"); sk = findsock("icmperr"); sk->f = fdopen(dup(perr[0]), "r"); /* set timer for 3 seconds */ /* timer is not currently used, since napping, if installed, times out after 3 seconds anyway. */ /* desc = strdup("[waiting for ping responses]"); addtimer(3, timed_pingresults, (void *)NULL, desc); */ return (1); }}/* timer is not currently used, since napping, if installed, times out after 3 seconds anyway. */void timed_pingresults(void *dummy) { sock_t *sk; sk = findsock("icmp"); if (sk) { fclose(sk->f); delsock(sk->fd); } sk = findsock("icmperr"); if (sk) { fclose(sk->f); delsock(sk->fd); } showresults(wchan, 2);}/* diplay search results, either on the main screen or on the result screen. LEVEL is 0 for browse, 1 for regular search, and 2 for search with pings. */void showresults(WINDOW *win, int level) { int min, sec, i; float mb; ssearch_t *a, *b, *cur; /* sort the list, by ping times if we have them, else connection speed, or by filename if this is a browse. A ping time of -1 is considered "infinitely large" */ switch (level) { case 2: /* display pings and connection speed, sort by pings first */ list_mergesort(ssearch_t, search, a, b, (a->ping == b->ping && a->conn >= b->conn) || (a->ping != -1 && (b->ping == -1 || a->ping < b->ping))); break; case 1: /* no pings; sort by connection speed */ list_mergesort(ssearch_t, search, a, b, a->conn >= b->conn); break; case 0: default: /* browse; sort by filename */ list_mergesort(ssearch_t, search, a, b, strcmp(a->song, b->song) <= 0); break; } srch = 0; /* show search result on main screen or result screen, depending on whether "noresultscreen" was selected. */ if (nvar_default("noresultscreen", 0)) { if (!search) { return; } wp(win, ""BOLD"#"WHITE" | "BOLD"Song"WHITE" | Bitrate | Frequency | "BOLD"Length"WHITE" | "BOLD"Size"WHITE" | User%s%s\n", level>=1 ? " | "BOLD"Speed"WHITE"" : "" , level>=2 ? " | Ping" : ""); wp(win, "-----------------------------------------------------%s%s\n", level>=1 ? "--------" : "", level>=2 ? "-------" : ""); i=1; list_forall (cur, search) { min = cur->time/60; sec = cur->time%60; mb = ((float)cur->sz)/1048576.0; wp(win, ""BOLD"%i. %s"WHITE" %ibps %ihz "BOLD"%i:%02i %.02fmb"WHITE" %s", i, (fl)?cur->rfn:cur->song, cur->brate, cur->freq, min, sec, mb, cur->nick); if (level>=1) { wp(win, " "BOLD"%s"WHITE"", conns[cur->conn]); } if (level>=2 && cur->ping == -1) wp(win, " N/A"); else if (level>=2) wp(win, " %i", cur->ping); wp(win, "\n"); i++; } drw(win); } else { if (search) { resetsscr(); switchtoscreen(RESULT_SCREEN); } plist(); }} /* received a browse response from server: * <nick> "<filename>" <md5> <size> <bitrate> <frequency> <time> * 0 1 2 3 4 5 6 */I_NAP_FUNC(srbrowse){ ssearch_t *cur, *cur1; char *t; if (num < 7) return(1); if (search == NULL) { search = (ssearch_t *)malloc(sizeof(ssearch_t)); cur = search; } else { for (cur1=NULL,cur=search;cur!=NULL;cur=cur->next) cur1 = cur; cur = (ssearch_t *)malloc(sizeof(ssearch_t)); cur1->next = cur; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -