📄 nap.c
字号:
wp(wchan, "Error: Invalid username\n"); drw(wchan); free(t1); free(rcv); return(-1); } else if (rcv->op == NAP_UNOK) { wp(wchan, "Registered username\n"); drw(wchan); } else { wp(wchan, "Unknown op: 0x%x\n", rcv->op); drw(wchan); free(t1); free(rcv); return(-1); } free(t1); free(rcv); t1 = NULL; r = sendpack(s, NAP_REG, "%s %s %i \"%s\" %i %s", user, pass, data, identity ? identity : IDENTITY, conn, email); if (r<0) { wp(wchan, "Error: %s\n", strerror(errno)); drw(wchan); return(-1); } r = recvpack_t(s, &t1, &rcv, timeout); while (r == -2) { r = recvpack_t(s, &t1, &rcv, timeout); } if (r == -1) { wp(wchan, "Error while receiving data: %s\n", strerror(errno)); drw(wchan); return(-1); } else if (r == -3) { wp(wchan, "Error: unexpected end of file from server\n"); drw(wchan); return(-1); } else if (r == -4) { wp(wchan, "Error: Connection timed out\n"); drw(wchan); return(-1); } if (rcv->op == NAP_LOGERROR) { wp(wchan, "Error: %s\n", t1); drw(wchan); free(t1); free(rcv); return(-1); } /* the following works for opennap and slavanap. The "email address" they send is of the form anon@servername. Slavanap also sends an additional integer. */ if (strncmp(t1, "anon@", 5)==0) { char *p = strchr(t1, ' '); if (p) { *p = 0; } wp(wchan, "Server's name appears to be %s\n", t1+5); drw(wchan); } free(t1); free(rcv); return r;}/* calculate the name of the hotlist file */char *glistn(char *t){ char *r1 = NULL; char *r2; msprintf(&r1, HOTLISTFILE, t); r2 = home_file(r1); free(r1); return(r2);}/* send initial hotlist during the login process */void checkhotlist(int s, char *fn){ FILE *f; char *rd; hotlist_t *elt; /* first delete old hlist, if any */ list_forall_unlink(elt, hlist) { free(elt->nm); free(elt); } f = fopen(fn, "r"); if (!f) return; while ((rd = nap_getline(f)) != NULL) { if (!strlen(rd)) { free(rd); break; } /* create new hotlist entry */ elt = (hotlist_t *)malloc(sizeof(hotlist_t)); elt->nm = rd; elt->conn = 0; elt->on = 0; /* add it to the list */ list_append(hotlist_t, hlist, elt); /* and register it with server */ sendpack(s, NOTIFY_CHECK, "%s", rd); } fclose(f);}/* Get news on the client. Write it to the given fd. Used by the command /news, or on startup. This simply looks at a specific web page which is assumed to have such news. Forward compatibility is important here, thus every line of that page starts with a keyword, and we ignore lines whose keyword we don't know. Note: this function may be executed in a child process, since it does not update any state. Return 1 if there was news, 0 if there was none, and -1 on error. Return 2 if there was news, but serial!=NULL and we have seen these very news before. In case of -1, the variable *errmsg is set to a (static) error message. If fd is 1, do some special formatting, write in black and white, and send the output through wp() for the log file's benefit. If we return 1 (there is new news) and serial!=NULL and the news had a serial identifier, that identifier is returned in *serial. */int checknv(int fd, int timeout, const char **errmsg, char **serial){ FILE *f, *nfile; int relevant, news, oldnews; char *b, *c; char *nfilename; if (serial) { *serial = NULL; } f = open_url(NEWSURL, timeout, errmsg); if (!f) { return -1; } relevant = 0; news = 0; oldnews = 0; /* parse each line of the file */ while ((b = nap_getline(f)) != NULL) { if (*b == 0 || !strncmp(b, "#", 1)) { /* skip comments and blank lines */ free(b); continue; } if (serial && !strncmp(b, "SERIAL ", 7)) { /* check to see if this version of the news is old */ nfilename = home_file(OLDNEWSFILE); nfile = fopen(nfilename, "r"); free(nfilename); if (nfile) { c = nap_getline(nfile); fclose(nfile); if (c && !strcmp(b+7, c)) { oldnews = 1; } if (c) { free(c); } } if (*serial) { free(*serial); } *serial = strdup(b+7); free(b); continue; } if (!strncmp(b, "VERSION ", 8) && !strcmp(b+8, VERSION)) { relevant = 1; /* news for this client */ free(b); continue; } if (!strncmp(b, "OTHER ", 6) || !strcmp(b, "OTHER")) { relevant = 1; free(b); continue; } if (relevant && (!strcmp(b, "END") || !strncmp(b, "END ", 4))) { free(b); break; } if (relevant && !strncmp(b, "ECHO ", 5)) { if (news==0 && fd==1) { wp(NULL, "\n**********************************************************************\n"); wp(NULL, "NEWS:\n"); } if (fd==1) { wp(NULL, "%s\n", b+5); } else { ssock(fd, ""MAGENTA"* %s"WHITE"\n", b+5); } news = 1; free(b); continue; } free(b); } if (news && fd==1) { wp(NULL, "**********************************************************************\n\n"); } fclose(f); if (news && !oldnews) { return 1; } if (serial && *serial) { free(*serial); } if (news) { return 2; } return 0;} /* save channels from channel list CL to file FN. Return -1 on i/o error with errno set, else 0 */int savechans(chans_t *cl, char *fn){ chans_t *cur; FILE *f; f = fopen(fn, "w"); if (!f) { return -1; } for (cur=cl;cur;cur=cur->next) if (!cur->q) fprintf(f, "%s\n", cur->nm); fclose(f); return 0;}/* load channels from file FN and join them. Return -1 on i/o error with errno set, else 0. S is server's fd. */int loadchans(int s, char *fn){ char *line; FILE *f; f = fopen(fn, "r"); if (!f) { return -1; } while (1) { line = nap_getline(f); if (line == NULL) { break; } if (*line != 0) sendpack(s, NAP_JOIN, "%s", line); free(line); } fclose(f); return 0;}chans_t *findchan(chans_t *h, char *chan){ chans_t *cur; list_find(cur, h, !strcasecmp(cur->nm, chan)); if (cur) return cur; if (chan[0]!='#') { list_find(cur, h, cur->nm[0]=='#' && !strcasecmp(cur->nm+1, chan)); } return(cur);}chans_t *findquery(chans_t *h, char *chan){ chans_t *cur; for (cur=h;;cur=cur->next) { if (!cur) return(NULL); if (!strcasecmp(cur->nm, chan) && cur->q == 1) return(cur); }}/* for sending a packet to the napster server, whose file descriptor is s. Return -1 on error (with errno set), or else the number of bytes written. If s==-1, we print an error message and set errno to EINVAL. */int sendpack(int s, int op, const char *fmt, ...){ char *data; char *pack; /* first four bytes of pack are header, remaining is data */ int len; va_list args; int r; if (s == -1) { wp(wchan, "%s* Not connected to the server%s\n", RED, WHITE); drw(wchan); errno = EINVAL; return(-1); } if (fmt) { data = NULL; va_start(args, fmt); vasprintf(&data, fmt, args); va_end(args); } else { data = strdup(""); } len = strlen(data); pack = (char *)malloc(len+5); strcpy(pack+4, data); /* len and op are sent as little-endian, 16-bit unsigned integers */ pack[0] = 0xff & len; pack[1] = 0xff & (len>>8); pack[2] = 0xff & op; pack[3] = 0xff & (op>>8); if (nvar("debug") == 2) { wp(wchan, ""DARK GREEN"--> (0x%x=%d) <%s>"WHITE"\n", op, op, quote(pack+4)); drw(wchan); } r = send(s, pack, len+4, 0); free(pack); free(data); return(r);}/* write formatted data to file descriptor, and possibly log debugging info. Return the number of characters written, or -1 on error with errno set. */int ssock(int s, const char *fmt, ...){ char *data; va_list args; int r; data = NULL; va_start(args, fmt); vasprintf(&data, fmt, args); va_end(args); if (nvar("debug") == 2) { sock_t *sk = findsockfd(s); wp(wchan, ""DARK GREEN"--> [to %d=%s] <%s>"WHITE"\n", s, sk ? sk->socknm : "?", quote(data)); drw(wchan); } r = write(s, data, strlen(data)); free(data); return(r);}/* activate keepalive so we will know when the other side silently disappears. (MVB) */int setkeepalive(int sock){ int on = 1; return setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));}/* receive a packet from the server (at file descriptor s). Return -1 if there was an error (with errno set), or -3 if there was an unexpected end-of-file. Return -2 if only part of the packet could be read; in this case, a subsequent call to recvpack will continue to read the same packet. Return 1 on success */int recvpack(int s, char **buf, phead_t **hdr) { return recvpack_t(s, buf, hdr, -1);}/* like recvpack, except it also has a timeout (in seconds). If t=-1, no timeout. If t=0, return immediately if there is no data to read. On timeout, return -4. */int recvpack_t(int s, char **buf, phead_t **hdr, int t){ int r, i; fd_set fs; struct timeval tv; /* the following two static objects, if non-NULL, contain partial information that was read at the previous call of recvpack */ static phead_t *thdr = NULL; static unsigned char *tdbuf = NULL; static int tpos; /* how many characters in tdbuf */ /* if timeout requested, wait at most t seconds until data becomes available for reading. */ if (t>=0) { FD_ZERO(&fs); FD_SET(s, &fs); tv.tv_usec = 0; tv.tv_sec = t; r = select(s+1, &fs, NULL, NULL, &tv); if (r==-1) { return -1; } else if (r==0) { /* timeout */ return -4; } } if (!thdr) { unsigned char acc[4]; for (i=0; i<4; i+=r) { r = read(s, acc+i, 4-i); /* note that this might hang */ if (r <= 0) { *hdr = NULL; *buf = NULL; return(r==0 ? -3 : -1); } } thdr = (phead_t *)malloc(sizeof(phead_t)); /* little-endian, 16 bit unsigned integers */ thdr->len = acc[0] | (acc[1]<<8); thdr->op = acc[2] | (acc[3]<<8); } if (!thdr->len) { *hdr = thdr; *buf = strdup(""); thdr = NULL; /* print messages with length 0 */ if (nvar("debug") == 2) { wp(wchan, ""DARK GREEN"<-- (0x%x=%d) <>"WHITE"\n", (*hdr)->op, (*hdr)->op); drw(wchan); } return(1); } FD_ZERO(&fs); FD_SET(s, &fs); tv.tv_usec = 0; tv.tv_sec = 0; if (!select(s+1, &fs, NULL, NULL, &tv)) return(-2); if (!tdbuf) { tdbuf = (char *)malloc(thdr->len+1); memset(tdbuf, 0, thdr->len+1); tpos = 0; } r = read(s, tdbuf+tpos, thdr->len-tpos); if (r <= 0) { free(tdbuf); free(thdr); tdbuf = NULL; thdr = NULL; *buf = NULL; *hdr = NULL; return(r==0 ? -3 : -1); } if ((r+tpos) < thdr->len) { *buf = NULL; *hdr = NULL; tpos += r; return(-2); } *buf = tdbuf; *hdr = thdr; tdbuf = NULL; thdr = NULL; if (nvar("debug") == 2) { wp(wchan, ""DARK GREEN"<-- (0x%x=%d) <%s>"WHITE"\n", (*hdr)->op, (*hdr)->op, quote(*buf)); drw(wchan); } return(1);}/* read at most 4096 bytes from the given file descriptor. Here, the arbitrary limit (4096) is actually desirable, since we want to avoid some talkative peer monopolizing our attention. */int rsock(int s, char **buf){ int r; fd_set fs; *buf = (char *)malloc(4096+1); FD_ZERO(&fs); FD_SET(s, &fs); if (select(s+1, &fs, NULL, NULL, NULL) == -1) { free(*buf); *buf = NULL; return(-1); } if ((r = read(s, *buf, 4096)) <= 0) { free(*buf); *buf = NULL; return(-1); } (*buf)[r] = 0; /* make sure it's 0 terminated */ *buf = (char *)realloc(*buf, r+1); if (nvar("debug") == 2) { sock_t *sk = findsockfd(s); wp(wchan, ""DARK GREEN"<-- [from %d=%s] <%s>"WHITE"\n", s, sk ? sk->socknm : "?", quote(*buf)); drw(wchan); } return(r);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -