/* ** Napster Protocol */ #include "include/config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "include/gui.h" #include "include/msg.h" #include "include/napster.h" #include "include/navigator.h" #include "include/protos.h" #include "include/prefs.h" #include "include/share.h" #include "include/transfer.h" #include "include/download.h" #include "include/upload.h" #include "amster_Cat.h" #define NAP_SWAPIP(x) ( ((x&0xFF)<<24) | ((x&0xFF00)<<8) | ((x&0xFF0000)>>8) | (x>>24) ) struct Library *SocketBase=NULL; u_long nap_sigmask; long nap_sock= -1; long loc_sock= -1; char nap_host[512]; char nap_server[512+6]; int nap_state= -1; #define NAPS_OFF -1 #define NAPS_MAINCON 0 #define NAPS_MAINON 1 #define NAPS_CON 2 #define NAPS_ON 3 char nap_buffer[AMSTER_NAPBUFSIZE]; char *nap_buf = &nap_buffer[4]; char *nap_linktype[] = { (char*)_MSG_LINE_UNKNOWN, (char*)_MSG_LINE_14400, (char*)_MSG_LINE_28800, (char*)_MSG_LINE_33600, (char*)_MSG_LINE_57600, (char*)_MSG_LINE_64000, (char*)_MSG_LINE_128000, (char*)_MSG_LINE_CABLE, (char*)_MSG_LINE_DSL, (char*)_MSG_LINE_T1, (char*)_MSG_LINE_T3, NULL }; BOOL nap_logininit(void); int nap_connect(char *server); int nap_recv(u_char *buf); void nap_interpret(u_int com, char *data); void nap_parseresult(int type, char *data); char *nap_token(char **s); u_long nap_ltoken(char **str); int nap_itoken(char **str); int createlistener(void); char *getneterror(int type); void nap_login_fromlist(char *server) { if (!nap_logininit()) return; nap_state = NAPS_CON; gui_stat((char*)MSG_STATUS2_CONNECTINGTO, server); if (!nap_connect(server)) { nap_logout(); return; } } void nap_login(void) { if (!nap_logininit()) return; if (prf->server) { nap_state = NAPS_CON; gui_stat((char*)MSG_STATUS2_CONNECTINGTO, prf->server); if (!nap_connect(prf->server)) { nap_logout(); return; } } else { nap_state = NAPS_MAINCON; gui_stat((char*)MSG_STATUS2_FINDINGOPTIMAL); if (!nap_connect(prf->mainserver)) { nap_logout(); return; } } } BOOL nap_logininit(void) { gui_state(0); SocketBase = OpenLibrary("bsdsocket.library", 0); if (!SocketBase) { gui_stat((char *)MSG_NO_TCPIP); nap_logout(); return FALSE; } SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (char *)nap_sigmask, TAG_DONE); return TRUE; } void nap_logout(void) { nap_state = NAPS_OFF; if(nap_sock>=0) CloseSocket(nap_sock); nap_sock = -1; if(loc_sock>=0) CloseSocket(loc_sock); loc_sock = -1; if(SocketBase) CloseLibrary(SocketBase); SocketBase = NULL; gui_state(-1); } void nap_listen(void) { static u_char buf[AMSTER_NAPBUFSIZE]; static struct fd_set fds; static struct timeval tv; if (nap_state == NAPS_OFF) return; FD_ZERO(&fds); FD_SET(nap_sock,&fds); tv.tv_sec = 0; tv.tv_usec = 0; switch (nap_state) { case NAPS_MAINCON: if (WaitSelect(nap_sock+1,NULL,&fds,NULL,&tv,0) != 1) break; { long tmp=0; IoctlSocket(nap_sock,FIONBIO,(char*)&tmp); nap_state = NAPS_MAINON; } case NAPS_MAINON: if (WaitSelect(nap_sock+1,&fds,NULL,NULL,&tv,0) != 1) break; { int r; char *col; r = recv(nap_sock, buf, 255,0); CloseSocket(nap_sock); nap_sock = -1; if (r <= 0) { gui_stat((char *)MSG_STATUS2_CONNECTFAILED_TMP, nap_server, getneterror(Errno())); nap_logout(); return; } buf[r] = 0; col = strchr(buf, '\n'); if (col) *col=0; if (strncmp(buf,"wait",4)==0 || strncmp(buf,"busy",4)==0 || strncmp(buf,"127.0.0.1",9)==0) { /* Sometimes the server returns "127.0.0.1:1111" - quite odd. */ gui_stat((char *)MSG_INFO_SERVERBUSY); nap_logout(); return; } gui_debugf((char *)MSG_INFO_OPTIMAL, buf); gui_stat((char *)MSG_STATUS2_CONNECTINGTO, buf); if (!nap_connect(buf)) { nap_logout(); return; } nap_state = NAPS_CON; } break; case NAPS_CON: if (WaitSelect(nap_sock+1,NULL,&fds,NULL,&tv,0) != 1) break; { long tmp=0; int r = 0; IoctlSocket(nap_sock, FIONBIO, (char *)&tmp); nap_state = NAPS_ON; gui_stat((char *)MSG_STATUS2_LOGGINGINTO, nap_server); gui_state(1); DoMethod(gui->WI_Navigator, NAVI_MARKSERVER, nap_server); if (prf->regflag > 0) r = nap_sendbuf(NAPC_CREATEUSER, prf->user); /* Create user before we attempt to log in */ if (r == -1) { prf->regflag = 1; if (Errno() == EPIPE) { gui_stat((char *)MSG_STATUS2_CONNECTFAILED_TMP, nap_server, getneterror(Errno())); nap_logout(); return; } } if (prf->regflag == 1) { sprintf(nap_buf, "%s %s %d \"%s\" %d", prf->user, prf->pass, 0 /*prf->port */, prf->napvers, prf->link); } else { sprintf(nap_buf, "%s %s %d \"%s\" %d", gui->ConnectUser, gui->ConnectPw, 0 /*prf->port */, prf->napvers, prf->link); } prf->regflag = 1; nap_send(NAPC_LOGIN); } break; case NAPS_ON: while (1) { int r; FD_ZERO(&fds); FD_SET(nap_sock,&fds); tv.tv_sec=0; tv.tv_usec=0; if (WaitSelect(nap_sock+1,&fds,NULL,NULL,&tv,0) < 1) { return; } r = nap_recv(buf); if (r == -1) { gui_stat((char *)MSG_ERR_NETWORKERROR); nap_logout(); return; } if (r == 1) nap_interpret(buf[2]+(buf[3]<<8), buf+4); } } } void nap_send(u_int com) { int len; if (!gui_napon) return; /* Avoid crash - but calling functions should check this first! */ len = strlen(nap_buf); nap_buffer[0] = len&0xFF; nap_buffer[1] = (len&0xFF00)>>8; nap_buffer[2] = com&0xFF; nap_buffer[3] = (com&0xFF00)>>8; send(nap_sock,nap_buffer,4+len,0); } int nap_sendbuf(u_int com, char *buf) { static u_char hdr[4]; int len, r; if (!gui_napon) return -1; /* Avoid crash - but calling functions should check this first! */ len = strlen(buf); hdr[0] = len&0xFF; hdr[1] = (len&0xFF00)>>8; hdr[2] = com&0xFF; hdr[3] = (com&0xFF00)>>8; r = send(nap_sock, hdr, 4, 0); if (r <= 0) return r; r = send(nap_sock, buf, len, 0); if (r <= 0) return r; else return 0; } void nap_songfree(song s) { if (!s) return; if (s->title) free(s->title); if (s->md5) free(s->md5); if (s->user) free(s->user); free(s); } song nap_songdup(song s) { song sn; sn = malloc(sizeof(_song)); if (!sn) return(NULL); memset(sn,0,sizeof(_song)); sn->title = strdup(s->title); sn->md5 = strdup(s->md5); sn->size = s->size; sn->bit = s->bit; sn->freq = s->freq; sn->time = s->time; sn->user = strdup(s->user); sn->ip = s->ip; sn->link = s->link; if (!sn->title || !sn->md5 || !sn->user) { nap_songfree(sn); return(NULL); } return(sn); } char *nap_strippath(char *name) { int i; char tmp; for (i=strlen(name)-1; i>=0; i--) { tmp = name[i]; if (tmp==':' || tmp=='/' || tmp=='\\') return(name+i+1); } return(name); } /* private functions */ int nap_connect(char *server) { struct hostent *host; struct sockaddr_in sin; long tmp=1; char *addr, *col; int port = 0; addr = strdup(server); col = strtok(addr, ":"); if (col) col = strtok(NULL,""); if (col) port = atoi(col); if (!port) { gui_stat((char *)MSG_INFO_PORTNEEDED); free(addr); return(0); } host = gethostbyname(addr); free(addr); if (!host) { gui_stat((char *)MSG_ERR_LOOKUPFAILED); return(0); } memcpy(&sin.sin_addr, host->h_addr, host->h_length); sin.sin_family = host->h_addrtype; sin.sin_port = port; sin.sin_len = sizeof(sin); strcpy(nap_host, host->h_name); strcpy(nap_server, server); nap_sock = socket(AF_INET,SOCK_STREAM,0); if (nap_sock<0) { gui_debug((char *)MSG_ERR_SOCKETERROR); return(0); } IoctlSocket(nap_sock,FIOASYNC,(char *)&tmp); IoctlSocket(nap_sock,FIONBIO,(char *)&tmp); tmp = connect(nap_sock, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)); if(tmp != -1) return(1); if(Errno()==EINPROGRESS) return(1); gui_stat((char *)MSG_STATUS2_CONNECTFAILED_TMP, nap_host, getneterror(Errno())); return(0); } int nap_recv(u_char *buf) { static u_int blen=0; u_int len=4; int ret; if (blen>=4) { len = buf[0] + (buf[1]<<8) + 4; if (len==0) { buf[blen] = 0; blen = 0; return(1); } } ret = recv(nap_sock, buf+blen, len-blen,0); if (ret<=0) { blen = 0; return(-1); } blen += ret; if (blen==4) { len = buf[0] + (buf[1]<<8) + 4; if (len==0) { buf[blen] = 0; blen = 0; return(1); } } if(blen==len) { buf[blen] = 0; blen = 0; return(1); } return(0); } void nap_interpret(u_int com, char *data) { switch(com) { case NAPC_PUBLICMSGRECV: case NAPC_JOINACK: case NAPC_JOINMSG: case NAPC_USERPART: case NAPC_USERLIST: case NAPC_USERLISTEND: case NAPC_CHANNELTOPIC: chat_interpret(com, data); break; case NAPC_LOGINERROR: gui_debugf("\33bLogin error:\33n %s\n", data); break; case NAPC_REGSUCCESS: gui_debug((char *)MSG_INFO_REGSUCCESS); break; case NAPC_REGUSED: gui_debug((char *)MSG_INFO_REGUSED); break; case NAPC_SEARCHRESULT: nap_parseresult(0,data); break; case NAPC_SEARCHCOMPLETE: gui_found(NULL); break; case NAPC_BROWSERESULT: nap_parseresult(1,data); break; case NAPC_BROWSECOMPLETE: gui_found(NULL); break; case NAPC_FILECOUNT: { int a,b,c; a = nap_itoken(&data); b = nap_itoken(&data); c = nap_itoken(&data); gui_srvstat(a,b,c); break; } case NAPC_PRIVATEMSG: { char *nick, *msg; nick = nap_token(&data); msg = nick + strlen(nick) + 1; msg_got(nick, msg); break; } case NAPC_FILEINFO: { char *title,*user; u_long ip; int port; user = nap_token(&data); ip = nap_ltoken(&data); port = nap_itoken(&data); title = nap_token(&data); dl_startq(title, user, NAP_SWAPIP(ip), port); } break; case NAPC_LOGINRESP: DoMethod(gui->shwin, SHARE_NOTIFYALL); gui_state(2); break; case NAPC_WHOISRESP: msg_gotwhois(data); break; case NAPC_WHOWASRESP: { char *user, *level; u_long lastseen; user = nap_token(&data); level = nap_token(&data); lastseen = nap_ltoken(&data); DoMethod(gui->mwin, MSG_WHOWAS, user, level, lastseen); } break; case NAPC_UPLOADREQ: { char *user,*fname; user = nap_token(&data); fname = nap_token(&data); upload_req(user,fname); } break; case NAPC_ALTDLACK: { char *nick, *fname, *md5; u_long ip; int port, speed; nick = nap_token(&data); ip = nap_ltoken(&data); port = nap_itoken(&data); fname = nap_token(&data); md5 = nap_token(&data); speed = nap_itoken(&data); ul_startq(fname, nick, NAP_SWAPIP(ip), port, speed); } break; case NAPC_REMOTEQUEUEFULL: { char *nick, *fname; int size, limit; nick = nap_token(&data); fname = nap_token(&data); size = nap_itoken(&data); limit = nap_itoken(&data); DoMethod(gui->dwin, DL_RETRY, fname, nick, limit); } break; case NAPC_GETERROR: { char *user,*fname; user = nap_token(&data); fname = nap_token(&data); DoMethod(gui->dwin, DL_SETERROR, fname, user, ERROR_LOGGEDOUT); } break; case NAPC_GENERALERROR: gui_debugf("\33bError:\33n %s\n", data); break; case NAPC_SYSMSG: gui_debug(data); break; case NAPC_GLOBALMSG: { char *nick, *text, buf[50]; nick = nap_token(&data); text = nick+strlen(nick)+1; sprintf(buf, MSG_GLOBALMESSAGE_TITLE, nick); MUI_Request(gui->app, gui->win, 0L, buf, (char *)MSG_OK_GAD, text); } break; default: gui_debugf("<<%d:%s>>",com,data); } } void nap_parseresult(int type, char *data) { song s; char *tmp=data; s = malloc(sizeof(_song)); if(!s) return; memset(s,0,sizeof(_song)); switch(type) { case 0: s->title = strdup(nap_token(&tmp)); s->md5 = strdup(nap_token(&tmp)); strtok(s->md5,"-"); s->size = nap_ltoken(&tmp); s->bit = nap_itoken(&tmp); s->freq = nap_itoken(&tmp); s->time = nap_itoken(&tmp); s->user = strdup(nap_token(&tmp)); s->ip = nap_ltoken(&tmp); s->ip = NAP_SWAPIP(s->ip); s->link = nap_itoken(&tmp); break; case 1: s->user = strdup(nap_token(&tmp)); s->title = strdup(nap_token(&tmp)); s->md5 = strdup(nap_token(&tmp)); strtok(s->md5,"-"); s->size = nap_ltoken(&tmp); s->bit = nap_itoken(&tmp); s->freq = nap_itoken(&tmp); s->time = nap_itoken(&tmp); break; } if (!s->user || !s->title || !s->md5) { nap_songfree(s); return; } gui_found(s); } u_long nap_ltoken(char **str) { char *t; t = nap_token(str); if(!t) return(0); return((u_long)atol(t)); } int nap_itoken(char **str) { char *t; t = nap_token(str); if(!t) return(0); return(atoi(t)); } char *nap_token(char **str) { int sf=0,i,len=0; char c, *t=NULL; if (!*str) return(NULL); for (i=0; ; i++) { c = *(*str + i); switch (c) { case '\0': *str = NULL; if (len==0 || sf) return(NULL); return(t); case '"': if (sf) { *(*str+i) = 0; *str = *str+i+1; return(t); } sf=1; break; case ' ': if (len==0) break; if (!sf) { *(*str+i) = 0; *str = *str+i+1; return(t); } break; default: if (!t) t=*str+i; len++; } } } /* int createlistener(void) { struct sockaddr_in server; if (loc_sock != -1) return 1; loc_sock = socket(AF_INET, SOCK_STREAM, 0); if (loc_sock < 0) { gui_debug("Error creating listener socket!\n"); return 0; } server.sin_family = AF_INET; server.sin_addr.s_addr = htonl(INADDR_ANY); server.sin_port = htons(prf->port); if (bind(loc_sock, (struct sockaddr *)&server, sizeof(server)) < 0) { gui_debug("Error binding listening socket\n"); CloseSocket(loc_sock); loc_sock = -1; return 0; } listen(loc_sock, 0); / Number of allowed connections / return 1; } */ char *getneterror(int type) { char *message, buf[512]; switch (type) { case ENETDOWN: message = (char *)MSG_NETERROR_ENETDOWN; break; case ENETUNREACH: message = (char *)MSG_NETERROR_ENETUNREACH; break; case ECONNRESET: message = (char *)MSG_NETERROR_ECONNRESET; break; case ETIMEDOUT: message = (char *)MSG_NETERROR_ETIMEDOUT; break; case ECONNREFUSED: message = (char *)MSG_NETERROR_ECONNREFUSED; break; case EPIPE: message = (char *)MSG_NETERROR_EPIPE; break; default: sprintf(buf, MSG_NETERROR_UNKNOWN, type); message = buf; } return message; }